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);
}
}
});
}
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);
}
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;
}
}
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;
}
}
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);
}
Aggregations