Projet

Général

Profil

0001-a2_rbac-change-self-admin-permission-to-manage_membe.patch

Valentin Deniaud, 26 mai 2020 10:20

Télécharger (11,5 ko)

Voir les différences:

Subject: [PATCH] a2_rbac: change self admin permission to manage_members
 (#42086)

 src/authentic2/a2_rbac/management.py          |  3 +-
 .../migrations/0023_fix_self_admin_perm.py    | 45 ++++++++++++
 src/authentic2/a2_rbac/models.py              | 21 +++---
 src/authentic2/manager/user_views.py          |  2 +-
 tests/test_a2_rbac.py                         | 70 +++++++++++++++----
 5 files changed, 118 insertions(+), 23 deletions(-)
 create mode 100644 src/authentic2/a2_rbac/migrations/0023_fix_self_admin_perm.py
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
-