Skip to content

Commit

Permalink
Redirect debugging (#2192)
Browse files Browse the repository at this point in the history
* Assure we always generated the redirect with the same exact peice of code. And debug the value that is used in that location

* missing argument.

* the final_url we want to return peoiple to is not the same as the redirect_url we send to an open id provider.

* final cleanup.

* remove accidental files.

* remove process_modesl symlink w/ burnettk

* ignore all process models at root, not just directories w/ burnettk

---------

Co-authored-by: jasquat <jasquat@users.noreply.github.com>
  • Loading branch information
danfunk and jasquat authored Dec 12, 2024
1 parent 6dfc790 commit 80b8e07
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 23 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ t
version_info.json
.coverage*
UNKNOWN.egg-info/
process_models/
process_models
.ipynb_checkpoints
.env*
.cache
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from flask import make_response
from flask import redirect
from flask import request
from flask import url_for
from werkzeug.wrappers import Response

from spiffworkflow_backend.exceptions.api_error import ApiError
Expand Down Expand Up @@ -137,16 +136,15 @@ def login(
)
return redirect(redirect_url)

state = AuthenticationService.generate_state(redirect_url, authentication_identifier)
login_redirect_url = AuthenticationService().get_login_redirect_url(
state.decode("UTF-8"), authentication_identifier=authentication_identifier
authentication_identifier=authentication_identifier, final_url=redirect_url
)
return redirect(login_redirect_url)


def login_return(code: str, state: str, session_state: str = "") -> Response | None:
state_dict = ast.literal_eval(base64.b64decode(state).decode("utf-8"))
state_redirect_url = state_dict["redirect_url"]
state_redirect_url = state_dict["final_url"]
authentication_identifier = state_dict["authentication_identifier"]
auth_token_object = AuthenticationService().get_auth_token_object(code, authentication_identifier=authentication_identifier)
if "id_token" in auth_token_object:
Expand Down Expand Up @@ -178,7 +176,7 @@ def login_return(code: str, state: str, session_state: str = "") -> Response | N
# we normally clear cookies on 401, but there is a high chance you do not have any yet in this case
current_app.logger.error(f"id_token not found in payload from provider: {auth_token_object}")
raise ApiError(
error_code="invalid_token",
error_code="missing_token",
message="Login failed. Please try again",
status_code=401,
)
Expand All @@ -202,17 +200,13 @@ def login_with_access_token(access_token: str, authentication_identifier: str) -


def login_api(authentication_identifier: str) -> Response:
host_url = request.host_url.strip("/")
login_return_path = url_for("/v1_0.spiffworkflow_backend_routes_authentication_controller_login_return")
redirect_url = f"{host_url}{login_return_path}"
state = AuthenticationService.generate_state(redirect_url, authentication_identifier)
login_redirect_url = AuthenticationService().get_login_redirect_url(state.decode("UTF-8"), redirect_url)
login_redirect_url = AuthenticationService().get_login_redirect_url(authentication_identifier)
return redirect(login_redirect_url)


def login_api_return(code: str, state: str, session_state: str) -> str:
state_dict = ast.literal_eval(base64.b64decode(state).decode("utf-8"))
state_dict["redirect_url"]
# state_dict = ast.literal_eval(base64.b64decode(state).decode("utf-8"))
# state_dict["final_url"]

auth_token_object = AuthenticationService().get_auth_token_object(code, "/v1.0/login_api_return")
access_token: str = auth_token_object["access_token"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,29 +279,36 @@ def logout(self, id_token: str, authentication_identifier: str, redirect_url: st
return redirect(request_url)

@staticmethod
def generate_state(redirect_url: str, authentication_identifier: str) -> bytes:
def generate_state(authentication_identifier: str, final_url: str | None = None) -> bytes:
# The final_url is where we want to return the user to, within the application - in case they
# where headed to a specific page. This is different than the "redirect url" we specify to
# the open id server - we want the open id server to always send us back to the login_return
# endpoint, and we'll redirect again from there.
my_final_url = final_url
if final_url is None:
my_final_url = str(current_app.config["SPIFFWORKFLOW_BACKEND_URL_FOR_FRONTEND"])
state = base64.b64encode(
bytes(str({"redirect_url": redirect_url, "authentication_identifier": authentication_identifier}), "UTF-8")
bytes(str({"final_url": my_final_url, "authentication_identifier": authentication_identifier}), "UTF-8")
)
return state

def get_redirect_uri_for_login_to_server(self) -> str:
host_url = request.host_url.strip("/")
login_return_path = url_for("/v1_0.spiffworkflow_backend_routes_authentication_controller_login_return")
redirect_url_to_use = f"{host_url}{login_return_path}"
current_app.logger.debug(f"Redirect URL requested of open ID provider is '{redirect_url_to_use}' ")
return redirect_url_to_use

def get_login_redirect_url(self, state: str, authentication_identifier: str, redirect_url: str | None = None) -> str:
redirect_url_to_use = redirect_url
if redirect_url_to_use is None:
redirect_url_to_use = self.get_redirect_uri_for_login_to_server()
def get_login_redirect_url(self, authentication_identifier: str, final_url: str | None = None) -> str:
redirect_url = self.get_redirect_uri_for_login_to_server()
state = self.generate_state(authentication_identifier, final_url).decode("UTF-8")
login_redirect_url = (
self.open_id_endpoint_for_name("authorization_endpoint", authentication_identifier=authentication_identifier)
+ f"?state={state}&"
+ "response_type=code&"
+ f"client_id={self.client_id(authentication_identifier)}&"
+ f"scope={' '.join(current_app.config['SPIFFWORKFLOW_BACKEND_OPEN_ID_SCOPES'])}&"
+ f"redirect_uri={redirect_url_to_use}"
+ f"redirect_uri={redirect_url}"
)
return login_redirect_url

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
class TestAuthentication(BaseTest):
def test_get_login_state(self) -> None:
redirect_url = "http://example.com/"
state = AuthenticationService.generate_state(redirect_url, authentication_identifier="default")
state = AuthenticationService.generate_state(authentication_identifier="default", final_url=redirect_url)
state_dict = ast.literal_eval(base64.b64decode(state).decode("utf-8"))

assert isinstance(state_dict, dict)
assert "redirect_url" in state_dict.keys()
assert state_dict["redirect_url"] == redirect_url
assert "final_url" in state_dict.keys()
assert state_dict["final_url"] == redirect_url

def test_properly_adds_user_to_groups_from_token_on_login(
self,
Expand Down

0 comments on commit 80b8e07

Please sign in to comment.