KEYCLOAK-2508 Possible NullPointerException during bigger load when removing UserSession
This commit is contained in:
parent
d5a57a2bbd
commit
a441be57ed
6 changed files with 56 additions and 16 deletions
|
@ -269,7 +269,8 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
|||
|
||||
@Override
|
||||
public void removeUserSession(RealmModel realm, UserSessionModel session) {
|
||||
removeUserSession(realm, session.getId(), false);
|
||||
UserSessionEntity entity = getUserSessionEntity(session, false);
|
||||
removeUserSession(realm, entity, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -280,9 +281,10 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
|||
protected void removeUserSessions(RealmModel realm, UserModel user, boolean offline) {
|
||||
Cache<String, SessionEntity> cache = getCache(offline);
|
||||
|
||||
Iterator<String> itr = cache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId()).user(user.getId())).map(Mappers.sessionId()).iterator();
|
||||
Iterator<SessionEntity> itr = cache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId()).user(user.getId())).map(Mappers.sessionEntity()).iterator();
|
||||
while (itr.hasNext()) {
|
||||
removeUserSession(realm, itr.next(), offline);
|
||||
UserSessionEntity userSessionEntity = (UserSessionEntity) itr.next();
|
||||
removeUserSession(realm, userSessionEntity, offline);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -486,12 +488,11 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
|||
}
|
||||
}
|
||||
|
||||
protected void removeUserSession(RealmModel realm, String userSessionId, boolean offline) {
|
||||
protected void removeUserSession(RealmModel realm, UserSessionEntity sessionEntity, boolean offline) {
|
||||
Cache<String, SessionEntity> cache = getCache(offline);
|
||||
|
||||
tx.remove(cache, userSessionId);
|
||||
tx.remove(cache, sessionEntity.getId());
|
||||
|
||||
UserSessionEntity sessionEntity = (UserSessionEntity) cache.get(userSessionId);
|
||||
if (sessionEntity.getClientSessions() != null) {
|
||||
for (String clientSessionId : sessionEntity.getClientSessions()) {
|
||||
tx.remove(cache, clientSessionId);
|
||||
|
@ -547,6 +548,15 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
|||
return models;
|
||||
}
|
||||
|
||||
UserSessionEntity getUserSessionEntity(UserSessionModel userSession, boolean offline) {
|
||||
if (userSession instanceof UserSessionAdapter) {
|
||||
return ((UserSessionAdapter) userSession).getEntity();
|
||||
} else {
|
||||
Cache<String, SessionEntity> cache = getCache(offline);
|
||||
return (UserSessionEntity) cache.get(userSession.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UserSessionModel createOfflineUserSession(UserSessionModel userSession) {
|
||||
|
@ -566,8 +576,9 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void removeOfflineUserSession(RealmModel realm, String userSessionId) {
|
||||
removeUserSession(realm, userSessionId, true);
|
||||
public void removeOfflineUserSession(RealmModel realm, UserSessionModel userSession) {
|
||||
UserSessionEntity userSessionEntity = getUserSessionEntity(userSession, true);
|
||||
removeUserSession(realm, userSessionEntity, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -45,6 +45,10 @@ public class Mappers {
|
|||
return new SessionIdMapper();
|
||||
}
|
||||
|
||||
public static Function<Map.Entry<String, SessionEntity>, SessionEntity> sessionEntity() {
|
||||
return new SessionEntityMapper();
|
||||
}
|
||||
|
||||
public static Function<Map.Entry<LoginFailureKey, LoginFailureEntity>, LoginFailureKey> loginFailureId() {
|
||||
return new LoginFailureIdMapper();
|
||||
}
|
||||
|
@ -76,6 +80,13 @@ public class Mappers {
|
|||
}
|
||||
}
|
||||
|
||||
private static class SessionEntityMapper implements Function<Map.Entry<String, SessionEntity>, SessionEntity>, Serializable {
|
||||
@Override
|
||||
public SessionEntity apply(Map.Entry<String, SessionEntity> entry) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
private static class LoginFailureIdMapper implements Function<Map.Entry<LoginFailureKey, LoginFailureEntity>, LoginFailureKey>, Serializable {
|
||||
@Override
|
||||
public LoginFailureKey apply(Map.Entry<LoginFailureKey, LoginFailureEntity> entry) {
|
||||
|
|
|
@ -61,7 +61,7 @@ public interface UserSessionProvider extends Provider {
|
|||
UserSessionModel getOfflineUserSession(RealmModel realm, String userSessionId);
|
||||
|
||||
// Removes the attached clientSessions as well
|
||||
void removeOfflineUserSession(RealmModel realm, String userSessionId);
|
||||
void removeOfflineUserSession(RealmModel realm, UserSessionModel userSession);
|
||||
|
||||
ClientSessionModel createOfflineClientSession(ClientSessionModel clientSession);
|
||||
ClientSessionModel getOfflineClientSession(RealmModel realm, String clientSessionId);
|
||||
|
|
|
@ -181,9 +181,7 @@ public class AuthenticationManager {
|
|||
String authMethod = clientSession.getAuthMethod();
|
||||
if (authMethod == null) continue; // must be a keycloak service like account
|
||||
redirectClients.add(clientSession);
|
||||
continue;
|
||||
}
|
||||
if (client instanceof ClientModel && !client.isFrontchannelLogout()) {
|
||||
} else {
|
||||
String authMethod = clientSession.getAuthMethod();
|
||||
if (authMethod == null) continue; // must be a keycloak service like account
|
||||
LoginProtocol protocol = session.getProvider(LoginProtocol.class, authMethod);
|
||||
|
|
|
@ -117,7 +117,7 @@ public class UserSessionManager {
|
|||
|
||||
kcSession.sessions().removeOfflineClientSession(realm, clientSession.getId());
|
||||
persister.removeClientSession(clientSession.getId(), true);
|
||||
checkOfflineUserSessionHasClientSessions(realm, user, clientSession.getUserSession().getId(), clientSessions);
|
||||
checkOfflineUserSessionHasClientSessions(realm, user, clientSession.getUserSession(), clientSessions);
|
||||
anyRemoved = true;
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ public class UserSessionManager {
|
|||
if (logger.isTraceEnabled()) {
|
||||
logger.tracef("Removing offline user session '%s' for user '%s' ", userSession.getId(), userSession.getLoginUsername());
|
||||
}
|
||||
kcSession.sessions().removeOfflineUserSession(userSession.getRealm(), userSession.getId());
|
||||
kcSession.sessions().removeOfflineUserSession(userSession.getRealm(), userSession);
|
||||
persister.removeUserSession(userSession.getId(), true);
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,8 @@ public class UserSessionManager {
|
|||
}
|
||||
|
||||
// Check if userSession has any offline clientSessions attached to it. Remove userSession if not
|
||||
private void checkOfflineUserSessionHasClientSessions(RealmModel realm, UserModel user, String userSessionId, List<ClientSessionModel> clientSessions) {
|
||||
private void checkOfflineUserSessionHasClientSessions(RealmModel realm, UserModel user, UserSessionModel userSession, List<ClientSessionModel> clientSessions) {
|
||||
String userSessionId = userSession.getId();
|
||||
for (ClientSessionModel clientSession : clientSessions) {
|
||||
if (clientSession.getUserSession().getId().equals(userSessionId)) {
|
||||
return;
|
||||
|
@ -175,7 +176,7 @@ public class UserSessionManager {
|
|||
if (logger.isTraceEnabled()) {
|
||||
logger.tracef("Removing offline userSession for user %s as it doesn't have any client sessions attached. UserSessionID: %s", user.getUsername(), userSessionId);
|
||||
}
|
||||
kcSession.sessions().removeOfflineUserSession(realm, userSessionId);
|
||||
kcSession.sessions().removeOfflineUserSession(realm, userSession);
|
||||
persister.removeUserSession(userSessionId, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -380,6 +380,25 @@ public class UserSessionProviderTest {
|
|||
}
|
||||
}
|
||||
|
||||
// KEYCLOAK-2508
|
||||
@Test
|
||||
public void testRemovingExpiredSession() {
|
||||
UserSessionModel[] sessions = createSessions();
|
||||
try {
|
||||
Time.setOffset(3600000);
|
||||
UserSessionModel userSession = sessions[0];
|
||||
RealmModel realm = userSession.getRealm();
|
||||
session.sessions().removeExpired(realm);
|
||||
|
||||
resetSession();
|
||||
|
||||
// Assert no exception is thrown here
|
||||
session.sessions().removeUserSession(realm, userSession);
|
||||
} finally {
|
||||
Time.setOffset(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByClient() {
|
||||
UserSessionModel[] sessions = createSessions();
|
||||
|
|
Loading…
Reference in a new issue