From 9057d3c481cf03bc00c2eaf0771e6a04c30ac348 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 27 Jan 2012 11:11:05 -0400 Subject: [PATCH 1/2] Add actor membership access checking --- apps/acls/managers.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/acls/managers.py b/apps/acls/managers.py index 1fe21cf231..384c01b504 100644 --- a/apps/acls/managers.py +++ b/apps/acls/managers.py @@ -11,7 +11,7 @@ from django.core.exceptions import PermissionDenied from django.core.urlresolvers import reverse from common.models import AnonymousUserSingleton -from permissions.models import Permission +from permissions.models import Permission, RoleMember from .classes import (EncapsulatedObject, AccessHolder, ClassAccessHolder, get_source_object) @@ -61,6 +61,7 @@ class AccessEntryManager(models.Manager): access_entry.delete() return True + def has_access(self, permission, actor, obj, db_only=False): """ Returns whether an actor has a specific permission for an object @@ -69,6 +70,8 @@ class AccessEntryManager(models.Manager): actor = get_source_object(actor) if isinstance(actor, User) and db_only == False: + # db_only causes the return of only the stored permissions + # and not the perceived permissions for an actor if actor.is_superuser or actor.is_staff: return True @@ -83,6 +86,20 @@ class AccessEntryManager(models.Manager): object_id=obj.pk ) except self.model.DoesNotExist: + # If not check if the actor's memberships is one of + # the access's holder? + roles = RoleMember.objects.get_roles_for_member(actor) + + if isinstance(actor, User): + groups = actor.groups.all() + else: + groups = [] + + for membership in list(set(roles) | set(groups)): + if self.has_access(permission, membership, obj, db_only): + return True + + logger.debug('Fallthru') return False else: return True From 9d52ce6683255f45615a6a6406b188f4f13ae078 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 27 Jan 2012 15:54:05 -0400 Subject: [PATCH 2/2] Add object_list/queryset ACL inheritance --- apps/acls/managers.py | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/apps/acls/managers.py b/apps/acls/managers.py index 384c01b504..66991003d2 100644 --- a/apps/acls/managers.py +++ b/apps/acls/managers.py @@ -9,6 +9,7 @@ from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied from django.core.urlresolvers import reverse +from django.db.models import Q from common.models import AnonymousUserSingleton from permissions.models import Permission, RoleMember @@ -132,15 +133,48 @@ class AccessEntryManager(models.Manager): actor = AnonymousUserSingleton.objects.passthru_check(actor) actor_type = ContentType.objects.get_for_model(actor) content_type = ContentType.objects.get_for_model(cls) + + # Calculate actor role membership ACL query + total_queries = None + for role in RoleMember.objects.get_roles_for_member(actor): + role_type = ContentType.objects.get_for_model(role) + if related: + query = Q(holder_type=role_type, holder_id=role.pk, permission=permission.get_stored_permission) + else: + query = Q(holder_type=role_type, holder_id=role.pk, content_type=content_type, permission=permission.get_stored_permission) + if total_queries is None: + total_queries = query + else: + total_queries = total_queries | query + + # Calculate actor group membership ACL query + if isinstance(actor, User): + groups = actor.groups.all() + else: + groups = [] + + for group in groups: + group_type = ContentType.objects.get_for_model(group) + if related: + query = Q(holder_type=group_type, holder_id=group.pk, permission=permission.get_stored_permission) + else: + query = Q(holder_type=group_type, holder_id=group.pk, content_type=content_type, permission=permission.get_stored_permission) + if total_queries is None: + total_queries = query + else: + total_queries = total_queries | query + if related: - master_list = [obj.content_object for obj in self.model.objects.select_related().filter(holder_type=actor_type, holder_id=actor.pk, permission=permission.get_stored_permission)] + actor_query = Q(holder_type=actor_type, holder_id=actor.pk, permission=permission.get_stored_permission) + master_list = [obj.content_object for obj in self.model.objects.select_related().filter(actor_query | total_queries)] logger.debug('master_list: %s' % master_list) # TODO: update to use Q objects and check performance diff # kwargs = {'%s__in' % related: master_list} # Q(**kwargs) return (obj for obj in cls.objects.all() if getattr(obj, related) in master_list) else: - return (obj.content_object for obj in self.model.objects.filter(holder_type=actor_type, holder_id=actor.pk, content_type=content_type, permission=permission.get_stored_permission)) + actor_query = Q(holder_type=actor_type, holder_id=actor.pk, content_type=content_type, permission=permission.get_stored_permission) + return (obj.content_object for obj in self.model.objects.filter(actor_query | total_queries)) def get_acl_url(self, obj): content_type = ContentType.objects.get_for_model(obj)