Search in sources :

Example 1 with ResetTimeOffsetEvent

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();
                }
            }
        }
    });
}
Also used : ProviderEventListener(org.keycloak.provider.ProviderEventListener) ProviderEvent(org.keycloak.provider.ProviderEvent) UserModel(org.keycloak.models.UserModel) UserSessionProvider(org.keycloak.models.UserSessionProvider) ResetTimeOffsetEvent(org.keycloak.models.utils.ResetTimeOffsetEvent) KeycloakSession(org.keycloak.models.KeycloakSession) InfinispanKeyGenerator(org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator) PostMigrationEvent(org.keycloak.models.utils.PostMigrationEvent)

Example 2 with ResetTimeOffsetEvent

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);
        }
    });
}
Also used : ResetTimeOffsetEvent(org.keycloak.models.utils.ResetTimeOffsetEvent) KeycloakSession(org.keycloak.models.KeycloakSession) AtomicReference(java.util.concurrent.atomic.AtomicReference) ModelTest(org.keycloak.testsuite.arquillian.annotation.ModelTest) ModelTest(org.keycloak.testsuite.arquillian.annotation.ModelTest) Test(org.junit.Test) AbstractTestRealmKeycloakTest(org.keycloak.testsuite.AbstractTestRealmKeycloakTest)

Example 3 with ResetTimeOffsetEvent

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);
        });
    }
}
Also used : RealmModel(org.keycloak.models.RealmModel) ClientModel(org.keycloak.models.ClientModel) UserSessionModel(org.keycloak.models.UserSessionModel) ResetTimeOffsetEvent(org.keycloak.models.utils.ResetTimeOffsetEvent) KeycloakSession(org.keycloak.models.KeycloakSession) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) HashSet(java.util.HashSet) ModelTest(org.keycloak.testsuite.arquillian.annotation.ModelTest) ModelTest(org.keycloak.testsuite.arquillian.annotation.ModelTest) Test(org.junit.Test) AbstractTestRealmKeycloakTest(org.keycloak.testsuite.AbstractTestRealmKeycloakTest)

Example 4 with ResetTimeOffsetEvent

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());
        }
    });
}
Also used : RealmModel(org.keycloak.models.RealmModel) UserSessionModel(org.keycloak.models.UserSessionModel) UserSessionPersisterProvider(org.keycloak.models.session.UserSessionPersisterProvider) ResetTimeOffsetEvent(org.keycloak.models.utils.ResetTimeOffsetEvent) Test(org.junit.Test) KeycloakModelTest(org.keycloak.testsuite.model.KeycloakModelTest)

Example 5 with 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();
    }
}
Also used : ClientModel(org.keycloak.models.ClientModel) IntStream(java.util.stream.IntStream) UserSessionProvider(org.keycloak.models.UserSessionProvider) Constants(org.keycloak.models.Constants) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) Cache(org.infinispan.Cache) AtomicReference(java.util.concurrent.atomic.AtomicReference) HashSet(java.util.HashSet) UserModel(org.keycloak.models.UserModel) RealmProvider(org.keycloak.models.RealmProvider) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) Map(java.util.Map) RequireProvider(org.keycloak.testsuite.model.RequireProvider) LinkedList(java.util.LinkedList) TimerProvider(org.keycloak.timer.TimerProvider) Time(org.keycloak.common.util.Time) InfinispanConnectionProvider(org.keycloak.connections.infinispan.InfinispanConnectionProvider) InfinispanTestUtil(org.keycloak.testsuite.model.infinispan.InfinispanTestUtil) UserManager(org.keycloak.models.UserManager) RealmModel(org.keycloak.models.RealmModel) UserSessionPersisterProvider(org.keycloak.models.session.UserSessionPersisterProvider) KeycloakSession(org.keycloak.models.KeycloakSession) Set(java.util.Set) Test(org.junit.Test) PersisterLastSessionRefreshStoreFactory(org.keycloak.models.sessions.infinispan.changes.sessions.PersisterLastSessionRefreshStoreFactory) KeycloakModelTest(org.keycloak.testsuite.model.KeycloakModelTest) UserSessionModel(org.keycloak.models.UserSessionModel) Collectors(java.util.stream.Collectors) UserProvider(org.keycloak.models.UserProvider) CountDownLatch(java.util.concurrent.CountDownLatch) List(java.util.List) UserSessionManager(org.keycloak.services.managers.UserSessionManager) ResetTimeOffsetEvent(org.keycloak.models.utils.ResetTimeOffsetEvent) Assert(org.junit.Assert) UserSessionModel(org.keycloak.models.UserSessionModel) HashSet(java.util.HashSet) Set(java.util.Set) HashMap(java.util.HashMap) RealmModel(org.keycloak.models.RealmModel) UserSessionManager(org.keycloak.services.managers.UserSessionManager) ClientModel(org.keycloak.models.ClientModel) UserSessionPersisterProvider(org.keycloak.models.session.UserSessionPersisterProvider) ResetTimeOffsetEvent(org.keycloak.models.utils.ResetTimeOffsetEvent) TimerProvider(org.keycloak.timer.TimerProvider) HashMap(java.util.HashMap) Map(java.util.Map) Test(org.junit.Test) KeycloakModelTest(org.keycloak.testsuite.model.KeycloakModelTest)

Aggregations

ResetTimeOffsetEvent (org.keycloak.models.utils.ResetTimeOffsetEvent)10 Test (org.junit.Test)8 RealmModel (org.keycloak.models.RealmModel)7 UserSessionModel (org.keycloak.models.UserSessionModel)7 KeycloakSession (org.keycloak.models.KeycloakSession)5 AuthenticatedClientSessionModel (org.keycloak.models.AuthenticatedClientSessionModel)4 AbstractTestRealmKeycloakTest (org.keycloak.testsuite.AbstractTestRealmKeycloakTest)4 ModelTest (org.keycloak.testsuite.arquillian.annotation.ModelTest)4 KeycloakModelTest (org.keycloak.testsuite.model.KeycloakModelTest)4 HashSet (java.util.HashSet)3 AtomicReference (java.util.concurrent.atomic.AtomicReference)3 ClientModel (org.keycloak.models.ClientModel)3 UserSessionProvider (org.keycloak.models.UserSessionProvider)3 UserSessionPersisterProvider (org.keycloak.models.session.UserSessionPersisterProvider)3 TimerProvider (org.keycloak.timer.TimerProvider)3 List (java.util.List)2 UserModel (org.keycloak.models.UserModel)2 UserSessionManager (org.keycloak.services.managers.UserSessionManager)2 HashMap (java.util.HashMap)1 LinkedList (java.util.LinkedList)1