use of org.keycloak.models.utils.ResetTimeOffsetEvent in project keycloak by keycloak.
the class InfinispanUserSessionProviderFactory method postInit.
@Override
public void postInit(final KeycloakSessionFactory factory) {
factory.register(new ProviderEventListener() {
@Override
public void onEvent(ProviderEvent event) {
if (event instanceof PostMigrationEvent) {
int preloadTransactionTimeout = getTimeoutForPreloadingSessionsSeconds();
log.debugf("Will preload sessions with transaction timeout %d seconds", preloadTransactionTimeout);
KeycloakModelUtils.runJobInTransactionWithTimeout(factory, (KeycloakSession session) -> {
keyGenerator = new InfinispanKeyGenerator();
checkRemoteCaches(session);
loadPersistentSessions(factory, getMaxErrors(), getSessionsPerSegment());
registerClusterListeners(session);
loadSessionsFromRemoteCaches(session);
}, preloadTransactionTimeout);
} else if (event instanceof UserModel.UserRemovedEvent) {
UserModel.UserRemovedEvent userRemovedEvent = (UserModel.UserRemovedEvent) event;
InfinispanUserSessionProvider provider = (InfinispanUserSessionProvider) userRemovedEvent.getKeycloakSession().getProvider(UserSessionProvider.class, getId());
provider.onUserRemoved(userRemovedEvent.getRealm(), userRemovedEvent.getUser());
} else if (event instanceof ResetTimeOffsetEvent) {
if (persisterLastSessionRefreshStore != null) {
persisterLastSessionRefreshStore.reset();
}
if (lastSessionRefreshStore != null) {
lastSessionRefreshStore.reset();
}
if (offlineLastSessionRefreshStore != null) {
offlineLastSessionRefreshStore.reset();
}
}
}
});
}
use of org.keycloak.models.utils.ResetTimeOffsetEvent in project keycloak by keycloak.
the class AuthenticationSessionProviderTest method testExpiredAuthSessions.
@Test
@ModelTest
public void testExpiredAuthSessions(KeycloakSession session) {
AtomicReference<String> authSessionID = new AtomicReference<>();
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession sessionExpired) -> {
KeycloakSession mainSession = sessionExpired;
try {
// AccessCodeLifespan = 10 ; AccessCodeLifespanUserAction = 10 ; AccessCodeLifespanLogin = 30
setAccessCodeLifespan(mainSession, 10, 10, 30);
createAuthSession(mainSession, authSessionID);
testExpiredOffset(mainSession, 25, false, authSessionID.get());
testExpiredOffset(mainSession, 35, true, authSessionID.get());
// AccessCodeLifespan = Not set ; AccessCodeLifespanUserAction = 10 ; AccessCodeLifespanLogin = Not set
setAccessCodeLifespan(mainSession, -1, 40, -1);
createAuthSession(mainSession, authSessionID);
testExpiredOffset(mainSession, 35, false, authSessionID.get());
testExpiredOffset(mainSession, 45, true, authSessionID.get());
// AccessCodeLifespan = 50 ; AccessCodeLifespanUserAction = Not set ; AccessCodeLifespanLogin = Not set
setAccessCodeLifespan(mainSession, 50, -1, -1);
createAuthSession(mainSession, authSessionID);
testExpiredOffset(mainSession, 45, false, authSessionID.get());
testExpiredOffset(mainSession, 55, true, authSessionID.get());
} finally {
Time.setOffset(0);
session.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent());
setAccessCodeLifespan(mainSession, 60, 300, 1800);
}
});
}
use of org.keycloak.models.utils.ResetTimeOffsetEvent in project keycloak by keycloak.
the class UserSessionProviderTest method testRemoveUserSessionsByExpiredRememberMe.
/**
* Tests the removal of expired sessions with remember-me enabled. It differs from the non remember me scenario by
* taking into consideration the specific remember-me timeout values.
*
* @param session the {@code KeycloakSession}
*/
@Test
@ModelTest
public void testRemoveUserSessionsByExpiredRememberMe(KeycloakSession session) {
RealmModel testRealm = session.realms().getRealmByName("test");
int previousMaxLifespan = testRealm.getSsoSessionMaxLifespanRememberMe();
int previousMaxIdle = testRealm.getSsoSessionIdleTimeoutRememberMe();
try {
ClientModel client = testRealm.getClientByClientId("test-app");
Set<String> validUserSessions = new HashSet<>();
Set<String> validClientSessions = new HashSet<>();
Set<String> expiredUserSessions = new HashSet<>();
// first lets update the realm by setting remember-me timeout values, which will be 4 times higher than the default timeout values.
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession kcSession) -> {
RealmModel r = kcSession.realms().getRealmByName("test");
r.setSsoSessionMaxLifespanRememberMe(r.getSsoSessionMaxLifespan() * 4);
r.setSsoSessionIdleTimeoutRememberMe(r.getSsoSessionIdleTimeout() * 4);
});
// update the realm reference so that the remember-me timeouts are now visible.
RealmModel realm = session.realms().getRealmByName("test");
// create an user session with remember-me enabled that is older than the default 'max lifespan' timeout but not older than the 'max lifespan remember-me' timeout.
// the session's last refresh also exceeds the default 'session idle' timeout but doesn't exceed the 'session idle remember-me' timeout.
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession kcSession) -> {
Time.setOffset(-(realm.getSsoSessionMaxLifespan() * 2));
UserSessionModel userSession = kcSession.sessions().createUserSession(realm, kcSession.users().getUserByUsername(realm, "user1"), "user1", "127.0.0.1", "form", true, null, null);
AuthenticatedClientSessionModel clientSession = kcSession.sessions().createClientSession(realm, client, userSession);
assertEquals(userSession, clientSession.getUserSession());
Time.setOffset(-(realm.getSsoSessionIdleTimeout() * 2));
userSession.setLastSessionRefresh(Time.currentTime());
clientSession.setTimestamp(Time.currentTime());
validUserSessions.add(userSession.getId());
validClientSessions.add(clientSession.getId());
});
// create an user session with remember-me enabled that is older than the 'max lifespan remember-me' timeout.
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession kcSession) -> {
Time.setOffset(-(realm.getSsoSessionMaxLifespanRememberMe() + 1));
UserSessionModel userSession = kcSession.sessions().createUserSession(realm, kcSession.users().getUserByUsername(realm, "user1"), "user1", "127.0.0.1", "form", true, null, null);
expiredUserSessions.add(userSession.getId());
});
// finally create an user session with remember-me enabled whose last refresh exceeds the 'session idle remember-me' timeout.
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession kcSession) -> {
Time.setOffset(-(realm.getSsoSessionIdleTimeoutRememberMe() + SessionTimeoutHelper.PERIODIC_CLEANER_IDLE_TIMEOUT_WINDOW_SECONDS + 1));
UserSessionModel userSession = kcSession.sessions().createUserSession(realm, kcSession.users().getUserByUsername(realm, "user2"), "user2", "127.0.0.1", "form", true, null, null);
// no need to explicitly set the last refresh time - it is the same as the creation time.
expiredUserSessions.add(userSession.getId());
});
// remove the expired sessions - the first session should not be removed as it doesn't exceed any of the remember-me timeout values.
Time.setOffset(0);
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession kcSession) -> kcSession.sessions().removeExpired(realm));
for (String sessionId : expiredUserSessions) {
assertNull(session.sessions().getUserSession(realm, sessionId));
}
for (String sessionId : validUserSessions) {
UserSessionModel userSessionLoaded = session.sessions().getUserSession(realm, sessionId);
assertNotNull(userSessionLoaded);
// the only valid user session should also have a valid client session that hasn't expired.
AuthenticatedClientSessionModel clientSessionModel = userSessionLoaded.getAuthenticatedClientSessions().get(client.getId());
assertNotNull(clientSessionModel);
assertTrue(validClientSessions.contains(clientSessionModel.getId()));
}
} finally {
Time.setOffset(0);
session.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent());
// restore the original remember-me timeout values in the realm.
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession kcSession) -> {
RealmModel r = kcSession.realms().getRealmByName("test");
r.setSsoSessionMaxLifespanRememberMe(previousMaxLifespan);
r.setSsoSessionIdleTimeoutRememberMe(previousMaxIdle);
});
}
}
use of org.keycloak.models.utils.ResetTimeOffsetEvent in project keycloak by keycloak.
the class UserSessionPersisterProviderTest method testExpiredSessions.
@Test
public void testExpiredSessions() {
int started = Time.currentTime();
final UserSessionModel[] userSession1 = { null };
final UserSessionModel[] userSession2 = { null };
UserSessionModel[] origSessions = inComittedTransaction(session -> {
// Create some sessions in infinispan
return createSessions(session, realmId);
});
inComittedTransaction(session -> {
// Persist 2 offline sessions of 2 users
RealmModel realm = session.realms().getRealm(realmId);
userSession1[0] = session.sessions().getUserSession(realm, origSessions[1].getId());
userSession2[0] = session.sessions().getUserSession(realm, origSessions[2].getId());
persistUserSession(session, userSession1[0], true);
persistUserSession(session, userSession2[0], true);
});
inComittedTransaction(session -> {
// Update one of the sessions with lastSessionRefresh of 20 days ahead
int lastSessionRefresh = Time.currentTime() + 1728000;
RealmModel realm = session.realms().getRealm(realmId);
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
persister.updateLastSessionRefreshes(realm, lastSessionRefresh, Collections.singleton(userSession1[0].getId()), true);
// Increase time offset - 40 days
Time.setOffset(3456000);
try {
// Run expiration thread
persister.removeExpired(realm);
// Test the updated session is still in persister. Not updated session is not there anymore
List<UserSessionModel> loadedSessions = loadPersistedSessionsPaginated(session, true, 10, 1, 1);
UserSessionModel persistedSession = loadedSessions.get(0);
assertSession(persistedSession, session.users().getUserByUsername(realm, "user1"), "127.0.0.2", started, lastSessionRefresh, "test-app");
} finally {
// Cleanup
Time.setOffset(0);
session.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent());
}
});
}
use of org.keycloak.models.utils.ResetTimeOffsetEvent in project keycloak by keycloak.
the class UserSessionProviderOfflineModelTest method testExpired.
@Test
public void testExpired() {
// Suspend periodic tasks to avoid race-conditions, which may cause missing updates of lastSessionRefresh times to UserSessionPersisterProvider
TimerProvider timer = kcSession.getProvider(TimerProvider.class);
TimerProvider.TimerTaskContext timerTaskCtx = null;
if (timer != null) {
timerTaskCtx = timer.cancelTask(PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
log.info("Cancelled periodic task " + PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
}
InfinispanTestUtil.setTestingTimeService(kcSession);
try {
// Key is userSessionId, value is set of client UUIDS
Map<String, Set<String>> offlineSessions = new HashMap<>();
ClientModel[] testApp = new ClientModel[1];
UserSessionModel[] origSessions = inComittedTransaction(session -> {
// Create some online sessions in infinispan
return UserSessionPersisterProviderTest.createSessions(session, realmId);
});
inComittedTransaction(session -> {
RealmModel realm = session.realms().getRealm(realmId);
sessionManager = new UserSessionManager(session);
persister = session.getProvider(UserSessionPersisterProvider.class);
// Persist 3 created userSessions and clientSessions as offline
testApp[0] = realm.getClientByClientId("test-app");
session.sessions().getUserSessionsStream(realm, testApp[0]).collect(Collectors.toList()).forEach(userSession -> offlineSessions.put(userSession.getId(), createOfflineSessionIncludeClientSessions(session, userSession)));
// Assert all previously saved offline sessions found
for (Map.Entry<String, Set<String>> entry : offlineSessions.entrySet()) {
UserSessionModel foundSession = sessionManager.findOfflineUserSession(realm, entry.getKey());
Assert.assertEquals(foundSession.getAuthenticatedClientSessions().keySet(), entry.getValue());
}
});
log.info("Persisted 3 sessions to UserSessionPersisterProvider");
inComittedTransaction(session -> {
RealmModel realm = session.realms().getRealm(realmId);
persister = session.getProvider(UserSessionPersisterProvider.class);
UserSessionModel session0 = session.sessions().getOfflineUserSession(realm, origSessions[0].getId());
Assert.assertNotNull(session0);
// sessions are in persister too
Assert.assertEquals(3, persister.getUserSessionsCount(true));
Time.setOffset(300);
log.infof("Set time offset to 300. Time is: %d", Time.currentTime());
// Set lastSessionRefresh to currentSession[0] to 0
session0.setLastSessionRefresh(Time.currentTime());
});
// Increase timeOffset and update LSR of the session two times - first to 20 days and then to 21 days. At least one of updates
// will propagate to PersisterLastSessionRefreshStore and update DB (Single update is not 100% sure as there is still a
// chance of delayed periodic task to be run in the meantime and causing race-condition, which would mean LSR not updated in the DB)
IntStream.range(0, 2).sequential().forEach(index -> inComittedTransaction(index, (session, i) -> {
int timeOffset = 1728000 + (i * 86400);
RealmModel realm = session.realms().getRealm(realmId);
Time.setOffset(timeOffset);
log.infof("Set time offset to %d. Time is: %d", timeOffset, Time.currentTime());
UserSessionModel session0 = session.sessions().getOfflineUserSession(realm, origSessions[0].getId());
session0.setLastSessionRefresh(Time.currentTime());
return null;
}));
inComittedTransaction(session -> {
RealmModel realm = session.realms().getRealm(realmId);
persister = session.getProvider(UserSessionPersisterProvider.class);
// Increase timeOffset - 40 days
Time.setOffset(3456000);
log.infof("Set time offset to 3456000. Time is: %d", Time.currentTime());
// Expire and ensure that all sessions despite session0 were removed
persister.removeExpired(realm);
});
inComittedTransaction(session -> {
RealmModel realm = session.realms().getRealm(realmId);
persister = session.getProvider(UserSessionPersisterProvider.class);
// assert session0 is the only session found
Assert.assertNotNull(session.sessions().getOfflineUserSession(realm, origSessions[0].getId()));
Assert.assertNull(session.sessions().getOfflineUserSession(realm, origSessions[1].getId()));
Assert.assertNull(session.sessions().getOfflineUserSession(realm, origSessions[2].getId()));
Assert.assertEquals(1, persister.getUserSessionsCount(true));
// Expire everything and assert nothing found
Time.setOffset(7000000);
persister.removeExpired(realm);
});
inComittedTransaction(session -> {
RealmModel realm = session.realms().getRealm(realmId);
sessionManager = new UserSessionManager(session);
persister = session.getProvider(UserSessionPersisterProvider.class);
for (String userSessionId : offlineSessions.keySet()) {
Assert.assertNull(sessionManager.findOfflineUserSession(realm, userSessionId));
}
Assert.assertEquals(0, persister.getUserSessionsCount(true));
});
} finally {
Time.setOffset(0);
kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent());
if (timer != null) {
timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
}
InfinispanTestUtil.revertTimeService();
}
}
Aggregations