Fix scope handling of token endpoint (#193)

The token endpoint handled the scope parameter incorrectly for all of
the three handled grant types:

 1. For "authorization_code" grant type the scope parameter in the token
    request should not be respected but the scope should be taken from
    the authorization code.  It was not totally ignored, but rather the
    scope parameter of the token request was used for the generated ID
    token.  This had two consequences:

      * Spec conforming implementations of authorization code flow
        didn't get correct ID tokens, since they usually don't pass
        scope parameter with the token request.

      * It's possible to get a broader scope for the ID token than what
        is authorized by the user in the original authorization code
        request.

 2. For "refresh_token" grant type the scope parameter in the token
    request should only allow narrowing down the scope.  It wasn't
    narrowed, but rather the original auth code scope was used for the
    access token and the passed in scope parameter was used for the ID
    token (again allowing unauthorized scopes in the ID token).

 3. For "password" grant type the scope parameter in the token request
    should be respected.  The problem with this was that it wasn't
    properly splitted when passed to ID token creation.

Fixes #186
This commit is contained in:
Tuomas Suutari 2017-07-10 18:48:12 +03:00 committed by Wojciech Bartosiak
parent eed581399e
commit ea340993b1
3 changed files with 116 additions and 21 deletions

View file

@ -159,6 +159,8 @@ class TokenEndpoint(object):
return self.create_access_token_response_dic()
def create_access_token_response_dic(self):
# See https://tools.ietf.org/html/rfc6749#section-4.3
token = create_token(
self.user,
self.client,
@ -170,7 +172,7 @@ class TokenEndpoint(object):
nonce='self.code.nonce',
at_hash=token.at_hash,
request=self.request,
scope=self.params['scope'],
scope=token.scope,
)
token.id_token = id_token_dic
@ -185,6 +187,8 @@ class TokenEndpoint(object):
}
def create_code_response_dic(self):
# See https://tools.ietf.org/html/rfc6749#section-4.1
token = create_token(
user=self.code.user,
client=self.code.client,
@ -197,7 +201,7 @@ class TokenEndpoint(object):
nonce=self.code.nonce,
at_hash=token.at_hash,
request=self.request,
scope=self.params['scope'],
scope=token.scope,
)
else:
id_token_dic = {}
@ -220,10 +224,18 @@ class TokenEndpoint(object):
return dic
def create_refresh_response_dic(self):
# See https://tools.ietf.org/html/rfc6749#section-6
scope_param = self.params['scope']
scope = (scope_param.split(' ') if scope_param else self.token.scope)
unauthorized_scopes = set(scope) - set(self.token.scope)
if unauthorized_scopes:
raise TokenError('invalid_scope')
token = create_token(
user=self.token.user,
client=self.token.client,
scope=self.token.scope)
scope=scope)
# If the Token has an id_token it's an Authentication request.
if self.token.id_token:
@ -233,7 +245,7 @@ class TokenEndpoint(object):
nonce=None,
at_hash=token.at_hash,
request=self.request,
scope=self.params['scope'],
scope=token.scope,
)
else:
id_token_dic = {}