예제 #1
0
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
예제 #2
0
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