diff --git a/lib/main/base_views.py b/lib/main/base_views.py index 0e07858ff5..885ccecfca 100644 --- a/lib/main/base_views.py +++ b/lib/main/base_views.py @@ -22,7 +22,7 @@ class BaseList(generics.ListCreateAPIView): if request.method == 'GET': return True if request.method == 'POST': - return False + return self.__class__.model.can_user_add(request.user) raise exceptions.NotImplementedError def get_queryset(self): @@ -32,6 +32,16 @@ class BaseSubList(BaseList): ''' used for subcollections with an overriden post ''' + def list_permissions_check(self, request, obj=None): + ''' determines some early yes/no access decisions, pre-filtering ''' + if request.method == 'GET': + return True + if request.method == 'POST': + # the can_user_attach methods will be called below + return True + raise exceptions.NotImplementedError + + def post(self, request, *args, **kwargs): parent_id = kwargs['pk'] diff --git a/lib/main/models/__init__.py b/lib/main/models/__init__.py index 51e247a53a..da31c9a5dd 100644 --- a/lib/main/models/__init__.py +++ b/lib/main/models/__init__.py @@ -44,17 +44,24 @@ class CommonModel(models.Model): def can_user_read(cls, user, obj): raise exceptions.NotImplementedError() + @classmethod + def can_user_add(cls, user): + return user.is_superuser + @classmethod def can_user_attach(cls, user, obj, sub_obj, relationship): ''' whether you can add sub_obj to obj using the relationship type in a subobject view ''' if relationship in [ 'projects', 'admins', 'users' ]: if not sub_obj.can_user_read(user, sub_obj): + print "DEBUG: can't attach" return False + print "DEBUG: defer" return cls.can_user_administrate(user, obj) raise Exception("unknown relationship type: %s" % relationship) @classmethod - def can_user_unattach(cls, user, obj, relationship): + def can_user_unattach(cls, user, obj, sub_obj, relationship): + print "DEBUG: CUA?" return cls.can_user_administrate(user, obj) class Tag(models.Model): diff --git a/lib/main/rbac.py b/lib/main/rbac.py index 2c44badb01..afba9318fb 100644 --- a/lib/main/rbac.py +++ b/lib/main/rbac.py @@ -13,6 +13,7 @@ class CustomRbac(permissions.BasePermission): # no anonymous users if request.user.is_anonymous(): # 401, not 403, hence no raised exception + print "PD4" return False # superusers are always good if request.user.is_superuser: @@ -30,6 +31,7 @@ class CustomRbac(permissions.BasePermission): if request.user.is_superuser: return True if not view.list_permissions_check(request): + print "DEBUG: PD1" raise PermissionDenied() elif not getattr(view, 'item_permissions_check', None): raise Exception("internal error, list_permissions_check or item_permissions_check must be defined") @@ -42,9 +44,11 @@ class CustomRbac(permissions.BasePermission): if request.user.is_superuser: return True if not self._common_user_check(request): + print "DEBUG: PD2" return False if not obj.active: raise Http404() if not view.item_permissions_check(request, obj): + print "DEBUG: PD3" raise PermissionDenied() return True diff --git a/lib/main/tests.py b/lib/main/tests.py index f4a9fcb214..56998b723f 100644 --- a/lib/main/tests.py +++ b/lib/main/tests.py @@ -273,33 +273,42 @@ class OrganizationsTest(BaseTest): # find projects attached to the first org projects0_url = orgs['results'][0]['related']['projects'] - projects7_url = orgs['results'][1]['related']['projects'] + projects1_url = orgs['results'][1]['related']['projects'] # get all the projects on the first org projects0 = self.get(projects0_url, expect=200, auth=self.get_super_credentials()) a_project = projects0['results'][-1] # attempt to add the project to the 7th org and see what happens - self.post(projects7_url, a_project, expect=204, auth=self.get_super_credentials()) + self.post(projects1_url, a_project, expect=204, auth=self.get_super_credentials()) projects1 = self.get(projects0_url, expect=200, auth=self.get_super_credentials()) self.assertEquals(projects1['count'], 3) # make sure we can't add the project again (should generate a conflict error) - self.post(projects7_url, a_project, expect=409, auth=self.get_super_credentials()) - projects7 = self.get(projects7_url, expect=200, auth=self.get_super_credentials()) - self.assertEquals(projects7['count'], 6) + self.post(projects1_url, a_project, expect=409, auth=self.get_super_credentials()) + projects1 = self.get(projects1_url, expect=200, auth=self.get_super_credentials()) + self.assertEquals(projects1['count'], 6) # make sure adding a project that does not exist, or a missing pk field, results in a 400 - self.post(projects7_url, dict(id=99999), expect=400, auth=self.get_super_credentials()) - self.post(projects7_url, dict(asdf=1234), expect=400, auth=self.get_super_credentials()) + self.post(projects1_url, dict(id=99999), expect=400, auth=self.get_super_credentials()) + self.post(projects1_url, dict(asdf=1234), expect=400, auth=self.get_super_credentials()) # test that by posting a pk + disassociate: True we can remove a relationship a_project['disassociate'] = True - self.post(projects7_url, a_project, expect=204, auth=self.get_super_credentials()) - projects7 = self.get(projects7_url, expect=200, auth=self.get_super_credentials()) - self.assertEquals(projects7['count'], 5) + self.post(projects1_url, a_project, expect=204, auth=self.get_super_credentials()) + projects1 = self.get(projects1_url, expect=200, auth=self.get_super_credentials()) + self.assertEquals(projects1['count'], 5) # FIXME: need to add tests for associating and disassocating from a non-priveledged acct + print projects1_url + a_project = projects1['results'][-1] + a_project['disassociate'] = 1 + projects1 = self.get(projects1_url, expect=200, auth=self.get_super_credentials()) + print "GOT: %s" % projects1 + print "POSTING: %s" % a_project + self.post(projects1_url, a_project, expect=204, auth=self.get_normal_credentials()) + projects1 = self.get(projects1_url, expect=200, auth=self.get_super_credentials()) + self.assertEquals(projects1['count'], 4) def test_post_item_subobjects_users(self): pass