Search in sources :

Example 1 with RemoteCache

use of org.infinispan.client.hotrod.RemoteCache in project keycloak by keycloak.

the class InfinispanUserSessionProvider method importSessionsWithExpiration.

private <T extends SessionEntity> void importSessionsWithExpiration(Map<? extends Object, SessionEntityWrapper<T>> sessionsById, BasicCache cache, BiFunction<RealmModel, T, Long> lifespanMsCalculator, BiFunction<RealmModel, T, Long> maxIdleTimeMsCalculator) {
    sessionsById.forEach((id, sessionEntityWrapper) -> {
        T sessionEntity = sessionEntityWrapper.getEntity();
        RealmModel currentRealm = session.realms().getRealm(sessionEntity.getRealmId());
        long lifespan = lifespanMsCalculator.apply(currentRealm, sessionEntity);
        long maxIdle = maxIdleTimeMsCalculator.apply(currentRealm, sessionEntity);
        if (lifespan != SessionTimeouts.ENTRY_EXPIRED_FLAG && maxIdle != SessionTimeouts.ENTRY_EXPIRED_FLAG) {
            if (cache instanceof RemoteCache) {
                Retry.executeWithBackoff((int iteration) -> {
                    try {
                        cache.put(id, sessionEntityWrapper, lifespan, TimeUnit.MILLISECONDS, maxIdle, TimeUnit.MILLISECONDS);
                    } catch (HotRodClientException re) {
                        if (log.isDebugEnabled()) {
                            log.debugf(re, "Failed to put import %d sessions to remoteCache. Iteration '%s'. Will try to retry the task", sessionsById.size(), iteration);
                        }
                        // Rethrow the exception. Retry will take care of handle the exception and eventually retry the operation.
                        throw re;
                    }
                }, 10, 10);
            } else {
                cache.put(id, sessionEntityWrapper, lifespan, TimeUnit.MILLISECONDS, maxIdle, TimeUnit.MILLISECONDS);
            }
        }
    });
}
Also used : RealmModel(org.keycloak.models.RealmModel) RemoteCache(org.infinispan.client.hotrod.RemoteCache) HotRodClientException(org.infinispan.client.hotrod.exceptions.HotRodClientException)

Example 2 with RemoteCache

use of org.infinispan.client.hotrod.RemoteCache 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 RemoteCache

use of org.infinispan.client.hotrod.RemoteCache 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)

Example 4 with RemoteCache

use of org.infinispan.client.hotrod.RemoteCache in project keycloak by keycloak.

the class InfinispanUserLoginFailureProviderFactory method checkRemoteCache.

private <K, V extends SessionEntity> RemoteCache checkRemoteCache(KeycloakSession session, Cache<K, SessionEntityWrapper<V>> ispnCache, RemoteCacheInvoker.MaxIdleTimeLoader maxIdleLoader, BiFunction<RealmModel, V, Long> lifespanMsLoader, BiFunction<RealmModel, V, Long> maxIdleTimeMsLoader) {
    Set<RemoteStore> remoteStores = InfinispanUtil.getRemoteStores(ispnCache);
    if (remoteStores.isEmpty()) {
        log.debugf("No remote store configured for cache '%s'", ispnCache.getName());
        return null;
    } else {
        log.infof("Remote store configured for cache '%s'", ispnCache.getName());
        RemoteCache<K, SessionEntityWrapper<V>> remoteCache = (RemoteCache) remoteStores.iterator().next().getRemoteCache();
        if (remoteCache == null) {
            throw new IllegalStateException("No remote cache available for the infinispan cache: " + ispnCache.getName());
        }
        remoteCacheInvoker.addRemoteCache(ispnCache.getName(), remoteCache, maxIdleLoader);
        RemoteCacheSessionListener hotrodListener = RemoteCacheSessionListener.createListener(session, ispnCache, remoteCache, lifespanMsLoader, maxIdleTimeMsLoader);
        remoteCache.addClientListener(hotrodListener);
        return remoteCache;
    }
}
Also used : RemoteCacheSessionListener(org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionListener) RemoteCache(org.infinispan.client.hotrod.RemoteCache) SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper) RemoteStore(org.infinispan.persistence.remote.RemoteStore)

Example 5 with RemoteCache

use of org.infinispan.client.hotrod.RemoteCache in project keycloak by keycloak.

the class InfinispanUserSessionProviderFactory method checkRemoteCaches.

protected void checkRemoteCaches(KeycloakSession session) {
    this.remoteCacheInvoker = new RemoteCacheInvoker();
    InfinispanConnectionProvider ispn = session.getProvider(InfinispanConnectionProvider.class);
    Cache<String, SessionEntityWrapper<UserSessionEntity>> sessionsCache = ispn.getCache(InfinispanConnectionProvider.USER_SESSION_CACHE_NAME);
    RemoteCache sessionsRemoteCache = checkRemoteCache(session, sessionsCache, (RealmModel realm) -> {
        // We won't write to the remoteCache during token refresh, so the timeout needs to be longer.
        return Time.toMillis(realm.getSsoSessionMaxLifespan());
    }, SessionTimeouts::getUserSessionLifespanMs, SessionTimeouts::getUserSessionMaxIdleMs);
    if (sessionsRemoteCache != null) {
        lastSessionRefreshStore = new CrossDCLastSessionRefreshStoreFactory().createAndInit(session, sessionsCache, false);
    }
    Cache<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> clientSessionsCache = ispn.getCache(InfinispanConnectionProvider.CLIENT_SESSION_CACHE_NAME);
    checkRemoteCache(session, clientSessionsCache, (RealmModel realm) -> {
        // We won't write to the remoteCache during token refresh, so the timeout needs to be longer.
        return Time.toMillis(realm.getSsoSessionMaxLifespan());
    }, SessionTimeouts::getClientSessionLifespanMs, SessionTimeouts::getClientSessionMaxIdleMs);
    Cache<String, SessionEntityWrapper<UserSessionEntity>> offlineSessionsCache = ispn.getCache(InfinispanConnectionProvider.OFFLINE_USER_SESSION_CACHE_NAME);
    RemoteCache offlineSessionsRemoteCache = checkRemoteCache(session, offlineSessionsCache, (RealmModel realm) -> {
        return Time.toMillis(realm.getOfflineSessionIdleTimeout());
    }, SessionTimeouts::getOfflineSessionLifespanMs, SessionTimeouts::getOfflineSessionMaxIdleMs);
    if (offlineSessionsRemoteCache != null) {
        offlineLastSessionRefreshStore = new CrossDCLastSessionRefreshStoreFactory().createAndInit(session, offlineSessionsCache, true);
    }
    Cache<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> offlineClientSessionsCache = ispn.getCache(InfinispanConnectionProvider.OFFLINE_CLIENT_SESSION_CACHE_NAME);
    checkRemoteCache(session, offlineClientSessionsCache, (RealmModel realm) -> {
        return Time.toMillis(realm.getOfflineSessionIdleTimeout());
    }, SessionTimeouts::getOfflineClientSessionLifespanMs, SessionTimeouts::getOfflineClientSessionMaxIdleMs);
}
Also used : RealmModel(org.keycloak.models.RealmModel) CrossDCLastSessionRefreshStoreFactory(org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshStoreFactory) RemoteCacheInvoker(org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker) RemoteCache(org.infinispan.client.hotrod.RemoteCache) SessionTimeouts(org.keycloak.models.sessions.infinispan.util.SessionTimeouts) UUID(java.util.UUID) InfinispanConnectionProvider(org.keycloak.connections.infinispan.InfinispanConnectionProvider) SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper)

Aggregations

RemoteCache (org.infinispan.client.hotrod.RemoteCache)26 SessionEntityWrapper (org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper)9 Cache (org.infinispan.Cache)8 Map (java.util.Map)5 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)5 HotRodClientException (org.infinispan.client.hotrod.exceptions.HotRodClientException)5 RemoteStore (org.infinispan.persistence.remote.RemoteStore)5 UUID (java.util.UUID)4 BasicCache (org.infinispan.commons.api.BasicCache)4 Logger (org.jboss.logging.Logger)4 KeycloakSession (org.keycloak.models.KeycloakSession)4 RealmModel (org.keycloak.models.RealmModel)4 UserSessionEntity (org.keycloak.models.sessions.infinispan.entities.UserSessionEntity)4 HashMap (java.util.HashMap)3 Objects (java.util.Objects)3 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)3 TimeUnit (java.util.concurrent.TimeUnit)3 BiFunction (java.util.function.BiFunction)3 Function (java.util.function.Function)3 Collectors (java.util.stream.Collectors)3