From 4ba643ed24e3ccf61e37477970d1c721712df2a6 Mon Sep 17 00:00:00 2001 From: Kyle Ferriter Date: Mon, 2 Apr 2018 16:45:28 -0400 Subject: [PATCH] added mechanism for manually retrieving a user's openid subject value --- .../token_service/redirect_handler.py | 7 +-- src/microservice/token_service/urls.py | 3 +- src/microservice/token_service/views.py | 59 +++++++++++++------ 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/microservice/token_service/redirect_handler.py b/src/microservice/token_service/redirect_handler.py index 05902c3..61a6a63 100644 --- a/src/microservice/token_service/redirect_handler.py +++ b/src/microservice/token_service/redirect_handler.py @@ -123,7 +123,7 @@ def block(self, uid, scopes, provider_tag): 'scopes': scopes, 'provider': provider_tag, 'lock': lock, - 'nonce': b['nonce'] + 'nonce': None } RedirectState.blocking.append(observer) return lock @@ -205,7 +205,6 @@ def accept(self, request): # expand the id_token to the encoded json object # TODO signature validation if signature provided - # fix padding if not a multiple of 4 id_token = jwt.decode(id_token, verify=False) print('id_token body:\n' + str(id_token)) @@ -376,10 +375,10 @@ def _generate_authorization_url(self, state, nonce, scopes, provider_tag): else: raise RuntimeError('unknown provider standard: ' + p['standard']) - url = '{}?state={}&nonce={}&redirect_uri={}&client_id={}&{}'.format( + url = '{}?nonce={}&state={}&redirect_uri={}&client_id={}&{}'.format( authorization_endpoint, - state, nonce, + state, redirect_uri, client_id, additional_params, diff --git a/src/microservice/token_service/urls.py b/src/microservice/token_service/urls.py index ea11559..f5cd62e 100644 --- a/src/microservice/token_service/urls.py +++ b/src/microservice/token_service/urls.py @@ -20,8 +20,9 @@ urlpatterns = [ path('admin/key', views.create_key, name='create_key'), + path('subject_by_nonce', views.subject_by_nonce, name='subject_by_nonce'), path('token', views.token, name='token'), - #path('tokenbynonce', views.token_by_nonce, name='token_by_url'), + path('authorize', views.url, name='url'), path('authcallback', views.authcallback, name='authcallback'), ] diff --git a/src/microservice/token_service/views.py b/src/microservice/token_service/views.py index 29e9f5f..78727ce 100644 --- a/src/microservice/token_service/views.py +++ b/src/microservice/token_service/views.py @@ -47,9 +47,9 @@ def _get_tokens(uid, scopes, provider): provider=provider ) -def _thread_block(lock, timeout): - with lock: - lock.wait(timeout) +def _get_tokens_by_nonce(nonce): + print('querying for tokens(nonce): ({})'.format(nonce)) + return models.Token.objects.filter(nonce=nonce) def _valid_api_key(request): authorization = request.META.get('HTTP_AUTHORIZATION') @@ -66,19 +66,45 @@ def _valid_api_key(request): return True return False +''' +No authentication required, will just return a login url +''' @require_http_methods(['GET']) -def token_by_nonce(request): - if not _valid_api_key(request): - return HttpResponseForbidden('must provide valid api key') +def url(request): + scope = request.GET.get('scope') + provider = request.GET.get('provider') + if not scope: + print('scope: ' + str(scope)) + return HttpResponseBadRequest('missing scope') + else: + scopes = scope.split(' ') + if len(scopes) == 0: + return HttpResponseBadRequest('no scopes provided') + + if not provider: + return HttpResponseBadRequest('missing provider') + + handler = redirect_handler.RedirectHandler() + url = handler.add(None, scopes, provider) + return JsonResponse(status=401, data={'authorization_url': url}) + + +@require_http_methods(['GET']) +def subject_by_nonce(request): nonce = request.GET.get('nonce') block = request.GET.get('block') - - # combine with other validation - block = int(block) + if block: + if isint(block): + block = int(block) + if block < 0: + return HttpResponseBadRequest('if block param included, must be false or a positive integer') + elif block.lower() == 'false': + block = False + else: + return HttpResponseBadRequest('if block param included, must be false or a positive integer') + tokens = models.Token.objects.filter(nonce=nonce) - if tokens.count() > 0: - return JsonResponse(status=200, data={'access_token': token.access_token,'uid':token.user.id}) - else: + if tokens.count() == 0: handler = redirect_handler.RedirectHandler() lock = handler.block_nonce(nonce) if not lock: #TODO clean this logic up @@ -91,9 +117,9 @@ def token_by_nonce(request): tokens = models.Token.objects.filter(nonce=nonce) if tokens.count() == 0: return HttpResponseNotFound('no token which meets required criteria') - else: - return JsonResponse(status=200, data={'access_token': token.access_token,'uid':token.user.id}) + token = tokens[0] + return JsonResponse(status=200, data={'uid':token.user.id}) @require_http_methods(['GET']) def token(request): @@ -165,7 +191,7 @@ def token(request): lock.wait(block) # see if it was actually satisfied, or just woken up for timeout if nonce: - models.Token.objects.filter(nonce=nonce) + tokens = models.Token.objects.filter(nonce=nonce) else: tokens = _get_tokens(uid, scopes, provider) @@ -189,9 +215,6 @@ def prune_duplicate_tokens(tokens): def authcallback(request): - #authorization_code = request.GET.get('code') - #state = request.GET.get('state') - # check state against active list # get provider corresponding to the state # exchange code for token response via that provider's token endpoint