diff --git a/src/postorius/auth/decorators.py b/src/postorius/auth/decorators.py index cc8f130..091aea4 100644 --- a/src/postorius/auth/decorators.py +++ b/src/postorius/auth/decorators.py @@ -37,7 +37,28 @@ if user.is_superuser: return fn(*args, **kwargs) mlist = List.objects.get_or_404(fqdn_listname=fqdn_listname) - if user.email not in mlist.members: + if user.email not in mlist.owners: + raise PermissionDenied + else: + return fn(*args, **kwargs) + return wrapper + + +def list_moderator_required(fn): + """Check if the logged in user is a moderator of the given list. + Assumes that the request object is the first arg and that fqdn_listname + is present in kwargs. + """ + def wrapper(*args, **kwargs): + user = args[0].user + fqdn_listname = kwargs['fqdn_listname'] + if not user.is_authenticated(): + raise PermissionDenied + if user.is_superuser: + return fn(*args, **kwargs) + mlist = List.objects.get_or_404(fqdn_listname=fqdn_listname) + if user.email not in mlist.moderators and \ + user.email not in mlist.owners: raise PermissionDenied else: return fn(*args, **kwargs) diff --git a/src/postorius/tests/test_auth_decorators.py b/src/postorius/tests/test_auth_decorators.py index 7a358dc..030b592 100644 --- a/src/postorius/tests/test_auth_decorators.py +++ b/src/postorius/tests/test_auth_decorators.py @@ -20,7 +20,8 @@ from django.utils import unittest from mock import patch -from postorius.auth.decorators import list_owner_required +from postorius.auth.decorators import (list_owner_required, + list_moderator_required) from postorius.models import (Domain, List, Member, MailmanUser, MailmanApiError, Mailman404Error) from mailman.client import Client @@ -31,6 +32,11 @@ return True +@list_moderator_required +def dummy_function_mod_req(request, fqdn_listname): + return True + + class ListOwnerRequiredTest(unittest.TestCase): """Tests the list_owner_required auth decorator.""" @@ -69,9 +75,9 @@ @patch.object(Client, 'get_list') def test_non_list_owner(self, mock_get_list): - """Should raise PermissionDenied user is not a list owner.""" + """Should raise PermissionDenied if user is not a list owner.""" # prepare mock list object - self.mock_list.members = ['geddy@rush.it'] + self.mock_list.owners = ['geddy@rush.it'] mock_get_list.return_value = self.mock_list # prepare request request = self.request_factory.get('/lists/foolist@example.org/' @@ -82,10 +88,10 @@ fqdn_listname='foolist@example.org') @patch.object(Client, 'get_list') - def test_non_list_owner(self, mock_get_list): - """Should raise PermissionDenied user is not a list owner.""" + def test_list_owner(self, mock_get_list): + """Should return fn return value if user is the list owner.""" # prepare mock list object - self.mock_list.members = ['les@primus.org'] + self.mock_list.owners = ['les@primus.org'] mock_get_list.return_value = self.mock_list # prepare request request = self.request_factory.get('/lists/foolist@example.org/' @@ -95,3 +101,84 @@ return_value = dummy_function(request, fqdn_listname='foolist@example.org') self.assertEqual(return_value, True) + + +class ListModeratorRequiredTest(unittest.TestCase): + """Tests the list_owner_required auth decorator.""" + + def setUp(self): + from django.test.client import RequestFactory + from postorius.tests.utils import create_mock_list + self.request_factory = RequestFactory() + # create a mock list with members + list_name = 'foolist@example.org' + list_id = 'foolist.example.org' + self.mock_list = create_mock_list(dict( + fqdn_listname=list_name, + list_id=list_id)) + + @patch.object(Client, 'get_list') + def test_not_authenticated(self, mock_get_list): + """Should raise PermissionDenied if user is not authenticated.""" + mock_get_list.return_value = self.mock_list + request = self.request_factory.get('/lists/foolist@example.org/' + 'settings/') + request.user = AnonymousUser() + self.assertRaises(PermissionDenied, dummy_function_mod_req, request, + fqdn_listname='foolist@example.org') + + @patch.object(Client, 'get_list') + def test_superuser(self, mock_get_list): + """Should call the dummy method, if user is superuser.""" + mock_get_list.return_value = self.mock_list + request = self.request_factory.get('/lists/foolist@example.org/' + 'settings/') + request.user = User.objects.create_superuser('su2', 'su@sodo.org', + 'pwd') + return_value = dummy_function_mod_req(request, + fqdn_listname='foolist@example.org') + self.assertEqual(return_value, True) + + @patch.object(Client, 'get_list') + def test_non_list_moderator(self, mock_get_list): + """Should raise PermissionDenied if user is not a list owner.""" + # prepare mock list object + self.mock_list.moderators = ['geddy@rush.it'] + mock_get_list.return_value = self.mock_list + # prepare request + request = self.request_factory.get('/lists/foolist@example.org/' + 'settings/') + request.user = User.objects.create_user('les cl2', 'les@primus.org', + 'pwd') + self.assertRaises(PermissionDenied, dummy_function_mod_req, request, + fqdn_listname='foolist@example.org') + + @patch.object(Client, 'get_list') + def test_list_owner(self, mock_get_list): + """Should return fn return value if user is the list owner.""" + # prepare mock list object + self.mock_list.owners = ['les@primus.org'] + mock_get_list.return_value = self.mock_list + # prepare request + request = self.request_factory.get('/lists/foolist@example.org/' + 'settings/') + request.user = User.objects.create_user('les cl3', 'les@primus.org', + 'pwd') + return_value = dummy_function_mod_req(request, + fqdn_listname='foolist@example.org') + self.assertEqual(return_value, True) + + @patch.object(Client, 'get_list') + def test_list_moderator(self, mock_get_list): + """Should return fn return value if user is the list moderator.""" + # prepare mock list object + self.mock_list.moderators = ['les@primus.org'] + mock_get_list.return_value = self.mock_list + # prepare request + request = self.request_factory.get('/lists/foolist@example.org/' + 'settings/') + request.user = User.objects.create_user('les cl4', 'les@primus.org', + 'pwd') + return_value = dummy_function_mod_req(request, + fqdn_listname='foolist@example.org') + self.assertEqual(return_value, True)