def _access_token_post_parse_request(self, request, client_id="", **kwargs): """ This is where clients come to get their access tokens :param request: The request :param authn: Authentication info, comes from HTTP header :returns: """ request = AccessTokenRequest(**request.to_dict()) if "state" in request: try: sinfo = self.endpoint_context.sdb[request["code"]] except KeyError: logger.error("Code not present in SessionDB") return self.error_cls(error="unauthorized_client") else: state = sinfo["authn_req"]["state"] if state != request["state"]: logger.error("State value mismatch") return self.error_cls(error="unauthorized_client") if "client_id" not in request: # Optional for access token request request["client_id"] = client_id logger.debug("%s: %s" % (request.__class__.__name__, sanitize(request))) return request
def service_endpoint(endpoint): logger.info('At the "{}" endpoint'.format(endpoint.endpoint_name)) try: authn = request.headers['Authorization'] except KeyError: pr_args = {} else: pr_args = {'auth': authn} if request.method == 'GET': req_args = endpoint.parse_request(request.args.to_dict(), **pr_args) else: if request.data: req_args = request.data else: req_args = dict([(k, v) for k, v in request.form.items()]) req_args = endpoint.parse_request(req_args, **pr_args) logger.info('request: {}'.format(req_args)) if isinstance(req_args, ResponseMessage) and 'error' in req_args: return make_response(req_args.to_json(), 400) try: if request.cookies: kwargs = {'cookie': request.cookies} else: kwargs = {} if isinstance(endpoint, AccessToken): args = endpoint.process_request(AccessTokenRequest(**req_args), **kwargs) else: args = endpoint.process_request(req_args, **kwargs) except Exception as err: message = traceback.format_exception(*sys.exc_info()) # cherrypy.response.headers['Content-Type'] = 'text/html' return make_response( json.dumps({ 'error': 'server_error', 'error_description': message }, sort_keys=True, indent=4), 400) logger.info('Response args: {}'.format(args)) if 'http_response' in args: return make_response(args['http_response'], 200) return do_response(endpoint, req_args, **args)
def test_construct_client_assertion(self): token_service = self.entity.client_get("service", 'accesstoken') request = AccessTokenRequest() pkj = PrivateKeyJWT() http_args = pkj.construct(request, service=token_service, authn_endpoint='token_endpoint') assert http_args == {} _jws = factory(request["client_assertion"]) _payload = _jws.jwt.payload() assert "iss" in _payload assert _payload["iss"] == 'https://foodle.uninett.no' assert _payload["sub"] == 'https://foodle.uninett.no' assert request['client_assertion_type'] == JWT_BEARER
def service_endpoint(request, endpoint): """ TODO: documentation here """ logger.info('Request at the "{}" endpoint'.format(endpoint.name)) http_info = _get_http_info(request) data = _get_http_data(request, http_info) req_args = endpoint.parse_request(data, http_info=http_info) try: if isinstance(endpoint, Token): args = endpoint.process_request(AccessTokenRequest(**req_args), http_info=http_info) else: args = endpoint.process_request(req_args, http_info=http_info) except (InvalidClient, UnknownClient, UnAuthorizedClient) as err: logger.error(err) return JsonResponse(json.dumps({ 'error': 'unauthorized_client', 'error_description': str(err) }), safe=False, status=400) except Exception as err: logger.error(err) return JsonResponse(json.dumps({ 'error': 'invalid_request', 'error_description': str(err), 'method': request.method }), safe=False, status=400) if isinstance(req_args, ResponseMessage) and 'error' in req_args: return JsonResponse(req_args.__dict__, status=400) elif 'redirect_location' in args: return HttpResponseRedirect(args['redirect_location']) elif 'http_response' in args: return HttpResponse(args['http_response'], status=200) return do_response(request, endpoint, req_args, **args)
"request_uri_parameter_supported": True, } AUTH_REQ = AuthorizationRequest( client_id="client_1", redirect_uri="https://example.com/cb", scope=["openid"], state="STATE", response_type="code id_token", ) TOKEN_REQ = AccessTokenRequest( client_id="client_1", redirect_uri="https://example.com/cb", state="STATE", grant_type="authorization_code", client_secret="hemligt", ) TOKEN_REQ_DICT = TOKEN_REQ.to_dict() BASEDIR = os.path.abspath(os.path.dirname(__file__)) def full_path(local_file): return os.path.join(BASEDIR, local_file) class TestEndpoint(object): @pytest.fixture(autouse=True)
def test_code_flow(self): # code is a Token instance code = self.auth() # next step is access token request TOKEN_REQ = AccessTokenRequest( client_id="client_1", redirect_uri="https://example.com/cb", state="STATE", grant_type="authorization_code", client_secret="hemligt", code=code.value, ) # parse the token session_id = self.session_manager.token_handler.sid(TOKEN_REQ["code"]) user_id, client_id, grant_id = self.session_manager.decrypt_session_id( session_id) # Now given I have the client_id from the request and the user_id from the # token I can easily find the grant # client_info = self.session_manager.get([user_id, TOKEN_REQ['client_id']]) tok = self.session_manager.find_token(session_id, TOKEN_REQ["code"]) # Verify that it's of the correct type and can be used assert tok.token_class == "authorization_code" assert tok.is_active() # Mint an access token and a refresh token and mark the code as used assert tok.supports_minting("access_token") client_info = self.session_manager.get( [user_id, TOKEN_REQ["client_id"]]) assert tok.supports_minting("access_token") grant = self.session_manager[session_id] grant.mint_token( session_id=session_id, endpoint_context=self.endpoint_context, token_class="access_token", token_handler=self.session_manager.token_handler["access_token"], expires_at=time_sans_frac() + 900, # 15 minutes from now based_on=tok, # Means the token (tok) was used to mint this token ) # this test is include in the mint_token methods # assert tok.supports_minting("refresh_token") refresh_token = grant.mint_token( session_id=session_id, endpoint_context=self.endpoint_context, token_class="refresh_token", token_handler=self.session_manager.token_handler["refresh_token"], based_on=tok, ) tok.register_usage() assert tok.max_usage_reached() is True # A bit later a refresh token is used to mint a new access token REFRESH_TOKEN_REQ = RefreshAccessTokenRequest( grant_type="refresh_token", client_id="client_1", client_secret="hemligt", refresh_token=refresh_token.value, scope=["openid", "mail", "offline_access"], ) session_id = self.session_manager.encrypted_session_id( user_id, REFRESH_TOKEN_REQ["client_id"], grant_id) reftok = self.session_manager.find_token( session_id, REFRESH_TOKEN_REQ["refresh_token"]) # Can I use this token to mint another token ? assert grant.is_active() user_claims = self.endpoint_context.userinfo( user_id, client_id=TOKEN_REQ["client_id"], user_info_claims=grant.claims) access_token_2 = grant.mint_token( session_id=session_id, endpoint_context=self.endpoint_context, token_class="access_token", token_handler=self.session_manager.token_handler["access_token"], expires_at=time_sans_frac() + 900, # 15 minutes from now based_on= reftok, # Means the refresh token (reftok) was used to mint this token ) assert access_token_2.is_active() token_info = self.session_manager.token_handler.info( access_token_2.value) assert token_info
True, "request_parameter_supported": True, "request_uri_parameter_supported": True, } AUTH_REQ = AuthorizationRequest(client_id='client_1', redirect_uri='https://example.com/cb', scope=['openid'], state='STATE', response_type='code') TOKEN_REQ = AccessTokenRequest(client_id='client_1', redirect_uri='https://example.com/cb', state='STATE', grant_type='authorization_code', client_secret='hemligt') TOKEN_REQ_DICT = TOKEN_REQ.to_dict() BASEDIR = os.path.abspath(os.path.dirname(__file__)) def full_path(local_file): return os.path.join(BASEDIR, local_file) USERINFO = UserInfo(json.loads(open(full_path('users.json')).read()))
def service_endpoint(endpoint): _log = current_app.srv_config.logger _log.info('At the "{}" endpoint'.format(endpoint.endpoint_name)) try: authn = request.headers['Authorization'] except KeyError: pr_args = {} else: pr_args = {'auth': authn} if request.method == 'GET': try: req_args = endpoint.parse_request(request.args.to_dict(), **pr_args) except Exception as err: _log.error(err) return make_response(json.dumps({ 'error': 'invalid_request', 'error_description': str(err) }), 400) else: if request.data: req_args = request.data else: req_args = dict([(k, v) for k, v in request.form.items()]) try: req_args = endpoint.parse_request(req_args, **pr_args) except Exception as err: _log.error(err) return make_response(json.dumps({ 'error': 'invalid_request', 'error_description': str(err) }), 400) _log.info('request: {}'.format(req_args)) if isinstance(req_args, ResponseMessage) and 'error' in req_args: return make_response(req_args.to_json(), 400) try: if request.cookies: _log.debug(request.cookies) kwargs = {'cookie': request.cookies} else: kwargs = {} if isinstance(endpoint, AccessToken): args = endpoint.process_request(AccessTokenRequest(**req_args), **kwargs) else: args = endpoint.process_request(req_args, **kwargs) except Exception as err: message = traceback.format_exception(*sys.exc_info()) _log.error(message) return make_response(json.dumps({ 'error': 'invalid_request', 'error_description': str(err) }), 400) _log.info('Response args: {}'.format(args)) if 'redirect_location' in args: return redirect(args['redirect_location']) if 'http_response' in args: return make_response(args['http_response'], 200) return do_response(endpoint, req_args, **args)
def service_endpoint(endpoint): _log = current_app.logger _log.info('At the "{}" endpoint'.format(endpoint.name)) http_info = { "headers": { k: v for k, v in request.headers.items(lower=True) if k not in IGNORE }, "method": request.method, "url": request.url, # name is not unique "cookie": [{ "name": k, "value": v } for k, v in request.cookies.items()] } if request.method == 'GET': try: req_args = endpoint.parse_request(request.args.to_dict(), http_info=http_info) except (InvalidClient, UnknownClient) as err: _log.error(err) return make_response( json.dumps({ 'error': 'unauthorized_client', 'error_description': str(err) }), 400) except Exception as err: _log.error(err) return make_response( json.dumps({ 'error': 'invalid_request', 'error_description': str(err) }), 400) else: if request.data: if isinstance(request.data, str): req_args = request.data else: req_args = request.data.decode() else: req_args = dict([(k, v) for k, v in request.form.items()]) try: req_args = endpoint.parse_request(req_args, http_info=http_info) except Exception as err: _log.error(err) err_msg = ResponseMessage(error='invalid_request', error_description=str(err)) return make_response(err_msg.to_json(), 400) _log.info('request: {}'.format(req_args)) if isinstance(req_args, ResponseMessage) and 'error' in req_args: return make_response(req_args.to_json(), 400) try: if isinstance(endpoint, Token): args = endpoint.process_request(AccessTokenRequest(**req_args), http_info=http_info) else: args = endpoint.process_request(req_args, http_info=http_info) except Exception as err: message = traceback.format_exception(*sys.exc_info()) _log.error(message) err_msg = ResponseMessage(error='invalid_request', error_description=str(err)) return make_response(err_msg.to_json(), 400) _log.info('Response args: {}'.format(args)) if 'redirect_location' in args: return redirect(args['redirect_location']) if 'http_response' in args: return make_response(args['http_response'], 200) response = do_response(endpoint, req_args, **args) return response
def service_endpoint(request, endpoint): """ TODO: documentation here """ logger = oidcendpoint_app.srv_config.logger logger.info('At the "{}" endpoint'.format(endpoint.endpoint_name)) # if hasattr(request, 'debug') and request.debug: # import pdb; pdb.set_trace() authn = request.headers.get('Authorization', {}) pr_args = {'auth': authn} if authn: logger.debug('request.headers["Authorization"] => {}'.format(pr_args)) if request.method == 'GET': data = {k:v for k,v in request.GET.items()} elif request.body: data = request.body \ if isinstance(request.body, str) else \ request.body.decode() #<oidcendpoint.oidc.token.AccessToken object at 0x7fd626329d68> if authn: data = {k:v[0] for k,v in urlib_parse.parse_qs(data).items()} else: data = {k:v for k,v in request.POST.items()} # for .well-known resources like provider-config no data are submitted # if not data: # ... not possible in this implementation logger.debug('Request arguments [{}]: {}'.format(request.method, data)) try: req_args = endpoint.parse_request(data, **pr_args) except Exception as err: logger.error(err) return JsonResponse(json.dumps({ 'error': 'invalid_request', 'error_description': str(err), 'method': request.method }), status=400) logger.info('request: {}'.format(req_args)) if isinstance(req_args, ResponseMessage) and 'error' in req_args: return JsonResponse(req_args.__dict__, status=400) if request.COOKIES: logger.debug(request.COOKIES) # TODO: cookie kwargs = {'cookie': request.COOKIES} else: kwargs = {} try: if isinstance(endpoint, AccessToken): args = endpoint.process_request(AccessTokenRequest(**req_args), **kwargs) else: args = endpoint.process_request(req_args, **kwargs) except Exception as err: message = '{}'.format(err) logger.error(message) return JsonResponse(json.dumps({ 'error': 'invalid_request', 'error_description': str(err) }), status=400) logger.info('Response args: {}'.format(args)) if 'redirect_location' in args: return HttpResponseRedirect(args['redirect_location']) if 'http_response' in args: return HttpResponse(args['http_response'], status=200) return do_response(endpoint, req_args, **args)