Merge branch 'feature/token_retun_claims' of https://github.com/dhrp/django-oidc-provider into dhrp-feature/token_retun_claims

This commit is contained in:
Juan Ignacio Fiorentino 2018-04-10 18:41:38 -03:00
commit 56ad376518
10 changed files with 58 additions and 16 deletions

View file

@ -103,6 +103,13 @@ Default is::
return str(user.id) return str(user.id)
OIDC_IDTOKEN_INCLUDE_CLAIMS
==============================
OPTIONAL. ``bool``. If enabled, id_token will include standard claims of the user (email, first name, etc.).
Default is ``False``.
OIDC_SESSION_MANAGEMENT_ENABLE OIDC_SESSION_MANAGEMENT_ENABLE
============================== ==============================

View file

@ -158,6 +158,7 @@ class AuthorizeEndpoint(object):
# We don't need id_token if it's an OAuth2 request. # We don't need id_token if it's an OAuth2 request.
if self.is_authentication: if self.is_authentication:
kwargs = { kwargs = {
'token': token,
'user': self.request.user, 'user': self.request.user,
'aud': self.client.client_id, 'aud': self.client.client_id,
'nonce': self.params['nonce'], 'nonce': self.params['nonce'],

View file

@ -171,6 +171,7 @@ class TokenEndpoint(object):
id_token_dic = create_id_token( id_token_dic = create_id_token(
user=self.code.user, user=self.code.user,
aud=self.client.client_id, aud=self.client.client_id,
token=token,
nonce=self.code.nonce, nonce=self.code.nonce,
at_hash=token.at_hash, at_hash=token.at_hash,
request=self.request, request=self.request,
@ -215,6 +216,7 @@ class TokenEndpoint(object):
id_token_dic = create_id_token( id_token_dic = create_id_token(
user=self.token.user, user=self.token.user,
aud=self.client.client_id, aud=self.client.client_id,
token=token,
nonce=None, nonce=None,
at_hash=token.at_hash, at_hash=token.at_hash,
request=self.request, request=self.request,
@ -249,6 +251,7 @@ class TokenEndpoint(object):
self.params['scope'].split(' ')) self.params['scope'].split(' '))
id_token_dic = create_id_token( id_token_dic = create_id_token(
token=token,
user=self.user, user=self.user,
aud=self.client.client_id, aud=self.client.client_id,
nonce='self.code.nonce', nonce='self.code.nonce',

View file

@ -10,6 +10,7 @@ from jwkest.jws import JWS
from jwkest.jwt import JWT from jwkest.jwt import JWT
from oidc_provider.lib.utils.common import get_issuer from oidc_provider.lib.utils.common import get_issuer
from oidc_provider.lib.claims import StandardScopeClaims
from oidc_provider.models import ( from oidc_provider.models import (
Code, Code,
RSAKey, RSAKey,
@ -18,7 +19,7 @@ from oidc_provider.models import (
from oidc_provider import settings from oidc_provider import settings
def create_id_token(user, aud, nonce='', at_hash='', request=None, scope=None): def create_id_token(token, user, aud, nonce='', at_hash='', request=None, scope=None):
""" """
Creates the id_token dictionary. Creates the id_token dictionary.
See: http://openid.net/specs/openid-connect-core-1_0.html#IDToken See: http://openid.net/specs/openid-connect-core-1_0.html#IDToken
@ -52,8 +53,14 @@ def create_id_token(user, aud, nonce='', at_hash='', request=None, scope=None):
if at_hash: if at_hash:
dic['at_hash'] = at_hash dic['at_hash'] = at_hash
if ('email' in scope) and getattr(user, 'email', None): # Inlude (or not) user standard claims in the id_token.
dic['email'] = user.email if settings.get('OIDC_IDTOKEN_INCLUDE_CLAIMS'):
if settings.get('OIDC_EXTRA_SCOPE_CLAIMS'):
custom_claims = settings.get('OIDC_EXTRA_SCOPE_CLAIMS', import_str=True)(token)
claims = custom_claims.create_response_dic()
else:
claims = StandardScopeClaims(token).create_response_dic()
dic.update(claims)
processing_hook = settings.get('OIDC_IDTOKEN_PROCESSING_HOOK') processing_hook = settings.get('OIDC_IDTOKEN_PROCESSING_HOOK')

View file

@ -72,6 +72,13 @@ class DefaultSettings(object):
""" """
return 'oidc_provider.lib.utils.common.default_sub_generator' return 'oidc_provider.lib.utils.common.default_sub_generator'
@property
def OIDC_IDTOKEN_INCLUDE_CLAIMS(self):
"""
OPTIONAL. If enabled, id_token will include standard claims of the user.
"""
return False
@property @property
def OIDC_SESSION_MANAGEMENT_ENABLE(self): def OIDC_SESSION_MANAGEMENT_ENABLE(self):
""" """

View file

@ -97,6 +97,7 @@ def userinfo(claims, user):
claims['family_name'] = 'Doe' claims['family_name'] = 'Doe'
claims['name'] = '{0} {1}'.format(claims['given_name'], claims['family_name']) claims['name'] = '{0} {1}'.format(claims['given_name'], claims['family_name'])
claims['email'] = user.email claims['email'] = user.email
claims['email_verified'] = True
claims['address']['country'] = 'Argentina' claims['address']['country'] = 'Argentina'
return claims return claims

View file

@ -6,6 +6,7 @@ except ImportError:
from django.test import TestCase from django.test import TestCase
from oidc_provider.lib.utils.token import ( from oidc_provider.lib.utils.token import (
create_token,
create_id_token, create_id_token,
encode_id_token, encode_id_token,
) )
@ -44,8 +45,9 @@ class EndSessionTestCase(TestCase):
response, settings.get('OIDC_LOGIN_URL'), response, settings.get('OIDC_LOGIN_URL'),
fetch_redirect_response=False) fetch_redirect_response=False)
token = create_token(self.user, self.oidc_client, [])
id_token_dic = create_id_token( id_token_dic = create_id_token(
user=self.user, aud=self.oidc_client.client_id) token=token, user=self.user, aud=self.oidc_client.client_id)
id_token = encode_id_token(id_token_dic, self.oidc_client) id_token = encode_id_token(id_token_dic, self.oidc_client)
query_params['id_token_hint'] = id_token query_params['id_token_hint'] = id_token
@ -59,8 +61,9 @@ class EndSessionTestCase(TestCase):
query_params = { query_params = {
'post_logout_redirect_uri': self.LOGOUT_URL, 'post_logout_redirect_uri': self.LOGOUT_URL,
} }
token = create_token(self.user, self.oidc_client, [])
id_token_dic = create_id_token( id_token_dic = create_id_token(
user=self.user, aud=self.oidc_client.client_id) token=token, user=self.user, aud=self.oidc_client.client_id)
id_token_dic['aud'] = [id_token_dic['aud']] id_token_dic['aud'] = [id_token_dic['aud']]
id_token = encode_id_token(id_token_dic, self.oidc_client) id_token = encode_id_token(id_token_dic, self.oidc_client)
query_params['id_token_hint'] = id_token query_params['id_token_hint'] = id_token

View file

@ -281,17 +281,19 @@ class TokenTestCase(TestCase):
self.assertEqual(id_token['sub'], str(self.user.id)) self.assertEqual(id_token['sub'], str(self.user.id))
self.assertEqual(id_token['aud'], self.client.client_id) self.assertEqual(id_token['aud'], self.client.client_id)
@override_settings(OIDC_TOKEN_EXPIRE=720) @override_settings(OIDC_TOKEN_EXPIRE=720,
OIDC_IDTOKEN_INCLUDE_CLAIMS=True)
def test_scope_is_ignored_for_auth_code(self): def test_scope_is_ignored_for_auth_code(self):
""" """
Scope is ignored for token respones to auth code grant type. Scope is ignored for token respones to auth code grant type.
This comes down to that the scopes requested in authorize are returned.
""" """
SIGKEYS = self._get_keys() SIGKEYS = self._get_keys()
for code_scope in [['openid'], ['openid', 'email']]: for code_scope in [['openid'], ['openid', 'email'], ['openid', 'profile']]:
code = self._create_code(code_scope) code = self._create_code(code_scope)
post_data = self._auth_code_post_data( post_data = self._auth_code_post_data(
code=code.code, scope=['openid', 'profile']) code=code.code, scope=code_scope)
response = self._post_request(post_data) response = self._post_request(post_data)
response_dic = json.loads(response.content.decode('utf-8')) response_dic = json.loads(response.content.decode('utf-8'))
@ -302,9 +304,15 @@ class TokenTestCase(TestCase):
if 'email' in code_scope: if 'email' in code_scope:
self.assertIn('email', id_token) self.assertIn('email', id_token)
self.assertIn('email_verified', id_token)
else: else:
self.assertNotIn('email', id_token) self.assertNotIn('email', id_token)
if 'profile' in code_scope:
self.assertIn('given_name', id_token)
else:
self.assertNotIn('given_name', id_token)
def test_refresh_token(self): def test_refresh_token(self):
""" """
A request to the Token Endpoint can also use a Refresh Token A request to the Token Endpoint can also use a Refresh Token
@ -333,6 +341,7 @@ class TokenTestCase(TestCase):
""" """
self.do_refresh_token_check(scope=['openid']) self.do_refresh_token_check(scope=['openid'])
@override_settings(OIDC_IDTOKEN_INCLUDE_CLAIMS=True)
def do_refresh_token_check(self, scope=None): def do_refresh_token_check(self, scope=None):
SIGKEYS = self._get_keys() SIGKEYS = self._get_keys()

View file

@ -41,18 +41,20 @@ class UserInfoTestCase(TestCase):
extra_scope = [] extra_scope = []
scope = ['openid', 'email'] + extra_scope scope = ['openid', 'email'] + extra_scope
token = create_token(
user=self.user,
client=self.client,
scope=scope)
id_token_dic = create_id_token( id_token_dic = create_id_token(
token=token,
user=self.user, user=self.user,
aud=self.client.client_id, aud=self.client.client_id,
nonce=FAKE_NONCE, nonce=FAKE_NONCE,
scope=scope, scope=scope,
) )
token = create_token( token.id_token = id_token_dic
user=self.user,
client=self.client,
id_token_dic=id_token_dic,
scope=scope)
token.save() token.save()
return token return token

View file

@ -8,8 +8,8 @@ from django.utils import timezone
from mock import mock from mock import mock
from oidc_provider.lib.utils.common import get_issuer, get_browser_state_or_default from oidc_provider.lib.utils.common import get_issuer, get_browser_state_or_default
from oidc_provider.lib.utils.token import create_id_token from oidc_provider.lib.utils.token import create_token, create_id_token
from oidc_provider.tests.app.utils import create_fake_user from oidc_provider.tests.app.utils import create_fake_user, create_fake_client
class Request(object): class Request(object):
@ -67,7 +67,9 @@ class TokenTest(TestCase):
start_time = int(time.time()) start_time = int(time.time())
login_timestamp = start_time - 1234 login_timestamp = start_time - 1234
self.user.last_login = timestamp_to_datetime(login_timestamp) self.user.last_login = timestamp_to_datetime(login_timestamp)
id_token_data = create_id_token(self.user, aud='test-aud') client = create_fake_client("code")
token = create_token(self.user, client, [])
id_token_data = create_id_token(token=token, user=self.user, aud='test-aud')
iat = id_token_data['iat'] iat = id_token_data['iat']
self.assertEqual(type(iat), int) self.assertEqual(type(iat), int)
self.assertGreaterEqual(iat, start_time) self.assertGreaterEqual(iat, start_time)