0001-a2_rbac-change-self-admin-permission-to-manage_membe.patch
src/authentic2/a2_rbac/management.py | ||
---|---|---|
152 | 152 |
old_perm = role.permissions.get(operation__slug=ADMIN_OP.slug) |
153 | 153 |
administered_role = old_perm.target |
154 | 154 |
admin_role = administered_role.get_admin_role() |
155 |
new_perm = admin_role.permissions.get(operation__slug=MANAGE_MEMBERS_OP.slug) |
|
155 |
new_perm = admin_role.permissions.get(operation__slug=MANAGE_MEMBERS_OP.slug, |
|
156 |
target_id=administered_role.pk) |
|
156 | 157 |
admin_role.delete() |
157 | 158 |
role.admin_scope_id = new_perm.pk |
158 | 159 |
role.save() |
src/authentic2/a2_rbac/migrations/0023_fix_self_admin_perm.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
# Generated by Django 1.11.18 on 2020-05-12 08:58 |
|
3 |
from __future__ import unicode_literals |
|
4 | ||
5 |
from django.db import migrations |
|
6 |
from django.db.utils import IntegrityError |
|
7 |
from django.utils.six import text_type |
|
8 | ||
9 |
from authentic2.a2_rbac.models import MANAGE_MEMBERS_OP |
|
10 |
from django_rbac.models import CHANGE_OP |
|
11 | ||
12 | ||
13 |
def update_self_administration_perm(apps, schema_editor): |
|
14 |
Role = apps.get_model('a2_rbac', 'Role') |
|
15 |
Permission = apps.get_model('a2_rbac', 'Permission') |
|
16 |
Operation = apps.get_model('django_rbac', 'Operation') |
|
17 |
ContentType = apps.get_model('contenttypes', 'ContentType') |
|
18 |
change_op, _ = Operation.objects.get_or_create(slug=text_type(CHANGE_OP.slug)) |
|
19 |
manage_members_op, _ = Operation.objects.get_or_create(slug=text_type(MANAGE_MEMBERS_OP.slug)) |
|
20 |
ct = ContentType.objects.get_for_model(Role) |
|
21 |
perms_to_delete = [] |
|
22 |
for role in Role.objects.all(): |
|
23 |
try: |
|
24 |
perm = role.permissions.get(operation=change_op, target_ct=ct, target_id=role.pk) |
|
25 |
except Permission.DoesNotExist: |
|
26 |
continue |
|
27 | ||
28 |
new_perm, _ = Permission.objects.get_or_create( |
|
29 |
operation=manage_members_op, target_ct=ct, target_id=role.pk, ou__isnull=True |
|
30 |
) |
|
31 |
role.permissions.add(new_perm) |
|
32 |
role.permissions.remove(perm) |
|
33 |
perms_to_delete.append(perm.pk) |
|
34 |
Permission.objects.filter(pk__in=perms_to_delete, roles__isnull=True).delete() |
|
35 | ||
36 | ||
37 |
class Migration(migrations.Migration): |
|
38 | ||
39 |
dependencies = [ |
|
40 |
('a2_rbac', '0022_auto_20200402_1101'), |
|
41 |
] |
|
42 | ||
43 |
operations = [ |
|
44 |
migrations.RunPython(update_self_administration_perm, migrations.RunPython.noop) |
|
45 |
] |
src/authentic2/a2_rbac/models.py | ||
---|---|---|
25 | 25 | |
26 | 26 |
from django_rbac.models import (RoleAbstractBase, PermissionAbstractBase, |
27 | 27 |
OrganizationalUnitAbstractBase, RoleParentingAbstractBase, VIEW_OP, |
28 |
CHANGE_OP, Operation)
|
|
28 |
Operation) |
|
29 | 29 |
from django_rbac import utils as rbac_utils |
30 | 30 | |
31 | 31 |
from authentic2.decorators import errorcollector |
... | ... | |
282 | 282 |
self.get_admin_role(create=False) |
283 | 283 |
return result |
284 | 284 | |
285 |
def has_self_administration(self, op=CHANGE_OP): |
|
285 |
def has_self_administration(self, op=None): |
|
286 |
if not op: |
|
287 |
op = MANAGE_MEMBERS_OP |
|
286 | 288 |
Permission = rbac_utils.get_permission_model() |
287 |
admin_op = rbac_utils.get_operation(op)
|
|
289 |
operation = rbac_utils.get_operation(op)
|
|
288 | 290 |
self_perm, created = Permission.objects.get_or_create( |
289 |
operation=admin_op,
|
|
291 |
operation=operation,
|
|
290 | 292 |
target_ct=ContentType.objects.get_for_model(self), |
291 |
target_id=self.pk) |
|
293 |
target_id=self.pk, |
|
294 |
ou__is_null=True) |
|
292 | 295 |
return self.permissions.filter(pk=self_perm.pk).exists() |
293 | 296 | |
294 |
def add_self_administration(self, op=CHANGE_OP):
|
|
297 |
def add_self_administration(self, op=None):
|
|
295 | 298 |
'Add permission to role so that it is self-administered' |
299 |
if not op: |
|
300 |
op = MANAGE_MEMBERS_OP |
|
296 | 301 |
Permission = rbac_utils.get_permission_model() |
297 |
admin_op = rbac_utils.get_operation(op)
|
|
302 |
operation = rbac_utils.get_operation(op)
|
|
298 | 303 |
self_perm, created = Permission.objects.get_or_create( |
299 |
operation=admin_op,
|
|
304 |
operation=operation,
|
|
300 | 305 |
target_ct=ContentType.objects.get_for_model(self), |
301 | 306 |
target_id=self.pk) |
302 | 307 |
self.permissions.through.objects.get_or_create(role=self, permission=self_perm) |
src/authentic2/manager/user_views.py | ||
---|---|---|
327 | 327 |
role_qs = get_role_model().objects.all() |
328 | 328 |
if app_settings.ROLE_MEMBERS_FROM_OU and instance.ou: |
329 | 329 |
role_qs = role_qs.filter(ou=instance.ou) |
330 |
return user.filter_by_perm('a2_rbac.change_role', role_qs).exists()
|
|
330 |
return user.filter_by_perm('a2_rbac.manage_members_role', role_qs).exists()
|
|
331 | 331 | |
332 | 332 |
def get_context_data(self, **kwargs): |
333 | 333 |
kwargs['default_ou'] = get_default_ou |
tests/test_a2_rbac.py | ||
---|---|---|
22 | 22 |
from django.contrib.contenttypes.models import ContentType |
23 | 23 | |
24 | 24 |
from django_rbac.utils import get_permission_model |
25 |
from django_rbac.models import Operation |
|
25 |
from django_rbac.models import Operation, CHANGE_OP
|
|
26 | 26 |
from authentic2.custom_user.models import User |
27 | 27 |
from authentic2.models import Service |
28 | 28 |
from django.core.management import call_command |
29 | 29 | |
30 |
from authentic2.a2_rbac.models import Role, OrganizationalUnit as OU, RoleAttribute |
|
31 | 30 |
from authentic2.a2_rbac.utils import get_default_ou, get_view_user_perm |
32 | 31 |
from authentic2.a2_rbac.models import ( |
33 | 32 |
Role, |
34 | 33 |
Permission, |
35 | 34 |
OrganizationalUnit as OU, |
36 |
RoleAttribute) |
|
35 |
RoleAttribute, |
|
36 |
MANAGE_MEMBERS_OP |
|
37 |
) |
|
37 | 38 |
from authentic2.utils import get_hex_uuid |
38 | 39 | |
39 | 40 | |
... | ... | |
59 | 60 |
# There should two more roles, the role and its admin counterpart |
60 | 61 |
assert Role.objects.count() == rcount + 2 |
61 | 62 | |
62 |
# There should be two more permissions the admin permission on the role
|
|
63 |
# and the admin permission on the admin role
|
|
64 |
admin_perm = Permission.objects.by_target(new_role) \
|
|
63 |
# There should be two more permissions the manage-members permission on the role
|
|
64 |
# and the manage-members permission on the admin role
|
|
65 |
manage_members_perm = Permission.objects.by_target(new_role) \
|
|
65 | 66 |
.get(operation__slug='manage_members') |
66 | 67 |
admin_role = Role.objects.get( |
67 |
admin_scope_ct=ContentType.objects.get_for_model(admin_perm),
|
|
68 |
admin_scope_id=admin_perm.pk)
|
|
69 |
admin_admin_perm = Permission.objects.by_target(admin_role) \
|
|
70 |
.get(operation__slug='change')
|
|
68 |
admin_scope_ct=ContentType.objects.get_for_model(manage_members_perm),
|
|
69 |
admin_scope_id=manage_members_perm.pk)
|
|
70 |
admin_manage_members_perm = Permission.objects.by_target(admin_role) \
|
|
71 |
.get(operation__slug='manage_members')
|
|
71 | 72 |
assert Permission.objects.count() == pcount + 2 |
72 | 73 |
new_role.delete() |
73 | 74 |
with pytest.raises(Permission.DoesNotExist): |
74 |
Permission.objects.get(pk=admin_perm.pk)
|
|
75 |
Permission.objects.get(pk=manage_members_perm.pk)
|
|
75 | 76 |
with pytest.raises(Role.DoesNotExist): |
76 | 77 |
Role.objects.get(pk=admin_role.pk) |
77 | 78 |
with pytest.raises(Permission.DoesNotExist): |
78 |
Permission.objects.get(pk=admin_admin_perm.pk)
|
|
79 |
Permission.objects.get(pk=admin_manage_members_perm.pk)
|
|
79 | 80 |
assert Role.objects.count() == rcount |
80 | 81 |
assert Permission.objects.count() == pcount |
81 | 82 | |
... | ... | |
260 | 261 |
name='other role name', slug='other-role-slug', uuid=get_hex_uuid(), ou=some_ou) |
261 | 262 |
ou = OU.objects.create(name='basic ou', slug='basic-ou', description='basic ou description') |
262 | 263 |
Permission = get_permission_model() |
263 |
op = Operation.objects.first()
|
|
264 |
op = Operation.objects.get(slug='add')
|
|
264 | 265 |
perm_saml = Permission.objects.create( |
265 | 266 |
operation=op, ou=ou, |
266 | 267 |
target_ct=ContentType.objects.get_for_model(ContentType), |
... | ... | |
526 | 527 |
emit_post_migrate_signal(verbosity=0, interactive=False, db='default', created_models=[]) |
527 | 528 |
assert simple_user.get_all_permissions(role) == \ |
528 | 529 |
{'a2_rbac.manage_members_role', 'a2_rbac.search_role', 'a2_rbac.view_role'} |
530 | ||
531 | ||
532 |
@pytest.mark.parametrize('new_perm_exists', [True, False]) |
|
533 |
def test_update_self_admin_perm_migration(migration, new_perm_exists): |
|
534 |
old_apps = migration.before([('a2_rbac', '0022_auto_20200402_1101')]) |
|
535 |
Role = old_apps.get_model('a2_rbac', 'Role') |
|
536 |
OrganizationalUnit = old_apps.get_model('a2_rbac', 'OrganizationalUnit') |
|
537 |
Permission = old_apps.get_model('a2_rbac', 'Permission') |
|
538 |
Operation = old_apps.get_model('django_rbac', 'Operation') |
|
539 |
ContentType = old_apps.get_model('contenttypes', 'ContentType') |
|
540 |
ct = ContentType.objects.get_for_model(Role) |
|
541 |
change_op, _ = Operation.objects.get_or_create(slug=CHANGE_OP.slug) |
|
542 |
manage_members_op, _ = Operation.objects.get_or_create(slug=MANAGE_MEMBERS_OP.slug) |
|
543 | ||
544 |
# add old self administration |
|
545 |
role = Role.objects.create(name='name', slug='slug') |
|
546 |
self_perm, _ = Permission.objects.get_or_create(operation=change_op, target_ct=ct, target_id=role.pk) |
|
547 |
role.permissions.add(self_perm) |
|
548 | ||
549 |
if new_perm_exists: |
|
550 |
new_self_perm, _ = Permission.objects.get_or_create(operation=manage_members_op, target_ct=ct, |
|
551 |
target_id=role.pk) |
|
552 |
else: |
|
553 |
Permission.objects.filter( |
|
554 |
operation=manage_members_op, target_ct=ct, target_id=role.pk |
|
555 |
).delete() |
|
556 | ||
557 |
new_apps = migration.apply([('a2_rbac', '0023_fix_self_admin_perm')]) |
|
558 |
Role = new_apps.get_model('a2_rbac', 'Role') |
|
559 |
Operation = old_apps.get_model('django_rbac', 'Operation') |
|
560 | ||
561 |
role = Role.objects.get(slug='slug') |
|
562 |
assert role.permissions.count() == 1 |
|
563 | ||
564 |
perm = role.permissions.first() |
|
565 |
assert perm.operation.pk == manage_members_op.pk |
|
566 |
assert perm.target_ct.pk == ct.pk |
|
567 |
assert perm.target_id == role.pk |
|
568 | ||
569 |
if new_perm_exists: |
|
570 |
assert perm.pk == new_self_perm.pk |
|
571 | ||
572 |
assert not Permission.objects.filter(operation=change_op, target_ct=ct, target_id=role.pk).exists() |
|
529 |
- |