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