From 84ca20ba81c13712836818cb8ebeff3d795d8c91 Mon Sep 17 00:00:00 2001
From: Mart van Santen <mart@greenhost.nl>
Date: Wed, 21 Sep 2022 23:51:28 +0800
Subject: [PATCH] Split logout flow in two steps (kratos/hydra)

---
 run_app.sh         |  2 +-
 web/login/login.py | 52 +++++++++++++++++++++++++++++++++++-----------
 2 files changed, 41 insertions(+), 13 deletions(-)

diff --git a/run_app.sh b/run_app.sh
index b4d203d9..456500bd 100755
--- a/run_app.sh
+++ b/run_app.sh
@@ -29,4 +29,4 @@ if [[ -z "$HYDRA_CLIENT_SECRET" ]]; then
     exit 1
 fi
 
-KUBECTL_UID=${UID:-1001} KUBECTL_GID=${GID:-0} docker compose up
+KUBECTL_UID=${UID:-1001} KUBECTL_GID=${GID:-0} docker-compose up
diff --git a/web/login/login.py b/web/login/login.py
index 591acc2a..3a41367c 100644
--- a/web/login/login.py
+++ b/web/login/login.py
@@ -385,21 +385,20 @@ def get_kratos_cookie():
     return cookie
 
 
-@web.route("/logout", methods=["GET"])
-def logout():
-    """Handles the Hydra OpenID Connect Logout flow as well as the Kratos
-    logout flow
 
-    Steps:
+@web.route("/prelogout", methods=["GET"])
+def prelogout():
+    """Handles the Hydra OpenID Connect Logout flow
 
+    Steps:
     1. Hydra's /oauth2/sessions/logout endpoint is called by an application
     2. Hydra calls this endpoint with a `logout_challenge` get parameter
     3. We retrieve the logout request using the challenge
-    4. We retrieve the Kratos cookie from the browser
-    5. We generate a Kratos logout URL
-    6. We accept the Hydra logout request
-    7. We redirect to the Kratos logout URL
+    4. We accept the Hydra logout request
+    5. We redirect to Hydro to clean-up cookies.
+    6. Hyrda calls back to us with a post logout handle (/logout)
 
+     
     Args:
         logout_challenge (string): Reference to a Hydra logout challenge object
 
@@ -421,9 +420,39 @@ def logout():
             challenge)
         abort(503)
 
+    current_app.logger.info("Logout request hydra, subject %s", logout_request.subject)
+
+    # Accept logout request and direct to hydra to remove cookies
+    try:
+        hydra_return = logout_request.accept(subject=logout_request.subject)
+        if hydra_return:
+          return redirect(hydra_return)
+
+    except Exception as ex:
+        current_app.logger.info("Error logging out hydra: %s", str(ex))
+
+
+    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:
-        abort(404, "Kratos session invalid or not found")
+        # No kratos cookie, already logged out
+        current_app.logger.info("Expected kratos cookie but not found. Redirecting to login");
+        return redirect("login")
+
     try:
         # Create a Logout URL for Browsers
         kratos_api_response = \
@@ -434,6 +463,5 @@ def logout():
         current_app.logger.error("Exception when calling"
             " V0alpha2Api->create_self_service_logout_flow_url_for_browsers: %s\n",
             ex)
-    hydra_return = logout_request.accept(subject=logout_request.subject)
-    current_app.logger.info("Hydra info: %s", hydra_return)
     return redirect(kratos_api_response.logout_url)
+
-- 
GitLab