LoginPreActions.groovy 4.79 KB
import javax.servlet.http.HttpServletRequestWrapper

import org.keycloak.KeycloakSecurityContext
import org.keycloak.AuthorizationContext

import org.keycloak.representations.AccessToken
import org.keycloak.representations.IDToken
import org.keycloak.adapters.KeycloakDeployment
import org.keycloak.adapters.KeycloakDeploymentBuilder

import org.keycloak.adapters.AdapterDeploymentContext
import org.keycloak.adapters.AuthenticatedActionsHandler
import org.keycloak.adapters.KeycloakConfigResolver
import org.keycloak.adapters.NodesRegistrationManagement
import org.keycloak.adapters.PreAuthActionsHandler
import org.keycloak.adapters.spi.AuthChallenge
import org.keycloak.adapters.spi.AuthOutcome
import org.keycloak.adapters.spi.InMemorySessionIdMapper
import org.keycloak.adapters.spi.SessionIdMapper
import org.keycloak.adapters.spi.UserSessionManagement

import org.keycloak.adapters.servlet.OIDCServletHttpFacade
import org.keycloak.adapters.servlet.OIDCFilterSessionStore
import org.keycloak.adapters.servlet.FilterRequestAuthenticator

def cache = ec.getCache().getCache('moqui-keycloak:deployment')

def keycloakJsonUrl = 'component://moqui-keycloak/config/moqui-keycloak.json'
def keycloakDeployment = cache.get(keycloakJsonUrl)

def idMapper = cache.get('SessionIdMapper')
if (idMapper == null) {
    idMapper = new InMemorySessionIdMapper()
    cache.put('SessionIdMapper', idMapper)
    idMapper = cache.get('SessionIdMapper')
}

if (true || !keycloakDeployment) {
    def configStream = ec.getResource().getLocationStream(keycloakJsonUrl)
    keycloakDeployment = KeycloakDeploymentBuilder.build(configStream)
    cache.put(keycloakJsonUrl, keycloakDeployment)
}
def facade = new OIDCServletHttpFacade(ec.web.request, ec.web.response)
def tokenStore = new OIDCFilterSessionStore(ec.web.request, facade, 100000, keycloakDeployment, idMapper)

def authenticator = new FilterRequestAuthenticator(keycloakDeployment, tokenStore, facade, ec.web.request, 8443)
def outcome = authenticator.authenticate()
ec.logger.info("outcome2: ${outcome}")
if (outcome == AuthOutcome.AUTHENTICATED) {
    if (facade.isEnded()) {
        ec.logger.info('facade has ended')
    } else {
        def actions = new AuthenticatedActionsHandler(keycloakDeployment, facade)
        ec.logger.info("actions: ${actions}")
        if (actions.handledRequest()) {
            ec.logger.info("actions.handledRequest")
new Exception().printStackTrace()
            //sri.stopRender()
            return
        } else {
            //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 {
    AuthChallenge challenge = authenticator.getChallenge()
    ec.logger.info("challenge: ${challenge}")
    if (challenge != null) {
        if (challenge.challenge(facade)) {
            ec.logger.info("challenge sent")
            // 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}")
}