keycloak-aplcache

Changes

testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java 205(+0 -205)

Details

diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java
new file mode 100644
index 0000000..81d9d0e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.model;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.TargetsContainer;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.common.util.Time;
+import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
+import org.keycloak.models.*;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.services.managers.UserSessionManager;
+import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
+import org.keycloak.testsuite.arquillian.annotation.ModelTest;
+import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import static org.keycloak.testsuite.arquillian.DeploymentTargetModifier.AUTH_SERVER_CURRENT;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ * @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
+ */
+public class UserSessionInitializerTest extends AbstractTestRealmKeycloakTest {
+    private final String realmName = "test";
+
+    @Deployment
+    @TargetsContainer(AUTH_SERVER_CURRENT)
+    public static WebArchive deploy() {
+        return RunOnServerDeployment.create(UserResource.class, org.keycloak.testsuite.model.UserSessionInitializerTest.class)
+                .addPackages(true,
+                        "org.keycloak.testsuite",
+                        "org.keycloak.testsuite.model");
+    }
+
+    @Before
+    public void before() {
+        testingClient.server().run(session -> {
+            RealmModel realm = session.realms().getRealm("test");
+            session.users().addUser(realm, "user1").setEmail("user1@localhost");
+            session.users().addUser(realm, "user2").setEmail("user2@localhost");
+        });
+    }
+
+    @After
+    public void after() {
+        testingClient.server().run(session -> {
+            RealmModel realm = session.realms().getRealmByName("test");
+            session.sessions().removeUserSessions(realm);
+
+            UserModel user1 = session.users().getUserByUsername("user1", realm);
+            UserModel user2 = session.users().getUserByUsername("user2", realm);
+
+            UserManager um = new UserManager(session);
+            if (user1 != null)
+                um.removeUser(realm, user1);
+            if (user2 != null)
+                um.removeUser(realm, user2);
+        });
+    }
+
+    @Test
+    @ModelTest
+    public void testUserSessionInitializer(KeycloakSession session) {
+        AtomicReference<Integer> startedAtomic = new AtomicReference<>();
+        AtomicReference<UserSessionModel[]> origSessionsAtomic = new AtomicReference<>();
+
+        KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession SessionInit1) -> {
+            KeycloakSession currentSession = SessionInit1;
+            UserSessionManager sessionManager = new UserSessionManager(currentSession);
+
+            int started = Time.currentTime();
+            startedAtomic.set(started);
+
+            UserSessionModel[] origSessions = createSessionsInPersisterOnly(currentSession);
+            origSessionsAtomic.set(origSessions);
+
+            // Load sessions from persister into infinispan/memory
+            UserSessionProviderFactory userSessionFactory = (UserSessionProviderFactory) currentSession.getKeycloakSessionFactory().getProviderFactory(UserSessionProvider.class);
+            userSessionFactory.loadPersistentSessions(currentSession.getKeycloakSessionFactory(), 1, 2);
+        });
+
+        KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession SessionInit2) -> {
+            KeycloakSession currentSession = SessionInit2;
+            RealmModel realm = currentSession.realms().getRealmByName(realmName);
+
+            int started = startedAtomic.get();
+
+            UserSessionModel[] origSessions = origSessionsAtomic.get();
+
+            // Assert sessions are in
+            ClientModel testApp = realm.getClientByClientId("test-app");
+            ClientModel thirdparty = realm.getClientByClientId("third-party");
+
+            assertThat("Count of offline sesions for client 'test-app'", currentSession.sessions().getOfflineSessionsCount(realm, testApp), is((long) 3));
+            assertThat("Count of offline sesions for client 'third-party'", currentSession.sessions().getOfflineSessionsCount(realm, thirdparty), is((long) 1));
+
+            List<UserSessionModel> loadedSessions = currentSession.sessions().getOfflineUserSessions(realm, testApp, 0, 10);
+            UserSessionProviderTest.assertSessions(loadedSessions, origSessions);
+
+            assertSessionLoaded(loadedSessions, origSessions[0].getId(), currentSession.users().getUserByUsername("user1", realm), "127.0.0.1", started, started, "test-app", "third-party");
+            assertSessionLoaded(loadedSessions, origSessions[1].getId(), currentSession.users().getUserByUsername("user1", realm), "127.0.0.2", started, started, "test-app");
+            assertSessionLoaded(loadedSessions, origSessions[2].getId(), currentSession.users().getUserByUsername("user2", realm), "127.0.0.3", started, started, "test-app");
+        });
+    }
+
+    @Test
+    @ModelTest
+    public void testUserSessionInitializerWithDeletingClient(KeycloakSession session) {
+        AtomicReference<Integer> startedAtomic = new AtomicReference<>();
+        AtomicReference<UserSessionModel[]> origSessionsAtomic = new AtomicReference<>();
+
+        KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession SessionInitWithDeleting1) -> {
+            KeycloakSession currentSession = SessionInitWithDeleting1;
+            UserSessionManager sessionManager = new UserSessionManager(currentSession);
+
+            RealmModel realm = currentSession.realms().getRealmByName(realmName);
+
+            int started = Time.currentTime();
+            startedAtomic.set(started);
+
+            origSessionsAtomic.set(createSessionsInPersisterOnly(currentSession));
+
+            // Delete one of the clients now. Delete it directly in DB just for the purpose of simulating the issue (normally clients should be removed through ClientManager)
+            ClientModel testApp = realm.getClientByClientId("test-app");
+            realm.removeClient(testApp.getId());
+        });
+
+        KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession SessionInitWithDeleting2) -> {
+            KeycloakSession currentSession = SessionInitWithDeleting2;
+
+            // Load sessions from persister into infinispan/memory
+            UserSessionProviderFactory userSessionFactory = (UserSessionProviderFactory) currentSession.getKeycloakSessionFactory().getProviderFactory(UserSessionProvider.class);
+            userSessionFactory.loadPersistentSessions(currentSession.getKeycloakSessionFactory(), 1, 2);
+        });
+
+        KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession SessionInitWithDeleting3) -> {
+            KeycloakSession currentSession = SessionInitWithDeleting3;
+            RealmModel realm = currentSession.realms().getRealmByName(realmName);
+
+            int started = startedAtomic.get();
+
+            UserSessionModel[] origSessions = origSessionsAtomic.get();
+
+            // Assert sessions are in
+            ClientModel thirdparty = realm.getClientByClientId("third-party");
+
+            assertThat("Count of offline sesions for client 'third-party'", currentSession.sessions().getOfflineSessionsCount(realm, thirdparty), is((long) 1));
+            List<UserSessionModel> loadedSessions = currentSession.sessions().getOfflineUserSessions(realm, thirdparty, 0, 10);
+
+            assertThat("Size of loaded Sessions", loadedSessions.size(), is(1));
+            assertSessionLoaded(loadedSessions, origSessions[0].getId(), currentSession.users().getUserByUsername("user1", realm), "127.0.0.1", started, started, "third-party");
+
+            // Revert client
+            realm.addClient("test-app");
+        });
+
+    }
+
+    // Create sessions in persister + infinispan, but then delete them from infinispan cache. This is to allow later testing of initializer. Return the list of "origSessions"
+    private UserSessionModel[] createSessionsInPersisterOnly(KeycloakSession session) {
+        AtomicReference<UserSessionModel[]> origSessionsAtomic = new AtomicReference<>();
+
+        KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession createSessionPersister1) -> {
+            KeycloakSession currentSession = createSessionPersister1;
+
+            UserSessionModel[] origSessions = createSessions(currentSession);
+            origSessionsAtomic.set(origSessions);
+        });
+
+        KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession createSessionPersister2) -> {
+            KeycloakSession currentSession = createSessionPersister2;
+            RealmModel realm = currentSession.realms().getRealmByName(realmName);
+            UserSessionManager sessionManager = new UserSessionManager(currentSession);
+
+            UserSessionModel[] origSessions = origSessionsAtomic.get();
+
+            for (UserSessionModel origSession : origSessions) {
+                UserSessionModel userSession = currentSession.sessions().getUserSession(realm, origSession.getId());
+                for (AuthenticatedClientSessionModel clientSession : userSession.getAuthenticatedClientSessions().values()) {
+                    sessionManager.createOrUpdateOfflineSession(clientSession, userSession);
+                }
+            }
+        });
+
+        KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession createSessionPersister3) -> {
+            KeycloakSession currentSession = createSessionPersister3;
+            RealmModel realm = currentSession.realms().getRealmByName(realmName);
+
+            // Delete cache (persisted sessions are still kept)
+            currentSession.sessions().onRealmRemoved(realm);
+
+            // Clear ispn cache to ensure initializerState is removed as well
+            InfinispanConnectionProvider infinispan = currentSession.getProvider(InfinispanConnectionProvider.class);
+            infinispan.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME).clear();
+
+        });
+
+        KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession createSessionPersister4) -> {
+            KeycloakSession currentSession = createSessionPersister4;
+            RealmModel realm = currentSession.realms().getRealmByName(realmName);
+
+            ClientModel testApp = realm.getClientByClientId("test-app");
+            ClientModel thirdparty = realm.getClientByClientId("third-party");
+            assertThat("Count of offline sessions for client 'test-app'", currentSession.sessions().getOfflineSessionsCount(realm, testApp), is((long) 0));
+            assertThat("Count of offline sessions for client 'third-party'", currentSession.sessions().getOfflineSessionsCount(realm, thirdparty), is((long) 0));
+        });
+
+        return origSessionsAtomic.get();
+    }
+
+    private AuthenticatedClientSessionModel createClientSession(KeycloakSession session, ClientModel client, UserSessionModel userSession, String redirect, String state) {
+        RealmModel realm = session.realms().getRealmByName(realmName);
+
+        AuthenticatedClientSessionModel clientSession = session.sessions().createClientSession(realm, client, userSession);
+        clientSession.setRedirectUri(redirect);
+        if (state != null)
+            clientSession.setNote(OIDCLoginProtocol.STATE_PARAM, state);
+        return clientSession;
+    }
+
+    private UserSessionModel[] createSessions(KeycloakSession session) {
+        RealmModel realm = session.realms().getRealmByName(realmName);
+
+        UserSessionModel[] sessions = new UserSessionModel[3];
+        sessions[0] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null);
+
+        createClientSession(session, realm.getClientByClientId("test-app"), sessions[0], "http://redirect", "state");
+        createClientSession(session, realm.getClientByClientId("third-party"), sessions[0], "http://redirect", "state");
+
+        sessions[1] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
+        createClientSession(session, realm.getClientByClientId("test-app"), sessions[1], "http://redirect", "state");
+
+        sessions[2] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user2", realm), "user2", "127.0.0.3", "form", true, null, null);
+        createClientSession(session, realm.getClientByClientId("test-app"), sessions[2], "http://redirect", "state");
+
+        return sessions;
+    }
+
+    private void assertSessionLoaded(List<UserSessionModel> sessions, String id, UserModel user, String ipAddress, int started, int lastRefresh, String... clients) {
+        for (UserSessionModel session : sessions) {
+            if (session.getId().equals(id)) {
+                UserSessionProviderTest.assertSession(session, user, ipAddress, started, lastRefresh, clients);
+                return;
+            }
+        }
+        Assert.fail("Session with ID " + id + " not found in the list");
+    }
+
+    @Override
+    public void configureTestRealm(RealmRepresentation testRealm) {
+    }
+}
+
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/run-on-server-jboss-deployment-structure.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/run-on-server-jboss-deployment-structure.xml
index ec7403c..24d714a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/run-on-server-jboss-deployment-structure.xml
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/run-on-server-jboss-deployment-structure.xml
@@ -12,6 +12,7 @@
             <module name="org.keycloak.keycloak-model-jpa"/>
             <module name="org.keycloak.keycloak-kerberos-federation"/>
             <module name="org.keycloak.keycloak-ldap-federation"/>
+            <module name="org.infinispan"/>
         </dependencies>
     </deployment>
-</jboss-deployment-structure>
\ No newline at end of file
+</jboss-deployment-structure>