async def validate_token_request(self): client = await self.authenticate_token_endpoint_client() log.debug("Validate token request of %r", client) if not client.check_grant_type(self.GRANT_TYPE): raise UnauthorizedClientError() code = self.request.form.get("code") if code is None: raise InvalidRequestError('Missing "code" in request.') # ensure that the authorization code was issued to the authenticated # confidential client, or if the client is public, ensure that the # code was issued to "client_id" in the request authorization_code = await self.query_authorization_code(code, client) if not authorization_code: raise InvalidRequestError('Invalid "code" in request.') # validate redirect_uri parameter log.debug("Validate token redirect_uri of %r", client) redirect_uri = self.request.redirect_uri original_redirect_uri = authorization_code.get_redirect_uri() if original_redirect_uri and redirect_uri != original_redirect_uri: raise InvalidRequestError('Invalid "redirect_uri" in request.') # save for create_token_response self.request.client = client self.request.credential = authorization_code await self.execute_hook("after_validate_token_request")
def authenticate_user(self, username, password): user = User.query.filter_by(username=username).first() if not user: raise InvalidRequestError("Username {} not found".format(username)) if not user.check_password(password): raise InvalidRequestError("Password not valid!") return user
def validate_nonce(request, exists_nonce, required=False): nonce = request.data.get('nonce') if not nonce: if required: raise InvalidRequestError('Missing "nonce" in request.') return True if exists_nonce(nonce, request): raise InvalidRequestError('Replay attack')
async def _validate_request_token(self, client=None): refresh_token = self.request.form.get("refresh_token") if refresh_token is None: raise InvalidRequestError('Missing "refresh_token" in request.', ) token = await self.authenticate_refresh_token(refresh_token) if not token or token.get_client_id() != client.get_client_id(): raise InvalidRequestError('Invalid "refresh_token" in request.', ) return token
async def validate_nonce(request, exists_nonce, required): nonce = request.data.get("nonce") if not nonce: if required: raise InvalidRequestError('Missing "nonce" in request.') return True if await exists_nonce(nonce, request): raise InvalidRequestError("Replay attack")
def create_response_mode_response(redirect_uri, params, response_mode=None): if response_mode is None: response_mode = os.getenv('AUTHLIB_DEFAULT_RESPONSE_CODE', 'fragment') if response_mode == 'form_post': tpl = ( '<html><head><title>Authlib</title></head>' '<body onload="javascript:document.forms[0].submit()">' '<form method="post" action="{}">{}</form></body></html>' ) inputs = ''.join([ '<input type="hidden" name="{}" value="{}"/>'.format( quote_url(k), quote_url(v)) for k, v in params ]) body = tpl.format(quote_url(redirect_uri), inputs) return 200, body, [('Content-Type', 'text/html; charset=utf-8')] if response_mode == 'query': uri = add_params_to_uri(redirect_uri, params, fragment=False) elif response_mode == 'fragment': uri = add_params_to_uri(redirect_uri, params, fragment=True) else: raise InvalidRequestError('Invalid "response_mode" value') return 302, '', [('Location', uri)]
def create_token_response(self): client = self.request.client authorization_code = self.request.credential user = self.authenticate_user(authorization_code) if not user: raise InvalidRequestError('There is no "user" for this code.') scope = authorization_code.scope nonce = authorization_code.nonce refresh_token_expires_in = authorization_code.refresh_token_expires_in token = self.generate_token( client, self.GRANT_TYPE, user=user, scope=scope, include_refresh_token=client.has_client_secret(), nonce=nonce, refresh_token_expires_in=refresh_token_expires_in, ) self.request.user = user self.server.save_token(token, self.request) self.execute_hook("process_token", token=token) self.delete_authorization_code(authorization_code) return 200, token, self.TOKEN_RESPONSE_HEADER
def validate_request_prompt(self, end_user): """ Override method in authlib to fix behavior with login prompt. """ prompt = self.request.data.get("prompt") if not prompt: if not end_user: self.prompt = "login" return self if prompt == "none" and not end_user: raise LoginRequiredError() prompts = prompt.split() if "none" in prompts and len(prompts) > 1: # If this parameter contains none with any other value, # an error is returned raise InvalidRequestError('Invalid "prompt" parameter.') if "login" in prompts: prompt = "login" if "consent" in prompts: if not end_user: raise ConsentRequiredError() prompt = "consent" elif "select_account" in prompts: if not end_user: raise AccountSelectionRequiredError() prompt = "select_account" if prompt: self.prompt = prompt return self
def validate_request_prompt(grant, redirect_uri, redirect_fragment=False): prompt = grant.request.data.get('prompt') end_user = grant.request.user if not prompt: if not end_user: grant.prompt = 'login' return grant if prompt == 'none' and not end_user: raise LoginRequiredError( redirect_uri=redirect_uri, redirect_fragment=redirect_fragment) prompts = prompt.split() if 'none' in prompts and len(prompts) > 1: # If this parameter contains none with any other value, # an error is returned raise InvalidRequestError( 'Invalid "prompt" parameter.', redirect_uri=redirect_uri, redirect_fragment=redirect_fragment) prompt = _guess_prompt_value( end_user, prompts, redirect_uri, redirect_fragment=redirect_fragment) if prompt: grant.prompt = prompt return grant
def create_token_response(self): client = self.request.client authorization_code = self.request.credential user = self.authenticate_user(authorization_code) if not user: raise InvalidRequestError('There is no "user" for this code.') scope = authorization_code.get_scope() query_args = dict(self.request.query_params) code = self.request.body.get("code") or query_args.get("code") with flask.current_app.db.session as session: authorization_code = (session.query(AuthorizationCode).filter_by( code=code, client_id=client.client_id).first()) nonce = authorization_code.nonce token = self.generate_token( client, self.GRANT_TYPE, user=user, scope=scope, include_refresh_token=client.has_client_secret(), nonce=nonce, ) self.request.user = user self.server.save_token(token, self.request) self.execute_hook("process_token", token=token) self.delete_authorization_code(authorization_code) return 200, token, self.TOKEN_RESPONSE_HEADER
async def create_token_response(self): credential = self.request.credential user = await self.authenticate_user(credential) if not user: raise InvalidRequestError('There is no "user" for this token.') client = self.request.client token = await self.issue_token(client, user, credential) log.debug("Issue token %r to %r", token, client) self.request.user = user await self.save_token(token) await self.execute_hook("process_token", token=token) await self.revoke_old_credential(credential) return 200, token, self.TOKEN_RESPONSE_HEADER
async def create_token_response(self): client = self.request.client authorization_code = self.request.credential user = await self.authenticate_user(authorization_code) if not user: raise InvalidRequestError('There is no "user" for this code.') scope = authorization_code.get_scope() token = await self.generate_token( client, self.GRANT_TYPE, user=user, scope=client.get_allowed_scope(scope), include_refresh_token=client.check_grant_type("refresh_token"), ) log.debug("Issue token %r to %r", token, client) self.request.user = user await self.save_token(token) await self.execute_hook("process_token", token=token) await self.delete_authorization_code(authorization_code) return 200, token, self.TOKEN_RESPONSE_HEADER
def _get_auth_response_for_prompts(prompts, grant, user, client, scope): """ Get response based on prompt parameter. TODO: not completely conforming yet FIXME: To conform to spec, some of the prompt params should be handled before AuthN or if it fails (so adequate and useful errors are provided). Right now the behavior is that the endpoint will just continue to redirect the user to log in without checking these params.... Args: prompts (TYPE): Description grant (TYPE): Description user (TYPE): Description client (TYPE): Description scope (TYPE): Description Returns: TYPE: Description """ show_consent_screen = True if prompts: prompts = prompts.split(" ") if "none" in prompts: # don't auth or consent, error if user not logged in show_consent_screen = False # if none is here, there shouldn't be others if len(prompts) != 1: error = InvalidRequestError(state=grant.params.get("state"), uri=grant.params.get("uri")) return _get_authorize_error_response( error, grant.params.get("redirect_uri")) try: get_current_user() response = server.create_authorization_response(user) except Unauthorized: error = AccessDeniedError(state=grant.params.get("state"), uri=grant.params.get("uri")) return _get_authorize_error_response( error, grant.params.get("redirect_uri")) if "login" in prompts: show_consent_screen = True try: # Re-AuthN user (kind of). # TODO (RR 2018-03-16): this could also include removing active # refresh tokens. flask.session.clear() # For a POST, return the redirect in JSON instead of headers. if flask.request.method == "POST": redirect_response = flask.make_response( flask.jsonify( {"redirect": response.headers["Location"]})) else: redirect_response = flask.make_response( flask.redirect(flask.url_for(".authorize"))) clear_cookies(redirect_response) return redirect_response except Unauthorized: error = AccessDeniedError(state=grant.params.get("state"), uri=grant.params.get("uri")) return _get_authorize_error_response( error, grant.params.get("redirect_uri")) if "consent" in prompts: # show consent screen (which is default behavior so pass) pass if "select_account" in prompts: # allow user to select one of their accounts, we # don't support this at the moment pass if show_consent_screen: shown_scopes = [] if not scope else scope.split(" ") if "openid" in shown_scopes: shown_scopes.remove("openid") enabled_idps = config.get("OPENID_CONNECT", {}) idp_names = [] for idp, info in enabled_idps.items(): # prefer name if its there, then just use the key for the provider idp_name = info.get("name") or idp.title() idp_names.append(idp_name) resource_description = [ SCOPE_DESCRIPTION[s].format(idp_names=" and ".join(idp_names)) for s in shown_scopes ] privacy_policy = config.get("BASE_URL").rstrip("/") + "/privacy-policy" response = flask.render_template( "oauthorize.html", grant=grant, user=user, client=client, app_name=config.get("APP_NAME"), resource_description=resource_description, privacy_policy=privacy_policy, ) return response