Skip to content
Snippets Groups Projects
Commit 0b27a554 authored by Arie Peterson's avatar Arie Peterson
Browse files

Fix logout to include redirect to hydra logout URL

parent 07722569
No related branches found
No related tags found
1 merge request!155Resolve "Clean up logout procedure"
Pipeline #43182 passed with stages
in 4 minutes and 13 seconds
...@@ -541,19 +541,28 @@ def get_kratos_cookie(): ...@@ -541,19 +541,28 @@ def get_kratos_cookie():
return cookie return cookie
@web.route("/logout", methods=["GET"])
@web.route("/prelogout", methods=["GET"]) def logout():
def prelogout(): """Handles the Hydra OpenID Connect Logout flow and Kratos logout flow.
"""Handles the Hydra OpenID Connect Logout flow
Steps: Steps:
1. Hydra's /oauth2/sessions/logout endpoint is called by an application 1. Hydra's /oauth2/sessions/logout endpoint is called by an application
2. Hydra calls this endpoint with a `logout_challenge` get parameter 2. Hydra calls this endpoint with a `logout_challenge` get parameter
3. We retrieve the logout request using the challenge 3. We retrieve the logout request using the challenge
4. We accept the Hydra logout request 4. We accept the Hydra logout request. This returns a URL -- let's call it
5. We redirect to Hydra to clean-up cookies. "next redirect" -- that we should redirect the browser to to finish the
6. Hyrda calls back to us with a post logout handle (/logout) Hydra logout.
5. We create a Kratos logout flow, setting its `return_to` parameter to the
"next redirect". This returns a Kratos logout URL.
6. We return a small HTML page to the browser, based on the `clear.html`
template, which clears dashboard local storage and redirects to the Kratos
logout URL.
7. The browser follows that redirect, Kratos does its thing and redirects
to the "next redirect".
8. The browser follows the "next redirect", Hydra does its thing and
redirects to the "post-logout URL". We set that to the dashboard root URL
by default, but OIDC clients can override it to something else. For
example, Nextcloud sets it to the root Nextcloud URL.
Args: Args:
logout_challenge (string): Reference to a Hydra logout challenge object logout_challenge (string): Reference to a Hydra logout challenge object
...@@ -576,7 +585,7 @@ def prelogout(): ...@@ -576,7 +585,7 @@ def prelogout():
current_app.logger.error( current_app.logger.error(
"Conflict. Logout request with challenge '%s' has been used already.", "Conflict. Logout request with challenge '%s' has been used already.",
challenge) challenge)
abort(503) abort(404, "Logout request has been accepted already.")
current_app.logger.info("Logout request hydra, subject %s", logout_request.subject) current_app.logger.info("Logout request hydra, subject %s", logout_request.subject)
...@@ -585,20 +594,28 @@ def prelogout(): ...@@ -585,20 +594,28 @@ def prelogout():
# browser flow and we can't do both. # browser flow and we can't do both.
try: try:
hydra_return = hydra_admin_api.accept_logout_request(challenge) hydra_return = hydra_admin_api.accept_logout_request(challenge)
next_redirect = hydra_return.redirect_to
except Exception as ex: except Exception as ex:
current_app.logger.info("Error logging out hydra: %s", str(ex)) current_app.logger.info("Error accepting hydra logout request: %s", str(ex))
next_redirect = DASHBOARD_URL
# Now start ending the kratos session. # Now end the kratos session.
kratos_cookie = get_kratos_cookie() kratos_cookie = get_kratos_cookie()
if not kratos_cookie: if not kratos_cookie:
# No kratos cookie, already logged out from kratos. # No kratos cookie, already logged out from kratos.
current_app.logger.info("Expected kratos cookie but not found. Redirecting to hydra post-logout"); current_app.logger.info("Expected kratos cookie but not found. Redirecting to hydra post-logout");
return redirect(hydra_post_logout) # We skip the Kratos logout, but we still need to follow
# `next_redirect` -- probably the Hydra logout URL -- and clear
# dashboard storage.
return render_template("clear.html",
url=next_redirect)
try: try:
# Create a Logout URL for Browsers # Create a Logout URL for Browsers
kratos_api_response = \ current_app.logger.info(f"Creating logout flow, with return_to={next_redirect}")
admin_frontend_api.create_browser_logout_flow( kratos_api_response = admin_frontend_api.create_browser_logout_flow(
cookie=kratos_cookie) return_to=next_redirect,
cookie=kratos_cookie)
current_app.logger.info("Kratos api response to creating logout flow:")
current_app.logger.info(kratos_api_response) current_app.logger.info(kratos_api_response)
return render_template("clear.html", return render_template("clear.html",
url=kratos_api_response.logout_url) url=kratos_api_response.logout_url)
...@@ -606,41 +623,7 @@ def prelogout(): ...@@ -606,41 +623,7 @@ def prelogout():
current_app.logger.error("Exception when calling" current_app.logger.error("Exception when calling"
" create_browser_logout_flow: %s\n", " create_browser_logout_flow: %s\n",
ex) ex)
return redirect(DASHBOARD_URL)
current_app.logger.info("Hydra logout not completed. Redirecting to kratos logout, maybe user removed cookies manually")
return redirect("logout")
@web.route("/logout", methods=["GET"])
def logout():
"""Handles the Kratos Logout flow
Steps:
1. We got here from hyrda
2. We retrieve the Kratos cookie from the browser
3. We generate a Kratos logout URL
4. We redirect to the Kratos logout URIL
"""
kratos_cookie = get_kratos_cookie()
if not kratos_cookie:
# No kratos cookie, already logged out
current_app.logger.info("Expected kratos cookie but not found. Redirecting to login");
return render_template("clear.html",
url="login")
try:
# Create a Logout URL for Browsers
kratos_api_response = \
admin_frontend_api.create_browser_logout_flow(
cookie=kratos_cookie)
current_app.logger.info(kratos_api_response)
except ory_kratos_client.ApiException as ex:
current_app.logger.error("Exception when calling"
" create_self_service_logout_flow_url_for_browsers: %s\n",
ex)
return render_template("clear.html",
url=kratos_api_response.logout_url)
if DEMO_INSTANCE: if DEMO_INSTANCE:
......
...@@ -6,9 +6,9 @@ ...@@ -6,9 +6,9 @@
// Wipe the local storage // Wipe the local storage
localStorage.removeItem("persist:root"); localStorage.removeItem("persist:root");
// Redirect // Redirect
window.location = '{{ url }}'; window.location = '{{ url | safe }}';
</script> </script>
Redirecting ... Clearing session data and redirecting...
{% endblock %} {% endblock %}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment