From 99a5656f0fceda6d1a26e9f5e58a6a19c0948f79 Mon Sep 17 00:00:00 2001 From: Martin Bartos RH Date: Mon, 3 Dec 2018 16:00:51 +0100 Subject: [PATCH] [KEYCLOAK-8389] Migrate ModelClass: UserSessionInitializerTest --- .../model/UserSessionInitializerTest.java | 281 ++++++++++++++++++ ...n-on-server-jboss-deployment-structure.xml | 3 +- .../model/UserSessionInitializerTest.java | 205 ------------- 3 files changed, 283 insertions(+), 206 deletions(-) create mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java delete mode 100644 testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java 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 0000000000..81d9d0e4ac --- /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 Marek Posolda + * @author Martin Bartos + */ +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 startedAtomic = new AtomicReference<>(); + AtomicReference 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 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 startedAtomic = new AtomicReference<>(); + AtomicReference 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 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 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 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 ec7403c73c..24d714a992 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 @@ + - \ No newline at end of file + diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java deleted file mode 100644 index a95e27ffbe..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * 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.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.keycloak.cluster.ClusterProvider; -import org.keycloak.common.util.Time; -import org.keycloak.connections.infinispan.InfinispanConnectionProvider; -import org.keycloak.models.AuthenticatedClientSessionModel; -import org.keycloak.models.ClientModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.models.UserModel; -import org.keycloak.models.UserSessionModel; -import org.keycloak.models.UserSessionProvider; -import org.keycloak.models.UserSessionProviderFactory; -import org.keycloak.protocol.oidc.OIDCLoginProtocol; -import org.keycloak.models.UserManager; -import org.keycloak.services.managers.UserSessionManager; -import org.keycloak.testsuite.rule.KeycloakRule; - -import java.util.List; - -/** - * @author Marek Posolda - */ -public class UserSessionInitializerTest { - - - @ClassRule - public static KeycloakRule kc = new KeycloakRule(); - - private KeycloakSession session; - private RealmModel realm; - private UserSessionManager sessionManager; - - @Before - public void before() { - session = kc.startSession(); - realm = session.realms().getRealm("test"); - session.users().addUser(realm, "user1").setEmail("user1@localhost"); - session.users().addUser(realm, "user2").setEmail("user2@localhost"); - sessionManager = new UserSessionManager(session); - } - - @After - public void after() { - resetSession(); - session.sessions().removeUserSessions(realm); - UserModel user1 = session.users().getUserByUsername("user1", realm); - UserModel user2 = session.users().getUserByUsername("user2", realm); - - UserManager um = new UserManager(session); - um.removeUser(realm, user1); - um.removeUser(realm, user2); - kc.stopSession(session, true); - } - - @Test - public void testUserSessionInitializer() { - int started = Time.currentTime(); - int serverStartTime = session.getProvider(ClusterProvider.class).getClusterStartupTime(); - - UserSessionModel[] origSessions = createSessionsInPersisterOnly(); - - // Load sessions from persister into infinispan/memory - UserSessionProviderFactory userSessionFactory = (UserSessionProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserSessionProvider.class); - userSessionFactory.loadPersistentSessions(session.getKeycloakSessionFactory(), 1, 2); - - resetSession(); - - // Assert sessions are in - ClientModel testApp = realm.getClientByClientId("test-app"); - ClientModel thirdparty = realm.getClientByClientId("third-party"); - Assert.assertEquals(3, session.sessions().getOfflineSessionsCount(realm, testApp)); - Assert.assertEquals(1, session.sessions().getOfflineSessionsCount(realm, thirdparty)); - - List loadedSessions = session.sessions().getOfflineUserSessions(realm, testApp, 0, 10); - UserSessionProviderTest.assertSessions(loadedSessions, origSessions); - - UserSessionPersisterProviderTest.assertSessionLoaded(loadedSessions, origSessions[0].getId(), session.users().getUserByUsername("user1", realm), "127.0.0.1", started, started, "test-app", "third-party"); - UserSessionPersisterProviderTest.assertSessionLoaded(loadedSessions, origSessions[1].getId(), session.users().getUserByUsername("user1", realm), "127.0.0.2", started, started, "test-app"); - UserSessionPersisterProviderTest.assertSessionLoaded(loadedSessions, origSessions[2].getId(), session.users().getUserByUsername("user2", realm), "127.0.0.3", started, started, "test-app"); - } - - - // KEYCLOAK-5245 - @Test - public void testUserSessionInitializerWithDeletingClient() { - int started = Time.currentTime(); - int serverStartTime = session.getProvider(ClusterProvider.class).getClusterStartupTime(); - - UserSessionModel[] origSessions = createSessionsInPersisterOnly(); - - // 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()); - - resetSession(); - - // Load sessions from persister into infinispan/memory - UserSessionProviderFactory userSessionFactory = (UserSessionProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserSessionProvider.class); - userSessionFactory.loadPersistentSessions(session.getKeycloakSessionFactory(), 1, 2); - - resetSession(); - - // Assert sessions are in - ClientModel thirdparty = realm.getClientByClientId("third-party"); - Assert.assertEquals(1, session.sessions().getOfflineSessionsCount(realm, thirdparty)); - - List loadedSessions = session.sessions().getOfflineUserSessions(realm, thirdparty, 0, 10); - Assert.assertEquals(1, loadedSessions.size()); - - UserSessionPersisterProviderTest.assertSessionLoaded(loadedSessions, origSessions[0].getId(), session.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() { - UserSessionModel[] origSessions = createSessions(); - - resetSession(); - - for (UserSessionModel origSession : origSessions) { - UserSessionModel userSession = session.sessions().getUserSession(realm, origSession.getId()); - for (AuthenticatedClientSessionModel clientSession : userSession.getAuthenticatedClientSessions().values()) { - sessionManager.createOrUpdateOfflineSession(clientSession, userSession); - } - } - - resetSession(); - - // Delete cache (persisted sessions are still kept) - session.sessions().onRealmRemoved(realm); - - // Clear ispn cache to ensure initializerState is removed as well - InfinispanConnectionProvider infinispan = session.getProvider(InfinispanConnectionProvider.class); - infinispan.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME).clear(); - - resetSession(); - - ClientModel testApp = realm.getClientByClientId("test-app"); - ClientModel thirdparty = realm.getClientByClientId("third-party"); - Assert.assertEquals(0, session.sessions().getOfflineSessionsCount(realm, testApp)); - Assert.assertEquals(0, session.sessions().getOfflineSessionsCount(realm, thirdparty)); - - return origSessions; - } - - - private AuthenticatedClientSessionModel createClientSession(ClientModel client, UserSessionModel userSession, String redirect, String state) { - 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() { - 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(realm.getClientByClientId("test-app"), sessions[0], "http://redirect", "state"); - createClientSession(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(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(realm.getClientByClientId("test-app"), sessions[2], "http://redirect", "state"); - - resetSession(); - - return sessions; - } - - private void resetSession() { - kc.stopSession(session, true); - session = kc.startSession(); - realm = session.realms().getRealm("test"); - sessionManager = new UserSessionManager(session); - } - -}