Testing to whether a user can attach/unattach is now deferred to the model.

This commit is contained in:
Michael DeHaan
2013-03-23 14:31:36 -04:00
parent 4e7827829f
commit 0c9aa1a498
4 changed files with 42 additions and 12 deletions

View File

@@ -22,7 +22,7 @@ class BaseList(generics.ListCreateAPIView):
if request.method == 'GET': if request.method == 'GET':
return True return True
if request.method == 'POST': if request.method == 'POST':
return False return self.__class__.model.can_user_add(request.user)
raise exceptions.NotImplementedError raise exceptions.NotImplementedError
def get_queryset(self): def get_queryset(self):
@@ -32,6 +32,16 @@ class BaseSubList(BaseList):
''' used for subcollections with an overriden post ''' ''' 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): def post(self, request, *args, **kwargs):
parent_id = kwargs['pk'] parent_id = kwargs['pk']

View File

@@ -44,17 +44,24 @@ class CommonModel(models.Model):
def can_user_read(cls, user, obj): def can_user_read(cls, user, obj):
raise exceptions.NotImplementedError() raise exceptions.NotImplementedError()
@classmethod
def can_user_add(cls, user):
return user.is_superuser
@classmethod @classmethod
def can_user_attach(cls, user, obj, sub_obj, relationship): 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 ''' ''' whether you can add sub_obj to obj using the relationship type in a subobject view '''
if relationship in [ 'projects', 'admins', 'users' ]: if relationship in [ 'projects', 'admins', 'users' ]:
if not sub_obj.can_user_read(user, sub_obj): if not sub_obj.can_user_read(user, sub_obj):
print "DEBUG: can't attach"
return False return False
print "DEBUG: defer"
return cls.can_user_administrate(user, obj) return cls.can_user_administrate(user, obj)
raise Exception("unknown relationship type: %s" % relationship) raise Exception("unknown relationship type: %s" % relationship)
@classmethod @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) return cls.can_user_administrate(user, obj)
class Tag(models.Model): class Tag(models.Model):

View File

@@ -13,6 +13,7 @@ class CustomRbac(permissions.BasePermission):
# no anonymous users # no anonymous users
if request.user.is_anonymous(): if request.user.is_anonymous():
# 401, not 403, hence no raised exception # 401, not 403, hence no raised exception
print "PD4"
return False return False
# superusers are always good # superusers are always good
if request.user.is_superuser: if request.user.is_superuser:
@@ -30,6 +31,7 @@ class CustomRbac(permissions.BasePermission):
if request.user.is_superuser: if request.user.is_superuser:
return True return True
if not view.list_permissions_check(request): if not view.list_permissions_check(request):
print "DEBUG: PD1"
raise PermissionDenied() raise PermissionDenied()
elif not getattr(view, 'item_permissions_check', None): elif not getattr(view, 'item_permissions_check', None):
raise Exception("internal error, list_permissions_check or item_permissions_check must be defined") 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: if request.user.is_superuser:
return True return True
if not self._common_user_check(request): if not self._common_user_check(request):
print "DEBUG: PD2"
return False return False
if not obj.active: if not obj.active:
raise Http404() raise Http404()
if not view.item_permissions_check(request, obj): if not view.item_permissions_check(request, obj):
print "DEBUG: PD3"
raise PermissionDenied() raise PermissionDenied()
return True return True

View File

@@ -273,33 +273,42 @@ class OrganizationsTest(BaseTest):
# find projects attached to the first org # find projects attached to the first org
projects0_url = orgs['results'][0]['related']['projects'] 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 # get all the projects on the first org
projects0 = self.get(projects0_url, expect=200, auth=self.get_super_credentials()) projects0 = self.get(projects0_url, expect=200, auth=self.get_super_credentials())
a_project = projects0['results'][-1] a_project = projects0['results'][-1]
# attempt to add the project to the 7th org and see what happens # 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()) projects1 = self.get(projects0_url, expect=200, auth=self.get_super_credentials())
self.assertEquals(projects1['count'], 3) self.assertEquals(projects1['count'], 3)
# make sure we can't add the project again (should generate a conflict error) # 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()) self.post(projects1_url, a_project, expect=409, auth=self.get_super_credentials())
projects7 = self.get(projects7_url, expect=200, auth=self.get_super_credentials()) projects1 = self.get(projects1_url, expect=200, auth=self.get_super_credentials())
self.assertEquals(projects7['count'], 6) self.assertEquals(projects1['count'], 6)
# make sure adding a project that does not exist, or a missing pk field, results in a 400 # 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(projects1_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(asdf=1234), expect=400, auth=self.get_super_credentials())
# test that by posting a pk + disassociate: True we can remove a relationship # test that by posting a pk + disassociate: True we can remove a relationship
a_project['disassociate'] = True a_project['disassociate'] = True
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())
projects7 = self.get(projects7_url, expect=200, auth=self.get_super_credentials()) projects1 = self.get(projects1_url, expect=200, auth=self.get_super_credentials())
self.assertEquals(projects7['count'], 5) self.assertEquals(projects1['count'], 5)
# FIXME: need to add tests for associating and disassocating from a non-priveledged acct # 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): def test_post_item_subobjects_users(self):
pass pass