diff --git a/server-spi-private/src/main/java/org/keycloak/utils/LockObjectsForModification.java b/server-spi-private/src/main/java/org/keycloak/utils/LockObjectsForModification.java deleted file mode 100644 index 832ec28400..0000000000 --- a/server-spi-private/src/main/java/org/keycloak/utils/LockObjectsForModification.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2022 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.utils; - -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.models.UserSessionModel; - -import java.util.HashSet; -import java.util.Set; - -/** - * This flags the session that all information loaded from the stores should be locked as the service layer - * plans to modify it. - * - * This is just a hint to the underlying storage, and a store might choose to ignore it. - * The lock for any object retrieved from the session will be kept until the end of the transaction. - * - * If the store supports it, this could prevent exceptions due to optimistic locking - * problems later in the processing. If the caller retrieved objects without this wrapper, they would still be - * able to modify those objects, and those changes would be written to the store at the end of the transaction at the lastet, - * but they won't be locked. - * - * - * @author Alexander Schwartz - */ -public class LockObjectsForModification { - - private static final String ATTRIBUTE = LockObjectsForModification.class.getCanonicalName(); - - public static boolean isEnabled(KeycloakSession session, Class model) { - Set> lockedModels = getAttribute(session); - return lockedModels != null && lockedModels.contains(model); - } - - private static Set> getAttribute(KeycloakSession session) { - //noinspection unchecked - return (Set>) session.getAttribute(ATTRIBUTE); - } - - private static Set> getOrCreateAttribute(KeycloakSession session) { - Set> attribute = getAttribute(session); - if (attribute == null) { - attribute = new HashSet<>(); - session.setAttribute(ATTRIBUTE, attribute); - } - return attribute; - } - - public static V lockUserSessionsForModification(KeycloakSession session, CallableWithoutThrowingAnException callable) { - return lockObjectsForModification(session, UserSessionModel.class, callable); - } - - public static V lockRealmsForModification(KeycloakSession session, CallableWithoutThrowingAnException callable) { - return lockObjectsForModification(session, RealmModel.class, callable); - } - - private static V lockObjectsForModification(KeycloakSession session, Class model, CallableWithoutThrowingAnException callable) { - // Only map storage supported locking objects for modification, this logic will be remove in a follow up PR - return callable.call(); - } - - @FunctionalInterface - public interface CallableWithoutThrowingAnException { - /** - * Computes a result. - * - * @return computed result - */ - V call(); - } - - public static class Enabled implements AutoCloseable { - - private final KeycloakSession session; - private final Class model; - - public Enabled(KeycloakSession session, Class model) { - this.session = session; - this.model = model; - getOrCreateAttribute(session).add(model); - } - - @Override - public void close() { - getOrCreateAttribute(session).remove(model); - } - } -} diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java index 2ca6d9f629..9640d926b5 100755 --- a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java +++ b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java @@ -71,7 +71,6 @@ import java.util.Map; import java.util.Set; import static org.keycloak.models.light.LightweightUserAdapter.isLightweightUser; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; /** * @author Bill Burke @@ -1064,7 +1063,7 @@ public class AuthenticationProcessor { if (userSession == null) { // if no authenticator attached a usersession - userSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, authSession.getParentSession().getId())); + userSession = session.sessions().getUserSession(realm, authSession.getParentSession().getId()); if (userSession == null) { UserSessionModel.SessionPersistenceState persistenceState = UserSessionModel.SessionPersistenceState.fromString(authSession.getClientNote(AuthenticationManager.USER_SESSION_PERSISTENT_STATE)); diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/sessionlimits/UserSessionLimitsAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/sessionlimits/UserSessionLimitsAuthenticator.java index 88e797b8dc..2544b4c910 100644 --- a/services/src/main/java/org/keycloak/authentication/authenticators/sessionlimits/UserSessionLimitsAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/sessionlimits/UserSessionLimitsAuthenticator.java @@ -25,8 +25,6 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.utils.StringUtil; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; - public class UserSessionLimitsAuthenticator implements Authenticator { private static Logger logger = Logger.getLogger(UserSessionLimitsAuthenticator.class); @@ -58,7 +56,7 @@ public class UserSessionLimitsAuthenticator implements Authenticator { if (context.getRealm() != null && context.getUser() != null) { // Get the session count in this realm for this specific user - List userSessionsForRealm = lockUserSessionsForModification(session, () -> session.sessions().getUserSessionsStream(context.getRealm(), context.getUser()).collect(Collectors.toList())); + List userSessionsForRealm = session.sessions().getUserSessionsStream(context.getRealm(), context.getUser()).collect(Collectors.toList()); int userSessionCountForRealm = userSessionsForRealm.size(); // Get the session count related to the current client for this user diff --git a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java index d251a8cd10..91ae169cf9 100644 --- a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java +++ b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java @@ -100,8 +100,6 @@ import org.keycloak.sessions.RootAuthenticationSessionModel; import org.keycloak.util.JsonSerialization; import org.keycloak.services.util.DefaultClientSessionContext; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; - /** * @author Pedro Igor */ @@ -318,7 +316,7 @@ public class AuthorizationTokenService { userSessionModel = new UserSessionManager(keycloakSession).createUserSession(KeycloakModelUtils.generateId(), realm, user, user.getUsername(), request.getClientConnection().getRemoteAddr(), ServiceAccountConstants.CLIENT_AUTH, false, null, null, UserSessionModel.SessionPersistenceState.TRANSIENT); } else { - userSessionModel = lockUserSessionsForModification(keycloakSession, () -> sessions.getUserSession(realm, accessToken.getSessionState())); + userSessionModel = sessions.getUserSession(realm, accessToken.getSessionState()); if (userSessionModel == null) { userSessionModel = sessions.getOfflineUserSession(realm, accessToken.getSessionState()); diff --git a/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java b/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java index 61cd0314f3..3bdcf937bc 100644 --- a/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java +++ b/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java @@ -46,8 +46,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; - /** * @author Pedro Igor */ @@ -128,7 +126,7 @@ public class KeycloakIdentity implements Identity { this.accessToken = AccessToken.class.cast(token); } else { UserSessionProvider sessions = keycloakSession.sessions(); - UserSessionModel userSession = lockUserSessionsForModification(keycloakSession, () -> sessions.getUserSession(realm, token.getSessionState())); + UserSessionModel userSession = sessions.getUserSession(realm, token.getSessionState()); if (userSession == null) { userSession = sessions.getOfflineUserSession(realm, token.getSessionState()); @@ -297,7 +295,7 @@ public class KeycloakIdentity implements Identity { } UserSessionProvider sessions = keycloakSession.sessions(); - UserSessionModel userSession = lockUserSessionsForModification(keycloakSession, () -> sessions.getUserSession(realm, accessToken.getSessionState())); + UserSessionModel userSession = sessions.getUserSession(realm, accessToken.getSessionState()); if (userSession == null) { userSession = sessions.getOfflineUserSession(realm, accessToken.getSessionState()); diff --git a/services/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java b/services/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java index eb9eb21463..05ed4b1411 100755 --- a/services/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java +++ b/services/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java @@ -43,8 +43,6 @@ import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.Response; import java.io.IOException; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; - /** * @author Bill Burke * @version $Revision: 1 $ @@ -97,7 +95,7 @@ public class KeycloakOIDCIdentityProvider extends OIDCIdentityProvider { if (action.getKeycloakSessionIds() != null) { for (String sessionId : action.getKeycloakSessionIds()) { String brokerSessionId = provider.getConfig().getAlias() + "." + sessionId; - UserSessionModel userSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSessionByBrokerSessionId(realm, brokerSessionId)); + UserSessionModel userSession = session.sessions().getUserSessionByBrokerSessionId(realm, brokerSessionId); if (userSession != null && userSession.getState() != UserSessionModel.State.LOGGING_OUT && userSession.getState() != UserSessionModel.State.LOGGED_OUT diff --git a/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java b/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java index 88c27409b5..fe2559b3ea 100755 --- a/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java +++ b/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java @@ -82,8 +82,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; - /** * @author Pedro Igor */ @@ -333,7 +331,7 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider session.sessions().getUserSession(realm, state)); + UserSessionModel userSession = session.sessions().getUserSession(realm, state); if (userSession == null) { logger.error("no valid user session"); EventBuilder event = new EventBuilder(realm, session, clientConnection); diff --git a/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java b/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java index df2a7664f0..bf1b499431 100755 --- a/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java +++ b/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java @@ -129,8 +129,6 @@ import java.util.Collections; import jakarta.ws.rs.core.MultivaluedMap; import javax.xml.crypto.dsig.XMLSignature; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; - /** * @author Bill Burke * @version $Revision: 1 $ @@ -349,7 +347,7 @@ public class SAMLEndpoint { } else { for (String sessionIndex : request.getSessionIndex()) { String brokerSessionId = config.getAlias() + "." + sessionIndex; - UserSessionModel userSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSessionByBrokerSessionId(realm, brokerSessionId)); + UserSessionModel userSession = session.sessions().getUserSessionByBrokerSessionId(realm, brokerSessionId); if (userSession != null) { if (userSession.getState() == UserSessionModel.State.LOGGING_OUT || userSession.getState() == UserSessionModel.State.LOGGED_OUT) { continue; @@ -724,7 +722,7 @@ public class SAMLEndpoint { event.error(Errors.USER_SESSION_NOT_FOUND); return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR); } - UserSessionModel userSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, relayState)); + UserSessionModel userSession = session.sessions().getUserSession(realm, relayState); if (userSession == null) { logger.error("no valid user session"); event.event(EventType.LOGOUT); diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java index 2c894b04a6..71a2187219 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java @@ -116,7 +116,6 @@ import jakarta.ws.rs.core.UriInfo; import static org.keycloak.models.light.LightweightUserAdapter.isLightweightUser; import static org.keycloak.representations.IDToken.NONCE; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; /** * Stateless object that creates tokens and manages oauth access codes @@ -164,7 +163,7 @@ public class TokenManager { } } else { // Find userSession regularly for online tokens - userSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, oldToken.getSessionState())); + userSession = session.sessions().getUserSession(realm, oldToken.getSessionState()); if (!AuthenticationManager.isSessionValid(realm, userSession)) { AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, connection, headers, true); throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Session not active", "Session not active"); @@ -325,10 +324,10 @@ public class TokenManager { private boolean validateTokenReuseForIntrospection(KeycloakSession session, RealmModel realm, AccessToken token) { UserSessionModel userSession = null; if (token.getType().equals(TokenUtil.TOKEN_TYPE_REFRESH)) { - userSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, token.getSessionState())); + userSession = session.sessions().getUserSession(realm, token.getSessionState()); } else { UserSessionManager sessionManager = new UserSessionManager(session); - userSession = lockUserSessionsForModification(session, () -> sessionManager.findOfflineUserSession(realm, token.getSessionState())); + userSession = sessionManager.findOfflineUserSession(realm, token.getSessionState()); } ClientModel client = realm.getClientByClientId(token.getIssuedFor()); diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java index c91267d7a2..affea61c5c 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java @@ -20,7 +20,6 @@ package org.keycloak.protocol.oidc.endpoints; import static org.keycloak.models.UserSessionModel.State.LOGGED_OUT; import static org.keycloak.models.UserSessionModel.State.LOGGING_OUT; import static org.keycloak.services.resources.LoginActionsService.SESSION_CODE; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; import org.jboss.logging.Logger; import org.jboss.resteasy.annotations.cache.NoCache; @@ -435,7 +434,7 @@ public class LogoutEndpoint { String idTokenIssuedAtStr = logoutSession.getAuthNote(OIDCLoginProtocol.LOGOUT_VALIDATED_ID_TOKEN_ISSUED_AT); if (userSessionIdFromIdToken != null && idTokenIssuedAtStr != null) { try { - userSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, userSessionIdFromIdToken)); + userSession = session.sessions().getUserSession(realm, userSessionIdFromIdToken); if (userSession == null) { event.event(EventType.LOGOUT); @@ -452,8 +451,7 @@ public class LogoutEndpoint { } // authenticate identity cookie, but ignore an access token timeout as we're logging out anyways. - AuthenticationManager.AuthResult authResult = lockUserSessionsForModification(session, - () -> AuthenticationManager.authenticateIdentityCookie(session, realm, false)); + AuthenticationManager.AuthResult authResult = AuthenticationManager.authenticateIdentityCookie(session, realm, false); if (authResult != null) { userSession = userSession != null ? userSession : authResult.getSession(); return initiateBrowserLogout(userSession); @@ -533,7 +531,7 @@ public class LogoutEndpoint { userSessionModel = sessionManager.findOfflineUserSession(realm, token.getSessionState()); } else { String sessionState = token.getSessionState(); - userSessionModel = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, sessionState)); + userSessionModel = session.sessions().getUserSession(realm, sessionState); } if (userSessionModel != null) { @@ -633,8 +631,7 @@ public class LogoutEndpoint { AtomicReference backchannelLogoutResponse = new AtomicReference<>(new BackchannelLogoutResponse()); backchannelLogoutResponse.get().setLocalLogoutSucceeded(true); identityProviderAliases.forEach(identityProviderAlias -> { - UserSessionModel userSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSessionByBrokerSessionId(realm, - identityProviderAlias + "." + sessionId)); + UserSessionModel userSession = session.sessions().getUserSessionByBrokerSessionId(realm, identityProviderAlias + "." + sessionId); if (logoutOfflineSessions) { if (offlineSessionsLazyLoadingEnabled) { diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java index 914304b8cc..0ca1fd499c 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java @@ -124,8 +124,6 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; - /** * @author Stian Thorgersen */ @@ -574,7 +572,7 @@ public class TokenEndpoint { res = responseBuilder.build(); if (!responseBuilder.isOfflineToken()) { - UserSessionModel userSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, res.getSessionState())); + UserSessionModel userSession = session.sessions().getUserSession(realm, res.getSessionState()); AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessionByClient(client.getId()); updateClientSession(clientSession); updateUserSessionFromClientAuth(userSession); diff --git a/services/src/main/java/org/keycloak/protocol/oidc/grants/device/DeviceGrantType.java b/services/src/main/java/org/keycloak/protocol/oidc/grants/device/DeviceGrantType.java index c021971b65..25a36fc01b 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/grants/device/DeviceGrantType.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/grants/device/DeviceGrantType.java @@ -18,7 +18,6 @@ package org.keycloak.protocol.oidc.grants.device; import static org.keycloak.protocol.oidc.OIDCLoginProtocolService.tokenServiceBaseUrl; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; import org.keycloak.OAuth2Constants; import org.keycloak.OAuthErrorException; @@ -291,7 +290,7 @@ public class DeviceGrantType { client.getId()); if (userSession == null) { - userSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, userSessionId)); + userSession = session.sessions().getUserSession(realm, userSessionId); if (userSession == null) { throw new CorsErrorResponseException(cors, OAuthErrorException.AUTHORIZATION_PENDING, "The authorization request is verified but can not lookup the user session yet", diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/OAuth2CodeParser.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/OAuth2CodeParser.java index ae5b991a9b..fdf170cc19 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/utils/OAuth2CodeParser.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/OAuth2CodeParser.java @@ -31,8 +31,6 @@ import org.keycloak.models.SingleUseObjectProvider; import org.keycloak.models.UserSessionModel; import org.keycloak.services.managers.UserSessionCrossDCManager; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; - /** * @author Marek Posolda */ @@ -101,10 +99,10 @@ public class OAuth2CodeParser { } // Retrieve UserSession - UserSessionModel userSession = lockUserSessionsForModification(session, () -> new UserSessionCrossDCManager(session).getUserSessionWithClient(realm, userSessionId, clientUUID)); + UserSessionModel userSession = new UserSessionCrossDCManager(session).getUserSessionWithClient(realm, userSessionId, clientUUID); if (userSession == null) { // Needed to track if code is invalid or was already used. - userSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, userSessionId)); + userSession = session.sessions().getUserSession(realm, userSessionId); if (userSession == null) { return result.illegalCode(); } diff --git a/services/src/main/java/org/keycloak/protocol/saml/SamlService.java b/services/src/main/java/org/keycloak/protocol/saml/SamlService.java index 235df586ab..8a8f031b1f 100755 --- a/services/src/main/java/org/keycloak/protocol/saml/SamlService.java +++ b/services/src/main/java/org/keycloak/protocol/saml/SamlService.java @@ -144,8 +144,6 @@ import jakarta.ws.rs.core.MultivaluedMap; import javax.xml.parsers.ParserConfigurationException; import static org.keycloak.common.util.StackUtil.getShortStackTrace; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; - /** * Resource class for the saml connect token service @@ -1164,7 +1162,7 @@ public class SamlService extends AuthorizationEndpointBase { return emptyArtifactResponseMessage(artifactResolveMessage, null); } - UserSessionModel userSessionModel = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, sessionMapping.get(SamlProtocol.USER_SESSION_ID))); + UserSessionModel userSessionModel = session.sessions().getUserSession(realm, sessionMapping.get(SamlProtocol.USER_SESSION_ID)); if (userSessionModel == null) { logger.errorf("UserSession with id: %s, that corresponds to artifact: %s does not exist.", sessionMapping.get(SamlProtocol.USER_SESSION_ID), artifact); return emptyArtifactResponseMessage(artifactResolveMessage, null); diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java index 6b5e225d3d..f9c3fe9a1c 100755 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java @@ -115,7 +115,6 @@ import static org.keycloak.models.light.LightweightUserAdapter.isLightweightUser import static org.keycloak.models.UserSessionModel.CORRESPONDING_SESSION_ID; import static org.keycloak.protocol.oidc.grants.device.DeviceGrantType.isOAuth2DeviceVerificationFlow; import static org.keycloak.services.util.CookieHelper.getCookie; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; /** * Stateless object that manages authentication @@ -229,7 +228,7 @@ public class AuthenticationManager { verifier.verifierContext(signatureVerifier); AccessToken token = verifier.verify().getToken(); - UserSessionModel cookieSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, token.getSessionState())); + UserSessionModel cookieSession = session.sessions().getUserSession(realm, token.getSessionState()); if (cookieSession == null || !cookieSession.getId().equals(userSession.getId())) return true; expireIdentityCookie(realm, uriInfo, session); return true; @@ -319,9 +318,9 @@ public class AuthenticationManager { // Check if "online" session still exists and remove it too String onlineUserSessionId = userSession.getNote(CORRESPONDING_SESSION_ID); - UserSessionModel onlineUserSession = lockUserSessionsForModification(session, () -> (onlineUserSessionId != null) ? + UserSessionModel onlineUserSession = onlineUserSessionId != null ? session.sessions().getUserSession(realm, onlineUserSessionId) : - session.sessions().getUserSession(realm, userSession.getId())); + session.sessions().getUserSession(realm, userSession.getId()); if (onlineUserSession != null) { session.sessions().removeUserSession(realm, onlineUserSession); @@ -950,7 +949,7 @@ public class AuthenticationManager { if (split.length >= 3) { String oldSessionId = split[2]; if (!oldSessionId.equals(userSession.getId())) { - UserSessionModel oldSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, oldSessionId)); + UserSessionModel oldSession = session.sessions().getUserSession(realm, oldSessionId); if (oldSession != null) { logger.debugv("Removing old user session: session: {0}", oldSessionId); session.sessions().removeUserSession(realm, oldSession); diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationSessionManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationSessionManager.java index 28453cfc04..92b4025d18 100644 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationSessionManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationSessionManager.java @@ -28,23 +28,18 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserSessionModel; import org.keycloak.models.utils.SessionExpiration; import org.keycloak.protocol.RestartLoginCookie; -import org.keycloak.services.resources.LoginActionsService; import org.keycloak.services.util.CookieHelper; import org.keycloak.sessions.AuthenticationSessionModel; -import org.keycloak.sessions.CommonClientSessionModel; import org.keycloak.sessions.RootAuthenticationSessionModel; import org.keycloak.sessions.StickySessionEncoderProvider; import jakarta.ws.rs.core.UriInfo; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; -import static org.keycloak.authentication.AuthenticationProcessor.CURRENT_FLOW_PATH; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; /** * @author Marek Posolda @@ -108,7 +103,7 @@ public class AuthenticationSessionManager { AuthSessionId authSessionId = decodeAuthSessionId(oldEncodedId); String sessionId = authSessionId.getDecodedId(); - UserSessionModel userSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, sessionId)); + UserSessionModel userSession = session.sessions().getUserSession(realm, sessionId); if (userSession != null) { reencodeAuthSessionCookie(oldEncodedId, authSessionId, realm); @@ -284,7 +279,7 @@ public class AuthenticationSessionManager { // Check to see if we already have authenticationSession with same ID public UserSessionModel getUserSession(AuthenticationSessionModel authSession) { - return lockUserSessionsForModification(session, () -> session.sessions().getUserSession(authSession.getRealm(), authSession.getParentSession().getId())); + return session.sessions().getUserSession(authSession.getRealm(), authSession.getParentSession().getId()); } diff --git a/services/src/main/java/org/keycloak/services/managers/UserSessionCrossDCManager.java b/services/src/main/java/org/keycloak/services/managers/UserSessionCrossDCManager.java index 6d6cacbdda..9ef67ab8d5 100644 --- a/services/src/main/java/org/keycloak/services/managers/UserSessionCrossDCManager.java +++ b/services/src/main/java/org/keycloak/services/managers/UserSessionCrossDCManager.java @@ -28,7 +28,6 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserSessionModel; import static org.keycloak.services.managers.AuthenticationManager.authenticateIdentityCookie; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; /** * @author Marek Posolda @@ -72,7 +71,7 @@ public class UserSessionCrossDCManager { // in case the auth session was removed, we fall back to the identity cookie // we are here doing the user session lookup twice, however the second lookup is going to make sure the // session exists in remote caches - AuthenticationManager.AuthResult authResult = lockUserSessionsForModification(kcSession, () -> authenticateIdentityCookie(kcSession, realm, true)); + AuthenticationManager.AuthResult authResult = authenticateIdentityCookie(kcSession, realm, true); if (authResult != null && authResult.getSession() != null) { sessionCookies = Collections.singletonList(authResult.getSession().getId()); @@ -84,9 +83,9 @@ public class UserSessionCrossDCManager { String sessionId = authSessionId.getDecodedId(); // This will remove userSession "locally" if it doesn't exist on remoteCache - lockUserSessionsForModification(kcSession, () -> kcSession.sessions().getUserSessionWithPredicate(realm, sessionId, false, (UserSessionModel userSession2) -> userSession2 == null)); + kcSession.sessions().getUserSessionWithPredicate(realm, sessionId, false, (UserSessionModel userSession2) -> userSession2 == null); - UserSessionModel userSession = lockUserSessionsForModification(kcSession, () -> kcSession.sessions().getUserSession(realm, sessionId)); + UserSessionModel userSession = kcSession.sessions().getUserSession(realm, sessionId); if (userSession != null) { asm.reencodeAuthSessionCookie(oldEncodedId, authSessionId, realm); diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsServiceChecks.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsServiceChecks.java index f7fb168492..bd34d05ae3 100644 --- a/services/src/main/java/org/keycloak/services/resources/LoginActionsServiceChecks.java +++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsServiceChecks.java @@ -43,8 +43,6 @@ import java.util.Objects; import java.util.function.Consumer; import org.jboss.logging.Logger; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; - /** * * @author hmlnarik @@ -123,7 +121,7 @@ public class LoginActionsServiceChecks { return; } - UserSessionModel userSession = lockUserSessionsForModification(context.getSession(), () -> context.getSession().sessions().getUserSession(context.getRealm(), authSessionId)); + UserSessionModel userSession = context.getSession().sessions().getUserSession(context.getRealm(), authSessionId); boolean hasNoRequiredActions = (userSession == null || userSession.getUser().getRequiredActionsStream().count() == 0) && diff --git a/services/src/main/java/org/keycloak/services/resources/SessionCodeChecks.java b/services/src/main/java/org/keycloak/services/resources/SessionCodeChecks.java index 26d9778bde..5e94939aca 100644 --- a/services/src/main/java/org/keycloak/services/resources/SessionCodeChecks.java +++ b/services/src/main/java/org/keycloak/services/resources/SessionCodeChecks.java @@ -18,7 +18,6 @@ package org.keycloak.services.resources; import static org.keycloak.services.managers.AuthenticationManager.authenticateIdentityCookie; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; import java.net.URI; @@ -40,7 +39,6 @@ import org.keycloak.models.ClientModel; import org.keycloak.models.Constants; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; -import org.keycloak.models.UserSessionModel; import org.keycloak.protocol.AuthorizationEndpointBase; import org.keycloak.protocol.RestartLoginCookie; import org.keycloak.services.ErrorPage; @@ -185,7 +183,7 @@ public class SessionCodeChecks { // if restart from cookie was not found check if the user is already authenticated if (response.getStatus() != Response.Status.FOUND.getStatusCode()) { - AuthenticationManager.AuthResult authResult = lockUserSessionsForModification(session, () -> authenticateIdentityCookie(session, realm, false)); + AuthenticationManager.AuthResult authResult = authenticateIdentityCookie(session, realm, false); if (authResult != null && authResult.getSession() != null) { LoginFormsProvider loginForm = session.getProvider(LoginFormsProvider.class).setAuthenticationSession(authSession) diff --git a/services/src/main/java/org/keycloak/services/resources/account/SessionResource.java b/services/src/main/java/org/keycloak/services/resources/account/SessionResource.java index cecf77872f..540f8cd0bb 100755 --- a/services/src/main/java/org/keycloak/services/resources/account/SessionResource.java +++ b/services/src/main/java/org/keycloak/services/resources/account/SessionResource.java @@ -32,7 +32,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.jboss.resteasy.annotations.cache.NoCache; -import org.keycloak.common.util.Time; import org.keycloak.device.DeviceActivityManager; import org.keycloak.models.AccountRoles; import org.keycloak.models.ClientModel; @@ -46,8 +45,6 @@ import org.keycloak.representations.account.SessionRepresentation; import org.keycloak.services.managers.Auth; import org.keycloak.services.managers.AuthenticationManager; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; - /** * @author Pedro Igor */ @@ -147,7 +144,7 @@ public class SessionResource { @NoCache public Response logout(@PathParam("id") String id) { auth.require(AccountRoles.MANAGE_ACCOUNT); - UserSessionModel userSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, id)); + UserSessionModel userSession = session.sessions().getUserSession(realm, id); if (userSession != null && userSession.getUser().equals(user)) { AuthenticationManager.backchannelLogout(session, userSession, true); } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java index a5a2401a7e..1b1623e177 100644 --- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java @@ -16,7 +16,6 @@ */ package org.keycloak.services.resources.admin; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; import static org.keycloak.util.JsonSerialization.readValue; import java.io.InputStream; @@ -633,7 +632,7 @@ public class RealmAdminResource { public void deleteSession(@PathParam("session") String sessionId) { auth.users().requireManage(); - UserSessionModel userSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, sessionId)); + UserSessionModel userSession = session.sessions().getUserSession(realm, sessionId); if (userSession == null) throw new NotFoundException("Sesssion not found"); AuthenticationManager.backchannelLogout(session, realm, userSession, session.getContext().getUri(), connection, headers, true); adminEvent.operation(OperationType.DELETE).resource(ResourceType.USER_SESSION).resourcePath(session.getContext().getUri()).success(); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java index edb5131f3e..7d21d4eb4a 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java @@ -125,7 +125,6 @@ import static org.keycloak.models.ImpersonationSessionNote.IMPERSONATOR_ID; import static org.keycloak.models.ImpersonationSessionNote.IMPERSONATOR_USERNAME; import static org.keycloak.services.resources.admin.UserProfileResource.createUserProfileMetadata; import static org.keycloak.userprofile.UserProfileContext.USER_API; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; /** * Base resource for managing users @@ -359,7 +358,7 @@ public class UserResource { String sessionState = auth.adminAuth().getToken().getSessionState(); if (authenticatedRealm.getId().equals(realm.getId()) && sessionState != null) { sameRealm = true; - UserSessionModel userSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(authenticatedRealm, sessionState)); + UserSessionModel userSession = session.sessions().getUserSession(authenticatedRealm, sessionState); AuthenticationManager.expireIdentityCookie(realm, session.getContext().getUri(), session); AuthenticationManager.expireRememberMeCookie(realm, session.getContext().getUri(), session); AuthenticationManager.expireAuthSessionCookie(realm, session.getContext().getUri(), session); diff --git a/testsuite/model/src/test/java/org/keycloak/testsuite/model/session/UserSessionConcurrencyTest.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/session/UserSessionConcurrencyTest.java index 0b09cdba27..de0530e450 100644 --- a/testsuite/model/src/test/java/org/keycloak/testsuite/model/session/UserSessionConcurrencyTest.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/session/UserSessionConcurrencyTest.java @@ -37,8 +37,6 @@ import java.util.stream.IntStream; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.aMapWithSize; import static org.hamcrest.Matchers.startsWith; -import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification; - @RequireProvider(UserSessionProvider.class) public class UserSessionConcurrencyTest extends KeycloakModelTest { @@ -87,7 +85,7 @@ public class UserSessionConcurrencyTest extends KeycloakModelTest { RealmModel realm = session.realms().getRealm(realmId); ClientModel client = realm.getClientByClientId("client" + (n % CLIENTS_COUNT)); - UserSessionModel uSession = lockUserSessionsForModification(session, () -> session.sessions().getUserSession(realm, uId)); + UserSessionModel uSession = session.sessions().getUserSession(realm, uId); AuthenticatedClientSessionModel cSession = uSession.getAuthenticatedClientSessionByClient(client.getId()); if (cSession == null) { wasWriting.set(true);