def test_copyannotations_command_adds_permissions(self, annotation_set): user_from = annotation_set.grader user_to = UserFactory() call_command( "copyannotations", user_from.username, user_to.username, stdout=None, # suppress output ) checker = ObjectPermissionChecker(user_to) for model, _ in self.annotations: model_instance = model.objects.get(grader=user_to) children = [] if model == PolygonAnnotationSet: children = model_instance.singlepolygonannotation_set.all() if model == LandmarkAnnotationSet: children = model_instance.singlelandmarkannotation_set.all() perms = checker.get_perms(model_instance) for permission_type in model._meta.default_permissions: assert f"{permission_type}_{model._meta.model_name}" in perms if children: checker.prefetch_perms(children) for child in children: perms = checker.get_perms(child) child_model_name = children.first()._meta.model_name for permission_type in child._meta.default_permissions: assert f"{permission_type}_{child_model_name}" in perms
def test_copyannotations_command_doesnt_add_permissions( self, annotation_set): user_from = annotation_set.grader user_to = UserFactory() call_command( "copyannotations", user_from.username, user_to.username, add_permissions=False, stdout=None, # suppress output ) checker = ObjectPermissionChecker(user_to) for model, _ in self.annotations: model_instance = model.objects.get(grader=user_to) children = [] if model == PolygonAnnotationSet: children = model_instance.singlepolygonannotation_set.all() if model == LandmarkAnnotationSet: children = model_instance.singlelandmarkannotation_set.all() perms = checker.get_perms(model_instance) assert len(perms) == 0 if children: checker.prefetch_perms(children) for child in children: perms = checker.get_perms(child) assert len(perms) == 0
def test_get_perms(self): group = Group.objects.create(name='group') obj1 = ContentType.objects.create(model='foo', app_label='guardian-tests') obj2 = ContentType.objects.create(model='bar', app_label='guardian-tests') assign_perms = { group: ('change_group', 'delete_group'), obj1: ('change_contenttype', 'delete_contenttype'), obj2: ('delete_contenttype', ), } check = ObjectPermissionChecker(self.user) for obj, perms in assign_perms.items(): for perm in perms: UserObjectPermission.objects.assign_perm(perm, self.user, obj) self.assertEqual(sorted(perms), sorted(check.get_perms(obj))) check = ObjectPermissionChecker(self.group) for obj, perms in assign_perms.items(): for perm in perms: GroupObjectPermission.objects.assign_perm( perm, self.group, obj) self.assertEqual(sorted(perms), sorted(check.get_perms(obj)))
def test_get_perms(self): group = Group.objects.create(name='group') obj1 = ContentType.objects.create(name='ct1', model='foo', app_label='guardian-tests') obj2 = ContentType.objects.create(name='ct2', model='bar', app_label='guardian-tests') assign_perms = { group: ('change_group', 'delete_group'), obj1: ('change_contenttype', 'delete_contenttype'), obj2: ('delete_contenttype',), } check = ObjectPermissionChecker(self.user) for obj, perms in assign_perms.items(): for perm in perms: UserObjectPermission.objects.assign_perm(perm, self.user, obj) self.assertEqual(sorted(perms), sorted(check.get_perms(obj))) check = ObjectPermissionChecker(self.group) for obj, perms in assign_perms.items(): for perm in perms: GroupObjectPermission.objects.assign_perm(perm, self.group, obj) self.assertEqual(sorted(perms), sorted(check.get_perms(obj)))
def test_copyannotations_command_doesnt_add_permissions( self, AnnotationSet ): user_from = AnnotationSet.grader user_to = UserFactory() call_command( "copyannotations", user_from.username, user_to.username, add_permissions=False, stdout=None, # suppress output ) checker = ObjectPermissionChecker(user_to) for model, _ in self.annotations: model_instance = model.objects.get(grader=user_to) children = [] if model == PolygonAnnotationSet: children = model_instance.singlepolygonannotation_set.all() if model == LandmarkAnnotationSet: children = model_instance.singlelandmarkannotation_set.all() perms = checker.get_perms(model_instance) assert len(perms) == 0 if children: checker.prefetch_perms(children) for child in children: perms = checker.get_perms(child) assert len(perms) == 0
def test_copyannotations_command_adds_permissions(self, AnnotationSet): user_from = AnnotationSet.grader user_to = UserFactory() call_command( "copyannotations", user_from.username, user_to.username, stdout=None, # suppress output ) checker = ObjectPermissionChecker(user_to) for model, _ in self.annotations: model_instance = model.objects.get(grader=user_to) children = [] if model == PolygonAnnotationSet: children = model_instance.singlepolygonannotation_set.all() if model == LandmarkAnnotationSet: children = model_instance.singlelandmarkannotation_set.all() perms = checker.get_perms(model_instance) for permission_type in model._meta.default_permissions: assert f"{permission_type}_{model._meta.model_name}" in perms if children: checker.prefetch_perms(children) for child in children: perms = checker.get_perms(child) child_model_name = children.first()._meta.model_name for permission_type in child._meta.default_permissions: assert f"{permission_type}_{child_model_name}" in perms
def test_roles_init_new_repo_2(self): """ Groups and permissions created by the repo creations """ repo = Repository.objects.create( name=self.repo_name, description=self.repo_desc, created_by=self.user ) admin = Group.objects.get(name=self.group_admin) curator = Group.objects.get(name=self.group_curator) author = Group.objects.get(name=self.group_author) checker_admin = ObjectPermissionChecker(admin) self.assertListEqual( sorted(checker_admin.get_perms(repo)), sorted(RepoPermission.administrator_permissions()) ) checker_curator = ObjectPermissionChecker(curator) self.assertListEqual( sorted(checker_curator.get_perms(repo)), sorted(RepoPermission.curator_permissions()) ) checker_author = ObjectPermissionChecker(author) self.assertListEqual( sorted(checker_author.get_perms(repo)), sorted(RepoPermission.author_permissions()) )
def render(self, context): for_whom = self.for_whom.resolve(context) if isinstance(for_whom, get_user_model()): self.user = for_whom self.group = None elif isinstance(for_whom, AnonymousUser): self.user = get_user_model().get_anonymous() self.group = None elif isinstance(for_whom, Group): self.user = None self.group = for_whom elif isinstance(for_whom, Organization): self.user = None self.group = for_whom else: raise NotUserNorGroup("User or Group instance required (got %s)" % for_whom.__class__) obj = self.obj.resolve(context) if not obj: return '' check = ObjectPermissionChecker(for_whom) perms = check.get_perms( obj, include_group_perms=self.include_group_permissions) context[self.context_var] = perms return ''
def get_perms(user_or_group, obj, field="codename"): """ Returns permissions for given user/group and object pair, as list of strings. """ check = ObjectPermissionChecker(user_or_group) return check.get_perms(obj, values_field=field)
def test_setannotationpermissions_sets_correct_permissions( self, AnnotationSet ): admins_group = Group.objects.get( name=settings.RETINA_ADMINS_GROUP_NAME ) graders_group = Group.objects.get( name=settings.RETINA_GRADERS_GROUP_NAME ) AnnotationSet.grader.groups.add(graders_group) call_command("setannotationpermissions") checker = ObjectPermissionChecker(AnnotationSet.grader) group_perms = Permission.objects.filter( group=admins_group ).values_list("codename", flat=True) for annotation_model in ANNOTATION_MODELS: annotation_codename = annotation_model._meta.model_name for annotation in annotation_model.objects.all(): perms = checker.get_perms(annotation) for permission_type in annotation._meta.default_permissions: assert f"{permission_type}_{annotation_codename}" in perms for permission_type in annotation._meta.default_permissions: assert ( f"{permission_type}_{annotation_codename}" in group_perms )
def render(self, context): for_whom = self.for_whom.resolve(context) if isinstance(for_whom, get_user_model()): self.user = for_whom self.group = None elif isinstance(for_whom, AnonymousUser): self.user = get_user_model().get_anonymous() self.group = None elif isinstance(for_whom, Group): self.user = None self.group = for_whom elif isinstance(for_whom, Organization): self.user = None self.group = for_whom else: raise NotUserNorGroup("User or Group instance required (got %s)" % for_whom.__class__) obj = self.obj.resolve(context) if not obj: return '' check = ObjectPermissionChecker(for_whom) perms = check.get_perms(obj, include_group_perms=self.include_group_permissions) context[self.context_var] = perms return ''
def get_perms(user_or_group, obj): """ Returns permissions for given user/group and object pair, as list of strings. """ check = ObjectPermissionChecker(user_or_group) return check.get_perms(obj)
def get_context_data(self, **kwargs): data = super().get_context_data(**kwargs) checker = ObjectPermissionChecker(self.request.user) component_perms = checker.get_perms(self.object) environment_perms = checker.get_perms(self.environment) data.update({ 'current_environment': self.environment, 'settings': self.settings_dict, 'component_perms': component_perms, 'environment_perms': environment_perms, }) return data
def get_context_data(self, **kwargs): data = super().get_context_data(**kwargs) component = self.object # type: Component environment = get_object_or_404( klass=self.request.view_environments, alias=self.kwargs['environment'] ) settings_dict = security.cleanse( data=get_settings( environment=environment, component=component, ), hidden=settings.SECURE_KEYS, ) settings_dict = dictutil.flatten(settings_dict) settings_dict = inject_settings( environment=environment, data=settings_dict, components=self.request.components, strict=False ) form = ComponentSettingsForm( component=component, environment=environment, initial={ 'settings': settings_dict } ) checker = ObjectPermissionChecker(self.request.user) component_perms = checker.get_perms(component) environment_perms = checker.get_perms(environment) data.update({ 'current_environment': environment, 'settings': settings_dict, 'form': form, 'component_perms': component_perms, 'environment_perms': environment_perms }) return data
def test_superuser(self): user = User.objects.create(username='******', is_superuser=True) check = ObjectPermissionChecker(user) ctype = ContentType.objects.get_for_model(self.ctype) perms = sorted( chain(*Permission.objects.filter( content_type=ctype).values_list('codename'))) self.assertEqual(perms, check.get_perms(self.ctype)) for perm in perms: self.assertTrue(check.has_perm(perm, self.ctype))
def test_superuser(self): user = User.objects.create(username='******', is_superuser=True) check = ObjectPermissionChecker(user) ctype = ContentType.objects.get_for_model(self.ctype) perms = sorted(chain(*Permission.objects .filter(content_type=ctype) .values_list('codename'))) self.assertEqual(perms, check.get_perms(self.ctype)) for perm in perms: self.assertTrue(check.has_perm(perm, self.ctype))
def get_all_permissions(self, user_obj, obj=None): """ Returns a set of permission strings that the given ``user_obj`` has for ``obj`` """ # check if user_obj and object are supported support, user_obj = check_support(user_obj, obj) if not support: return set() check = ObjectPermissionChecker(user_obj) return check.get_perms(obj)
def test_not_active_superuser(self): user = User.objects.create(username='******', is_superuser=True, is_active=False) check = ObjectPermissionChecker(user) ctype = ContentType.objects.get_for_model(self.flatpage) perms = sorted(chain(*Permission.objects .filter(content_type=ctype) .values_list('codename'))) self.assertEqual(check.get_perms(self.flatpage), []) for perm in perms: self.assertFalse(check.has_perm(perm, self.flatpage))
def test_get_perms(self): group = Group.objects.create(name='group') key1 = Keycard.objects.create(key='key1') key2 = Keycard.objects.create(key='key2') assign_perms = { group: ('change_group', 'delete_group'), key1: ('change_keycard', 'can_use_keycard', 'can_suspend_keycard'), key2: ('delete_keycard', 'can_suspend_keycard'), } check = ObjectPermissionChecker(self.user) for obj, perms in assign_perms.items(): for perm in perms: UserObjectPermission.objects.assign(perm, self.user, obj) self.assertEqual(sorted(perms), sorted(check.get_perms(obj))) check = ObjectPermissionChecker(self.group) for obj, perms in assign_perms.items(): for perm in perms: GroupObjectPermission.objects.assign(perm, self.group, obj) self.assertEqual(sorted(perms), sorted(check.get_perms(obj)))
def get_user_perms(self, user, object_list): checker = ObjectPermissionChecker(user) checker.prefetch_perms(object_list) perms = [] for obj in object_list: perms.extend([ ':'.join([ perm, str(obj.pk) ]) for perm in checker.get_perms(obj) ]) return perms
def get_perms(user_or_group, obj, direct_perms_only=False): """ Returns permissions for given user/group and object pair, as list of strings. :param user_or_group: instance of ``User``, ``AnonymousUser`` or ``Group``; passing any other object would raise ``guardian.exceptions.NotUserNorGroup`` exception :param obj: persisted Django's ``Model`` instance :param direct_perms_only: If set to ``True`` and ``user_or_group`` is a ``User`` instance, result would contain only permissions assigned directly to the user for the given ``obj``, not those coming via user's superuser status or group memberships. """ check = ObjectPermissionChecker(user_or_group, direct_perms_only) return check.get_perms(obj)
def render(self, context): for_whom = self.for_whom.resolve(context) if isinstance(for_whom, User): self.user = for_whom self.group = None elif isinstance(for_whom, AnonymousUser): self.user = User.get_anonymous() self.group = None elif isinstance(for_whom, Group): self.user = None self.group = for_whom else: raise NotUserNorGroup("User or Group instance required (got %s)" % for_whom.__class__) obj = self.obj.resolve(context) check = ObjectPermissionChecker(for_whom) perms = check.get_perms(obj) context[self.context_var] = perms return ''
def list(self, request, *args, **kwargs): # Copy-paste of old implementation queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True) # Add user permissions perms_checker = ObjectPermissionChecker(request.user) perms_checker.prefetch_perms(queryset) response_data = serializer.data for idx, obj in enumerate(queryset): response_data[idx]['permissions'] = perms_checker.get_perms(obj) return Response(response_data)
def test_setannotationpermissions_removes_correct_permissions( self, AnnotationSet): admins_group = Group.objects.get( name=settings.RETINA_ADMINS_GROUP_NAME) graders_group = Group.objects.get( name=settings.RETINA_GRADERS_GROUP_NAME) AnnotationSet.grader.groups.add(graders_group) call_command("setannotationpermissions") call_command("setannotationpermissions", remove=True) checker = ObjectPermissionChecker(AnnotationSet.grader) group_perms = Permission.objects.filter( group=admins_group, content_type__app_label="annotations").values_list("codename", flat=True) assert len(group_perms) == 0 for annotation_model in ANNOTATION_MODELS: for annotation in annotation_model.objects.all(): perms = checker.get_perms(annotation) assert len(perms) == 0
def render(self, context): for_whom = self.for_whom.resolve(context) if isinstance(for_whom, get_user_model()): self.user = for_whom self.group = None elif isinstance(for_whom, AnonymousUser): self.user = get_user_model().get_anonymous() self.group = None elif isinstance(for_whom, Group): self.user = None self.group = for_whom else: raise NotUserNorGroup("User or Group instance required (got %s)" % for_whom.__class__) obj = self.obj.resolve(context) check = ObjectPermissionChecker(for_whom) perms = check.get_perms(obj) perms += [ap.split('.')[1] for ap in list(get_uog_permissions(self.user, obj))] context[self.context_var] = perms return ''
def test_setannotationpermissions_sets_correct_permissions( self, AnnotationSet): admins_group = Group.objects.get( name=settings.RETINA_ADMINS_GROUP_NAME) graders_group = Group.objects.get( name=settings.RETINA_GRADERS_GROUP_NAME) AnnotationSet.grader.groups.add(graders_group) call_command("setannotationpermissions") checker = ObjectPermissionChecker(AnnotationSet.grader) group_perms = Permission.objects.filter( group=admins_group).values_list("codename", flat=True) for annotation_model in ANNOTATION_MODELS: annotation_codename = annotation_model._meta.model_name for annotation in annotation_model.objects.all(): perms = checker.get_perms(annotation) for permission_type in annotation._meta.default_permissions: assert f"{permission_type}_{annotation_codename}" in perms for permission_type in annotation._meta.default_permissions: assert (f"{permission_type}_{annotation_codename}" in group_perms)
def test_setannotationpermissions_removes_correct_permissions( self, AnnotationSet ): admins_group = Group.objects.get( name=settings.RETINA_ADMINS_GROUP_NAME ) graders_group = Group.objects.get( name=settings.RETINA_GRADERS_GROUP_NAME ) AnnotationSet.grader.groups.add(graders_group) call_command("setannotationpermissions") call_command("setannotationpermissions", remove=True) checker = ObjectPermissionChecker(AnnotationSet.grader) group_perms = Permission.objects.filter( group=admins_group, content_type__app_label="annotations" ).values_list("codename", flat=True) assert len(group_perms) == 0 for annotation_model in ANNOTATION_MODELS: for annotation in annotation_model.objects.all(): perms = checker.get_perms(annotation) assert len(perms) == 0
def sync_config_entity_group_permissions(obj, config_entity_groups, permission_lookup, permission_key_class=PermissionKey, **kwargs): """ Syncs ConfigEntity Group permissions for a ConfigEntity or DbEntity All superior Groups will also receive permissions. Superior groups to a ConfigEntity Group are the ConfigEntity Group of the parent ConfigEntity (if one exists) and the global Group to which the ConfigEntity Group corresponds. For instance, for a Project ConfigEntity Group, the superiors are the parent Region ConfigEntity Group and the UserGroupKey.MANAGER group (the global Group used for Projects) :param obj: A ConfigEntity or DbEntity :param config_entity_groups: ConfigEntity Groups :param permission_lookup, a mapping of user groups to PermissionKeys. When giving permission to a ConfigEntity group, this lookup will be consulted. The user group that closest matches the ConfigEntity group will be used. Only a direct match or global version will be accepted. For instance if the ConfigEntity group is a User ConfigEntity group, then group in the permission_lookup must be the same group or the global UserGroupKey.USER group :param permission_key_class: Default PermissionKey. Specify a PermissionKey subclass when the obj class defines extra permissions. (This is only needed to resolve keys that map to multiple permissions) :param kwargs: :return: """ def _resolve_permission(group, permission_lookup): """ Matches the group to a key in the permission_lookup. The group name and it's immediate superiors will be checked for a match, but only superiors that are global Groups. It's unlikely that we'd have a permission_lookup specific to a ConfigEntity Group. They will normally contain only global groups (UserGroupKey.SUPERADMIN, UserGroupKey.USER, etc) :param group: The group to test :param permission_lookup: keyed by group names, valued by a PermissionKey strings :return: """ # Get the global superior, which exists except for ADMIN global_superior = GroupHierarchy.objects.get( group=group).superiors.get( name__in=UserGroupKey.GLOBAL ) if group.name != UserGroupKey.SUPERADMIN else None # See if we have a permission matching the group or global superior for check_group in [group ] + ([global_superior] if global_superior else []): if permission_lookup.get(check_group.name): return permission_lookup[check_group.name] # No match, no problem. Recurse on the next Global group or its subordinate subordinates = filter( lambda subordinate: subordinate.group.name in UserGroupKey.GLOBAL, (group if group.name in UserGroupKey.GLOBAL else global_superior).subordinates.all()) if len(subordinates) == 1: return _resolve_permission(subordinates[0].group, permission_lookup) else: raise Exception( "For group {group_name} no permission in permission_lookup matches: {permission_lookup} \ and not exactly one global subordinate exists: {subordinates}". format(group_name=group.name, permission_lookup=permission_lookup, subordinates=subordinates)) # Sync ConfigEntity groups permissions # Give full permission to the ConfigEntity Group(s) to access this object # TODO this might change in the future if we define subordinate ConfigEntity Groups on the object config_entity_group_permissions = map_to_dict( lambda group: [group.name, _resolve_permission(group, permission_lookup)], config_entity_groups) obj.sync_permissions( additional_permissions=config_entity_group_permissions, permission_key_class=permission_key_class, superior_permission_lookup=permission_lookup) # TODO this is for debugging/logging. It can be commented out for group_name, permission_key in config_entity_group_permissions.items(): logger.info( "User Publishing. For %s %s gave %s permission(s) to ConfigEntity UserGroup: %s" % (obj.__class__.__name__, obj.name, permission_key, group_name)) for class_permission_key in permission_key_class.permission_keys( permission_key, obj.__class__): perm_checker = ObjectPermissionChecker( Group.objects.get(name=group_name)) assert perm_checker.has_perm(class_permission_key, obj), \ "No permission for Group %s, Permission %s, ConfigEntity %s. It has permissions %s" % \ (group_name, class_permission_key, obj.name, perm_checker.get_perms(obj)) return config_entity_group_permissions
def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) profile_user = context["object"].user profile_groups = profile_user.groups.all() organizations = Organization.objects.filter( Q(members_group__in=profile_groups) | Q(editors_group__in=profile_groups)).distinct() archives = (get_objects_for_user( user=self.request.user, perms="view_archive", klass=Archive, use_groups=True, ).filter( Q(editors_group__in=profile_groups) | Q(uploaders_group__in=profile_groups) | Q(users_group__in=profile_groups)).distinct()) reader_studies = (get_objects_for_user( user=self.request.user, perms="view_readerstudy", klass=ReaderStudy, use_groups=True, ).filter( Q(editors_group__in=profile_groups) | Q(readers_group__in=profile_groups)).distinct()) challenges = Challenge.objects.filter( Q(admins_group__in=profile_groups) | Q(participants_group__in=profile_groups), hidden=False, ).distinct() algorithms = (get_objects_for_user( user=self.request.user, perms="view_algorithm", klass=Algorithm, use_groups=True, ).filter( Q(editors_group__in=profile_groups) | Q(users_group__in=profile_groups)).distinct()) checker = ObjectPermissionChecker(user_or_group=profile_user) for qs in [ archives, reader_studies, challenges, algorithms, ]: # Perms can only be prefetched for sets of the same objects checker.prefetch_perms(objects=qs) object_list = [ *archives, *reader_studies, *challenges, *algorithms, ] role = {} for obj in object_list: obj_perms = checker.get_perms(obj) if f"change_{obj._meta.model_name}" in obj_perms: role[obj] = "editor" elif f"view_{obj._meta.model_name}" in obj_perms: role[obj] = "user" else: role[obj] = "participant" context.update({ "object_list": object_list, "object_role": role, "num_submissions": Submission.objects.filter(creator=profile_user).count(), "num_algorithms_run": Job.objects.filter(creator=profile_user).count(), "organizations": organizations, }) return context
def test_anonymous_user(self): user = AnonymousUser() check = ObjectPermissionChecker(user) # assert anonymous user has no object permissions at all for obj self.assertTrue([] == list(check.get_perms(self.ctype)))
def get_all_permissions(user, object_list): checker = ObjectPermissionChecker(user) checker.prefetch_perms(object_list) return {obj.pk: checker.get_perms(obj) for obj in object_list}
def test_anonymous_user(self): user = AnonymousUser() check = ObjectPermissionChecker(user) # assert anonymous user has no object permissions at all for obj self.assertTrue( [] == list(check.get_perms(self.ctype)) )
def sync_config_entity_group_permissions(obj, config_entity_groups, permission_lookup, permission_key_class=PermissionKey, **kwargs): """ Syncs ConfigEntity Group permissions for a ConfigEntity or DbEntity All superior Groups will also receive permissions. Superior groups to a ConfigEntity Group are the ConfigEntity Group of the parent ConfigEntity (if one exists) and the global Group to which the ConfigEntity Group corresponds. For instance, for a Project ConfigEntity Group, the superiors are the parent Region ConfigEntity Group and the UserGroupKey.MANAGER group (the global Group used for Projects) :param obj: A ConfigEntity or DbEntity :param config_entity_groups: ConfigEntity Groups :param permission_lookup, a mapping of user groups to PermissionKeys. When giving permission to a ConfigEntity group, this lookup will be consulted. The user group that closest matches the ConfigEntity group will be used. Only a direct match or global version will be accepted. For instance if the ConfigEntity group is a User ConfigEntity group, then group in the permission_lookup must be the same group or the global UserGroupKey.USER group :param permission_key_class: Default PermissionKey. Specify a PermissionKey subclass when the obj class defines extra permissions. (This is only needed to resolve keys that map to multiple permissions) :param kwargs: :return: """ def _resolve_permission(group, permission_lookup): """ Matches the group to a key in the permission_lookup. The group name and it's immediate superiors will be checked for a match, but only superiors that are global Groups. It's unlikely that we'd have a permission_lookup specific to a ConfigEntity Group. They will normally contain only global groups (UserGroupKey.SUPERADMIN, UserGroupKey.USER, etc) :param group: The group to test :param permission_lookup: keyed by group names, valued by a PermissionKey strings :return: """ # Get the global superior, which exists except for ADMIN global_superior = GroupHierarchy.objects.get(group=group).superiors.get( name__in=UserGroupKey.GLOBAL ) if group.name != UserGroupKey.SUPERADMIN else None # See if we have a permission matching the group or global superior for check_group in [group] + ([global_superior] if global_superior else []): if permission_lookup.get(check_group.name): return permission_lookup[check_group.name] # No match, no problem. Recurse on the next Global group or its subordinate subordinates = filter( lambda subordinate: subordinate.group.name in UserGroupKey.GLOBAL, (group if group.name in UserGroupKey.GLOBAL else global_superior).subordinates.all()) if len(subordinates) == 1: return _resolve_permission(subordinates[0].group, permission_lookup) else: raise Exception( "For group {group_name} no permission in permission_lookup matches: {permission_lookup} \ and not exactly one global subordinate exists: {subordinates}".format( group_name=group.name, permission_lookup=permission_lookup, subordinates=subordinates ) ) # Sync ConfigEntity groups permissions # Give full permission to the ConfigEntity Group(s) to access this object # TODO this might change in the future if we define subordinate ConfigEntity Groups on the object config_entity_group_permissions = map_to_dict( lambda group: [group.name, _resolve_permission(group, permission_lookup)], config_entity_groups) obj.sync_permissions( additional_permissions=config_entity_group_permissions, permission_key_class=permission_key_class, superior_permission_lookup=permission_lookup ) # TODO this is for debugging/logging. It can be commented out for group_name, permission_key in config_entity_group_permissions.items(): logger.info("User Publishing. For %s %s gave %s permission(s) to ConfigEntity UserGroup: %s" % (obj.__class__.__name__, obj.name, permission_key, group_name)) for class_permission_key in permission_key_class.permission_keys(permission_key, obj.__class__): perm_checker = ObjectPermissionChecker(Group.objects.get(name=group_name)) assert perm_checker.has_perm(class_permission_key, obj), \ "No permission for Group %s, Permission %s, ConfigEntity %s. It has permissions %s" % \ (group_name, class_permission_key, obj.name, perm_checker.get_perms(obj)) return config_entity_group_permissions
class SlugObjectsMixin: """ A mixin to get objects from url slugs. Also adds breadcrumbs based on the objects we have and the view we are in. """ def setup(self, *args, **kwargs): # super setup() so we have self.request available super().setup(*args, **kwargs) # add a checker we can use to cache permissions for objects self.checker = ObjectPermissionChecker(self.request.user) # start out with an almost empty context_data dict self.context_data = {"checker": self.checker} # do we have a team? if "team_slug" in kwargs: self.team = get_object_or_404(Team, slug=kwargs["team_slug"]) self.checker.prefetch_perms([self.team]) if not self.checker.has_perm("team.view_team", self.team): raise PermissionDenied self.url_namespace_prefixes = ["team"] self.add_breadcrumbs(self.team) self.url_kwargs = {"team_slug": self.team.slug} self.object_kwargs = {"team": self.team} self.context_data["team"] = self.team self.context_data["team_perms"] = self.checker.get_perms(self.team) self.gfk_object = self.team # do we have a context? if "context_slug" in kwargs: self.context = get_object_or_404( Context, team=self.team, slug=self.kwargs["context_slug"]) self.checker.prefetch_perms([self.context]) if not self.checker.has_perm("context.view_context", self.context): raise PermissionDenied self.url_namespace_prefixes.append("context") self.add_breadcrumbs(self.context) self.url_kwargs["context_slug"] = self.context.slug self.context_data["context"] = self.context self.context_data["context_perms"] = self.checker.get_perms( self.context) self.gfk_object = self.context # do we have a category? if "category_slug" in kwargs: self.category = get_object_or_404( Category, team=self.team, slug=self.kwargs["category_slug"]) self.checker.prefetch_perms([self.category]) if not self.checker.has_perm("category.view_category", self.category): raise PermissionDenied self.url_namespace_prefixes.append("category") self.add_breadcrumbs(self.category) self.url_kwargs["category_slug"] = self.category.slug self.context_data["category"] = self.category self.context_data["category_perms"] = self.checker.get_perms( self.category) self.gfk_object = self.category # do we have a fact? if "fact_slug" in kwargs: self.fact = get_object_or_404( Fact, category=self.category, slug=self.kwargs["fact_slug"]) self.checker.prefetch_perms([self.fact]) if not self.checker.has_perm("fact.view_fact", self.fact): raise PermissionDenied self.url_namespace_prefixes.append("fact") self.add_breadcrumbs(self.fact) self.context_data["fact"] = self.fact self.context_data["fact_perms"] = self.checker.get_perms( self.fact) self.gfk_object = self.fact # do we have a rating? elif "rating_slug" in kwargs: self.rating = get_object_or_404( Rating, category=self.category, slug=self.kwargs["rating_slug"]) self.checker.prefetch_perms([self.rating]) if not self.checker.has_perm("rating.view_rating", self.rating): raise PermissionDenied self.url_namespace_prefixes.append("rating") self.add_breadcrumbs(self.rating) self.context_data["rating"] = self.rating self.context_data["rating_perms"] = self.checker.get_perms( self.rating) self.gfk_object = self.rating # do we have an item? elif "item_slug" in kwargs: self.item = get_object_or_404( Item, category=self.category, slug=self.kwargs["item_slug"]) self.checker.prefetch_perms([self.item]) if not self.checker.has_perm("item.view_item", self.item): raise PermissionDenied self.url_namespace_prefixes.append("item") self.add_breadcrumbs(self.item) self.url_kwargs["item_slug"] = self.item.slug self.context_data["item"] = self.item self.context_data["item_perms"] = self.checker.get_perms( self.item) self.gfk_object = self.item # do we have a review? if "review_uuid" in kwargs: self.review = get_object_or_404( Review, item=self.item, uuid=self.kwargs["review_uuid"]) self.checker.prefetch_perms([self.review]) if not self.checker.has_perm("review.view_review", self.review): raise PermissionDenied self.url_namespace_prefixes.append("review") self.add_breadcrumbs(self.review) self.url_kwargs["review_uuid"] = self.review.uuid self.context_data["review"] = self.review self.context_data[ "review_perms"] = self.checker.get_perms( self.review) self.gfk_object = self.review # do we have a vote? if "vote_uuid" in kwargs: # get the vote self.vote = get_object_or_404( Vote, review=self.review, uuid=self.kwargs["vote_uuid"]) self.checker.prefetch_perms([self.vote]) if not self.checker.has_perm( "vote.view_vote", self.vote): raise PermissionDenied self.url_namespace_prefixes.append("vote") self.add_breadcrumbs(self.vote) self.url_kwargs["vote_uuid"] = self.vote.uuid self.context_data["vote"] = self.vote self.context_data[ "vote_perms"] = self.checker.get_perms( self.vote) self.gfk_object = self.vote # do we have a forum? if "forum_slug" in kwargs: self.forum = get_object_or_404(Forum, team=self.team, slug=self.kwargs["forum_slug"]) self.checker.prefetch_perms([self.forum]) if not self.checker.has_perm("forum.view_forum", self.forum): raise PermissionDenied self.url_namespace_prefixes.append("forum") self.add_breadcrumbs(self.forum) self.url_kwargs["forum_slug"] = self.forum.slug self.context_data["forum"] = self.forum self.context_data["forum_perms"] = self.checker.get_perms( self.forum) self.gfk_object = self.forum # do we have a thread? if "thread_slug" in kwargs: self.thread = get_object_or_404( Thread, forum=self.forum, slug=self.kwargs["thread_slug"]) self.checker.prefetch_perms([self.thread]) if not self.checker.has_perm("thread.view_thread", self.thread): raise PermissionDenied self.url_namespace_prefixes.append("thread") self.add_breadcrumbs(self.thread) self.url_kwargs["thread_slug"] = self.thread.slug self.context_data["thread"] = self.thread self.context_data["thread_perms"] = self.checker.get_perms( self.thread) self.gfk_object = self.thread # do we have a comment? (GFK object outside normal hierachy) if "comment_uuid" in kwargs: self.comment = get_object_or_404( Comment, uuid=self.kwargs["comment_uuid"], object_id=self.gfk_object.pk, content_type=ContentType.objects.get_for_model( self.gfk_object), ) self.checker.prefetch_perms([self.comment]) if not self.checker.has_perm("comment.view_comment", self.comment): raise PermissionDenied self.url_namespace_prefixes.append("comment") self.add_breadcrumbs(self.comment) self.url_kwargs["comment_uuid"] = self.comment.uuid self.context_data["comment"] = self.comment self.context_data["comment_perms"] = self.checker.get_perms( self.comment) self.gfk_object = self.comment # do we have an attachment? (GFK object outside normal hierachy) if "attachment_uuid" in kwargs: self.attachment = get_object_or_404( Attachment, uuid=self.kwargs["attachment_uuid"], object_id=self.gfk_object.pk, content_type=ContentType.objects.get_for_model( self.gfk_object), ) self.checker.prefetch_perms([self.attachment]) if not self.checker.has_perm("attachment.view_attachment", self.attachment): raise PermissionDenied self.url_namespace_prefixes.append("attachment") self.add_breadcrumbs(self.attachment) self.url_kwargs["attachment_uuid"] = self.attachment.uuid self.context_data["attachment"] = self.attachment self.context_data["attachment_perms"] = self.checker.get_perms( self.attachment) self.gfk_object = self.attachment # do we have an event? (GFK object outside normal hierachy) if "event_uuid" in kwargs: self.event = get_object_or_404( Event, uuid=self.kwargs["event_uuid"], object_id=self.gfk_object.pk, content_type=ContentType.objects.get_for_model( self.gfk_object), ) self.checker.prefetch_perms([self.event]) if not self.checker.has_perm("event.view_event", self.event): raise PermissionDenied self.url_namespace_prefixes.append("event") self.add_breadcrumbs(self.event) self.url_kwargs["event_uuid"] = self.event.uuid self.context_data["event"] = self.event self.context_data["event_perms"] = self.checker.get_perms( self.event) # finally add any missing action breadcrumbs, # but if this is a CreateView add a link to the ListView first if self.request.resolver_match.url_name == "create": self.add_listview_breadcrumb() # add action breadcrumb self.add_action_breadcrumb() def get_context_data(self, **kwargs): """ Add Team and related objects and permissions to context """ context = super().get_context_data(**kwargs) context.update(self.context_data) return context