From a39ae63bdee9d9e6b6a3845f5622a8defa6eb154 Mon Sep 17 00:00:00 2001 From: jasquat Date: Mon, 13 Feb 2023 11:57:31 -0500 Subject: [PATCH] added api endpoint to allow logging in for the first time with an openid access_token w/ burnettk --- spiffworkflow-backend/bin/get_token | 25 ++++++++++--------- .../src/spiffworkflow_backend/api.yml | 20 +++++++++++++++ .../src/spiffworkflow_backend/routes/user.py | 21 ++++++++++++++-- 3 files changed, 52 insertions(+), 14 deletions(-) diff --git a/spiffworkflow-backend/bin/get_token b/spiffworkflow-backend/bin/get_token index dc26e769..c9e7bb0b 100755 --- a/spiffworkflow-backend/bin/get_token +++ b/spiffworkflow-backend/bin/get_token @@ -20,10 +20,10 @@ set -o errtrace -o errexit -o nounset -o pipefail # ./bin/get_token repeat_form_user_1 repeat_form_user_1 # actually has permissions to the resource in this script # ./bin/get_token ciadmin1 ciadmin1 '%2Fprocess-models' -# KEYCLOAK_BASE_URL=http://localhost:7002 -KEYCLOAK_BASE_URL=https://keycloak.dev.spiffworkflow.org -# BACKEND_BASE_URL=http://localhost:7000 -BACKEND_BASE_URL=https://api.dev.spiffworkflow.org +KEYCLOAK_BASE_URL=http://localhost:7002 +# KEYCLOAK_BASE_URL=https://keycloak.dev.spiffworkflow.org +BACKEND_BASE_URL=http://localhost:7000 +# BACKEND_BASE_URL=https://api.dev.spiffworkflow.org REALM_NAME=spiffworkflow USERNAME=${1-fin} PASSWORD=${2-fin} @@ -36,12 +36,12 @@ SECURE=false BACKEND_BASIC_AUTH=$(echo -n "${BACKEND_CLIENT_ID}:${BACKEND_CLIENT_SECRET}" | base64) KEYCLOAK_URL=$KEYCLOAK_BASE_URL/realms/$REALM_NAME/protocol/openid-connect/token -echo "Using Keycloak: $KEYCLOAK_URL" -echo "realm: $REALM_NAME" -echo "client-id: $FRONTEND_CLIENT_ID" -echo "username: $USERNAME" -echo "password: $PASSWORD" -echo "secure: $SECURE" +>&2 echo "Using Keycloak: $KEYCLOAK_URL" +>&2 echo "realm: $REALM_NAME" +>&2 echo "client-id: $FRONTEND_CLIENT_ID" +>&2 echo "username: $USERNAME" +>&2 echo "password: $PASSWORD" +>&2 echo "secure: $SECURE" if [[ $SECURE = 'y' ]]; then @@ -61,8 +61,9 @@ result=$(curl -s -X POST "$KEYCLOAK_URL" "$INSECURE" \ -d "client_id=$BACKEND_CLIENT_ID" \ ) backend_token=$(jq -r '.access_token' <<< "$result") -echo "testing hitting backend with token: $backend_token" -curl --fail -v "${BACKEND_BASE_URL}/v1.0/process-groups?per_page=1" -H "Authorization: Bearer $backend_token" +echo "$backend_token" +# curl --fail -v "${BACKEND_BASE_URL}/v1.0/process-groups?per_page=1" -H "Authorization: Bearer $backend_token" +# curl -v -X POST "${BACKEND_BASE_URL}/v1.0/login_with_access_token?access_token=${backend_token}" -H "Authorization: Bearer $backend_token" ### Get with frontend and exchange with backend - not configured to work in keycloak atm diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/api.yml b/spiffworkflow-backend/src/spiffworkflow_backend/api.yml index 326d55b6..842491c2 100755 --- a/spiffworkflow-backend/src/spiffworkflow_backend/api.yml +++ b/spiffworkflow-backend/src/spiffworkflow_backend/api.yml @@ -79,6 +79,26 @@ paths: "200": description: Logout Authenticated User + /login_with_access_token: + parameters: + - name: access_token + in: query + required: true + schema: + type: string + post: + operationId: spiffworkflow_backend.routes.user.login_with_access_token + summary: Authenticate user for API access with an openid token already posessed. + tags: + - Authentication + responses: + "200": + description: "Returns ok: true if user successfully logged in." + content: + application/json: + schema: + $ref: "#/components/schemas/OkTrue" + /login_api: get: operationId: spiffworkflow_backend.routes.user.login_api diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/user.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/user.py index 6fd7d39c..a86e48be 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/user.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/user.py @@ -1,5 +1,7 @@ """User.""" import ast +from flask import make_response +from flask import jsonify import base64 import json import re @@ -261,13 +263,11 @@ def parse_id_token(token: str) -> Any: def login_return(code: str, state: str, session_state: str = "") -> Optional[Response]: - """Login_return.""" state_dict = ast.literal_eval(base64.b64decode(state).decode("utf-8")) state_redirect_url = state_dict["redirect_url"] auth_token_object = AuthenticationService().get_auth_token_object(code) if "id_token" in auth_token_object: id_token = auth_token_object["id_token"] - user_info = parse_id_token(id_token) if AuthenticationService.validate_id_or_access_token(id_token): @@ -299,6 +299,23 @@ def login_return(code: str, state: str, session_state: str = "") -> Optional[Res ) +# FIXME: share more code with login_return and maybe attempt to get a refresh token +def login_with_access_token(access_token: str) -> Response: + user_info = parse_id_token(access_token) + + if AuthenticationService.validate_id_or_access_token(access_token): + if user_info and "error" not in user_info: + AuthorizationService.create_user_from_sign_in(user_info) + else: + raise ApiError( + error_code="invalid_login", + message="Login failed. Please try again", + status_code=401, + ) + + return make_response(jsonify({"ok": True})) + + def login_api() -> Response: """Login_api.""" redirect_url = "/v1.0/login_api_return"