Project

General

Profile

0001-add-get-or-create-users-api-call-22376.patch

Paul Marillonnet, 05 Oct 2018 04:04 PM

Download (6.12 KB)

View differences:

Subject: [PATCH] add 'get or create' users api call (#22376)

 src/authentic2/api_views.py    |  7 ++++++
 src/authentic2/app_settings.py |  1 +
 src/authentic2/utils.py        | 41 +++++++++++++++++++++++++++++++++-
 tests/test_api.py              | 31 +++++++++++++++++++++++++
 4 files changed, 79 insertions(+), 1 deletion(-)
src/authentic2/api_views.py
571 571
    def put(self, request, *args, **kwargs):
572 572
        return self.patch(request, *args, **kwargs)
573 573

  
574
    def list(self, request, *args, **kwargs):
575
        get_or_create_kwargs = utils.user_get_or_create_kwargs(request)
576
        if get_or_create_kwargs:
577
           payload, status = utils.user_get_or_create(request, get_or_create_kwargs)
578
           return Response(payload, status)
579
        return super(UsersAPI, self).list(request, *args, **kwargs)
580

  
574 581
    def check_perm(self, perm, ou):
575 582
        if ou:
576 583
            if not self.request.user.has_ou_perm(perm, ou):
src/authentic2/app_settings.py
206 206
    A2_ACCOUNTS_URL=Setting(default=None, definition='IdP has no account page, redirect to this one.'),
207 207
    A2_CACHE_ENABLED=Setting(default=True, definition='Disable all cache decorators for testing purpose.'),
208 208
    A2_ACCEPT_EMAIL_AUTHENTICATION=Setting(default=True, definition='Enable authentication by email'),
209
    A2_USERS_API_GET_OR_CREATE_WHITELIST_FIELDS=Setting(default=['email', 'username', 'ou__slug'], definition='Whitelist fields for "get or create" operations in the users API.'),
209 210

  
210 211
)
211 212

  
src/authentic2/utils.py
16 16

  
17 17
from django.conf import settings
18 18
from django.http import HttpResponseRedirect, HttpResponse
19
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
19
from django.core.exceptions import (ImproperlyConfigured, PermissionDenied,
20
        ObjectDoesNotExist, MultipleObjectsReturned)
20 21
from django.http.request import QueryDict
21 22
from django.contrib.auth import (REDIRECT_FIELD_NAME, login as auth_login, SESSION_KEY,
22 23
                                 HASH_SESSION_KEY, BACKEND_SESSION_KEY, authenticate,
......
1073 1074
        if ou_value is not None:
1074 1075
            return ou_value
1075 1076
    return default
1077

  
1078

  
1079
def user_get_or_create(request, get_or_create_kwargs):
1080
    from django_rbac.utils import get_ou_model
1081

  
1082
    OrganizationalUnit = get_ou_model()
1083
    ou_slug = get_or_create_kwargs.get('ou__slug')
1084

  
1085
    try :
1086
        ou = OrganizationalUnit.objects.get(slug=ou_slug)
1087
    except (ObjectDoesNotExist, MultipleObjectsReturned) as e:
1088
        return ({'reason': 'OrganizationalUnit %s: %s' % (ou_slug, e)}, 400)
1089

  
1090
    if not request.user.has_ou_perm('custom_user.add_user', ou):
1091
        return ({'reason': 'Permission denied'}, 403)
1092

  
1093
    get_or_create_kwargs.update({'ou': ou})
1094
    try:
1095
        user, created = get_user_model().objects.get_or_create(**get_or_create_kwargs)
1096
    except MultipleObjectsReturned as e:
1097
        return ({'reason': 'Multiple objects returned'}, 400)
1098

  
1099
    return (user.to_json(), 200+created)
1100

  
1101

  
1102
def user_get_or_create_kwargs(request):
1103
    from authentic2.a2_rbac.utils import get_default_ou
1104

  
1105
    kwargs_dict = dict()
1106
    for key, value in request.GET.items():
1107
        if key.startswith('get_or_create_'):
1108
            fieldkey = key.split('get_or_create_')[-1]
1109
            if fieldkey in app_settings.A2_USERS_API_GET_OR_CREATE_WHITELIST_FIELDS:
1110
                kwargs_dict.update({fieldkey: value})
1111
    # provide default values for missing fields when possible:
1112
    if kwargs_dict and not kwargs_dict.get('ou__slug'):
1113
        kwargs_dict['ou__slug'] = get_default_ou().slug
1114
    return kwargs_dict
tests/test_api.py
934 934
    assert response.json['checks'][3]['result'] is True
935 935
    assert response.json['checks'][4]['label'] == 'must contain "ok"'
936 936
    assert response.json['checks'][4]['result'] is True
937

  
938

  
939
def test_api_users_get_or_create(app, superuser, simple_user, ou1):
940
    User = get_user_model()
941
    app.authorization = ('Basic', (superuser.username, superuser.username))
942
    url = u'/api/users/?get_or_create_email=john.doe@nowhere.null&' \
943
            'get_or_create_username=jdoe&get_or_create_ou__slug=%s' % ou1.slug
944

  
945
    assert not len(User.objects.filter(email='john.doe@nowhere.null',
946
            username='jdoe', ou__slug=ou1.slug))
947

  
948
    response = app.get(url, status=201) # created
949
    assert len(User.objects.filter(email='john.doe@nowhere.null',
950
            username='jdoe', ou__slug=ou1.slug)) == 1
951

  
952
    john = User.objects.get(email='john.doe@nowhere.null')
953
    uuid = john.uuid
954
    response = app.get(url, status=200) # not created
955
    assert len(User.objects.filter(email='john.doe@nowhere.null',
956
            username='jdoe', ou__slug=ou1.slug)) == 1
957
    assert uuid == User.objects.get(email='john.doe@nowhere.null').uuid
958

  
959
    wrong_ou_url = u'/api/users/?get_or_create_email=john.doe@nowhere.null&' \
960
            'get_or_create_username=jdoe&get_or_create_ou__slug=wrongwrongwrong'
961
    response = app.get(wrong_ou_url, status=400) # bad request
962

  
963
    app.authorization = ('Basic', (superuser.username, superuser.username+'nope'))
964
    response = app.get(url, status=401) # unauthorized
965

  
966
    app.authorization = ('Basic', (simple_user.username, simple_user.username))
967
    response = app.get(url, status=403) # permission denied
937
-