From 557ca3bb76c00b592bd566037aef663534c7bfd4 Mon Sep 17 00:00:00 2001
From: Ean Schuessler <ean@brainfood.com>
Date: Mon, 14 Apr 2025 19:32:43 -0500
Subject: [PATCH] Correct token access in LoginPreActions

Moved the logic for retrieving Keycloak tokens (ID token, subject) and
logging the user into Moqui to occur only *after* the Keycloak
authentication outcome is confirmed as AUTHENTICATED.

Previously, the script attempted to access these tokens regardless of the
authentication outcome, leading to errors (likely NullPointerException on
idToken.getSubject()) when authentication failed or resulted in a
challenge. This issue may have surfaced after the Keycloak upgrade to
version 23. Added null checks for KeycloakSecurityContext and IDToken
before accessing them.
---
 scripts/LoginPreActions.groovy | 56 +++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 37 insertions(+), 19 deletions(-)

diff --git a/scripts/LoginPreActions.groovy b/scripts/LoginPreActions.groovy
index de4edf7..d451866 100644
--- a/scripts/LoginPreActions.groovy
+++ b/scripts/LoginPreActions.groovy
@@ -61,6 +61,40 @@ new Exception().printStackTrace()
             //HttpServletRequestWrapper wrapper = tokenStore.buildWrapper()
             //postKeycloakFilter(wrapper, response, chain)
             //return
+
+            // If we get here, authentication was successful and the request wasn't handled by Keycloak actions
+            // Proceed to get tokens and log the user in
+            def ksc = ec.web.request.getAttribute(KeycloakSecurityContext.class.getName())
+            if (ksc == null) {
+                ec.logger.error("KeycloakSecurityContext not found in request after successful authentication outcome.")
+                // Optionally handle this error, maybe redirect to an error page
+                return
+            }
+
+            def idToken = ksc.getIdToken()
+            ec.logger.info("idToken: ${idToken}")
+            if (idToken == null) {
+                ec.logger.error("IDToken not found in KeycloakSecurityContext.")
+                // Optionally handle this error
+                return
+            }
+
+            def subject = idToken.getSubject()
+            ec.logger.info("subject: ${subject}")
+
+            def accessToken = ksc.getToken()
+            ec.logger.info("accessToken: ${accessToken}")
+
+            EntityValue userAccount = ec.entity.find('UserAccount').condition('externalUserId', subject).disableAuthz().one()
+            ec.logger.info("userAccount: ${userAccount}")
+            if (userAccount) {
+                //ec.user.pushUser(userAccount.username)
+                ec.user.internalLoginUser(userAccount.username)
+                ec.logger.info("Successfully logged in user ${userAccount.username} via Keycloak subject ${subject}")
+            } else {
+                ec.logger.warn("No UserAccount found for Keycloak subject ${subject}")
+                // Optionally handle this case, e.g., redirect to registration or show an error
+            }
         }
     }
 } else {
@@ -69,26 +103,10 @@ new Exception().printStackTrace()
     if (challenge != null) {
         if (challenge.challenge(facade)) {
             ec.logger.info("challenge sent")
-new Exception().printStackTrace()
-            //sri.stopRender()
+            // sri.stopRender() // Stop rendering if challenge was sent
             return
         }
     }
+    // If no challenge was sent, maybe log or handle other outcomes
+    ec.logger.warn("Keycloak authentication outcome was not AUTHENTICATED and no challenge was sent. Outcome: ${outcome}")
 }
-
-def ksc = ec.web.request.getAttribute(KeycloakSecurityContext.class.getName())
-def idToken = ksc.getIdToken()
-ec.logger.info("idToken: ${idToken}")
-def subject = idToken.getSubject()
-ec.logger.info("subject: ${subject}")
-
-def accessToken = ksc.getToken()
-ec.logger.info("accessToken: ${accessToken}")
-
-EntityValue userAccount = ec.entity.find('UserAccount').condition('externalUserId', subject).disableAuthz().one()
-ec.logger.info("userAccount: ${userAccount}")
-if (userAccount) {
-    //ec.user.pushUser(userAccount.username)
-    ec.user.internalLoginUser(userAccount.username)
-}
-
--
libgit2 0.24.0