Projet

Général

Profil

0001-WIP-add-role-creation-API-20706.patch

Paul Marillonnet, 18 janvier 2018 21:35

Télécharger (7,55 ko)

Voir les différences:

Subject: [PATCH] WIP add role-creation API (#20706)

 src/authentic2/api_urls.py  |  4 +++
 src/authentic2/api_views.py | 74 ++++++++++++++++++++++++++++++++++++++++++++-
 tests/conftest.py           |  6 ++++
 tests/test_api.py           | 45 +++++++++++++++++++++++++++
 4 files changed, 128 insertions(+), 1 deletion(-)
src/authentic2/api_urls.py
13 13
                           api_views.role_memberships, name='a2-api-role-member'),
14 14
                       url(r'^check-password/$', api_views.check_password,
15 15
                           name='a2-api-check-password'),
16
                       url(r'^ous/(?P<ou>[\w+]*)/roles/$',
17
                           api_views.roles_list_or_create, name='a2-api-role'),
18
                       url(r'^ous/(?P<ou>[\w+]*)/roles/(?P<slug>[\w+]*)/$',
19
                           api_views.roles_detail, name='a2-api-role'),
16 20
)
17 21
urlpatterns += api_views.router.urls
src/authentic2/api_views.py
27 27

  
28 28
from .custom_user.models import User
29 29
from . import utils, decorators, attribute_kinds, app_settings, hooks
30
from .models import Attribute, PasswordReset
30
from .models import Attribute, PasswordReset, Service
31 31
from .a2_rbac.utils import get_default_ou
32 32

  
33 33

  
......
444 444
        exclude = ('date_joined', 'user_permissions', 'groups', 'last_login')
445 445

  
446 446

  
447
class RoleSerializer(serializers.ModelSerializer):
448
    ou = serializers.SlugRelatedField(
449
        many=False,
450
        required=True,
451
        queryset=get_ou_model().objects.all(),
452
        slug_field='slug')
453
    uuid = serializers.CharField(required=True)
454
    name = serializers.CharField(required=True)
455
    slug = serializers.CharField(required=True)  # TODO? slugify from name?
456
    service = serializers.SlugRelatedField(
457
        many=False,
458
        required=False,
459
        queryset=Service.objects.all(),
460
        slug_field='slug')
461
    admin_scope_id = serializers.IntegerField(required=True, allow_null=True)
462
    # admin_scope_ct = serializers.IntegerField(required=True, allow_null=True) # XXX todo
463

  
464
    def __init__(self, *args, **kwargs):
465
        super(RoleSerializer, self).__init__(*args, **kwargs)
466
        request = kwargs['context'].get('request')
467
        if hasattr(request, 'parser_context'):
468
            ou = request.parser_context.get('kwargs', {}).get('ou')
469
            # XXX dirty
470
            #  /api/ous/(?P<ou>) not really a role lookup field
471
            #  but is necessary to restrain roles to a single OU.
472
            #  Gladly offering a pint to whoever fixes it...
473
            if 'data' in kwargs:
474
                kwargs['data']['ou'] = ou
475
            else:
476
                kwargs['data'] = {'ou': ou}
477

  
478
    # XXX That one won't fix the OU FK dereferencing issue while saving roles
479
    """
480
    def create(self, validated_data):
481
        Role = get_role_model()
482
        role = Role(**validated_data) # Necessary to created to FK linking to OU? Nope
483
        self.instance = role
484
        self.instance.save() # XXX Broken!! role.ou not saved in DB?!
485
        return role
486
    """
487

  
488
    # XXX That one won't fix it either, as it's not a data validation issue
489
    """
490
    def validate(self, data, *args, **kwargs):
491
        logger = logging.getLogger(__name__)
492
        data = super(RoleSerializer, self).validate(data, *args, **kwargs)
493
        Role = get_role_model()
494
        if len(Role.objects.filter(slug=data['slug'])):
495
            logger.error('error: role already existing in the A2 database')
496
            return
497
        return data
498
    """
499

  
500
    class Meta:
501
        model = get_role_model()
502
        fields = ['uuid', 'name', 'slug', 'ou',
503
                  'admin_scope_id', 'service']
504

  
505

  
447 506
class UsersFilter(FilterSet):
448 507
    class Meta:
449 508
        model = get_user_model()
......
576 635
        return Response({'result': 1})
577 636

  
578 637

  
638
class RolesAPI(ExceptionHandlerMixin, ModelViewSet):
639
    permission_classes = (permissions.IsAuthenticated,)
640
    serializer_class = RoleSerializer
641
    lookup_field = 'slug'
642

  
643
    def get_queryset(self):
644
        Role = get_role_model()
645
        return Role.objects.all()
646

  
647
roles_detail = RolesAPI.as_view({'get': 'retrieve'})
648
roles_list_or_create = RolesAPI.as_view({'post': 'create', 'get': 'list'})
649

  
650

  
579 651
class RoleMembershipsAPI(ExceptionHandlerMixin, APIView):
580 652
    permission_classes = (permissions.IsAuthenticated,)
581 653

  
tests/conftest.py
14 14
from authentic2.a2_rbac.utils import get_default_ou
15 15
from authentic2_idp_oidc.models import OIDCClient
16 16
from authentic2.authentication import OIDCUser
17
from authentic2.models import Service
17 18

  
18 19
import utils
19 20

  
......
46 47
    return OU.objects.create(name='ou_rando', slug='ou_rando')
47 48

  
48 49

  
50
@pytest.fixture
51
def service1(db):
52
    return Service.objects.create(name='Service1', slug='service1')
53

  
54

  
49 55
def create_user(**kwargs):
50 56
    User = get_user_model()
51 57
    password = kwargs.pop('password', None) or kwargs['username']
tests/test_api.py
30 30
    assert 'username' in resp.json
31 31

  
32 32

  
33
def test_api_post_role_simple(app, user, ou1, service1):
34
    role_data = {
35
        'slug': 'coffee-manager',
36
        'service': 'service1',
37
        'uuid': 'RhFactor001',
38
        'name': 'Coffee Manager',
39
        'admin_scope_id': 2
40
        }
41
    # 'admin_scope_ct': 1, # TODO
42
    app.authorization = ('Basic', (user.username, user.username))
43
    resp = app.post_json('/api/ous/ou1/roles/', params=role_data)
44
    assert isinstance(resp.json, dict)
45
    Role = get_role_model()
46
    posted_role = Role.objects.get(slug='coffee-manager')
47
    for key, value in role_data.items():
48
        assert key in resp.json.keys()
49
        assert value in resp.json.values()
50

  
51
    assert posted_role.slug == role_data['slug']
52
    assert posted_role.uuid == role_data['uuid']
53
    assert posted_role.name == role_data['name']
54
    assert posted_role.admin_scope_id == role_data['admin_scope_id']
55

  
56
    #assert posted_role.ou.slug == 'ou1' # XXX
57
    assert posted_role.service.slug == role_data['service']
58

  
59

  
60
def test_api_get_role_description(app, user, role_random):
61
    app.authorization = ('Basic', (user.username, user.username))
62
    resp = app.get('/api/ous/ou1/roles/rando/')
63

  
64
    assert resp.json['slug'] == 'rando'
65
    # TODO
66

  
67

  
68
def test_api_get_role_list(app, user, role_random):
69
    app.authorization = ('Basic', (user.username, user.username))
70
    resp = app.get('/api/ous/ou1/roles/')
71

  
72
    role_fields = ['slug', 'uuid', 'name', 'admin_scope_id', 'service']
73

  
74
    for role_dict in resp.json['results']:
75
        for field in role_fields:
76
            assert field in role_dict
77

  
33 78
def test_api_user(client):
34 79
    # create an user, an ou role, a service and a service role
35 80
    ou = get_default_ou()
36
-