diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java b/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java index 38a06862f5..96dfd64fdf 100755 --- a/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java +++ b/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java @@ -76,6 +76,8 @@ import java.util.stream.Stream; import org.keycloak.models.AccountRoles; import org.keycloak.provider.Provider; import org.keycloak.provider.ProviderFactory; +import org.keycloak.sessions.AuthenticationSessionModel; +import org.keycloak.sessions.RootAuthenticationSessionModel; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; @@ -275,14 +277,82 @@ public final class KeycloakModelUtils { } /** - * Copy all the objects in the context to the session. - * @param session The session - * @param context The context + * Sets up the context for the specified session with the RealmModel. + * + * @param origContext The original context to propagate + * @param targetSession The new target session to propagate the context to */ - public static void propagateContext(KeycloakSession session, KeycloakContext context) { - session.getContext().setRealm(context.getRealm()); - session.getContext().setClient(context.getClient()); - session.getContext().setAuthenticationSession(context.getAuthenticationSession()); + public static void cloneContextRealmClientToSession(final KeycloakContext origContext, final KeycloakSession targetSession) { + cloneContextToSession(origContext, targetSession, false); + } + + /** + * Sets up the context for the specified session with the RealmModel, clientModel and + * AuthenticatedSessionModel. + * + * @param origContext The original context to propagate + * @param targetSession The new target session to propagate the context to + */ + public static void cloneContextRealmClientSessionToSession(final KeycloakContext origContext, final KeycloakSession targetSession) { + cloneContextToSession(origContext, targetSession, true); + } + + /** + * Sets up the context for the specified session.The original realm's context is used to + * determine what models need to be re-loaded using the current session. The models + * in the context are re-read from the new session via the IDs. + */ + private static void cloneContextToSession(final KeycloakContext origContext, final KeycloakSession targetSession, + final boolean includeAuthenticatedSessionModel) { + if (origContext == null) { + return; + } + + // setup realm model if necessary. + RealmModel realmModel = null; + if (origContext.getRealm() != null) { + realmModel = targetSession.realms().getRealm(origContext.getRealm().getId()); + if (realmModel != null) { + targetSession.getContext().setRealm(realmModel); + } + } + + // setup client model if necessary. + ClientModel clientModel = null; + if (origContext.getClient() != null) { + if (origContext.getRealm() == null || !Objects.equals(origContext.getRealm().getId(), origContext.getClient().getRealm().getId())) { + realmModel = targetSession.realms().getRealm(origContext.getClient().getRealm().getId()); + } + if (realmModel != null) { + clientModel = targetSession.clients().getClientById(realmModel, origContext.getClient().getId()); + if (clientModel != null) { + targetSession.getContext().setClient(clientModel); + } + } + } + + // setup auth session model if necessary. + if (includeAuthenticatedSessionModel && origContext.getAuthenticationSession() != null) { + if (origContext.getClient() == null || !Objects.equals(origContext.getClient().getId(), origContext.getAuthenticationSession().getClient().getId())) { + realmModel = (origContext.getRealm() == null || !Objects.equals(origContext.getRealm().getId(), origContext.getAuthenticationSession().getRealm().getId())) + ? targetSession.realms().getRealm(origContext.getAuthenticationSession().getRealm().getId()) + : targetSession.getContext().getRealm(); + clientModel = (realmModel != null) + ? targetSession.clients().getClientById(realmModel, origContext.getAuthenticationSession().getClient().getId()) + : null; + } + if (clientModel != null) { + RootAuthenticationSessionModel rootAuthSession = targetSession.authenticationSessions().getRootAuthenticationSession( + realmModel, origContext.getAuthenticationSession().getParentSession().getId()); + if (rootAuthSession != null) { + AuthenticationSessionModel authSessionModel = rootAuthSession.getAuthenticationSession(clientModel, + origContext.getAuthenticationSession().getTabId()); + if (authSessionModel != null) { + targetSession.getContext().setAuthenticationSession(authSessionModel); + } + } + } + } } /** @@ -307,11 +377,9 @@ public final class KeycloakModelUtils { public static V runJobInTransactionWithResult(KeycloakSessionFactory factory, KeycloakContext context, final KeycloakSessionTaskWithResult callable) { V result; try (KeycloakSession session = factory.create()) { - if (context != null) { - propagateContext(session, context); - } session.getTransactionManager().begin(); try { + cloneContextRealmClientToSession(context, session); result = callable.run(session); } catch (Throwable t) { session.getTransactionManager().setRollbackOnly(); diff --git a/services/src/main/java/org/keycloak/common/util/ResponseSessionTask.java b/services/src/main/java/org/keycloak/common/util/ResponseSessionTask.java index 9b189e4836..e4e37eb052 100644 --- a/services/src/main/java/org/keycloak/common/util/ResponseSessionTask.java +++ b/services/src/main/java/org/keycloak/common/util/ResponseSessionTask.java @@ -19,12 +19,9 @@ package org.keycloak.common.util; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; -import org.keycloak.models.ClientModel; -import org.keycloak.models.KeycloakContext; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionTaskWithResult; -import org.keycloak.models.RealmModel; -import org.keycloak.sessions.RootAuthenticationSessionModel; +import org.keycloak.models.utils.KeycloakModelUtils; /** * A {@link KeycloakSessionTaskWithResult} that is aimed to be used by endpoints that want to produce a {@link Response} in @@ -60,7 +57,7 @@ public abstract class ResponseSessionTask implements KeycloakSessionTaskWithResu KeycloakSession originalContextSession = Resteasy.getContextData(KeycloakSession.class); try { // set up the current session context based on the original session context. - this.setupSessionContext(session); + KeycloakModelUtils.cloneContextRealmClientSessionToSession(originalSession.getContext(), session); // push the current session into the resteasy context. Resteasy.pushContext(KeycloakSession.class, session); // run the actual task. @@ -83,38 +80,6 @@ public abstract class ResponseSessionTask implements KeycloakSessionTaskWithResu } } - /** - * Sets up the context for the specified session. The original realm's context is used to determine what models - * need to be re-loaded using the current session. - * - * @param session the session whose context is to be prepared. - */ - private void setupSessionContext(final KeycloakSession session) { - if (this.originalSession == null) return; - KeycloakContext context = this.originalSession.getContext(); - // setup realm model if necessary. - RealmModel realmModel = null; - if (context.getRealm() != null) { - realmModel = session.realms().getRealm(context.getRealm().getId()); - session.getContext().setRealm(realmModel); - } - // setup client model if necessary. - ClientModel clientModel = null; - if (context.getClient() != null) { - clientModel = session.clients().getClientById(realmModel, context.getClient().getId()); - session.getContext().setClient(clientModel); - } - // setup auth session model if necessary. - if (context.getAuthenticationSession() != null) { - RootAuthenticationSessionModel rootAuthSession = session.authenticationSessions().getRootAuthenticationSession(realmModel, - context.getAuthenticationSession().getParentSession().getId()); - if (rootAuthSession != null) { - session.getContext().setAuthenticationSession(rootAuthSession.getAuthenticationSession(clientModel, - context.getAuthenticationSession().getTabId())); - } - } - } - /** * Builds the response that is to be returned. *