0001-WIP-add-role-creation-API-20706.patch
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 |
- |