def get_admin_role(self, instance, name, slug, ou=None, operation=ADMIN_OP, update_name=False, update_slug=False, permissions=(), self_administered=False): '''Get or create the role of manager's of this object instance''' kwargs = {} if ou or getattr(instance, 'ou', None): ou = kwargs['ou'] = ou or instance.ou else: kwargs['ou__isnull'] = True # find an operation matching the template op = get_operation(operation) Permission = rbac_utils.get_permission_model() perm, created = Permission.objects.get_or_create( operation=op, target_ct=ContentType.objects.get_for_model(instance), target_id=instance.pk, **kwargs) admin_role = self.get_mirror_role(perm, name, slug, ou=ou, update_name=update_name, update_slug=update_slug) permissions = set(permissions) permissions.add(perm) if self_administered: self_perm = admin_role.add_self_administration() permissions.add(self_perm) if set(admin_role.permissions.all()) != permissions: for permission in permissions: admin_role.permissions.through.objects.get_or_create(role=admin_role, permission=permission) return admin_role
def has_self_administration(self, op=CHANGE_OP): Permission = rbac_utils.get_permission_model() admin_op = rbac_utils.get_operation(op) self_perm, created = Permission.objects.get_or_create( operation=admin_op, target_ct=ContentType.objects.get_for_model(self), target_id=self.pk) return self.permissions.filter(pk=self_perm.pk).exists()
def get_search_ou_perm(ou=None): if ou: Permission = rbac_utils.get_permission_model() view_ou_perm, created = Permission.objects.get_or_create( operation=rbac_utils.get_operation(SEARCH_OP), target_ct=ContentType.objects.get_for_model(ou), target_id=ou.pk, ou__isnull=True) else: OU = rbac_utils.get_ou_model() Permission = rbac_utils.get_permission_model() view_ou_perm, created = Permission.objects.get_or_create( operation=rbac_utils.get_operation(SEARCH_OP), target_ct=ContentType.objects.get_for_model(ContentType), target_id=ContentType.objects.get_for_model(OU).pk, ou__isnull=True) return view_ou_perm
def add_self_administration(self, op=CHANGE_OP): 'Add permission to role so that it is self-administered' Permission = rbac_utils.get_permission_model() admin_op = rbac_utils.get_operation(op) self_perm, created = Permission.objects.get_or_create( operation=admin_op, target_ct=ContentType.objects.get_for_model(self), target_id=self.pk) self.permissions.add(self_perm) return self_perm
def get_view_user_perm(ou=None): User = get_user_model() Permission = rbac_utils.get_permission_model() view_user_perm, created = Permission.objects.get_or_create( operation=rbac_utils.get_operation(VIEW_OP), target_ct=ContentType.objects.get_for_model(ContentType), target_id=ContentType.objects.get_for_model(User).pk, ou__isnull=ou is None, ou=ou) return view_user_perm
def add_self_administration(self, op=CHANGE_OP): 'Add permission to role so that it is self-administered' Permission = rbac_utils.get_permission_model() admin_op = rbac_utils.get_operation(op) self_perm, created = Permission.objects.get_or_create( operation=admin_op, target_ct=ContentType.objects.get_for_model(self), target_id=self.pk) self.permissions.through.objects.get_or_create(role=self, permission=self_perm) return self_perm
def handle(self, *args, **options): from django_rbac.utils import get_permission_model, get_role_model Permission = get_permission_model() count = Permission.objects.cleanup() if count: print 'Deleted %d permissions.' % count Role = get_role_model() count = 0 count = Role.objects.cleanup() if count: print 'Deleted %d roles.' % count
def update_ous_admin_roles(): '''Create general admin roles linked to all organizational units, they give general administrative rights to all mamanged content types scoped to the given organizational unit. ''' Role = get_role_model() Permission = get_permission_model() OU = get_ou_model() ou_all = OU.objects.all() if len(ou_all) < 2: # If there is no ou or less than two, only generate global management # roles return for ou in ou_all: update_ou_admin_roles(ou)
def form_valid(self, form): if self.can_change: operation = form.cleaned_data["operation"] ou = form.cleaned_data["ou"] target = form.cleaned_data["target"] action = form.cleaned_data["action"] if action == "add": Permission = get_permission_model() perm, created = Permission.objects.get_or_create( operation=operation, ou=ou, target_ct=ContentType.objects.get_for_model(target), target_id=target.pk ) self.object.permissions.add(perm) else: messages.warning(self.request, _("You are not authorized")) return super(RolePermissionsView, self).form_valid(form)
def get_queryset(self): qs = super(RolesMixin, self).get_queryset() qs = qs.select_related("ou") Permission = get_permission_model() permission_ct = ContentType.objects.get_for_model(Permission) ct_ct = ContentType.objects.get_for_model(ContentType) ou_ct = ContentType.objects.get_for_model(get_ou_model()) permission_qs = Permission.objects.filter(target_ct_id__in=[ct_ct.id, ou_ct.id]).values_list("id", flat=True) # only non role-admin roles, they are accessed through the # RoleManager views if not self.admin_roles: qs = qs.filter( Q(admin_scope_ct__isnull=True) | Q(admin_scope_ct=permission_ct, admin_scope_id__in=permission_qs) ) if not self.service_roles: qs = qs.filter(service__isnull=True) return qs
class ChoosePermissionForm(CssClass, forms.Form): operation = forms.ModelChoiceField(required=False, label=_('Operation'), queryset=Operation.objects) ou = forms.ModelChoiceField(label=_('Organizational unit'), queryset=get_ou_model().objects, required=False) target = forms.ModelChoiceField(label=_('Target object'), required=False, queryset=ContentType.objects) action = forms.CharField(initial='add', required=False, widget=forms.HiddenInput) permission = forms.ModelChoiceField( queryset=get_permission_model().objects, required=False, widget=forms.HiddenInput)
def update_ous_admin_roles(): '''Create general admin roles linked to all organizational units, they give general administrative rights to all mamanged content types scoped to the given organizational unit. ''' Role = get_role_model() Permission = get_permission_model() OU = get_ou_model() ou_all = OU.objects.all() if len(ou_all) < 2: # If there is no ou or less than two, only generate global management # roles Role.objects.filter(slug__startswith='_a2', ou__isnull=False).delete() Role.objects.filter(slug__startswith='_a2-managers-of-').delete() Permission.objects.filter(roles__isnull=True).delete() return for ou in ou_all: update_ou_admin_roles(ou)
def get_queryset(self): qs = super(RolesMixin, self).get_queryset() qs = qs.select_related('ou') Permission = get_permission_model() permission_ct = ContentType.objects.get_for_model(Permission) ct_ct = ContentType.objects.get_for_model(ContentType) ou_ct = ContentType.objects.get_for_model(get_ou_model()) permission_qs = Permission.objects.filter(target_ct_id__in=[ct_ct.id, ou_ct.id]) \ .values_list('id', flat=True) # only non role-admin roles, they are accessed through the # RoleManager views if not self.admin_roles: qs = qs.filter( Q(admin_scope_ct__isnull=True) | Q(admin_scope_ct=permission_ct, admin_scope_id__in=permission_qs)) if not self.service_roles: qs = qs.filter(service__isnull=True) return qs
def test_massive_role_parenting(db): User = get_user_model() Role = utils.get_role_model() RoleParenting = utils.get_role_parenting_model() Permission = utils.get_permission_model() user = User.objects.create(username='******') roles = [] # Try a depth=10 tree of roles for i in range(0, SIZE): name = 'role%s' % i roles.append(Role(pk=i + 1, name=name, slug=name)) Role.objects.bulk_create(roles) relations = [] for i in range(0, SIZE): if not i: continue relations.append( RoleParenting(parent=roles[i], child=roles[(i - 1) / SPAN])) RoleParenting.objects.bulk_create(relations) RoleParenting.objects.update_transitive_closure() operation, created = models.Operation.objects.get_or_create( slug='admin', defaults={'name': 'Administration'}) perm, created = Permission.objects.get_or_create( operation=operation, target_ct=ContentType.objects.get_for_model(ContentType), target_id=ContentType.objects.get_for_model(User).id) roles[0].members.add(user) Role.objects.get(pk=roles[-1].pk).permissions.add(perm) b = time.time() for i in range(1000): assert models.Operation.objects.has_perm(user, 'admin', User) t = time.time() - b assert float(t) / 1000 < 0.008 b = time.time() for i in range(1000): assert (list(Role.objects.for_user(user).order_by('pk')) == list( Role.objects.order_by('pk'))) t = time.time() - b assert float(t) / 1000 < 0.1 b = time.time()
def form_valid(self, form): if self.can_change: operation = form.cleaned_data.get('operation') ou = form.cleaned_data.get('ou') target = form.cleaned_data.get('target') action = form.cleaned_data.get('action') Permission = get_permission_model() if action == 'add' and operation and target: perm, created = Permission.objects \ .get_or_create(operation=operation, ou=ou, target_ct=ContentType.objects.get_for_model( target), target_id=target.pk) self.object.permissions.add(perm) hooks.call_hooks('event', name='manager-add-permission', user=self.request.user, role=self.object, permission=perm) elif action == 'remove': try: permission_id = int(self.request.POST.get( 'permission', '')) perm = Permission.objects.get(id=permission_id) except (ValueError, Permission.DoesNotExist): pass else: if self.object.permissions.filter( id=permission_id).exists(): self.object.permissions.remove(perm) hooks.call_hooks('event', name='manager-remove-permission', user=self.request.user, role=self.object, permission=perm) else: messages.warning(self.request, _('You are not authorized')) return super(RolePermissionsView, self).form_valid(form)
def permissions(self): """ Update permissions (delete everything then create) """ created, deleted = [], [] for perm in self._obj.permissions.all(): perm.delete() deleted.append(perm) self._obj.permissions.clear() if self._permissions: for perm in self._permissions: op = Operation.objects.get_by_natural_key_json( perm['operation']) ou = get_ou_model().objects.get_by_natural_key_json( perm['ou']) if perm['ou'] else None ct = ContentType.objects.get_by_natural_key_json( perm['target_ct']) target = ct.model_class().objects.get_by_natural_key_json( perm['target']) perm = get_permission_model().objects.create( operation=op, ou=ou, target_ct=ct, target_id=target.pk) self._obj.permissions.add(perm) created.append(perm) return created, deleted
class Meta: model = get_permission_model() attrs = {'class': 'main', 'id': 'role-table'} fields = ('operation', 'scope', 'target') empty_text = _('None')
from django.test import TestCase from django.contrib.contenttypes.models import ContentType from django.contrib.auth import get_user_model from django.core.exceptions import ValidationError from django_rbac.utils import get_permission_model, get_role_model Permission = get_permission_model() Role = get_role_model() User = get_user_model() class A2RBACTestCase(TestCase): def test_update_rbac(self): # 3 content types managers and 1 global manager self.assertEquals(Role.objects.count(), 4) # 3 content type global permissions, 4 role administration permissions # and 1 user view permission (for the role administrator) self.assertEquals(Permission.objects.count(), 9) def test_delete_role(self): rcount = Role.objects.count() pcount = Permission.objects.count() new_role = Role.objects.create(name='Coucou') admin_role = new_role.get_admin_role() # There should two more roles, the role and its admin counterpart self.assertEquals(Role.objects.count(), rcount+2) # There should be two more permissions the admin permission on the role # and the admin permission on the admin role
def test_rbac_backend(db): Permission = utils.get_permission_model() User = get_user_model() OU = utils.get_ou_model() ou1 = OU.objects.create(name=u'ou1', slug=u'ou1') ou2 = OU.objects.create(name=u'ou2', slug=u'ou2') user1 = User.objects.create(username='******') Role = utils.get_role_model() ct_ct = ContentType.objects.get_for_model(ContentType) role_ct = ContentType.objects.get_for_model(Role) change_op = models.Operation.objects.get(slug='change') view_op = models.Operation.objects.get(slug='view') delete_op = models.Operation.objects.get(slug='delete') add_op = models.Operation.objects.get(slug='add') admin_op = models.Operation.objects.get(slug='admin') perm1 = Permission.objects.create(operation=change_op, target_ct=ct_ct, target_id=role_ct.pk) perm2 = Permission.objects.create(operation=view_op, target_ct=ct_ct, target_id=role_ct.pk) role1 = Role.objects.create(name='role1') role2 = Role.objects.create(name='role2', ou=ou1) role1.permissions.add(perm1) role2.permissions.add(perm2) role1.add_child(role2) role2.members.add(user1) perm3 = Permission.objects.create(operation=delete_op, target_ct=role_ct, target_id=role1.pk) perm4 = Permission.objects.create(operation=add_op, ou=ou1, target_ct=ct_ct, target_id=role_ct.pk) role1.permissions.add(perm3) role1.permissions.add(perm4) rbac_backend = backends.DjangoRBACBackend() ctx = CaptureQueriesContext(connection) with ctx: assert rbac_backend.get_all_permissions(user1) == set([ 'django_rbac.change_role', 'django_rbac.search_role', 'django_rbac.view_role' ]) assert rbac_backend.get_all_permissions(user1, obj=role1) == set([ 'django_rbac.delete_role', 'django_rbac.change_role', 'django_rbac.search_role', 'django_rbac.view_role' ]) assert rbac_backend.get_all_permissions(user1, obj=role2) == set([ 'django_rbac.change_role', 'django_rbac.view_role', 'django_rbac.search_role', 'django_rbac.add_role' ]) assert not rbac_backend.has_perm( user1, 'django_rbac.delete_role', obj=role2) assert rbac_backend.has_perm(user1, 'django_rbac.delete_role', obj=role1) assert rbac_backend.has_perms(user1, [ 'django_rbac.delete_role', 'django_rbac.change_role', 'django_rbac.view_role' ], obj=role1) assert rbac_backend.has_module_perms(user1, 'django_rbac') assert not rbac_backend.has_module_perms(user1, 'contenttypes') assert len(ctx.captured_queries) == 1 assert (set( rbac_backend.filter_by_perm(user1, 'django_rbac.add_role', Role.objects.all())) == set([role2])) assert (set( rbac_backend.filter_by_perm(user1, 'django_rbac.delete_role', Role.objects.all())) == set([role1])) assert set( rbac_backend.filter_by_perm( user1, ['django_rbac.delete_role', 'django_rbac.add_role'], Role.objects.all())) == set([role1, role2]) assert (set( rbac_backend.filter_by_perm(user1, 'django_rbac.view_role', Role.objects.all())) == set([role1, role2])) assert (set( rbac_backend.filter_by_perm(user1, 'django_rbac.change_role', Role.objects.all())) == set([role1, role2])) # Test admin op as a generalization of other ops user2 = User.objects.create(username='******') role3 = Role.objects.create(name='role3') role3.members.add(user2) perm5 = Permission.objects.create(operation=admin_op, target_ct=ct_ct, target_id=role_ct.pk) role3.permissions.add(perm5) assert rbac_backend.get_all_permissions(user2) == set([ 'django_rbac.add_role', 'django_rbac.change_role', 'django_rbac.search_role', 'django_rbac.admin_role', 'django_rbac.view_role', 'django_rbac.delete_role' ]) # test ous_with_perm assert set(rbac_backend.ous_with_perm( user1, 'django_rbac.add_role')) == set([ou1]) assert set(rbac_backend.ous_with_perm( user1, 'django_rbac.view_role')) == set([ou1, ou2]) assert set(rbac_backend.ous_with_perm( user1, 'django_rbac.delete_role')) == set([])
from django.test import TestCase from django.contrib.contenttypes.models import ContentType from django.contrib.auth import get_user_model from django.core.exceptions import ValidationError from django_rbac.utils import get_permission_model, get_role_model Permission = get_permission_model() Role = get_role_model() User = get_user_model() class CustomUserTestCase(TestCase): def test_roles_and_parents(self): rchild1 = Role.objects.create(name='role-child1') rparent1 = Role.objects.create(name='role-parent1') rparent2 = Role.objects.create(name='role-parent2') rchild2 = Role.objects.create(name='role-child2') rparent1.add_child(rchild1) rparent1.add_child(rchild2) rparent2.add_child(rchild1) rparent2.add_child(rchild2) user1 = User.objects.create(username='******') user1.roles.add(rchild1) self.assertEqual(set([r.id for r in user1.roles_and_parents()]), set([rchild1.id, rparent1.id, rparent2.id])) for r in user1.roles_and_parents(): if r.id == rchild1.id: self.assertEqual(r.member, [user1]) else: