Project

General

Profile

0001-api-include-roles-in-users-API-25645.patch

Benjamin Dauvergne, 04 Dec 2018 07:41 PM

Download (8.07 KB)

View differences:

Subject: [PATCH] api: include roles in users API (#25645)

 src/authentic2/api_views.py | 94 ++++++++++++++++++++-----------------
 tests/test_api.py           | 52 +++++++++++++++++++-
 2 files changed, 101 insertions(+), 45 deletions(-)
src/authentic2/api_views.py
310 310
    return hash(tuple((at.name, at.required) for at in attributes))
311 311

  
312 312

  
313
class RoleSerializer(serializers.ModelSerializer):
314
    ou = serializers.SlugRelatedField(
315
        many=False,
316
        required=False,
317
        default=CreateOnlyDefault(get_default_ou),
318
        queryset=get_ou_model().objects.all(),
319
        slug_field='slug')
320

  
321
    @property
322
    def user(self):
323
        return self.context['request'].user
324

  
325
    def __init__(self, instance=None, **kwargs):
326
        super(RoleSerializer, self).__init__(instance, **kwargs)
327
        if self.instance:
328
            self.fields['ou'].read_only = True
329

  
330
    def create(self, validated_data):
331
        ou = validated_data.get('ou')
332
        # Creating roles also means being allowed to within the OU:
333
        if not self.user.has_ou_perm('a2_rbac.add_role', ou):
334
            raise PermissionDenied(u'User %s can\'t create role in OU %s' % (self.user, ou))
335
        return super(RoleSerializer, self).create(validated_data)
336

  
337
    def update(self, instance, validated_data):
338
        # Check role-updating permissions:
339
        if not self.user.has_perm('a2_rbac.change_role', obj=instance):
340
            raise PermissionDenied(u'User %s can\'t change role %s' % (self.user, instance))
341
        super(RoleSerializer, self).update(instance, validated_data)
342
        return instance
343

  
344
    def partial_update(self, instance, validated_data):
345
        # Check role-updating permissions:
346
        if not self.user.has_perm('a2_rbac.change_role', obj=instance):
347
            raise PermissionDenied(u'User %s can\'t change role %s' % (self.user, instance))
348
        super(RoleSerializer, self).partial_update(instance, validated_data)
349
        return instance
350

  
351
    class Meta:
352
        model = get_role_model()
353
        fields = ('uuid', 'name', 'slug', 'ou',)
354
        extra_kwargs = {'uuid': {'read_only': True}}
355

  
356

  
357
class RoleCustomField(RoleSerializer):
358
    class Meta(RoleSerializer.Meta):
359
        fields = ('uuid', 'name', 'slug',)
360

  
361

  
313 362
class BaseUserSerializer(serializers.ModelSerializer):
314 363
    ou = serializers.SlugRelatedField(
315 364
        queryset=get_ou_model().objects.all(),
......
324 373
                                     default=CreateOnlyDefault(utils.generate_password),
325 374
                                     required=False)
326 375
    force_password_reset = serializers.BooleanField(write_only=True, required=False, default=False)
376
    roles = RoleCustomField(many=True, read_only=True, source='roles_and_parents')
327 377

  
328 378
    def __init__(self, *args, **kwargs):
329 379
        super(BaseUserSerializer, self).__init__(*args, **kwargs)
......
452 502
        exclude = ('date_joined', 'user_permissions', 'groups', 'last_login')
453 503

  
454 504

  
455
class RoleSerializer(serializers.ModelSerializer):
456
    ou = serializers.SlugRelatedField(
457
        many=False,
458
        required=False,
459
        default=CreateOnlyDefault(get_default_ou),
460
        queryset=get_ou_model().objects.all(),
461
        slug_field='slug')
462

  
463
    @property
464
    def user(self):
465
        return self.context['request'].user
466

  
467
    def __init__(self, instance=None, **kwargs):
468
        super(RoleSerializer, self).__init__(instance, **kwargs)
469
        if self.instance:
470
            self.fields['ou'].read_only = True
471

  
472
    def create(self, validated_data):
473
        ou = validated_data.get('ou')
474
        # Creating roles also means being allowed to within the OU:
475
        if not self.user.has_ou_perm('a2_rbac.add_role', ou):
476
            raise PermissionDenied(u'User %s can\'t create role in OU %s' % (self.user, ou))
477
        return super(RoleSerializer, self).create(validated_data)
478

  
479
    def update(self, instance, validated_data):
480
        # Check role-updating permissions:
481
        if not self.user.has_perm('a2_rbac.change_role', obj=instance):
482
            raise PermissionDenied(u'User %s can\'t change role %s' % (self.user, instance))
483
        super(RoleSerializer, self).update(instance, validated_data)
484
        return instance
485

  
486
    def partial_update(self, instance, validated_data):
487
        # Check role-updating permissions:
488
        if not self.user.has_perm('a2_rbac.change_role', obj=instance):
489
            raise PermissionDenied(u'User %s can\'t change role %s' % (self.user, instance))
490
        super(RoleSerializer, self).partial_update(instance, validated_data)
491
        return instance
492

  
493
    class Meta:
494
        model = get_role_model()
495
        fields = ('uuid', 'name', 'slug', 'ou',)
496
        extra_kwargs = {'uuid': {'read_only': True}}
497

  
498

  
499 505
class UsersFilter(FilterSet):
500 506
    class Meta:
501 507
        model = get_user_model()
tests/test_api.py
251 251
    if api_user.is_superuser or api_user.roles.exists():
252 252
        assert set(['ou', 'id', 'uuid', 'is_staff', 'is_superuser', 'first_name', 'last_name',
253 253
                    'date_joined', 'last_login', 'username', 'password', 'email', 'is_active',
254
                    'title', 'modified', 'email_verified']) == set(resp.json.keys())
254
                    'title', 'modified', 'email_verified', 'roles']) == set(resp.json.keys())
255 255
        assert resp.json['first_name'] == payload['first_name']
256 256
        assert resp.json['last_name'] == payload['last_name']
257 257
        assert resp.json['email'] == payload['email']
......
944 944
    assert response.json['checks'][3]['result'] is True
945 945
    assert response.json['checks'][4]['label'] == 'must contain "ok"'
946 946
    assert response.json['checks'][4]['result'] is True
947

  
948

  
949
def test_roles_in_users_api(app, admin):
950

  
951
    User = get_user_model()
952
    user1 = User(username='john.doe', email='john.doe@example.com')
953
    user1.set_password('password')
954
    user1.save()
955
    user2 = User(username='bob.smith', email='bob.smith@example.com')
956
    user2.set_password('password')
957
    user2.save()
958

  
959
    Role = get_role_model()
960
    role1 = Role.objects.create(name='Role1')
961
    role1.members.add(user1)
962
    role2 = Role.objects.create(name='Role2')
963
    role2.members.add(user1)
964
    role2.members.add(user2)
965
    role2.add_parent(role1)
966
    role3 = Role.objects.create(name='Role3')
967
    role3.members.add(user2)
968
    role3.add_parent(role1)
969

  
970
    app.authorization = ('Basic', (admin.username, admin.username))
971
    response = app.get(u'/api/users/', status=200)
972
    assert len(response.json['results']) == 3
973
    for user in response.json['results']:
974
        assert user['roles']
975
        for role in user['roles']:
976
            keys = ['slug', 'name', 'uuid']
977
            for key, value in role.items():
978
                assert key in keys
979
                assert value
980
                keys.remove(key)
981

  
982
    url = u'/api/users/%s/' % admin.uuid
983
    response = app.get(url, status=200)
984
    assert len(response.json['roles']) == 4
985
    assert set(role['slug'] for role in response.json['roles']) == set([
986
        '_a2-manager',
987
        '_a2-manager-of-users',
988
        '_a2-manager-of-roles',
989
        '_a2-manager-of-organizational-units'])
990

  
991
    for user in [user1, user2]:
992
        url = u'/api/users/%s/' % user.uuid
993
        response = app.get(url, status=200)
994
        roles = user.roles_and_parents().all()
995
        assert len(response.json['roles']) == roles.count()
996
        assert set(role['name'] for role in response.json['roles']) == set(roles.values_list('name', flat=True))
947
-