diff --git a/README.md b/README.md index 979bef4..8f6ab97 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,9 @@ OIDC_AUTH = { # (Optional) Token prefix in Bearer authorization header (default 'Bearer') 'BEARER_AUTH_HEADER_PREFIX': 'Bearer', + + # (Optional) Create user if user authenticates but is not in the local database (default False) + 'CREATE_USER': False, } ``` diff --git a/oidc_auth/authentication.py b/oidc_auth/authentication.py index 9d76895..40e78ce 100644 --- a/oidc_auth/authentication.py +++ b/oidc_auth/authentication.py @@ -18,11 +18,27 @@ def get_user_by_id(request, id_token): User = get_user_model() - try: - user = User.objects.get_by_natural_key(id_token.get('sub')) - except User.DoesNotExist: - msg = _('Invalid Authorization header. User not found.') - raise AuthenticationFailed(msg) + if api_settings.CREATE_USER: + email = id_token.get('email', None) + first_name = id_token.get('given_name', '') + last_name = id_token.get('family_name', '') + if email: + user, created = User.objects.get_or_create(username=id_token.get('sub').lower(), + defaults={'first_name': first_name, + 'last_name': last_name, + 'email': email, + }) + else: + user, created = User.objects.get_or_create(username=id_token.get('sub'.lower()), + defaults={'first_name': first_name, + 'last_name': last_name, + }) + else: + try: + user = User.objects.get_by_natural_key(id_token.get('sub')) + except User.DoesNotExist: + msg = _('Invalid Authorization header. User not found.') + raise AuthenticationFailed(msg) return user diff --git a/oidc_auth/settings.py b/oidc_auth/settings.py index 5cccf26..5301e77 100644 --- a/oidc_auth/settings.py +++ b/oidc_auth/settings.py @@ -23,6 +23,9 @@ 'JWT_AUTH_HEADER_PREFIX': 'JWT', 'BEARER_AUTH_HEADER_PREFIX': 'Bearer', + + # Create user if user authenticates but is not in the local database + 'CREATE_USER': False, } # List of settings that may be in string import notation. diff --git a/tests/settings.py b/tests/settings.py index 8f768da..7280fdf 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -1,3 +1,5 @@ +import os + SECRET_KEY='secret' DATABASES = { 'default': { @@ -13,4 +15,5 @@ OIDC_AUTH = { 'OIDC_ENDPOINT': 'http://example.com', 'OIDC_AUDIENCES': ('you',), + 'CREATE_USER': os.getenv('CREATE_USER', 'yes') == 'yes', } diff --git a/tests/test_authentication.py b/tests/test_authentication.py index 538ecde..19d5e9c 100644 --- a/tests/test_authentication.py +++ b/tests/test_authentication.py @@ -11,6 +11,7 @@ from rest_framework.views import APIView from requests import Response, HTTPError, ConnectionError from oidc_auth.authentication import JSONWebTokenAuthentication, BearerTokenAuthentication +from oidc_auth.settings import api_settings import sys if sys.version_info > (3,): long = int @@ -208,7 +209,10 @@ def test_with_too_new_jwt(self): def test_with_unknown_subject(self): auth = 'JWT ' + make_id_token(self.user.username + 'x') resp = self.client.get('/test/', HTTP_AUTHORIZATION=auth) - self.assertEqual(resp.status_code, 401) + if not api_settings.CREATE_USER: + self.assertEqual(resp.status_code, 401) + else: + self.assertEqual(resp.status_code, 200) def test_with_multiple_audiences(self): auth = 'JWT ' + make_id_token(self.user.username, aud=['you', 'me']) diff --git a/tox.ini b/tox.ini index 8e8a14e..6d8b392 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - {py27,py34}-django{18,19,110}-drf{32} + {py27,py34}-django{18,19,110}-drf{32}-createuser{yes,no} [testenv] commands = @@ -9,6 +9,8 @@ setenv = PYTHONDONTWRITEBYTECODE=1 DJANGO_SETTINGS_MODULE=tests.settings PYTHONPATH={toxinidir} + createuseryes: CREATE_USER=yes + createuserno: CREATE_USER=no deps = django18: Django==1.8.4 django19: Django==1.9.12