Respect add mailaccount perms

This commit is contained in:
shamoon 2024-10-07 12:51:07 -07:00
parent 92b03745aa
commit 947245a930
3 changed files with 71 additions and 25 deletions

View File

@ -14,12 +14,12 @@
<i-bs name="plus-circle"></i-bs>&nbsp;<ng-container i18n>Add Account</ng-container> <i-bs name="plus-circle"></i-bs>&nbsp;<ng-container i18n>Add Account</ng-container>
</button> </button>
@if (gmailOAuthUrl) { @if (gmailOAuthUrl) {
<a class="btn btn-sm btn-outline-secondary ms-2" [href]="gmailOAuthUrl"> <a class="btn btn-sm btn-outline-secondary ms-2" [href]="gmailOAuthUrl" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.MailAccount }">
<i-bs name="google"></i-bs>&nbsp;<ng-container i18n>Connect Gmail Account</ng-container> <i-bs name="google"></i-bs>&nbsp;<ng-container i18n>Connect Gmail Account</ng-container>
</a> </a>
} }
@if (outlookOAuthUrl) { @if (outlookOAuthUrl) {
<a class="btn btn-sm btn-outline-secondary ms-2" [href]="outlookOAuthUrl"> <a class="btn btn-sm btn-outline-secondary ms-2" [href]="outlookOAuthUrl" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.MailAccount }">
<i-bs name="microsoft"></i-bs>&nbsp;<ng-container i18n>Connect Outlook Account</ng-container> <i-bs name="microsoft"></i-bs>&nbsp;<ng-container i18n>Connect Outlook Account</ng-container>
</a> </a>
} }

View File

@ -2,6 +2,7 @@ from datetime import timedelta
from unittest import mock from unittest import mock
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.test import TestCase from django.test import TestCase
from django.test import override_settings from django.test import override_settings
@ -20,6 +21,14 @@ class TestMailOAuth(
): ):
def setUp(self) -> None: def setUp(self) -> None:
self.user = User.objects.create_user("testuser") self.user = User.objects.create_user("testuser")
self.user.user_permissions.add(
*Permission.objects.filter(
codename__in=[
"add_mailaccount",
],
),
)
self.user.save()
self.client.force_login(self.user) self.client.force_login(self.user)
self.mail_account_handler = MailAccountHandler() self.mail_account_handler = MailAccountHandler()
# Mock settings # Mock settings
@ -82,7 +91,7 @@ class TestMailOAuth(
@mock.patch( @mock.patch(
"paperless_mail.oauth.PaperlessMailOAuth2Manager.get_outlook_access_token", "paperless_mail.oauth.PaperlessMailOAuth2Manager.get_outlook_access_token",
) )
def test_oauth_callback_view( def test_oauth_callback_view_success(
self, self,
mock_get_outlook_access_token, mock_get_outlook_access_token,
mock_get_gmail_access_token, mock_get_gmail_access_token,
@ -128,29 +137,8 @@ class TestMailOAuth(
MailAccount.objects.filter(imap_server="outlook.office365.com").exists(), MailAccount.objects.filter(imap_server="outlook.office365.com").exists(),
) )
def test_oauth_callback_view_no_code(self):
"""
GIVEN:
- Mocked settings for Gmail and Outlook OAuth client IDs and secrets
WHEN:
- OAuth callback is called without a code
THEN:
- 400 bad request returned, no mail accounts are created
"""
response = self.client.get(
"/api/oauth/callback/",
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertFalse(
MailAccount.objects.filter(imap_server="imap.gmail.com").exists(),
)
self.assertFalse(
MailAccount.objects.filter(imap_server="outlook.office365.com").exists(),
)
@mock.patch("httpx_oauth.oauth2.BaseOAuth2.get_access_token") @mock.patch("httpx_oauth.oauth2.BaseOAuth2.get_access_token")
def test_oauth_callback_view_error(self, mock_get_access_token): def test_oauth_callback_view_fails(self, mock_get_access_token):
""" """
GIVEN: GIVEN:
- Mocked settings for Gmail and Outlook OAuth client IDs and secrets - Mocked settings for Gmail and Outlook OAuth client IDs and secrets
@ -185,6 +173,57 @@ class TestMailOAuth(
self.assertIn("Error getting access token: test_error", cm.output[0]) self.assertIn("Error getting access token: test_error", cm.output[0])
def test_oauth_callback_view_insufficient_permissions(self):
"""
GIVEN:
- Mocked settings for Gmail and Outlook OAuth client IDs and secrets
- User without add_mailaccount permission
WHEN:
- OAuth callback is called
THEN:
- 400 bad request returned, no mail accounts are created
"""
self.user.user_permissions.remove(
*Permission.objects.filter(
codename__in=[
"add_mailaccount",
],
),
)
self.user.save()
response = self.client.get(
"/api/oauth/callback/?code=test_code&scope=https://mail.google.com/",
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertFalse(
MailAccount.objects.filter(imap_server="imap.gmail.com").exists(),
)
self.assertFalse(
MailAccount.objects.filter(imap_server="outlook.office365.com").exists(),
)
def test_oauth_callback_view_no_code(self):
"""
GIVEN:
- Mocked settings for Gmail and Outlook OAuth client IDs and secrets
WHEN:
- OAuth callback is called without a code
THEN:
- 400 bad request returned, no mail accounts are created
"""
response = self.client.get(
"/api/oauth/callback/",
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertFalse(
MailAccount.objects.filter(imap_server="imap.gmail.com").exists(),
)
self.assertFalse(
MailAccount.objects.filter(imap_server="outlook.office365.com").exists(),
)
@mock.patch("paperless_mail.mail.get_mailbox") @mock.patch("paperless_mail.mail.get_mailbox")
@mock.patch( @mock.patch(
"httpx_oauth.oauth2.BaseOAuth2.refresh_token", "httpx_oauth.oauth2.BaseOAuth2.refresh_token",

View File

@ -99,6 +99,13 @@ class OauthCallbackView(GenericAPIView):
permission_classes = (IsAuthenticated,) permission_classes = (IsAuthenticated,)
def get(self, request, format=None): def get(self, request, format=None):
if not (
request.user and request.user.has_perms(["paperless_mail.add_mailaccount"])
):
return HttpResponseBadRequest(
"You do not have permission to add mail accounts",
)
logger = logging.getLogger("paperless_mail") logger = logging.getLogger("paperless_mail")
code = request.query_params.get("code") code = request.query_params.get("code")
# Gmail passes scope as a query param, Outlook does not # Gmail passes scope as a query param, Outlook does not