diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java index 96bbf152a4..4dfafcb826 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java @@ -382,7 +382,8 @@ public class InfinispanUserSessionProvider implements UserSessionProvider { // and then mapped locally to avoid serialization issues when trying to manipulate the cache stream directly. return StreamSupport.stream(cache.entrySet().stream().filter(predicate).spliterator(), false) .map(Mappers.userSessionEntity()) - .map(entity -> this.wrap(realm, entity, offline)); + .map(entity -> this.wrap(realm, entity, offline)) + .filter(Objects::nonNull).map(Function.identity()); } @Override @@ -739,7 +740,17 @@ public class InfinispanUserSessionProvider implements UserSessionProvider { UserSessionAdapter wrap(RealmModel realm, UserSessionEntity entity, boolean offline) { InfinispanChangelogBasedTransaction userSessionUpdateTx = getTransaction(offline); InfinispanChangelogBasedTransaction clientSessionUpdateTx = getClientSessionTransaction(offline); - return entity != null ? new UserSessionAdapter(session, this, userSessionUpdateTx, clientSessionUpdateTx, realm, entity, offline) : null; + + if (entity == null) { + return null; + } + + UserModel user = session.users().getUserById(realm, entity.getUser()); + if (user == null) { + return null; + } + + return new UserSessionAdapter(session, user, this, userSessionUpdateTx, clientSessionUpdateTx, realm, entity, offline); } AuthenticatedClientSessionAdapter wrap(UserSessionModel userSession, ClientModel client, AuthenticatedClientSessionEntity entity, boolean offline) { diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java index cc26d02f4f..ae314e1d7c 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java @@ -60,17 +60,20 @@ public class UserSessionAdapter implements UserSessionModel { private final RealmModel realm; + private final UserModel user; + private final UserSessionEntity entity; private final boolean offline; private SessionPersistenceState persistenceState; - public UserSessionAdapter(KeycloakSession session, InfinispanUserSessionProvider provider, + public UserSessionAdapter(KeycloakSession session, UserModel user, InfinispanUserSessionProvider provider, InfinispanChangelogBasedTransaction userSessionUpdateTx, InfinispanChangelogBasedTransaction clientSessionUpdateTx, RealmModel realm, UserSessionEntity entity, boolean offline) { this.session = session; + this.user = user; this.provider = provider; this.userSessionUpdateTx = userSessionUpdateTx; this.clientSessionUpdateTx = clientSessionUpdateTx; @@ -138,20 +141,20 @@ public class UserSessionAdapter implements UserSessionModel { if (removedClientUUIDS.size() >= MINIMUM_INACTIVE_CLIENT_SESSIONS_TO_CLEANUP) { // Update user session UserSessionUpdateTask task = new UserSessionUpdateTask() { - @Override - public void runUpdate(UserSessionEntity entity) { - removedClientUUIDS.forEach(entity.getAuthenticatedClientSessions()::remove); - } - }; + @Override + public void runUpdate(UserSessionEntity entity) { + removedClientUUIDS.forEach(entity.getAuthenticatedClientSessions()::remove); + } + }; update(task); } // do not iterate the removedClientUUIDS and remove the clientSession directly as the addTask can manipulate // the collection being iterated, and that can lead to unpredictable behaviour (e.g. NPE) List clientSessionUuids = removedClientUUIDS.stream() - .map(entity.getAuthenticatedClientSessions()::get) - .filter(Objects::nonNull) - .collect(Collectors.toList()); + .map(entity.getAuthenticatedClientSessions()::get) + .filter(Objects::nonNull) + .collect(Collectors.toList()); clientSessionUuids.forEach(clientSessionId -> this.clientSessionUpdateTx.addTask(clientSessionId, Tasks.removeSync())); } @@ -174,8 +177,9 @@ public class UserSessionAdapter implements UserSessionModel { public String getBrokerUserId() { return entity.getBrokerUserId(); } + public UserModel getUser() { - return session.users().getUserById(realm, entity.getUser()); + return this.user; } @Override @@ -339,8 +343,12 @@ public class UserSessionAdapter implements UserSessionModel { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !(o instanceof UserSessionModel)) return false; + if (this == o) { + return true; + } + if (o == null || !(o instanceof UserSessionModel)) { + return false; + } UserSessionModel that = (UserSessionModel) o; return that.getId().equals(getId()); diff --git a/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionAdapter.java b/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionAdapter.java index 7662907749..a7595e32b6 100644 --- a/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionAdapter.java +++ b/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionAdapter.java @@ -43,8 +43,11 @@ import static org.keycloak.models.map.userSession.SessionExpiration.setUserSessi */ public class MapUserSessionAdapter extends AbstractUserSessionModel { - public MapUserSessionAdapter(KeycloakSession session, RealmModel realm, MapUserSessionEntity entity) { + private final UserModel user; + + public MapUserSessionAdapter(KeycloakSession session, RealmModel realm, UserModel userModel, MapUserSessionEntity entity) { super(session, realm, entity); + this.user = userModel; } @Override @@ -69,7 +72,7 @@ public class MapUserSessionAdapter extends AbstractUserSessionModel { @Override public UserModel getUser() { - return session.users().getUserById(getRealm(), entity.getUserId()); + return this.user; } @Override @@ -127,11 +130,11 @@ public class MapUserSessionAdapter extends AbstractUserSessionModel { } return authenticatedClientSessions - .stream() - .filter(this::filterAndRemoveExpiredClientSessions) - .filter(this::matchingOfflineFlag) - .filter(this::filterAndRemoveClientSessionWithoutClient) - .collect(Collectors.toMap(MapAuthenticatedClientSessionEntity::getClientId, this::clientSessionEntityToModel)); + .stream() + .filter(this::filterAndRemoveExpiredClientSessions) + .filter(this::matchingOfflineFlag) + .filter(this::filterAndRemoveClientSessionWithoutClient) + .collect(Collectors.toMap(MapAuthenticatedClientSessionEntity::getClientId, this::clientSessionEntityToModel)); } private AuthenticatedClientSessionModel clientSessionEntityToModel(MapAuthenticatedClientSessionEntity clientSessionEntity) { @@ -176,7 +179,9 @@ public class MapUserSessionAdapter extends AbstractUserSessionModel { Boolean isClientSessionOffline = clientSession.isOffline(); // If client session doesn't have offline flag default to false - if (isClientSessionOffline == null) return !isOffline(); + if (isClientSessionOffline == null) { + return !isOffline(); + } return isOffline() == isClientSessionOffline; } @@ -190,6 +195,7 @@ public class MapUserSessionAdapter extends AbstractUserSessionModel { .map(this::clientSessionEntityToModel) .orElse(null); } + @Override public void removeAuthenticatedClientSessions(Collection removedClientUKS) { removedClientUKS.forEach(entity::removeAuthenticatedClientSession); @@ -254,8 +260,9 @@ public class MapUserSessionAdapter extends AbstractUserSessionModel { String correspondingSessionId = entity.getNote(CORRESPONDING_SESSION_ID); entity.setNotes(new ConcurrentHashMap<>()); - if (correspondingSessionId != null) + if (correspondingSessionId != null) { entity.setNote(CORRESPONDING_SESSION_ID, correspondingSessionId); + } entity.clearAuthenticatedClientSessions(); } @@ -267,8 +274,12 @@ public class MapUserSessionAdapter extends AbstractUserSessionModel { @Override public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof UserSessionModel)) return false; + if (this == o) { + return true; + } + if (!(o instanceof UserSessionModel)) { + return false; + } UserSessionModel that = (UserSessionModel) o; return Objects.equals(that.getId(), getId()); diff --git a/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java b/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java index 99bac4edb0..5fcb63035c 100644 --- a/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java +++ b/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java @@ -88,7 +88,11 @@ public class MapUserSessionProvider implements UserSessionProvider { } return null; } else { - return new MapUserSessionAdapter(session, realm, origEntity); + UserModel userModel = session.users().getUserById(realm, origEntity.getUserId()); + if (userModel != null) { + return new MapUserSessionAdapter(session, realm, userModel, origEntity); + } + return null; } }; } diff --git a/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java b/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java index 2138d5c258..ea8be79120 100755 --- a/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java +++ b/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java @@ -97,7 +97,7 @@ public interface UserSessionProvider extends Provider { * Obtains the online user sessions associated with the specified client, starting from the {@code firstResult} and containing * at most {@code maxResults}. * - * @param realm a reference tot he realm. + * @param realm a reference to the realm. * @param client the client whose user sessions are being searched. * @param firstResult first result to return. Ignored if negative or {@code null}. * @param maxResults maximum number of results to return. Ignored if negative or {@code null}. @@ -117,8 +117,8 @@ public interface UserSessionProvider extends Provider { UserSessionModel getUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId); /** - * Return userSession of specified ID as long as the predicate passes. Otherwise returns {@code null}. - * If predicate doesn't pass, implementation can do some best-effort actions to try have predicate passing (eg. download userSession from other DC) + * Return userSession of specified ID as long as the predicate passes. Otherwise, returns {@code null}. + * If predicate doesn't pass, implementation can do some best-effort actions to try to have predicate passing (e.g. download userSession from other DC) */ UserSessionModel getUserSessionWithPredicate(RealmModel realm, String id, boolean offline, Predicate predicate); @@ -192,7 +192,7 @@ public interface UserSessionProvider extends Provider { * Obtains the offline user sessions associated with the specified client, starting from the {@code firstResult} and * containing at most {@code maxResults}. * - * @param realm a reference tot he realm. + * @param realm a reference to the realm. * @param client the client whose user sessions are being searched. * @param firstResult first result to return. Ignored if negative or {@code null}. * @param maxResults maximum number of results to return. Ignored if negative or {@code 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 798d707156..ccfd4ec379 100755 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java @@ -281,13 +281,16 @@ public class AuthenticationManager { backchannelLogoutResponse.setLocalLogoutSucceeded(true); return backchannelLogoutResponse; } - UserModel user = userSession.getUser(); if (userSession.getState() != UserSessionModel.State.LOGGING_OUT) { userSession.setState(UserSessionModel.State.LOGGING_OUT); } - logger.debugv("Logging out: {0} ({1}) offline: {2}", user.getUsername(), userSession.getId(), - userSession.isOffline()); + if (logger.isDebugEnabled()) { + UserModel user = userSession.getUser(); + logger.debugv("Logging out: {0} ({1}) offline: {2}", user.getUsername(), userSession.getId(), + userSession.isOffline()); + } + boolean expireUserSessionCookieSucceeded = expireUserSessionCookie(session, userSession, realm, uriInfo, headers, connection);