merged in main and resolved conflicts
This commit is contained in:
commit
e6cc68fc9d
|
@ -8,8 +8,9 @@ servers:
|
|||
- url: http://localhost:5000/v1.0
|
||||
security:
|
||||
- jwt: ["secret"]
|
||||
# - oAuth2AuthCode:
|
||||
# - read_email
|
||||
- oAuth2AuthCode:
|
||||
- read_email
|
||||
- uid
|
||||
|
||||
paths:
|
||||
/login:
|
||||
|
@ -85,47 +86,41 @@ paths:
|
|||
"200":
|
||||
description: Logout Authenticated User
|
||||
|
||||
# /login_api:
|
||||
# parameters:
|
||||
# - name: redirect_url
|
||||
# in: query
|
||||
# required: false
|
||||
# schema:
|
||||
# type: string
|
||||
# get:
|
||||
# security: []
|
||||
# operationId: spiffworkflow_backend.routes.user.login_api
|
||||
# summary: Authenticate user for API access
|
||||
# tags:
|
||||
# - Authentication
|
||||
# responses:
|
||||
# "304":
|
||||
# description: Redirection to the hosted frontend with an auth_token header.
|
||||
# /login_api_return:
|
||||
# parameters:
|
||||
# - name: code
|
||||
# in: query
|
||||
# required: true
|
||||
# schema:
|
||||
# type: string
|
||||
# - name: state
|
||||
# in: query
|
||||
# required: true
|
||||
# schema:
|
||||
# type: string
|
||||
# - name: session_state
|
||||
# in: query
|
||||
# required: false
|
||||
# schema:
|
||||
# type: string
|
||||
# get:
|
||||
# security: []
|
||||
# operationId: spiffworkflow_backend.routes.user.login_api_return
|
||||
# tags:
|
||||
# - Authentication
|
||||
# responses:
|
||||
# "200":
|
||||
# description: Test Return Response
|
||||
/login_api:
|
||||
get:
|
||||
security: []
|
||||
operationId: spiffworkflow_backend.routes.user.login_api
|
||||
summary: Authenticate user for API access
|
||||
tags:
|
||||
- Authentication
|
||||
responses:
|
||||
"200":
|
||||
description: Redirects to authentication server
|
||||
/login_api_return:
|
||||
parameters:
|
||||
- name: code
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: state
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: session_state
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
get:
|
||||
security: []
|
||||
operationId: spiffworkflow_backend.routes.user.login_api_return
|
||||
tags:
|
||||
- Authentication
|
||||
responses:
|
||||
"200":
|
||||
description: Test Return Response
|
||||
|
||||
/status:
|
||||
get:
|
||||
|
@ -1250,10 +1245,20 @@ components:
|
|||
flows:
|
||||
authorizationCode:
|
||||
authorizationUrl: /v1.0/login_api
|
||||
tokenUrl: /v1.0/login_return
|
||||
tokenUrl: /v1.0/login_api_return
|
||||
scopes:
|
||||
read_email: read email
|
||||
x-tokenInfoFunc: spiffworkflow_backend.routes.user.get_scope
|
||||
# oAuth2AuthCode:
|
||||
# type: oauth2
|
||||
# description: authenticate with openid server
|
||||
# flows:
|
||||
# implicit:
|
||||
# authorizationUrl: /v1.0/login_api
|
||||
# scopes:
|
||||
# uid: uid
|
||||
# x-tokenInfoUrl: localhost:7000/v1.0/login_api_return
|
||||
# x-tokenInfoFunc: spiffworkflow_backend.routes.user.get_scope
|
||||
|
||||
schemas:
|
||||
OkTrue:
|
||||
|
|
|
@ -206,9 +206,11 @@ def process_model_update(
|
|||
process_group_id: str, process_model_id: str, body: Dict[str, Union[str, bool, int]]
|
||||
) -> Any:
|
||||
"""Process_model_update."""
|
||||
body_include_list = ["display_name"]
|
||||
body_include_list = ["display_name", "primary_file_name", "primary_process_id"]
|
||||
body_filtered = {
|
||||
include_item: body[include_item] for include_item in body_include_list
|
||||
include_item: body[include_item]
|
||||
for include_item in body_include_list
|
||||
if include_item in body
|
||||
}
|
||||
|
||||
process_model = get_process_model(process_model_id, process_group_id)
|
||||
|
|
|
@ -214,49 +214,86 @@ def login_return(code: str, state: str, session_state: str) -> Optional[Response
|
|||
state_redirect_url = state_dict["redirect_url"]
|
||||
|
||||
id_token_object = PublicAuthenticationService().get_id_token_object(code)
|
||||
id_token = id_token_object["id_token"]
|
||||
if "id_token" in id_token_object:
|
||||
id_token = id_token_object["id_token"]
|
||||
|
||||
if PublicAuthenticationService.validate_id_token(id_token):
|
||||
user_info = PublicAuthenticationService.get_user_info_from_id_token(
|
||||
id_token_object["access_token"]
|
||||
)
|
||||
if user_info and "error" not in user_info:
|
||||
user_model = (
|
||||
UserModel.query.filter(UserModel.service == "open_id")
|
||||
.filter(UserModel.service_id == user_info["sub"])
|
||||
.first()
|
||||
if PublicAuthenticationService.validate_id_token(id_token):
|
||||
user_info = PublicAuthenticationService.get_user_info_from_id_token(
|
||||
id_token_object["access_token"]
|
||||
)
|
||||
if user_model is None:
|
||||
current_app.logger.debug("create_user in login_return")
|
||||
name = username = email = ""
|
||||
if "name" in user_info:
|
||||
name = user_info["name"]
|
||||
if "username" in user_info:
|
||||
username = user_info["username"]
|
||||
elif "preferred_username" in user_info:
|
||||
username = user_info["preferred_username"]
|
||||
if "email" in user_info:
|
||||
email = user_info["email"]
|
||||
user_model = UserService.create_user(
|
||||
service="open_id",
|
||||
service_id=user_info["sub"],
|
||||
name=name,
|
||||
username=username,
|
||||
email=email,
|
||||
if user_info and "error" not in user_info:
|
||||
user_model = (
|
||||
UserModel.query.filter(UserModel.service == "open_id")
|
||||
.filter(UserModel.service_id == user_info["sub"])
|
||||
.first()
|
||||
)
|
||||
|
||||
if user_model:
|
||||
g.user = user_model.id
|
||||
if user_model is None:
|
||||
current_app.logger.debug("create_user in login_return")
|
||||
name = username = email = ""
|
||||
if "name" in user_info:
|
||||
name = user_info["name"]
|
||||
if "username" in user_info:
|
||||
username = user_info["username"]
|
||||
elif "preferred_username" in user_info:
|
||||
username = user_info["preferred_username"]
|
||||
if "email" in user_info:
|
||||
email = user_info["email"]
|
||||
user_model = UserService().create_user(
|
||||
service="open_id",
|
||||
service_id=user_info["sub"],
|
||||
name=name,
|
||||
username=username,
|
||||
email=email,
|
||||
)
|
||||
|
||||
redirect_url = (
|
||||
f"{state_redirect_url}?"
|
||||
+ f"access_token={id_token_object['access_token']}&"
|
||||
+ f"id_token={id_token}"
|
||||
)
|
||||
return redirect(redirect_url)
|
||||
raise ApiError(
|
||||
code="invalid_login", message="Login failed. Please try again", status_code=401
|
||||
if user_model:
|
||||
g.user = user_model.id
|
||||
|
||||
redirect_url = (
|
||||
f"{state_redirect_url}?"
|
||||
+ f"access_token={id_token_object['access_token']}&"
|
||||
+ f"id_token={id_token}"
|
||||
)
|
||||
return redirect(redirect_url)
|
||||
|
||||
raise ApiError(
|
||||
code="invalid_login",
|
||||
message="Login failed. Please try again",
|
||||
status_code=401,
|
||||
)
|
||||
|
||||
else:
|
||||
raise ApiError(
|
||||
code="invalid_token",
|
||||
message="Login failed. Please try again",
|
||||
status_code=401,
|
||||
)
|
||||
|
||||
|
||||
def login_api() -> Response:
|
||||
"""Login_api."""
|
||||
redirect_url = "/v1.0/login_api_return"
|
||||
state = PublicAuthenticationService.generate_state(redirect_url)
|
||||
login_redirect_url = PublicAuthenticationService().get_login_redirect_url(
|
||||
state.decode("UTF-8"), redirect_url
|
||||
)
|
||||
return redirect(login_redirect_url)
|
||||
|
||||
|
||||
def login_api_return(code: str, state: str, session_state: str) -> str:
|
||||
"""Login_api_return."""
|
||||
state_dict = ast.literal_eval(base64.b64decode(state).decode("utf-8"))
|
||||
state_dict["redirect_url"]
|
||||
|
||||
id_token_object = PublicAuthenticationService().get_id_token_object(
|
||||
code, "/v1.0/login_api_return"
|
||||
)
|
||||
access_token: str = id_token_object["access_token"]
|
||||
assert access_token # noqa: S101
|
||||
return access_token
|
||||
# return redirect("localhost:7000/v1.0/ui")
|
||||
# return {'uid': 'user_1'}
|
||||
|
||||
|
||||
def logout(id_token: str, redirect_url: Optional[str]) -> Response:
|
||||
|
|
|
@ -114,7 +114,9 @@ class PublicAuthenticationService:
|
|||
state = base64.b64encode(bytes(str({"redirect_url": redirect_url}), "UTF-8"))
|
||||
return state
|
||||
|
||||
def get_login_redirect_url(self, state: str) -> str:
|
||||
def get_login_redirect_url(
|
||||
self, state: str, redirect_url: str = "/v1.0/login_return"
|
||||
) -> str:
|
||||
"""Get_login_redirect_url."""
|
||||
(
|
||||
open_id_server_url,
|
||||
|
@ -122,7 +124,7 @@ class PublicAuthenticationService:
|
|||
open_id_realm_name,
|
||||
open_id_client_secret_key,
|
||||
) = PublicAuthenticationService.get_open_id_args()
|
||||
return_redirect_url = f"{self.get_backend_url()}/v1.0/login_return"
|
||||
return_redirect_url = f"{self.get_backend_url()}{redirect_url}"
|
||||
login_redirect_url = (
|
||||
f"{open_id_server_url}/realms/{open_id_realm_name}/protocol/openid-connect/auth?"
|
||||
+ f"state={state}&"
|
||||
|
@ -133,7 +135,9 @@ class PublicAuthenticationService:
|
|||
)
|
||||
return login_redirect_url
|
||||
|
||||
def get_id_token_object(self, code: str) -> dict:
|
||||
def get_id_token_object(
|
||||
self, code: str, redirect_url: str = "/v1.0/login_return"
|
||||
) -> dict:
|
||||
"""Get_id_token_object."""
|
||||
(
|
||||
open_id_server_url,
|
||||
|
@ -152,7 +156,7 @@ class PublicAuthenticationService:
|
|||
data = {
|
||||
"grant_type": "authorization_code",
|
||||
"code": code,
|
||||
"redirect_uri": f"{self.get_backend_url()}/v1.0/login_return",
|
||||
"redirect_uri": f"{self.get_backend_url()}{redirect_url}",
|
||||
}
|
||||
|
||||
request_url = f"{open_id_server_url}/realms/{open_id_realm_name}/protocol/openid-connect/token"
|
||||
|
|
|
@ -179,9 +179,13 @@ class TestProcessApi(BaseTest):
|
|||
assert process_model.id == "make_cookies"
|
||||
assert process_model.display_name == "Cooooookies"
|
||||
assert process_model.is_review is False
|
||||
assert process_model.primary_file_name is None
|
||||
assert process_model.primary_process_id is None
|
||||
|
||||
process_model.display_name = "Updated Display Name"
|
||||
process_model.is_review = True
|
||||
process_model.primary_file_name = "superduper.bpmn"
|
||||
process_model.primary_process_id = "superduper"
|
||||
process_model.is_review = True # not in the include list, so get ignored
|
||||
|
||||
user = self.find_or_create_user()
|
||||
response = client.put(
|
||||
|
@ -193,6 +197,8 @@ class TestProcessApi(BaseTest):
|
|||
assert response.status_code == 200
|
||||
assert response.json is not None
|
||||
assert response.json["display_name"] == "Updated Display Name"
|
||||
assert response.json["primary_file_name"] == "superduper.bpmn"
|
||||
assert response.json["primary_process_id"] == "superduper"
|
||||
assert response.json["is_review"] is False
|
||||
|
||||
def test_process_model_list(
|
||||
|
|
Loading…
Reference in New Issue