use of org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper in project keycloak by keycloak.
the class InfinispanUserSessionProvider method removeUserSessions.
protected void removeUserSessions(RealmModel realm, UserModel user, boolean offline) {
Cache<String, SessionEntityWrapper<UserSessionEntity>> cache = getCache(offline);
cache = CacheDecorators.skipCacheLoaders(cache);
Iterator<UserSessionEntity> itr = cache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId()).user(user.getId())).map(Mappers.userSessionEntity()).iterator();
while (itr.hasNext()) {
UserSessionEntity userSessionEntity = itr.next();
removeUserSession(userSessionEntity, offline);
}
}
use of org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper in project keycloak by keycloak.
the class InfinispanUserSessionProvider method removeLocalUserSessions.
// public for usage in the testsuite
public void removeLocalUserSessions(String realmId, boolean offline) {
FuturesHelper futures = new FuturesHelper();
Cache<String, SessionEntityWrapper<UserSessionEntity>> cache = getCache(offline);
Cache<String, SessionEntityWrapper<UserSessionEntity>> localCache = CacheDecorators.localCache(cache);
Cache<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> clientSessionCache = getClientSessionCache(offline);
Cache<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> localClientSessionCache = CacheDecorators.localCache(clientSessionCache);
Cache<String, SessionEntityWrapper<UserSessionEntity>> localCacheStoreIgnore = CacheDecorators.skipCacheLoaders(localCache);
final AtomicInteger userSessionsSize = new AtomicInteger();
localCacheStoreIgnore.entrySet().stream().filter(SessionPredicate.create(realmId)).map(Mappers.userSessionEntity()).forEach(new Consumer<UserSessionEntity>() {
@Override
public void accept(UserSessionEntity userSessionEntity) {
userSessionsSize.incrementAndGet();
// Remove session from remoteCache too. Use removeAsync for better perf
Future future = localCache.removeAsync(userSessionEntity.getId());
futures.addTask(future);
userSessionEntity.getAuthenticatedClientSessions().forEach((clientUUID, clientSessionId) -> {
Future f = localClientSessionCache.removeAsync(clientSessionId);
futures.addTask(f);
});
}
});
futures.waitForAllToFinish();
log.debugf("Removed %d sessions in realm %s. Offline: %b", (Object) userSessionsSize.get(), realmId, offline);
}
use of org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper in project keycloak by keycloak.
the class InfinispanUserSessionProvider method getUserSessionsStream.
protected Stream<UserSessionModel> getUserSessionsStream(RealmModel realm, UserSessionPredicate predicate, boolean offline) {
if (offline && loadOfflineSessionsFromDatabase) {
// fetch the offline user-sessions from the persistence provider
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
if (predicate.getUserId() != null) {
UserModel user = session.users().getUserById(realm, predicate.getUserId());
if (user != null) {
return persister.loadUserSessionsStream(realm, user, true, 0, null);
}
}
if (predicate.getBrokerUserId() != null) {
String[] idpAliasSessionId = predicate.getBrokerUserId().split("\\.");
Map<String, String> attributes = new HashMap<>();
attributes.put(UserModel.IDP_ALIAS, idpAliasSessionId[0]);
attributes.put(UserModel.IDP_USER_ID, idpAliasSessionId[1]);
UserProvider userProvider = session.getProvider(UserProvider.class);
UserModel userModel = userProvider.searchForUserStream(realm, attributes, 0, null).findFirst().orElse(null);
return userModel != null ? persister.loadUserSessionsStream(realm, userModel, true, 0, null) : Stream.empty();
}
if (predicate.getBrokerSessionId() != null) {
// currently it is not possible to access the brokerSessionId in offline user-session in a database agnostic way
throw new ModelException("Dynamic database lookup for offline user-sessions by broker session ID is currently only supported for preloaded sessions. " + "Set preloadOfflineSessionsFromDatabase option to \"true\" in " + UserSessionSpi.NAME + " SPI in " + InfinispanUserSessionProviderFactory.PROVIDER_ID + " provider to enable the lookup.");
}
}
Cache<String, SessionEntityWrapper<UserSessionEntity>> cache = getCache(offline);
cache = CacheDecorators.skipCacheLoaders(cache);
// 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));
}
use of org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper in project keycloak by keycloak.
the class InfinispanUserSessionProvider method getActiveClientSessionStats.
@Override
public Map<String, Long> getActiveClientSessionStats(RealmModel realm, boolean offline) {
if (offline && loadOfflineSessionsFromDatabase) {
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
return persister.getUserSessionsCountsByClients(realm, true);
}
Cache<String, SessionEntityWrapper<UserSessionEntity>> cache = getCache(offline);
cache = CacheDecorators.skipCacheLoaders(cache);
return cache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId())).map(Mappers.authClientSessionSetMapper()).flatMap((Serializable & Function<Set<String>, Stream<? extends String>>) Mappers::toStream).collect(CacheCollectors.serializableCollector(() -> Collectors.groupingBy(Function.identity(), Collectors.counting())));
}
use of org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper in project keycloak by keycloak.
the class InfinispanUserSessionProvider method getUserSessionWithPredicate.
@Override
public UserSessionModel getUserSessionWithPredicate(RealmModel realm, String id, boolean offline, Predicate<UserSessionModel> predicate) {
UserSessionModel userSession = getUserSession(realm, id, offline);
if (userSession == null) {
return null;
}
// We have userSession, which passes predicate. No need for remote lookup.
if (predicate.test(userSession)) {
log.debugf("getUserSessionWithPredicate(%s): found in local cache", id);
return userSession;
}
// Try lookup userSession from remoteCache
Cache<String, SessionEntityWrapper<UserSessionEntity>> cache = getCache(offline);
RemoteCache remoteCache = InfinispanUtil.getRemoteCache(cache);
if (remoteCache != null) {
SessionEntityWrapper<UserSessionEntity> remoteSessionEntityWrapper = (SessionEntityWrapper<UserSessionEntity>) remoteCache.get(id);
if (remoteSessionEntityWrapper != null) {
UserSessionEntity remoteSessionEntity = remoteSessionEntityWrapper.getEntity();
log.debugf("getUserSessionWithPredicate(%s): remote cache contains session entity %s", id, remoteSessionEntity);
UserSessionModel remoteSessionAdapter = wrap(realm, remoteSessionEntity, offline);
if (predicate.test(remoteSessionAdapter)) {
InfinispanChangelogBasedTransaction<String, UserSessionEntity> tx = getTransaction(offline);
// Remote entity contains our predicate. Update local cache with the remote entity
SessionEntityWrapper<UserSessionEntity> sessionWrapper = remoteSessionEntity.mergeRemoteEntityWithLocalEntity(tx.get(id));
// Replace entity just in ispn cache. Skip remoteStore
cache.getAdvancedCache().withFlags(Flag.SKIP_CACHE_STORE, Flag.SKIP_CACHE_LOAD, Flag.IGNORE_RETURN_VALUES).replace(id, sessionWrapper);
tx.reloadEntityInCurrentTransaction(realm, id, sessionWrapper);
// Recursion. We should have it locally now
return getUserSessionWithPredicate(realm, id, offline, predicate);
} else {
log.debugf("getUserSessionWithPredicate(%s): found, but predicate doesn't pass", id);
return null;
}
} else {
log.debugf("getUserSessionWithPredicate(%s): not found", id);
// Session not available on remoteCache. Was already removed there. So removing locally too.
// TODO: Can be optimized to skip calling remoteCache.remove
removeUserSession(realm, userSession);
return null;
}
} else {
log.debugf("getUserSessionWithPredicate(%s): remote cache not available", id);
return null;
}
}
Aggregations