generate a random state linked to the session

Instead of encoding the redirect_uri in the state we:
* generate a random state with 128 bits of entropy
* store the state and the redirect_uri in the session
* verify that the state exist when receivng the callback
* retrieving the redirect_uri linked to this state from the session
This commit is contained in:
Benjamin Dauvergne 2017-06-14 09:35:41 +02:00
parent d888f1f8ac
commit 27642283cc
1 changed files with 23 additions and 9 deletions

View File

@ -64,13 +64,20 @@ def ask_authorization(request, scopes, logger):
if not isinstance(scopes, (list, tuple)):
scopes = [scopes]
redirect_uri = request.build_absolute_uri()
state = unicode(uuid.uuid4())
nonce = unicode(uuid.uuid4())
states = request.session.setdefault('fc-states', {})
states[state] = {
'redirect_uri': redirect_uri,
}
request.session.modified = True
params = {
'client_id': app_settings.client_id,
'scope': ' '.join(scopes),
'redirect_uri': redirect_uri,
'response_type': 'code',
'state': base64.b64encode(redirect_uri),
'nonce': str(uuid.uuid1()),
'state': state,
'nonce': nonce,
}
logger.debug('query string %s', params)
url = '{0}?{1}'.format(app_settings.authorize_url, urlencode(params))
@ -119,13 +126,19 @@ def access_token_from_request(request, logger):
'''Resolve an access token given a request returning from the authorization
endpoint.
'''
authorization_code = request.GET['code']
if 'state' in request.GET:
state = request.GET.get('state')
redirect_uri = base64.b64decode(state)
else:
redirect_uri = request.GET['redirect_uri']
return resolve_access_token(authorization_code, redirect_uri, logger)
code = request.GET.get('code')
state = request.GET.get('state')
if not code:
return
if not state:
return
states = request.session.get('fc-states', {})
if state not in states:
return
# there should not be many FC SSO in flight
request.session.pop('fc-states', None)
redirect_uri = states[state]['redirect_uri']
return resolve_access_token(code, redirect_uri, logger)
ACCESS_GRANT_CODE = 'accessgrantcode'
@ -452,6 +465,7 @@ class LogoutReturnView(View):
request.session.pop('fc-id_token_raw', None)
request.session.pop('fc-user_info', None)
request.session.pop('fc-data', None)
request.session.pop('fc-states', None)
return HttpResponseRedirect(reverse('auth_logout'))
logout = LogoutReturnView.as_view()