def authorize(*args, **kwargs): """ OIDC Authorization Endpoint From the OIDC Specification: 3.1.1. Authorization Code Flow Steps The Authorization Code Flow goes through the following steps. - Client prepares an Authentication Request containing the desired request parameters. - Client sends the request to the Authorization Server. - Authorization Server Authenticates the End-User. - Authorization Server obtains End-User Consent/Authorization. - Authorization Server sends the End-User back to the Client with an Authorization Code. - Client requests a response using the Authorization Code at the Token Endpoint. - Client receives a response that contains an ID Token and Access Token in the response body. - Client validates the ID token and retrieves the End-User's Subject Identifier. Args: *args: additional arguments **kwargs: additional keyword arguments """ need_authentication = False try: user = get_current_user() except Unauthorized: need_authentication = True if need_authentication or not user: redirect_url = config.get("BASE_URL") + flask.request.full_path params = {"redirect": redirect_url} login_url = config.get("DEFAULT_LOGIN_URL") idp = flask.request.args.get("idp") if idp: if idp not in IDP_URL_MAP or idp not in config["OPENID_CONNECT"]: raise UserError("idp {} is not supported".format(idp)) idp_url = IDP_URL_MAP[idp] login_url = "{}/login/{}".format(config.get("BASE_URL"), idp_url) login_url = add_params_to_uri(login_url, params) return flask.redirect(login_url) try: grant = server.validate_consent_request(end_user=user) except OAuth2Error as e: raise Unauthorized("{} failed to authorize".format(str(e))) client_id = grant.client.client_id with flask.current_app.db.session as session: client = session.query(Client).filter_by(client_id=client_id).first() # TODO: any way to get from grant? confirm = flask.request.form.get("confirm") or flask.request.args.get( "confirm") if client.auto_approve: confirm = "yes" if confirm is not None: response = _handle_consent_confirmation(user, confirm) # if it's a 302 for POST confirm, return 200 instead and include # redirect url in body because browser ajax POST doesn't follow # cross origin redirect if flask.request.method == "POST" and response.status_code == 302: return flask.jsonify({"redirect": response.headers["Location"]}) else: # no confirm param, so no confirmation has occured yet response = _authorize(user, grant, client) return response
def authorize(*args, **kwargs): """ OIDC Authorization Endpoint From the OIDC Specification: 3.1.1. Authorization Code Flow Steps The Authorization Code Flow goes through the following steps. - Client prepares an Authentication Request containing the desired request parameters. - Client sends the request to the Authorization Server. - Authorization Server Authenticates the End-User. - Authorization Server obtains End-User Consent/Authorization. - Authorization Server sends the End-User back to the Client with an Authorization Code. - Client requests a response using the Authorization Code at the Token Endpoint. - Client receives a response that contains an ID Token and Access Token in the response body. - Client validates the ID token and retrieves the End-User's Subject Identifier. Args: *args: additional arguments **kwargs: additional keyword arguments """ need_authentication = False user = None try: user = get_current_user() except Unauthorized: need_authentication = True idp = flask.request.args.get("idp") fence_idp = flask.request.args.get("fence_idp") shib_idp = flask.request.args.get("shib_idp") login_url = None if not idp: if not config.get("DEFAULT_LOGIN_IDP") and "default" not in ( config.get("ENABLED_IDENTITY_PROVIDERS") or {}): # fall back on deprecated DEFAULT_LOGIN_URL login_url = config.get("DEFAULT_LOGIN_URL") else: default_provider_info, _ = get_login_providers_info() idp = default_provider_info["idp"] # if more than 1 URL is configured, default to the 1st one login_url = default_provider_info["urls"][0]["url"] if need_authentication or not user: redirect_url = config.get("BASE_URL") + flask.request.full_path params = {"redirect": redirect_url} if not login_url: if idp not in config["OPENID_CONNECT"]: raise UserError("idp {} is not supported".format(idp)) idp_endpoint = get_idp_route_name(idp) login_url = "{}/login/{}".format(config.get("BASE_URL"), idp_endpoint) # handle valid extra params for fence multi-tenant and shib login if idp == "fence" and fence_idp: params["idp"] = fence_idp if fence_idp == "shibboleth": params["shib_idp"] = shib_idp elif idp == "shibboleth" and shib_idp: params["shib_idp"] = shib_idp # store client_id for later use in login endpoint prepare_login_log() flask.session["client_id"] = flask.request.args.get("client_id") login_url = add_params_to_uri(login_url, params) return flask.redirect(login_url) try: grant = server.validate_consent_request(end_user=user) except OAuth2Error as e: raise Unauthorized("Failed to authorize: {}".format(str(e))) client_id = grant.client.client_id with flask.current_app.db.session as session: client = session.query(Client).filter_by(client_id=client_id).first() # TODO: any way to get from grant? confirm = flask.request.form.get("confirm") or flask.request.args.get( "confirm") if client.auto_approve: confirm = "yes" if confirm is not None: response = _handle_consent_confirmation(user, confirm) # if it's a 302 for POST confirm, return 200 instead and include # redirect url in body because browser ajax POST doesn't follow # cross origin redirect if flask.request.method == "POST" and response.status_code == 302: response = flask.jsonify( {"redirect": response.headers["Location"]}) else: # no confirm param, so no confirmation has occured yet response = _authorize(user, grant, client) return response