From aa50eb8474c5f0f44256df6a2ca7310a0b781674 Mon Sep 17 00:00:00 2001 From: Paul Marillonnet Date: Wed, 4 Apr 2018 14:31:25 +0200 Subject: [PATCH] WIP role api: add extra role attributes (#21488) --- src/authentic2/api_views.py | 22 ++++++++++++++++++++-- tests/conftest.py | 13 +++++++++++++ tests/test_api.py | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/authentic2/api_views.py b/src/authentic2/api_views.py index 2b4d498f..5db57825 100644 --- a/src/authentic2/api_views.py +++ b/src/authentic2/api_views.py @@ -28,6 +28,7 @@ from django_filters.rest_framework import FilterSet from .custom_user.models import User from . import utils, decorators, attribute_kinds, app_settings, hooks from .models import Attribute, PasswordReset +from .a2_rbac.models import RoleAttribute from .a2_rbac.utils import get_default_ou @@ -444,6 +445,12 @@ class BaseUserSerializer(serializers.ModelSerializer): exclude = ('date_joined', 'user_permissions', 'groups', 'last_login') +class RoleAttributeSerializer(serializers.ModelSerializer): + class Meta: + model = RoleAttribute + fields = ('name', 'kind', 'value') + + class RoleSerializer(serializers.ModelSerializer): ou = serializers.SlugRelatedField( many=False, @@ -451,6 +458,10 @@ class RoleSerializer(serializers.ModelSerializer): default=CreateOnlyDefault(get_default_ou), queryset=get_ou_model().objects.all(), slug_field='slug') + role_attributes = RoleAttributeSerializer( + many=True, + read_only=False, + required=False) @property def user(self): @@ -466,7 +477,14 @@ class RoleSerializer(serializers.ModelSerializer): # Creating roles also means being allowed to within the OU: if not self.user.has_ou_perm('a2_rbac.add_role', ou): raise PermissionDenied(u'User %s can\'t create role in OU %s' % (self.user, ou)) - return super(RoleSerializer, self).create(validated_data) + instance = super(RoleSerializer, self).create(validated_data) + + # Create additional RoleAttribute objects: + if 'role_attributes' in validated_data: + role_attributes_data = validated_data.pop('role_attributes') + for role_attribute_data in role_attributes_data: + RoleAttribute.create(role=instance, **role_attributes_data) + return instance def update(self, instance, validated_data): # Check role-updating permissions: @@ -484,7 +502,7 @@ class RoleSerializer(serializers.ModelSerializer): class Meta: model = get_role_model() - fields = ('uuid', 'name', 'slug', 'ou',) + fields = ('uuid', 'name', 'slug', 'ou', 'role_attributes') extra_kwargs = {'uuid': {'read_only': True}} diff --git a/tests/conftest.py b/tests/conftest.py index 3ccca669..014f8852 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -13,6 +13,7 @@ from django.conf import settings from pytest_django.migrations import DisableMigrations from authentic2.a2_rbac.utils import get_default_ou +from authentic2.a2_rbac.models import RoleAttribute from authentic2_idp_oidc.models import OIDCClient from authentic2.authentication import OIDCUser @@ -144,6 +145,18 @@ def role_random(db, ou_rando): return Role.objects.create(name='rando', slug='rando', ou=ou_rando) +@pytest.fixture +def role_attribute_details(db, role_random): + return RoleAttribute.objects.create(role=role_random, name='details', + kind='string', value='list') + + +@pytest.fixture +def role_attribute_emails(db, role_random): + return RoleAttribute.objects.create(role=role_random, name='emails', + kind='string', value='list') + + @pytest.fixture def role_ou1(db, ou1): return Role.objects.create(name='role_ou1', slug='role_ou1', ou=ou1) diff --git a/tests/test_api.py b/tests/test_api.py index f6d7bf29..ca9a911f 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -767,6 +767,35 @@ def test_api_post_role(app, admin_ou1, ou1): assert role.ou.slug == role_data['ou'] +def test_api_role_extra_attributes(app, admin_ou1, ou1): + app.authorization = ('Basic', (admin_ou1.username, admin_ou1.username)) + + role_data = { + 'slug': 'coffee-manager', + 'name': 'Coffee Manager', + 'ou': 'ou1', + 'role_attributes': ({ + 'name': 'details', + 'kind': 'string', + 'value': 'nodetails' + }, + { + 'name': 'emails', + 'kind': 'string', + 'value': 'foo@email.none' + }) + } + resp = app.post_json('/api/roles/', params=role_data) + assert isinstance(resp.json, dict) + uuid = resp.json['uuid'] + + # Check attributes values against the DB: + role = get_role_model().objects.get(uuid=uuid) + assert role.slug == role_data['slug'] + assert role.name == role_data['name'] + assert role.ou.slug == role_data['ou'] + + def test_api_post_role_no_ou(app, superuser): app.authorization = ('Basic', (superuser.username, superuser.username)) Role = get_role_model() @@ -803,6 +832,13 @@ def test_api_get_role_description(app, admin_rando_role, role_random): assert resp.json['ou'] == 'ou_rando' +def test_api_get_role_attributes(app, admin_rando_role, role_random, role_attribute_details, role_attribute_emails): + app.authorization = ('Basic', (admin_rando_role.username, admin_rando_role.username)) + resp = app.get('/api/roles/{}/'.format(role_random.uuid)) + + assert len(RoleAttribute.objects.filter(role=role_random)) == 2 + + def test_api_get_role_not_found(app, superuser): app.authorization = ('Basic', (superuser.username, superuser.username)) app.get('/api/roles/thisisnotavalidroleslug/', status=404) -- 2.17.0