Fix token introspection "aud" and "client_id" response

Based on the OAuth 2.0 Token Introspection spec the "aud" field should
be based on the token. Previously "aud" was populated with the id of the
client making the introspection request which seems wrong. This changes
the endpoint to return the value from the token.

The "client_id" field is then changed to return the client id for the
client that originally requested the token rather than returning the
"aud" value from the token.

From the spec https://tools.ietf.org/html/rfc7662:

   client_id
      OPTIONAL.  Client identifier for the OAuth 2.0 client that
      requested this token.

   aud
      OPTIONAL.  Service-specific string identifier or list of string
      identifiers representing the intended audience for this token, as
      defined in JWT [RFC7519].
This commit is contained in:
Andy Clayton 2018-07-03 11:32:29 -05:00
parent 50733f8135
commit b1e994aa7e
2 changed files with 11 additions and 10 deletions

View file

@ -18,6 +18,7 @@ class TokenIntrospectionEndpoint(object):
def __init__(self, request):
self.request = request
self.params = {}
self.token = None
self.id_token = None
self.client = None
self._extract_params()
@ -37,19 +38,19 @@ class TokenIntrospectionEndpoint(object):
logger.debug('[Introspection] No token provided')
raise TokenIntrospectionError()
try:
token = Token.objects.get(access_token=self.params['token'])
self.token = Token.objects.get(access_token=self.params['token'])
except Token.DoesNotExist:
logger.debug('[Introspection] Token does not exist: %s', self.params['token'])
raise TokenIntrospectionError()
if token.has_expired():
if self.token.has_expired():
logger.debug('[Introspection] Token is not valid: %s', self.params['token'])
raise TokenIntrospectionError()
if not token.id_token:
if not self.token.id_token:
logger.debug('[Introspection] Token not an authentication token: %s',
self.params['token'])
raise TokenIntrospectionError()
self.id_token = token.id_token
self.id_token = self.token.id_token
audience = self.id_token.get('aud')
if not audience:
logger.debug('[Introspection] No audience found for token: %s', self.params['token'])
@ -74,10 +75,9 @@ class TokenIntrospectionEndpoint(object):
raise TokenIntrospectionError()
def create_response_dic(self):
response_dic = dict((k, self.id_token[k]) for k in ('sub', 'exp', 'iat', 'iss'))
response_dic = dict((k, self.id_token[k]) for k in ('aud', 'sub', 'exp', 'iat', 'iss'))
response_dic['active'] = True
response_dic['client_id'] = self.id_token.get('aud')
response_dic['aud'] = self.client.client_id
response_dic['client_id'] = self.token.client.client_id
response_dic = run_processing_hook(response_dic,
'OIDC_INTROSPECTION_PROCESSING_HOOK',

View file

@ -30,16 +30,17 @@ class IntrospectionTestCase(TestCase):
call_command('creatersakey')
self.factory = RequestFactory()
self.user = create_fake_user()
self.aud = 'testaudience'
self.client = create_fake_client(response_type='id_token token')
self.resource = create_fake_client(response_type='id_token token')
self.resource.scope = ['token_introspection', self.client.client_id]
self.resource.scope = ['token_introspection', self.aud]
self.resource.save()
self.token = create_fake_token(self.user, self.client.scope, self.client)
self.token.access_token = str(random.randint(1, 999999)).zfill(6)
self.now = time.time()
with patch('oidc_provider.lib.utils.token.time.time') as time_func:
time_func.return_value = self.now
self.token.id_token = create_id_token(self.token, self.user, self.client.client_id)
self.token.id_token = create_id_token(self.token, self.user, self.aud)
self.token.save()
def _assert_inactive(self, response):
@ -50,7 +51,7 @@ class IntrospectionTestCase(TestCase):
self.assertEqual(response.status_code, 200)
expected_content = {
'active': True,
'aud': self.resource.client_id,
'aud': self.aud,
'client_id': self.client.client_id,
'sub': str(self.user.pk),
'iat': int(self.now),