Search in sources :

Example 1 with SessionEntityWrapper

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);
    }
}
Also used : SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper) UserSessionEntity(org.keycloak.models.sessions.infinispan.entities.UserSessionEntity)

Example 2 with SessionEntityWrapper

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);
}
Also used : UserSessionProvider(org.keycloak.models.UserSessionProvider) RemoveUserSessionsEvent(org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent) BiFunction(java.util.function.BiFunction) Cache(org.infinispan.Cache) RemoteCache(org.infinispan.client.hotrod.RemoteCache) FuturesHelper(org.keycloak.models.sessions.infinispan.util.FuturesHelper) ClusterProvider(org.keycloak.cluster.ClusterProvider) PersisterLastSessionRefreshStore(org.keycloak.models.sessions.infinispan.changes.sessions.PersisterLastSessionRefreshStore) Future(java.util.concurrent.Future) RealmRemovedSessionEvent(org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) Map(java.util.Map) SessionEntity(org.keycloak.models.sessions.infinispan.entities.SessionEntity) Time(org.keycloak.common.util.Time) InfinispanUtil(org.keycloak.connections.infinispan.InfinispanUtil) OfflineUserSessionModel(org.keycloak.models.OfflineUserSessionModel) RealmModel(org.keycloak.models.RealmModel) UserSessionPersisterProvider(org.keycloak.models.session.UserSessionPersisterProvider) CrossDCLastSessionRefreshStore(org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshStore) SessionPredicate(org.keycloak.models.sessions.infinispan.stream.SessionPredicate) Predicate(java.util.function.Predicate) Collection(java.util.Collection) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Set(java.util.Set) UUID(java.util.UUID) Collectors(java.util.stream.Collectors) Serializable(java.io.Serializable) Objects(java.util.Objects) UserProvider(org.keycloak.models.UserProvider) InfinispanChangelogBasedTransaction(org.keycloak.models.sessions.infinispan.changes.InfinispanChangelogBasedTransaction) Stream(java.util.stream.Stream) Flag(org.infinispan.context.Flag) AuthenticatedClientSessionEntity(org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity) DeviceActivityManager(org.keycloak.device.DeviceActivityManager) ClientModel(org.keycloak.models.ClientModel) Mappers(org.keycloak.models.sessions.infinispan.stream.Mappers) InfinispanKeyGenerator(org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator) Logger(org.jboss.logging.Logger) UserSessionSpi(org.keycloak.models.UserSessionSpi) HashMap(java.util.HashMap) Function(java.util.function.Function) HotRodClientException(org.infinispan.client.hotrod.exceptions.HotRodClientException) UserModel(org.keycloak.models.UserModel) AuthenticatedClientSessionStore(org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionStore) SessionTimeouts(org.keycloak.models.sessions.infinispan.util.SessionTimeouts) BasicCache(org.infinispan.commons.api.BasicCache) UserSessionPredicate(org.keycloak.models.sessions.infinispan.stream.UserSessionPredicate) StreamSupport(java.util.stream.StreamSupport) Retry(org.keycloak.common.util.Retry) UserSessionEntity(org.keycloak.models.sessions.infinispan.entities.UserSessionEntity) RemoteCacheInvoker(org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker) Iterator(java.util.Iterator) SessionUpdateTask(org.keycloak.models.sessions.infinispan.changes.SessionUpdateTask) KeycloakSession(org.keycloak.models.KeycloakSession) UserSessionModel(org.keycloak.models.UserSessionModel) CacheCollectors(org.infinispan.stream.CacheCollectors) Comparators(org.keycloak.models.sessions.infinispan.stream.Comparators) Tasks(org.keycloak.models.sessions.infinispan.changes.Tasks) SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) ModelException(org.keycloak.models.ModelException) StreamsUtil.paginatedStream(org.keycloak.utils.StreamsUtil.paginatedStream) SessionEventsSenderTransaction(org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction) Collections(java.util.Collections) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Future(java.util.concurrent.Future) UUID(java.util.UUID) SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper) FuturesHelper(org.keycloak.models.sessions.infinispan.util.FuturesHelper) UserSessionEntity(org.keycloak.models.sessions.infinispan.entities.UserSessionEntity)

Example 3 with SessionEntityWrapper

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));
}
Also used : UserModel(org.keycloak.models.UserModel) UserSessionPersisterProvider(org.keycloak.models.session.UserSessionPersisterProvider) ModelException(org.keycloak.models.ModelException) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) UserProvider(org.keycloak.models.UserProvider) SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper)

Example 4 with SessionEntityWrapper

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())));
}
Also used : UserSessionPersisterProvider(org.keycloak.models.session.UserSessionPersisterProvider) Set(java.util.Set) Mappers(org.keycloak.models.sessions.infinispan.stream.Mappers) Stream(java.util.stream.Stream) StreamsUtil.paginatedStream(org.keycloak.utils.StreamsUtil.paginatedStream) SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper)

Example 5 with SessionEntityWrapper

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;
    }
}
Also used : OfflineUserSessionModel(org.keycloak.models.OfflineUserSessionModel) UserSessionModel(org.keycloak.models.UserSessionModel) RemoteCache(org.infinispan.client.hotrod.RemoteCache) SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper) UserSessionEntity(org.keycloak.models.sessions.infinispan.entities.UserSessionEntity)

Aggregations

SessionEntityWrapper (org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper)30 UserSessionEntity (org.keycloak.models.sessions.infinispan.entities.UserSessionEntity)13 RemoteCache (org.infinispan.client.hotrod.RemoteCache)9 AuthenticatedClientSessionEntity (org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity)8 HashMap (java.util.HashMap)5 UUID (java.util.UUID)5 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)5 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)5 InfinispanConnectionProvider (org.keycloak.connections.infinispan.InfinispanConnectionProvider)5 UserSessionPersisterProvider (org.keycloak.models.session.UserSessionPersisterProvider)5 Map (java.util.Map)4 Cache (org.infinispan.Cache)4 RealmModel (org.keycloak.models.RealmModel)4 Set (java.util.Set)3 Future (java.util.concurrent.Future)3 TimeUnit (java.util.concurrent.TimeUnit)3 BiFunction (java.util.function.BiFunction)3 Stream (java.util.stream.Stream)3 HotRodClientException (org.infinispan.client.hotrod.exceptions.HotRodClientException)3 Flag (org.infinispan.context.Flag)3