From c6422e57ee2bf0512783927ed8bfd2a6e3eafee0 Mon Sep 17 00:00:00 2001 From: Paul Marillonnet Date: Fri, 12 Jan 2018 11:27:12 +0100 Subject: [PATCH] WIP add role creation api (#20706) --- src/authentic2/api_urls.py | 2 ++ src/authentic2/api_views.py | 64 +++++++++++++++++++++++++++++++++++++++++++-- tests/conftest.py | 6 +++++ tests/test_api.py | 27 +++++++++++++++++++ 4 files changed, 97 insertions(+), 2 deletions(-) diff --git a/src/authentic2/api_urls.py b/src/authentic2/api_urls.py index 61e6d9df..4a725bdf 100644 --- a/src/authentic2/api_urls.py +++ b/src/authentic2/api_urls.py @@ -13,5 +13,7 @@ urlpatterns = patterns('', api_views.role_memberships, name='a2-api-role-member'), url(r'^check-password/$', api_views.check_password, name='a2-api-check-password'), + url(r'^ous/(?P[\w+]*)/roles/', + api_views.roles, name='a2-api-role'), ) urlpatterns += api_views.router.urls diff --git a/src/authentic2/api_views.py b/src/authentic2/api_views.py index 95fb99ee..d973f48b 100644 --- a/src/authentic2/api_views.py +++ b/src/authentic2/api_views.py @@ -4,7 +4,7 @@ import smtplib from django.db import models from django.contrib.auth import get_user_model -from django.core.exceptions import MultipleObjectsReturned +from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist from django.utils.translation import ugettext as _ from django.views.decorators.vary import vary_on_headers from django.views.decorators.cache import cache_control @@ -27,7 +27,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 .models import Attribute, PasswordReset, Service from .a2_rbac.utils import get_default_ou @@ -444,6 +444,59 @@ class BaseUserSerializer(serializers.ModelSerializer): exclude = ('date_joined', 'user_permissions', 'groups', 'last_login') +class RoleSerializer(serializers.ModelSerializer): + ou = serializers.SlugRelatedField( + many=False, + required=True, + queryset=get_ou_model().objects.all(), + slug_field='slug') + uuid = serializers.CharField(required=True) + name = serializers.CharField(required=True) + slug = serializers.CharField(required=True) # TODO? slugify from name? + service = serializers.SlugRelatedField( + many=False, + required=False, + queryset=Service.objects.all(), + slug_field='slug') + admin_scope_id = serializers.IntegerField(required=True, allow_null=True) + # admin_scope_ct = serializers.IntegerField(required=True, allow_null=True) # XXX todo + + def __init__(self, *args, **kwargs): + super(RoleSerializer, self).__init__(*args, **kwargs) + request = kwargs['context'].get('request') + if hasattr(request, 'parser_context'): + ou = request.parser_context.get('kwargs', {}).get('ou') + kwargs['data']['ou'] = ou + + """ + # XXX That one won't fix the OU FK dereferencing issue while saving + def create(self, validated_data): + Role = get_role_model() + role = Role(**validated_data) # Necessary to created to FK linking to OU? Nope + self.instance = role + self.instance.save() # XXX Broken!! role.ou not saved in DB?! + return role + """ + + """ + # XXX That one won't fix it either, as it's not a data validation issue + def validate(self, data, *args, **kwargs): + logger = logging.getLogger(__name__) + data = super(RoleSerializer, self).validate(data, *args, **kwargs) + Role = get_role_model() + if len(Role.objects.filter(slug=data['slug'])): + logger.error('error: role already existing in the A2 database') + return + import pdb; pdb.set_trace() + return data + """ + + class Meta: + model = get_role_model() + fields = ['uuid', 'name', 'slug', 'ou', + 'admin_scope_id', 'service'] + + class UsersFilter(FilterSet): class Meta: model = get_user_model() @@ -576,6 +629,13 @@ class UsersAPI(HookMixin, ExceptionHandlerMixin, ModelViewSet): return Response({'result': 1}) +class RolesAPI(ExceptionHandlerMixin, ModelViewSet): + permission_classes = (permissions.IsAuthenticated,) + serializer_class = RoleSerializer + +roles = RolesAPI.as_view({'post': 'create'}) + + class RoleMembershipsAPI(ExceptionHandlerMixin, APIView): permission_classes = (permissions.IsAuthenticated,) diff --git a/tests/conftest.py b/tests/conftest.py index e968d341..39635c77 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,6 +14,7 @@ from pytest_django.migrations import DisableMigrations from authentic2.a2_rbac.utils import get_default_ou from authentic2_idp_oidc.models import OIDCClient from authentic2.authentication import OIDCUser +from authentic2.models import Service import utils @@ -46,6 +47,11 @@ def ou_rando(db): return OU.objects.create(name='ou_rando', slug='ou_rando') +@pytest.fixture +def service1(db): + return Service.objects.create(name='Service1', slug='service1') + + def create_user(**kwargs): User = get_user_model() password = kwargs.pop('password', None) or kwargs['username'] diff --git a/tests/test_api.py b/tests/test_api.py index 96085590..b21902b4 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -30,6 +30,33 @@ def test_api_user_simple(logged_app): assert 'username' in resp.json +def test_api_role_simple(app, user, ou1, service1): + role_data = { + 'slug': 'coffee-manager', + 'service': 'service1', + 'uuid': 'RhFactor001', + 'name': 'Coffee Manager', + 'admin_scope_id': 2 + } + # 'admin_scope_ct': 1, # TODO + app.authorization = ('Basic', (user.username, user.username)) + resp = app.post_json('/api/ous/ou1/roles/', params=role_data) + assert isinstance(resp.json, dict) + Role = get_role_model() + posted_role = Role.objects.get(slug='coffee-manager') + for key, value in role_data.items(): + assert key in resp.json.keys() + assert value in resp.json.values() + + assert posted_role.slug == role_data['slug'] + assert posted_role.uuid == role_data['uuid'] + assert posted_role.name == role_data['name'] + assert posted_role.admin_scope_id == role_data['admin_scope_id'] + + assert posted_role.ou.slug == 'ou1' + assert posted_role.service.slug == role_data['service'] + + def test_api_user(client): # create an user, an ou role, a service and a service role ou = get_default_ou() -- 2.11.0