Reuse already fixed code to fetch offline user (#22429)

The problem is again the wrap(...) function.
In case the user is not found, then null is
returned. This can happen when a federated user
is deleted on the federation side but Keycloak
is not informed about it. In that case, the
session is still present but no UserModel can
be created.

Without this patch the stream contains null
values. Some downstream users can not cope well
with that.

The adjustment of the function getUserSessionsCount(...)
is slightly more expensive in execution, but
returns the correct number.

Closes #22428

Co-authored-by: Martin Krüger <mkrueger@mkru.de>
This commit is contained in:
mkrueger92 2023-09-21 22:19:09 +02:00 committed by GitHub
parent 47d9ae71c4
commit 498be3d928
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -65,6 +65,7 @@ import org.keycloak.models.sessions.infinispan.util.SessionTimeouts;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@ -331,9 +332,13 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
private UserSessionEntity getUserSessionEntity(RealmModel realm, String id, boolean offline) {
InfinispanChangelogBasedTransaction<String, UserSessionEntity> tx = getTransaction(offline);
SessionEntityWrapper<UserSessionEntity> entityWrapper = tx.get(id);
if (entityWrapper==null) return null;
if (entityWrapper == null) {
return null;
}
UserSessionEntity entity = entityWrapper.getEntity();
if (!entity.getRealmId().equals(realm.getId())) return null;
if (!entity.getRealmId().equals(realm.getId())) {
return null;
}
return entity;
}
@ -472,23 +477,10 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
return persister.loadUserSessionsStream(realm, client, true, firstResult, maxResults);
}
final String clientUuid = client.getId();
UserSessionPredicate predicate = UserSessionPredicate.create(realm.getId()).client(clientUuid);
UserSessionPredicate predicate = UserSessionPredicate.create(realm.getId()).client(client.getId());
return getUserSessionModels(realm, firstResult, maxResults, offline, predicate);
}
protected Stream<UserSessionModel> getUserSessionModels(RealmModel realm, Integer firstResult, Integer maxResults, boolean offline, UserSessionPredicate predicate) {
Cache<String, SessionEntityWrapper<UserSessionEntity>> cache = getCache(offline);
cache = CacheDecorators.skipCacheLoaders(cache);
// return a stream that 'wraps' the infinispan cache stream so that the cache stream's elements are read one by one
// and then filtered/mapped locally to avoid serialization issues when trying to manipulate the cache stream directly.
Stream<UserSessionEntity> stream = StreamSupport.stream(cache.entrySet().stream().filter(predicate).spliterator(), false)
.map(Mappers.userSessionEntity())
.sorted(Comparators.userSessionLastSessionRefresh());
return paginatedStream(stream, firstResult, maxResults).map(entity -> this.wrap(realm, entity, offline));
return paginatedStream(getUserSessionsStream(realm, predicate, offline)
.sorted(Comparator.comparing(UserSessionModel::getLastSessionRefresh)), firstResult, maxResults);
}
@Override
@ -587,14 +579,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
return persister.getUserSessionsCount(realm, client, true);
}
Cache<String, SessionEntityWrapper<UserSessionEntity>> cache = getCache(offline);
cache = CacheDecorators.skipCacheLoaders(cache);
final String clientUuid = client.getId();
return cache.entrySet().stream()
.filter(UserSessionPredicate.create(realm.getId()).client(clientUuid))
.count();
return getUserSessionsStream(realm, UserSessionPredicate.create(realm.getId()).client(client.getId()), offline).count();
}
@Override
@ -775,7 +760,9 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
UserSessionEntity getUserSessionEntity(RealmModel realm, UserSessionModel userSession, boolean offline) {
if (userSession instanceof UserSessionAdapter) {
if (!userSession.getRealm().equals(realm)) return null;
if (!userSession.getRealm().equals(realm)) {
return null;
}
return ((UserSessionAdapter) userSession).getEntity();
} else {
return getUserSessionEntity(realm, userSession.getId(), offline);