Map Store Removal: Delete map profiles and scopes from model tests
Closes #24093
This commit is contained in:
parent
8867dd6370
commit
e05effe62d
28 changed files with 7 additions and 2409 deletions
|
@ -49,76 +49,4 @@ mvn test -Pjpa -Dtest=ClientModelTest \
|
|||
|
||||
The results are available in the `target/profile.html` file.
|
||||
|
||||
Usage of Testcontainers
|
||||
-----------------------
|
||||
|
||||
Some profiles within model tests require running 3rd party software, for
|
||||
example, database or Infinispan. For running these we are using
|
||||
[Testcontainers](https://www.testcontainers.org/). This may require some
|
||||
additional configuration of your container engine.
|
||||
|
||||
#### Podman settings
|
||||
|
||||
For more details see the following [Podman guide from Quarkus webpage](https://quarkus.io/guides/podman).
|
||||
|
||||
Specifically, these steps are required:
|
||||
```shell
|
||||
# Enable the podman socket with Docker REST API (only needs to be done once)
|
||||
systemctl --user enable podman.socket --now
|
||||
|
||||
# Set the required environment variables (need to be run everytime or added to profile)
|
||||
export DOCKER_HOST=unix:///run/user/${UID}/podman/podman.sock
|
||||
```
|
||||
|
||||
Testcontainers are using [ryuk](https://hub.docker.com/r/testcontainers/ryuk)
|
||||
to cleanup containers after tests. To make this work with Podman add the
|
||||
following line to `~/.testcontainers.properties`
|
||||
```shell
|
||||
ryuk.container.privileged=true
|
||||
```
|
||||
Alternatively, disable usage of ryuk (using this may result in stale containers
|
||||
still running after tests finish. This is not recommended especially if you are
|
||||
executing tests from Intellij IDE as it [may not stop](https://youtrack.jetbrains.com/issue/IDEA-190385)
|
||||
the containers created during test run).
|
||||
```shell
|
||||
export TESTCONTAINERS_RYUK_DISABLED=true #not recommended - see above!
|
||||
```
|
||||
|
||||
#### Docker settings
|
||||
|
||||
To use Testcontainers with Docker it is necessary to
|
||||
[make Docker available for non-root users](https://docs.docker.com/engine/install/linux-postinstall/).
|
||||
|
||||
Running HotRod tests with external Infinispan
|
||||
---------------------------------------------
|
||||
|
||||
By default, Model tests with `hot-rod` profile spawn a new Infinispan container
|
||||
with each test execution. It is also possible, to configure Model tests to
|
||||
connect to an external instance of Infinispan. To do so, execute tests with
|
||||
the following command:
|
||||
```shell
|
||||
mvn test -Phot-rod \
|
||||
-Dkeycloak.testsuite.start-hotrod-container=false \
|
||||
-Dkeycloak.connectionsHotRod.host=<host> \
|
||||
-Dkeycloak.connectionsHotRod.port=<port> \
|
||||
-Dkeycloak.connectionsHotRod.username=<username> \
|
||||
-Dkeycloak.connectionsHotRod.password=<password>
|
||||
```
|
||||
|
||||
Running tests with `map-jpa` profile using external Postgres database
|
||||
---------------------------------------------
|
||||
|
||||
By default, Model tests with `map-jpa` profile spawns a new Postgres container
|
||||
with each test execution. Default image used is "postgres:alpine". To spawn different
|
||||
version, it can be used "keycloak.map.storage.postgres.docker.image" system property.
|
||||
|
||||
It is also possible, to configure Model tests to connect to an external instance
|
||||
of Postgres. To do so, execute tests with the following command:
|
||||
```shell
|
||||
mvn test -Pmap-jpa \
|
||||
-Dpostgres.start-container=false \
|
||||
-Dkeycloak.map.storage.connectionsJpa.url=<jdbc_url> \
|
||||
-Dkeycloak.map.storage.connectionsJpa.user=<user> \
|
||||
-Dkeycloak.map.storage.connectionsJpa.password=<password>
|
||||
```
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
<jdbc.mvn.version>${h2.version}</jdbc.mvn.version>
|
||||
<log4j.configuration>file:${project.build.directory}/dependency/log4j.properties</log4j.configuration>
|
||||
<jacoco.skip>true</jacoco.skip>
|
||||
<keycloak.profile.feature.map_storage>disabled</keycloak.profile.feature.map_storage>
|
||||
<keycloak.userSessions.infinispan.preloadOfflineSessionsFromDatabase>false</keycloak.userSessions.infinispan.preloadOfflineSessionsFromDatabase>
|
||||
</properties>
|
||||
|
||||
|
@ -93,23 +92,11 @@
|
|||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-infinispan</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-map</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<artifactId>integration-arquillian-testsuite-providers</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-map-hot-rod</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-map-ldap</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.infinispan</groupId>
|
||||
<artifactId>infinispan-core-jakarta</artifactId>
|
||||
|
@ -119,18 +106,6 @@
|
|||
<artifactId>postgresql</artifactId>
|
||||
<version>${postgresql-jdbc.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
<version>${testcontainers.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>${testcontainers.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- annotations needed to avoid compile time warnings about enums constants -->
|
||||
<dependency>
|
||||
<groupId>org.infinispan</groupId>
|
||||
|
@ -181,11 +156,7 @@
|
|||
<keycloak.connectionsJpa.default.user>${keycloak.connectionsJpa.user}</keycloak.connectionsJpa.default.user>
|
||||
<keycloak.connectionsJpa.default.password>${keycloak.connectionsJpa.password}</keycloak.connectionsJpa.default.password>
|
||||
<keycloak.connectionsJpa.default.url>${keycloak.connectionsJpa.url}</keycloak.connectionsJpa.default.url>
|
||||
<keycloak.map.storage.connectionsJpa.url>${keycloak.map.storage.connectionsJpa.url}</keycloak.map.storage.connectionsJpa.url>
|
||||
<keycloak.map.storage.connectionsJpa.user>${keycloak.map.storage.connectionsJpa.user}</keycloak.map.storage.connectionsJpa.user>
|
||||
<keycloak.map.storage.connectionsJpa.password>${keycloak.map.storage.connectionsJpa.password}</keycloak.map.storage.connectionsJpa.password>
|
||||
<log4j.configuration>file:${project.build.directory}/test-classes/log4j.properties</log4j.configuration> <!-- for the logging to properly work with tests in the 'other' module -->
|
||||
<keycloak.profile.feature.map_storage>${keycloak.profile.feature.map_storage}</keycloak.profile.feature.map_storage>
|
||||
<keycloak.userSessions.infinispan.preloadOfflineSessionsFromDatabase>${keycloak.userSessions.infinispan.preloadOfflineSessionsFromDatabase}</keycloak.userSessions.infinispan.preloadOfflineSessionsFromDatabase>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
<org.jboss.logging.provider>log4j</org.jboss.logging.provider>
|
||||
|
@ -200,26 +171,6 @@
|
|||
</properties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>process-test-resources</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<target>
|
||||
<delete>
|
||||
<fileset dir="${project.build.directory}" includes="map-*.json"/>
|
||||
<fileset dir="${project.build.directory}" includes="map/**/*.json"/>
|
||||
</delete>
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
|
@ -341,46 +292,6 @@
|
|||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>map</id>
|
||||
<properties>
|
||||
<keycloak.profile.feature.map_storage>enabled</keycloak.profile.feature.map_storage>
|
||||
<keycloak.model.parameters>Map,ConcurrentHashMapStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>file</id>
|
||||
<properties>
|
||||
<keycloak.profile.feature.map_storage>enabled</keycloak.profile.feature.map_storage>
|
||||
<keycloak.model.parameters>Map,FileMapStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>hot-rod</id>
|
||||
<properties>
|
||||
<keycloak.profile.feature.map_storage>enabled</keycloak.profile.feature.map_storage>
|
||||
<keycloak.model.parameters>Map,HotRodMapStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>map-ldap</id>
|
||||
<properties>
|
||||
<keycloak.profile.feature.map_storage>enabled</keycloak.profile.feature.map_storage>
|
||||
<keycloak.model.parameters>Map,LdapMapStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>map-jpa</id>
|
||||
<properties>
|
||||
<keycloak.profile.feature.map_storage>enabled</keycloak.profile.feature.map_storage>
|
||||
<keycloak.model.parameters>Map,JpaMapStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>.asyncProfiler</id>
|
||||
<activation>
|
||||
|
|
|
@ -1,206 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.hamcrest.Matchers;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientProvider;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.map.client.MapClientEntity;
|
||||
import org.keycloak.models.map.client.MapClientEntityImpl;
|
||||
import org.keycloak.models.map.client.MapClientProviderFactory;
|
||||
import org.keycloak.models.map.common.DeepCloner;
|
||||
import org.keycloak.models.map.common.StringKeyConverter;
|
||||
import org.keycloak.models.map.storage.MapStorage;
|
||||
import org.keycloak.models.map.storage.MapStorageProvider;
|
||||
import org.keycloak.models.map.storage.MapStorageProviderFactory;
|
||||
import org.keycloak.models.map.storage.chm.ConcurrentHashMapStorage;
|
||||
import org.keycloak.models.map.storage.chm.ConcurrentHashMapStorageProviderFactory;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.provider.InvalidationHandler;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
@RequireProvider(value = ClientProvider.class, only = {MapClientProviderFactory.PROVIDER_ID})
|
||||
@RequireProvider(RealmProvider.class)
|
||||
@RequireProvider(value = MapStorageProvider.class, only = {ConcurrentHashMapStorageProviderFactory.PROVIDER_ID})
|
||||
public class ConcurrentHashMapStorageTest extends KeycloakModelTest {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(ConcurrentHashMapStorageTest.class.getName());
|
||||
|
||||
private String realmId;
|
||||
|
||||
private String mapStorageProviderId;
|
||||
|
||||
@Before
|
||||
public void initMapStorageProviderId() {
|
||||
MapStorageProviderFactory ms = (MapStorageProviderFactory) getFactory().getProviderFactory(MapStorageProvider.class, ConcurrentHashMapStorageProviderFactory.PROVIDER_ID);
|
||||
mapStorageProviderId = ms.getId();
|
||||
assertThat(mapStorageProviderId, Matchers.notNullValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createEnvironment(KeycloakSession s) {
|
||||
RealmModel realm = createRealm(s, "realm");
|
||||
realm.setDefaultRole(s.roles().addRealmRole(realm, Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + realm.getName()));
|
||||
this.realmId = realm.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanEnvironment(KeycloakSession s) {
|
||||
s.realms().removeRealm(realmId);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public <K, K1, K2> void testStorageSeparation() {
|
||||
String component1Id = createMapStorageComponent("component1", "keyType", "ulong");
|
||||
String component2Id = createMapStorageComponent("component2", "keyType", "string");
|
||||
|
||||
String[] ids = withRealm(realmId, (session, realm) -> {
|
||||
ConcurrentHashMapStorage<K, MapClientEntity, ClientModel, ?> storageMain = (ConcurrentHashMapStorage<K, MapClientEntity, ClientModel, ?>) (MapStorage) session.getProvider(MapStorageProvider.class, ConcurrentHashMapStorageProviderFactory.PROVIDER_ID).getMapStorage(ClientModel.class);
|
||||
ConcurrentHashMapStorage<K1, MapClientEntity, ClientModel, ?> storage1 = (ConcurrentHashMapStorage<K1, MapClientEntity, ClientModel, ?>) (MapStorage) session.getComponentProvider(MapStorageProvider.class, component1Id).getMapStorage(ClientModel.class);
|
||||
ConcurrentHashMapStorage<K2, MapClientEntity, ClientModel, ?> storage2 = (ConcurrentHashMapStorage<K2, MapClientEntity, ClientModel, ?>) (MapStorage) session.getComponentProvider(MapStorageProvider.class, component2Id).getMapStorage(ClientModel.class);
|
||||
|
||||
// Assert that the map storage can be used both as a standalone store and a component
|
||||
assertThat(storageMain, notNullValue());
|
||||
assertThat(storage1, notNullValue());
|
||||
assertThat(storage2, notNullValue());
|
||||
|
||||
final StringKeyConverter<K> kcMain = (StringKeyConverter<K>) StringKeyConverter.UUIDKey.INSTANCE;
|
||||
final StringKeyConverter<K1> kc1 = (StringKeyConverter<K1>) StringKeyConverter.ULongKey.INSTANCE;
|
||||
final StringKeyConverter<K2> kc2 = (StringKeyConverter<K2>) StringKeyConverter.StringKey.INSTANCE;
|
||||
|
||||
String idMain = kcMain.keyToString(kcMain.yieldNewUniqueKey());
|
||||
String id1 = kc1.keyToString(kc1.yieldNewUniqueKey());
|
||||
String id2 = kc2.keyToString(kc2.yieldNewUniqueKey());
|
||||
|
||||
assertThat(idMain, notNullValue());
|
||||
assertThat(id1, notNullValue());
|
||||
assertThat(id2, notNullValue());
|
||||
|
||||
// Assert that the stores do not contain the to-be-created clients
|
||||
assertThat(storageMain.read(idMain), nullValue());
|
||||
assertThat(storage1.read(id1), nullValue());
|
||||
assertThat(storage2.read(id2), nullValue());
|
||||
|
||||
assertClientDoesNotExist(storageMain, id1, kc1, kcMain);
|
||||
assertClientDoesNotExist(storageMain, id2, kc2, kcMain);
|
||||
assertClientDoesNotExist(storage1, idMain, kcMain, kc1);
|
||||
assertClientDoesNotExist(storage1, id2, kc2, kc1);
|
||||
assertClientDoesNotExist(storage2, idMain, kcMain, kc2);
|
||||
assertClientDoesNotExist(storage2, id1, kc1, kc2);
|
||||
|
||||
MapClientEntity clientMain = new MapClientEntityImpl(DeepCloner.DUMB_CLONER);
|
||||
clientMain.setId(idMain);
|
||||
clientMain.setRealmId(realmId);
|
||||
MapClientEntity client1 = new MapClientEntityImpl(DeepCloner.DUMB_CLONER);
|
||||
client1.setId(id1);
|
||||
client1.setRealmId(realmId);
|
||||
MapClientEntity client2 = new MapClientEntityImpl(DeepCloner.DUMB_CLONER);
|
||||
client2.setId(id2);
|
||||
client2.setRealmId(realmId);
|
||||
|
||||
clientMain = storageMain.create(clientMain);
|
||||
client1 = storage1.create(client1);
|
||||
client2 = storage2.create(client2);
|
||||
|
||||
return new String[] {clientMain.getId(), client1.getId(), client2.getId()};
|
||||
});
|
||||
|
||||
String idMain = ids[0];
|
||||
String id1 = ids[1];
|
||||
String id2 = ids[2];
|
||||
|
||||
LOG.debugf("Object IDs: %s, %s, %s", idMain, id1, id2);
|
||||
|
||||
assertClientsPersisted(component1Id, component2Id, idMain, id1, id2);
|
||||
|
||||
// Invalidate one component and check that the storage still contains what it should
|
||||
getFactory().invalidate(null, InvalidationHandler.ObjectType.COMPONENT, component1Id);
|
||||
assertClientsPersisted(component1Id, component2Id, idMain, id1, id2);
|
||||
|
||||
// Invalidate whole realm and check that the storage still contains what it should
|
||||
getFactory().invalidate(null, InvalidationHandler.ObjectType.REALM, realmId);
|
||||
assertClientsPersisted(component1Id, component2Id, idMain, id1, id2);
|
||||
|
||||
// Refresh factory (akin server restart) and check that the storage still contains what it should
|
||||
reinitializeKeycloakSessionFactory();
|
||||
assertClientsPersisted(component1Id, component2Id, idMain, id1, id2);
|
||||
}
|
||||
|
||||
private <K,K1> void assertClientDoesNotExist(ConcurrentHashMapStorage<K, MapClientEntity, ClientModel, ?> storage, String id, final StringKeyConverter<K1> kc, final StringKeyConverter<K> kcStorage) {
|
||||
// Assert that the other stores do not contain the to-be-created clients (if they use compatible key format)
|
||||
try {
|
||||
assertThat(storage.read(id), nullValue());
|
||||
} catch (Exception ex) {
|
||||
// If the format is incompatible then the object does not exist in the store
|
||||
}
|
||||
}
|
||||
|
||||
private <K, K1, K2> void assertClientsPersisted(String component1Id, String component2Id, String idMain, String id1, String id2) {
|
||||
// Check that in the next transaction, the objects are still there
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
ConcurrentHashMapStorage<K, MapClientEntity, ClientModel, ?> storageMain = (ConcurrentHashMapStorage<K, MapClientEntity, ClientModel, ?>) (MapStorage) session.getProvider(MapStorageProvider.class, ConcurrentHashMapStorageProviderFactory.PROVIDER_ID).getMapStorage(ClientModel.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
ConcurrentHashMapStorage<K1, MapClientEntity, ClientModel, ?> storage1 = (ConcurrentHashMapStorage<K1, MapClientEntity, ClientModel, ?>) (MapStorage) session.getComponentProvider(MapStorageProvider.class, component1Id).getMapStorage(ClientModel.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
ConcurrentHashMapStorage<K2, MapClientEntity, ClientModel, ?> storage2 = (ConcurrentHashMapStorage<K2, MapClientEntity, ClientModel, ?>) (MapStorage) session.getComponentProvider(MapStorageProvider.class, component2Id).getMapStorage(ClientModel.class);
|
||||
|
||||
final StringKeyConverter<K> kcMain = (StringKeyConverter<K>) StringKeyConverter.UUIDKey.INSTANCE;
|
||||
final StringKeyConverter<K1> kc1 = (StringKeyConverter<K1>) StringKeyConverter.ULongKey.INSTANCE;
|
||||
final StringKeyConverter<K2> kc2 = (StringKeyConverter<K2>) StringKeyConverter.StringKey.INSTANCE;
|
||||
|
||||
// Assert that the stores contain the created clients
|
||||
assertThat(storageMain.read(idMain), notNullValue());
|
||||
assertThat(storage1.read(id1), notNullValue());
|
||||
assertThat(storage2.read(id2), notNullValue());
|
||||
|
||||
// Assert that the other stores do not contain the to-be-created clients (if they use compatible key format)
|
||||
assertClientDoesNotExist(storageMain, id1, kc1, kcMain);
|
||||
assertClientDoesNotExist(storageMain, id2, kc2, kcMain);
|
||||
assertClientDoesNotExist(storage1, idMain, kcMain, kc1);
|
||||
assertClientDoesNotExist(storage1, id2, kc2, kc1);
|
||||
assertClientDoesNotExist(storage2, idMain, kcMain, kc2);
|
||||
assertClientDoesNotExist(storage2, id1, kc1, kc2);
|
||||
assertThat(storageMain.read(idMain), notNullValue());
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private String createMapStorageComponent(String name, String... config) {
|
||||
ComponentModel c1 = KeycloakModelUtils.createComponentModel(name, realmId, mapStorageProviderId, MapStorageProvider.class.getName(), config);
|
||||
|
||||
return withRealm(realmId, (s, r) -> r.addComponentModel(c1).getId());
|
||||
}
|
||||
}
|
|
@ -16,10 +16,7 @@
|
|||
*/
|
||||
package org.keycloak.testsuite.model.client;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
@ -28,23 +25,17 @@ import static org.hamcrest.Matchers.notNullValue;
|
|||
import org.junit.Test;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientProvider;
|
||||
import org.keycloak.models.ClientScopeModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.RoleProvider;
|
||||
import org.keycloak.models.map.client.MapClientProvider;
|
||||
import org.keycloak.models.map.client.MapClientProviderFactory;
|
||||
|
||||
import org.keycloak.testsuite.model.KeycloakModelTest;
|
||||
import org.keycloak.testsuite.model.RequireProvider;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -154,23 +145,6 @@ public class ClientModelTest extends KeycloakModelTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequireProvider(value = ClientProvider.class, only = MapClientProviderFactory.PROVIDER_ID)
|
||||
public void testDeleteClientUsingQueryParameters() {
|
||||
final String CLIENT_ID = "createDeleteClientId";
|
||||
// Create client
|
||||
withRealm(realmId, (session, realm) -> session.clients().addClient(realm, CLIENT_ID));
|
||||
|
||||
// Check if exists
|
||||
assertThat(withRealm(realmId, (session, realm) -> session.clients().getClientByClientId(realm, CLIENT_ID)), notNullValue());
|
||||
|
||||
// Remove
|
||||
withRealm(realmId, (session, realm) -> {((MapClientProvider)session.clients()).preRemove(realm); return null;});
|
||||
|
||||
// Check is null
|
||||
assertThat(withRealm(realmId, (session, realm) -> session.clients().getClientByClientId(realm, CLIENT_ID)), nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScopeMappingRoleRemoval() {
|
||||
// create two clients, one realm role and one client role and assign both to one of the clients
|
||||
|
|
|
@ -20,26 +20,17 @@ import org.keycloak.common.ClientConnection;
|
|||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.events.EventStoreProvider;
|
||||
import org.keycloak.events.EventStoreSpi;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.events.admin.AdminEvent;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.map.events.MapEventStoreProviderFactory;
|
||||
import org.keycloak.models.map.storage.file.FileMapStorageProviderFactory;
|
||||
import org.keycloak.testsuite.model.KeycloakModelTest;
|
||||
import org.keycloak.testsuite.model.RequireProvider;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import org.junit.Test;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -64,12 +55,6 @@ public class EventQueryTest extends KeycloakModelTest {
|
|||
|
||||
@Test
|
||||
public void testClear() {
|
||||
// Skip the test if EventProvider == File
|
||||
String evProvider = CONFIG.getConfig().get(EventStoreSpi.NAME + ".provider");
|
||||
String evMapStorageProvider = CONFIG.getConfig().get(EventStoreSpi.NAME + ".map.storage-auth-events.provider");
|
||||
assumeFalse(MapEventStoreProviderFactory.PROVIDER_ID.equals(evProvider) &&
|
||||
(evMapStorageProvider == null || FileMapStorageProviderFactory.PROVIDER_ID.equals(evMapStorageProvider)));
|
||||
|
||||
inRolledBackTransaction(null, (session, t) -> {
|
||||
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
|
||||
eventStore.clear();
|
||||
|
@ -149,84 +134,6 @@ public class EventQueryTest extends KeycloakModelTest {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@RequireProvider(value = EventStoreProvider.class, only = "map")
|
||||
public void testEventExpiration() {
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
|
||||
|
||||
// Set expiration so no event is valid
|
||||
realm.setEventsExpiration(5);
|
||||
Event e = createAuthEventForUser(session, realm, "u1");
|
||||
eventStore.onEvent(e);
|
||||
|
||||
// Set expiration to 1000 seconds
|
||||
realm.setEventsExpiration(1000);
|
||||
e = createAuthEventForUser(session, realm, "u2");
|
||||
eventStore.onEvent(e);
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
setTimeOffset(10);
|
||||
|
||||
try {
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
|
||||
|
||||
Set<Event> events = eventStore.createQuery()
|
||||
.realm(realmId)
|
||||
.getResultStream().collect(Collectors.toSet());
|
||||
|
||||
assertThat(events, hasSize(1));
|
||||
assertThat(events.iterator().next().getUserId(), equalTo("u2"));
|
||||
return null;
|
||||
});
|
||||
} finally {
|
||||
setTimeOffset(0);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequireProvider(value = EventStoreProvider.class, only = "map")
|
||||
public void testEventsClearedOnRealmRemoval() {
|
||||
// Create another realm
|
||||
String newRealmId = inComittedTransaction(null, (session, t) -> {
|
||||
RealmModel realm = session.realms().createRealm("events-realm");
|
||||
realm.setDefaultRole(session.roles().addRealmRole(realm, Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + realm.getName()));
|
||||
|
||||
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
|
||||
Event e = createAuthEventForUser(session, realm, "u1");
|
||||
eventStore.onEvent(e);
|
||||
|
||||
AdminEvent ae = new AdminEvent();
|
||||
ae.setRealmId(realm.getId());
|
||||
eventStore.onEvent(ae, false);
|
||||
|
||||
return realm.getId();
|
||||
});
|
||||
|
||||
// Check if events were created
|
||||
inComittedTransaction(session -> {
|
||||
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
|
||||
assertThat(eventStore.createQuery().realm(newRealmId).getResultStream().count(), is(1L));
|
||||
assertThat(eventStore.createAdminQuery().realm(newRealmId).getResultStream().count(), is(1L));
|
||||
});
|
||||
|
||||
// Remove realm
|
||||
inComittedTransaction((Consumer<KeycloakSession>) session -> session.realms().removeRealm(newRealmId));
|
||||
|
||||
// Check events were removed
|
||||
inComittedTransaction(session -> {
|
||||
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
|
||||
assertThat(eventStore.createQuery().realm(newRealmId).getResultStream().count(), is(0L));
|
||||
assertThat(eventStore.createAdminQuery().realm(newRealmId).getResultStream().count(), is(0L));
|
||||
});
|
||||
}
|
||||
|
||||
private static class DummyClientConnection implements ClientConnection {
|
||||
|
||||
private static DummyClientConnection DUMMY_CONNECTION = new DummyClientConnection();
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.parameters;
|
||||
|
||||
import org.keycloak.common.crypto.CryptoIntegration;
|
||||
import org.keycloak.common.crypto.CryptoProvider;
|
||||
import org.keycloak.exportimport.ExportSpi;
|
||||
import org.keycloak.exportimport.ImportSpi;
|
||||
import org.keycloak.exportimport.dir.DirExportProviderFactory;
|
||||
import org.keycloak.exportimport.dir.DirImportProviderFactory;
|
||||
import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory;
|
||||
import org.keycloak.exportimport.singlefile.SingleFileImportProviderFactory;
|
||||
import org.keycloak.keys.KeyProviderFactory;
|
||||
import org.keycloak.keys.KeySpi;
|
||||
import org.keycloak.models.ClientScopeSpi;
|
||||
import org.keycloak.models.map.storage.MapStorageSpi;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyManagerFactory;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyManagerSpi;
|
||||
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyFactory;
|
||||
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicySpi;
|
||||
import org.keycloak.testsuite.model.KeycloakModelParameters;
|
||||
import org.keycloak.models.map.storage.chm.ConcurrentHashMapStorageProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.testsuite.model.Config;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class ConcurrentHashMapStorage extends KeycloakModelParameters {
|
||||
|
||||
static final Set<Class<? extends Spi>> ALLOWED_SPIS = ImmutableSet.<Class<? extends Spi>>builder()
|
||||
.add(ExportSpi.class)
|
||||
.add(ClientPolicyManagerSpi.class)
|
||||
.add(ImportSpi.class)
|
||||
.add(ClientRegistrationPolicySpi.class)
|
||||
.add(ClientScopeSpi.class)
|
||||
.add(KeySpi.class)
|
||||
.build();
|
||||
|
||||
static {
|
||||
// CryptoIntegration needed for import of realms
|
||||
CryptoIntegration.init(CryptoProvider.class.getClassLoader());
|
||||
}
|
||||
|
||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
.add(ConcurrentHashMapStorageProviderFactory.class)
|
||||
// start providers needed for export
|
||||
.add(SingleFileExportProviderFactory.class)
|
||||
.add(DirExportProviderFactory.class)
|
||||
.add(ClientPolicyManagerFactory.class)
|
||||
// end providers needed for export
|
||||
// start providers needed for import
|
||||
.add(SingleFileImportProviderFactory.class)
|
||||
.add(DirImportProviderFactory.class)
|
||||
.add(ClientRegistrationPolicyFactory.class)
|
||||
.add(KeyProviderFactory.class)
|
||||
// end providers needed for import
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public void updateConfig(Config cf) {
|
||||
cf.spi(MapStorageSpi.NAME)
|
||||
.defaultProvider(ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.provider(ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("dir", "${project.build.directory:target}");
|
||||
}
|
||||
|
||||
public ConcurrentHashMapStorage() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023 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.parameters;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Set;
|
||||
import org.keycloak.authorization.store.StoreFactorySpi;
|
||||
import org.keycloak.events.EventStoreSpi;
|
||||
import org.keycloak.models.DeploymentStateSpi;
|
||||
import org.keycloak.models.SingleUseObjectSpi;
|
||||
import org.keycloak.models.UserLoginFailureSpi;
|
||||
import org.keycloak.models.UserSessionSpi;
|
||||
import org.keycloak.models.map.authSession.MapRootAuthenticationSessionProviderFactory;
|
||||
import org.keycloak.models.map.authorization.MapAuthorizationStoreFactory;
|
||||
import org.keycloak.models.map.client.MapClientProviderFactory;
|
||||
import org.keycloak.models.map.clientscope.MapClientScopeProviderFactory;
|
||||
import org.keycloak.models.map.deploymentState.MapDeploymentStateProviderFactory;
|
||||
import org.keycloak.models.map.events.MapEventStoreProviderFactory;
|
||||
import org.keycloak.models.map.group.MapGroupProviderFactory;
|
||||
import org.keycloak.models.map.keys.MapPublicKeyStorageProviderFactory;
|
||||
import org.keycloak.models.map.loginFailure.MapUserLoginFailureProviderFactory;
|
||||
import org.keycloak.models.map.realm.MapRealmProviderFactory;
|
||||
import org.keycloak.models.map.role.MapRoleProviderFactory;
|
||||
import org.keycloak.models.map.singleUseObject.MapSingleUseObjectProviderFactory;
|
||||
import org.keycloak.models.map.storage.MapStorageSpi;
|
||||
import org.keycloak.models.map.storage.chm.ConcurrentHashMapStorageProviderFactory;
|
||||
import org.keycloak.models.map.storage.file.FileMapStorageProviderFactory;
|
||||
import org.keycloak.models.map.user.MapUserProviderFactory;
|
||||
import org.keycloak.models.map.userSession.MapUserSessionProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.sessions.AuthenticationSessionSpi;
|
||||
import org.keycloak.testsuite.model.Config;
|
||||
import org.keycloak.testsuite.model.KeycloakModelParameters;
|
||||
|
||||
public class FileMapStorage extends KeycloakModelParameters {
|
||||
|
||||
static final Set<Class<? extends Spi>> ALLOWED_SPIS = ImmutableSet.<Class<? extends Spi>>builder()
|
||||
.build();
|
||||
|
||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
.add(FileMapStorageProviderFactory.class)
|
||||
.add(ConcurrentHashMapStorageProviderFactory.class)
|
||||
.build();
|
||||
|
||||
public FileMapStorage() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateConfig(Config cf) {
|
||||
cf.spi(MapStorageSpi.NAME)
|
||||
.provider(FileMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("dir", "${project.build.directory:target/file}")
|
||||
.provider(ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("dir", "${project.build.directory:target/chm}")
|
||||
|
||||
.spi(AuthenticationSessionSpi.PROVIDER_ID).provider(MapRootAuthenticationSessionProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, FileMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("client").provider(MapClientProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, FileMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("clientScope").provider(MapClientScopeProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, FileMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("group").provider(MapGroupProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, FileMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("realm").provider(MapRealmProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, FileMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("role").provider(MapRoleProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, FileMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(DeploymentStateSpi.NAME).provider(MapDeploymentStateProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(StoreFactorySpi.NAME).provider(MapAuthorizationStoreFactory.PROVIDER_ID) .config(STORAGE_CONFIG, FileMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("user").provider(MapUserProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, FileMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(UserLoginFailureSpi.NAME).provider(MapUserLoginFailureProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, FileMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(SingleUseObjectSpi.NAME).provider(MapSingleUseObjectProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("publicKeyStorage").provider(MapPublicKeyStorageProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(UserSessionSpi.NAME).provider(MapUserSessionProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, FileMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(EventStoreSpi.NAME).provider(MapEventStoreProviderFactory.PROVIDER_ID) .config("storage-admin-events.provider", FileMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("storage-auth-events.provider", FileMapStorageProviderFactory.PROVIDER_ID);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.parameters;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.authorization.store.StoreFactorySpi;
|
||||
import org.keycloak.events.EventStoreSpi;
|
||||
import org.keycloak.models.DeploymentStateSpi;
|
||||
import org.keycloak.models.SingleUseObjectSpi;
|
||||
import org.keycloak.models.UserLoginFailureSpi;
|
||||
import org.keycloak.models.UserSessionSpi;
|
||||
import org.keycloak.models.locking.GlobalLockProviderSpi;
|
||||
import org.keycloak.models.locking.NoneGlobalLockProviderFactory;
|
||||
import org.keycloak.models.map.authSession.MapRootAuthenticationSessionProviderFactory;
|
||||
import org.keycloak.models.map.authorization.MapAuthorizationStoreFactory;
|
||||
import org.keycloak.models.map.client.MapClientProviderFactory;
|
||||
import org.keycloak.models.map.clientscope.MapClientScopeProviderFactory;
|
||||
import org.keycloak.models.map.keys.MapPublicKeyStorageProviderFactory;
|
||||
import org.keycloak.models.map.singleUseObject.MapSingleUseObjectProviderFactory;
|
||||
import org.keycloak.models.map.storage.hotRod.connections.DefaultHotRodConnectionProviderFactory;
|
||||
import org.keycloak.models.map.storage.hotRod.connections.HotRodConnectionProviderFactory;
|
||||
import org.keycloak.models.map.storage.hotRod.connections.HotRodConnectionSpi;
|
||||
import org.keycloak.models.map.deploymentState.MapDeploymentStateProviderFactory;
|
||||
import org.keycloak.models.map.group.MapGroupProviderFactory;
|
||||
import org.keycloak.models.map.loginFailure.MapUserLoginFailureProviderFactory;
|
||||
import org.keycloak.models.map.realm.MapRealmProviderFactory;
|
||||
import org.keycloak.models.map.role.MapRoleProviderFactory;
|
||||
import org.keycloak.models.map.storage.MapStorageSpi;
|
||||
import org.keycloak.models.map.storage.chm.ConcurrentHashMapStorageProviderFactory;
|
||||
import org.keycloak.models.map.storage.hotRod.HotRodMapStorageProviderFactory;
|
||||
import org.keycloak.models.map.storage.hotRod.locking.HotRodGlobalLockProviderFactory;
|
||||
import org.keycloak.models.map.user.MapUserProviderFactory;
|
||||
import org.keycloak.models.map.userSession.MapUserSessionProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.sessions.AuthenticationSessionSpi;
|
||||
import org.keycloak.testsuite.model.Config;
|
||||
import org.keycloak.testsuite.model.KeycloakModelParameters;
|
||||
import org.keycloak.testsuite.util.InfinispanContainer;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.keycloak.testsuite.model.transaction.StorageTransactionTest.LOCK_TIMEOUT_SYSTEM_PROPERTY;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class HotRodMapStorage extends KeycloakModelParameters {
|
||||
|
||||
private final Logger LOG = Logger.getLogger(getClass());
|
||||
public static final Boolean START_CONTAINER = Boolean.valueOf(System.getProperty("keycloak.testsuite.start-hotrod-container", "true"));
|
||||
static final Set<Class<? extends Spi>> ALLOWED_SPIS = ImmutableSet.<Class<? extends Spi>>builder()
|
||||
.add(HotRodConnectionSpi.class)
|
||||
.build();
|
||||
|
||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
.add(HotRodMapStorageProviderFactory.class)
|
||||
.add(HotRodConnectionProviderFactory.class)
|
||||
.add(HotRodGlobalLockProviderFactory.class)
|
||||
.build();
|
||||
|
||||
private final InfinispanContainer hotRodContainer = new InfinispanContainer();
|
||||
|
||||
@Override
|
||||
public void updateConfig(Config cf) {
|
||||
cf.spi(AuthenticationSessionSpi.PROVIDER_ID).provider(MapRootAuthenticationSessionProviderFactory.PROVIDER_ID).config(STORAGE_CONFIG, HotRodMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(SingleUseObjectSpi.NAME).provider(MapSingleUseObjectProviderFactory.PROVIDER_ID).config(STORAGE_CONFIG, HotRodMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("publicKeyStorage").provider(MapPublicKeyStorageProviderFactory.PROVIDER_ID).config(STORAGE_CONFIG, ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("client").provider(MapClientProviderFactory.PROVIDER_ID).config(STORAGE_CONFIG, HotRodMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("clientScope").provider(MapClientScopeProviderFactory.PROVIDER_ID).config(STORAGE_CONFIG, HotRodMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("group").provider(MapGroupProviderFactory.PROVIDER_ID).config(STORAGE_CONFIG, HotRodMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("realm").provider(MapRealmProviderFactory.PROVIDER_ID).config(STORAGE_CONFIG, HotRodMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("role").provider(MapRoleProviderFactory.PROVIDER_ID).config(STORAGE_CONFIG, HotRodMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(DeploymentStateSpi.NAME).provider(MapDeploymentStateProviderFactory.PROVIDER_ID).config(STORAGE_CONFIG, ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(StoreFactorySpi.NAME).provider(MapAuthorizationStoreFactory.PROVIDER_ID).config(STORAGE_CONFIG, HotRodMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("user").provider(MapUserProviderFactory.PROVIDER_ID).config(STORAGE_CONFIG, HotRodMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(UserSessionSpi.NAME).provider(MapUserSessionProviderFactory.PROVIDER_ID).config(STORAGE_CONFIG, HotRodMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(UserLoginFailureSpi.NAME).provider(MapUserLoginFailureProviderFactory.PROVIDER_ID).config(STORAGE_CONFIG, HotRodMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(EventStoreSpi.NAME).provider(MapUserSessionProviderFactory.PROVIDER_ID).config("storage-admin-events.provider", HotRodMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("storage-auth-events.provider", HotRodMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(GlobalLockProviderSpi.GLOBAL_LOCK).defaultProvider(HotRodGlobalLockProviderFactory.PROVIDER_ID);
|
||||
|
||||
cf.spi(MapStorageSpi.NAME)
|
||||
.provider(ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("dir", "${project.build.directory:target}")
|
||||
.config("keyType.single-use-objects", "string");
|
||||
|
||||
cf.spi(HotRodConnectionSpi.NAME).provider(DefaultHotRodConnectionProviderFactory.PROVIDER_ID)
|
||||
.config("host", hotRodContainer.getHost())
|
||||
.config("port", hotRodContainer.getPort())
|
||||
.config("username", hotRodContainer.getUsername())
|
||||
.config("password", hotRodContainer.getPassword())
|
||||
.config("configureRemoteCaches", "true")
|
||||
.config("lockTimeout", "${" + LOCK_TIMEOUT_SYSTEM_PROPERTY + ":}");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeSuite(Config cf) {
|
||||
if (START_CONTAINER) {
|
||||
hotRodContainer.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSuite() {
|
||||
if (START_CONTAINER) {
|
||||
hotRodContainer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public HotRodMapStorage() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.parameters;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Set;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.authorization.store.StoreFactorySpi;
|
||||
import org.keycloak.events.EventStoreSpi;
|
||||
import org.keycloak.models.DeploymentStateSpi;
|
||||
import org.keycloak.models.SingleUseObjectSpi;
|
||||
import org.keycloak.models.UserLoginFailureSpi;
|
||||
import org.keycloak.models.UserSessionSpi;
|
||||
import org.keycloak.models.locking.GlobalLockProviderSpi;
|
||||
import org.keycloak.models.map.authSession.MapRootAuthenticationSessionProviderFactory;
|
||||
import org.keycloak.models.map.authorization.MapAuthorizationStoreFactory;
|
||||
import org.keycloak.models.map.client.MapClientProviderFactory;
|
||||
import org.keycloak.models.map.clientscope.MapClientScopeProviderFactory;
|
||||
import org.keycloak.models.map.deploymentState.MapDeploymentStateProviderFactory;
|
||||
import org.keycloak.models.map.events.MapEventStoreProviderFactory;
|
||||
import org.keycloak.models.map.group.MapGroupProviderFactory;
|
||||
import org.keycloak.models.map.keys.MapPublicKeyStorageProviderFactory;
|
||||
import org.keycloak.models.map.loginFailure.MapUserLoginFailureProviderFactory;
|
||||
import org.keycloak.models.map.realm.MapRealmProviderFactory;
|
||||
import org.keycloak.models.map.role.MapRoleProviderFactory;
|
||||
import org.keycloak.models.map.singleUseObject.MapSingleUseObjectProviderFactory;
|
||||
import org.keycloak.models.map.storage.MapStorageSpi;
|
||||
import org.keycloak.models.map.storage.chm.ConcurrentHashMapStorageProviderFactory;
|
||||
import org.keycloak.models.map.lock.MapGlobalLockProviderFactory;
|
||||
import org.keycloak.models.map.storage.jpa.JpaMapStorageProviderFactory;
|
||||
import org.keycloak.models.map.storage.jpa.liquibase.connection.MapLiquibaseConnectionProviderFactory;
|
||||
import org.keycloak.models.map.storage.jpa.liquibase.connection.MapLiquibaseConnectionSpi;
|
||||
import org.keycloak.models.map.storage.jpa.updater.MapJpaUpdaterProviderFactory;
|
||||
import org.keycloak.models.map.storage.jpa.updater.MapJpaUpdaterSpi;
|
||||
import org.keycloak.models.map.user.MapUserProviderFactory;
|
||||
import org.keycloak.models.map.userSession.MapUserSessionProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.sessions.AuthenticationSessionSpi;
|
||||
import org.keycloak.testsuite.model.Config;
|
||||
import org.keycloak.testsuite.model.KeycloakModelParameters;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
import static org.keycloak.testsuite.model.transaction.StorageTransactionTest.LOCK_TIMEOUT_SYSTEM_PROPERTY;
|
||||
|
||||
public class JpaMapStorage extends KeycloakModelParameters {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(JpaMapStorage.class.getName());
|
||||
|
||||
private static final Boolean START_CONTAINER = Boolean.valueOf(System.getProperty("postgres.start-container", "true"));
|
||||
private static final String POSTGRES_DOCKER_IMAGE_NAME = System.getProperty("keycloak.map.storage.postgres.docker.image", "postgres:alpine");
|
||||
private static final PostgreSQLContainer POSTGRES_CONTAINER = new PostgreSQLContainer(DockerImageName.parse(POSTGRES_DOCKER_IMAGE_NAME).asCompatibleSubstituteFor("postgres"));
|
||||
private static final String POSTGRES_DB_DEFAULT_NAME = System.getProperty("keycloak.map.storage.connectionsJpa.databaseName", "keycloak");
|
||||
private static final String POSTGRES_DB_USER = System.getProperty("keycloak.map.storage.connectionsJpa.user", "keycloak");
|
||||
private static final String POSTGRES_DB_PASSWORD = System.getProperty("keycloak.map.storage.connectionsJpa.password", "pass");
|
||||
|
||||
private static String POSTGRES_DB_JDBC_URL = System.getProperty("keycloak.map.storage.connectionsJpa.url");
|
||||
|
||||
static final Set<Class<? extends Spi>> ALLOWED_SPIS = ImmutableSet.<Class<? extends Spi>>builder()
|
||||
.add(MapJpaUpdaterSpi.class)
|
||||
.add(MapLiquibaseConnectionSpi.class)
|
||||
.build();
|
||||
|
||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
.add(ConcurrentHashMapStorageProviderFactory.class)
|
||||
.add(JpaMapStorageProviderFactory.class)
|
||||
.add(MapJpaUpdaterProviderFactory.class)
|
||||
.add(MapLiquibaseConnectionProviderFactory.class)
|
||||
.add(MapGlobalLockProviderFactory.class)
|
||||
.build();
|
||||
|
||||
public JpaMapStorage() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateConfig(Config cf) {
|
||||
cf.spi(MapStorageSpi.NAME)
|
||||
.provider(ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("dir", "${project.build.directory:target}");
|
||||
|
||||
cf.spi(MapStorageSpi.NAME)
|
||||
.provider(JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("url", POSTGRES_DB_JDBC_URL)
|
||||
.config("user", POSTGRES_DB_USER)
|
||||
.config("password", POSTGRES_DB_PASSWORD)
|
||||
.config("driver", "org.postgresql.Driver")
|
||||
.config("lockTimeout", "${" + LOCK_TIMEOUT_SYSTEM_PROPERTY + ":}");
|
||||
|
||||
cf.spi(AuthenticationSessionSpi.PROVIDER_ID).provider(MapRootAuthenticationSessionProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("client").provider(MapClientProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("clientScope").provider(MapClientScopeProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("group").provider(MapGroupProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("realm").provider(MapRealmProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("role").provider(MapRoleProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(DeploymentStateSpi.NAME).provider(MapDeploymentStateProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(StoreFactorySpi.NAME).provider(MapAuthorizationStoreFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("user").provider(MapUserProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(UserLoginFailureSpi.NAME).provider(MapUserLoginFailureProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(SingleUseObjectSpi.NAME).provider(MapSingleUseObjectProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("publicKeyStorage").provider(MapPublicKeyStorageProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(UserSessionSpi.NAME).provider(MapUserSessionProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(EventStoreSpi.NAME).provider(MapEventStoreProviderFactory.PROVIDER_ID) .config("storage-admin-events.provider", JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("storage-auth-events.provider", JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(GlobalLockProviderSpi.GLOBAL_LOCK) .config("provider", MapGlobalLockProviderFactory.PROVIDER_ID)
|
||||
.spi(GlobalLockProviderSpi.GLOBAL_LOCK).provider(MapGlobalLockProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeSuite(Config cf) {
|
||||
if (START_CONTAINER) {
|
||||
POSTGRES_CONTAINER
|
||||
.withDatabaseName(POSTGRES_DB_DEFAULT_NAME)
|
||||
.withUsername(POSTGRES_DB_USER)
|
||||
.withPassword(POSTGRES_DB_PASSWORD)
|
||||
.start();
|
||||
|
||||
POSTGRES_DB_JDBC_URL = POSTGRES_CONTAINER.getJdbcUrl();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSuite() {
|
||||
if (START_CONTAINER) {
|
||||
POSTGRES_CONTAINER.stop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* Copyright 2022 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.parameters;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.keycloak.authorization.store.StoreFactorySpi;
|
||||
import org.keycloak.events.EventStoreSpi;
|
||||
import org.keycloak.models.DeploymentStateSpi;
|
||||
import org.keycloak.models.SingleUseObjectSpi;
|
||||
import org.keycloak.models.UserLoginFailureSpi;
|
||||
import org.keycloak.models.UserSessionSpi;
|
||||
import org.keycloak.models.locking.GlobalLockProviderSpi;
|
||||
import org.keycloak.models.map.authSession.MapRootAuthenticationSessionProviderFactory;
|
||||
import org.keycloak.models.map.authorization.MapAuthorizationStoreFactory;
|
||||
import org.keycloak.models.map.client.MapClientProviderFactory;
|
||||
import org.keycloak.models.map.clientscope.MapClientScopeProviderFactory;
|
||||
import org.keycloak.models.map.deploymentState.MapDeploymentStateProviderFactory;
|
||||
import org.keycloak.models.map.events.MapEventStoreProviderFactory;
|
||||
import org.keycloak.models.map.group.MapGroupProviderFactory;
|
||||
import org.keycloak.models.map.keys.MapPublicKeyStorageProviderFactory;
|
||||
import org.keycloak.models.map.lock.MapGlobalLockProviderFactory;
|
||||
import org.keycloak.models.map.loginFailure.MapUserLoginFailureProviderFactory;
|
||||
import org.keycloak.models.map.realm.MapRealmProviderFactory;
|
||||
import org.keycloak.models.map.role.MapRoleProviderFactory;
|
||||
import org.keycloak.models.map.singleUseObject.MapSingleUseObjectProviderFactory;
|
||||
import org.keycloak.models.map.storage.MapStorageSpi;
|
||||
import org.keycloak.models.map.storage.chm.ConcurrentHashMapStorageProviderFactory;
|
||||
import org.keycloak.models.map.storage.jpa.JpaMapStorageProviderFactory;
|
||||
import org.keycloak.models.map.storage.jpa.liquibase.connection.MapLiquibaseConnectionProviderFactory;
|
||||
import org.keycloak.models.map.storage.jpa.liquibase.connection.MapLiquibaseConnectionSpi;
|
||||
import org.keycloak.models.map.storage.jpa.updater.MapJpaUpdaterProviderFactory;
|
||||
import org.keycloak.models.map.storage.jpa.updater.MapJpaUpdaterSpi;
|
||||
import org.keycloak.models.map.user.MapUserProviderFactory;
|
||||
import org.keycloak.models.map.userSession.MapUserSessionProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.sessions.AuthenticationSessionSpi;
|
||||
import org.keycloak.testsuite.model.Config;
|
||||
import org.keycloak.testsuite.model.KeycloakModelParameters;
|
||||
import org.keycloak.testsuite.model.KeycloakModelTest;
|
||||
import org.testcontainers.containers.CockroachContainer;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static org.keycloak.testsuite.model.transaction.StorageTransactionTest.LOCK_TIMEOUT_SYSTEM_PROPERTY;
|
||||
|
||||
public class JpaMapStorageCockroachdb extends KeycloakModelParameters {
|
||||
|
||||
private static final Boolean START_CONTAINER = Boolean.valueOf(System.getProperty("cockroachdb.start-container", "true"));
|
||||
private static final String COCKROACHDB_DOCKER_IMAGE_NAME = System.getProperty("keycloak.map.storage.cockroachdb.docker.image", "cockroachdb/cockroach:v22.1.0");
|
||||
private static final CockroachContainer COCKROACHDB_CONTAINER = new CockroachContainer(DockerImageName.parse(COCKROACHDB_DOCKER_IMAGE_NAME).asCompatibleSubstituteFor("cockroachdb"));
|
||||
private static final String COCKROACHDB_DB_USER = System.getProperty("keycloak.map.storage.connectionsJpa.user", "keycloak");
|
||||
private static final String COCKROACHDB_DB_PASSWORD = System.getProperty("keycloak.map.storage.connectionsJpa.password", "pass");
|
||||
|
||||
private static String COCKROACHDB_DB_JDBC_URL = System.getProperty("keycloak.map.storage.connectionsJpa.url");
|
||||
|
||||
static final Set<Class<? extends Spi>> ALLOWED_SPIS = ImmutableSet.<Class<? extends Spi>>builder()
|
||||
.add(MapJpaUpdaterSpi.class)
|
||||
.add(MapLiquibaseConnectionSpi.class)
|
||||
.build();
|
||||
|
||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
.add(ConcurrentHashMapStorageProviderFactory.class)
|
||||
.add(JpaMapStorageProviderFactory.class)
|
||||
.add(MapJpaUpdaterProviderFactory.class)
|
||||
.add(MapLiquibaseConnectionProviderFactory.class)
|
||||
.add(MapGlobalLockProviderFactory.class)
|
||||
.build();
|
||||
|
||||
public JpaMapStorageCockroachdb() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateConfig(Config cf) {
|
||||
cf.spi(MapStorageSpi.NAME)
|
||||
.provider(ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("dir", "${project.build.directory:target}");
|
||||
|
||||
cf.spi(MapStorageSpi.NAME)
|
||||
.provider(JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("url", COCKROACHDB_DB_JDBC_URL)
|
||||
.config("user", COCKROACHDB_DB_USER)
|
||||
.config("password", COCKROACHDB_DB_PASSWORD)
|
||||
.config("driver", "org.postgresql.Driver")
|
||||
.config("lockTimeout", "${" + LOCK_TIMEOUT_SYSTEM_PROPERTY + ":}");
|
||||
|
||||
cf.spi(AuthenticationSessionSpi.PROVIDER_ID).provider(MapRootAuthenticationSessionProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("client").provider(MapClientProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("clientScope").provider(MapClientScopeProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("group").provider(MapGroupProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("realm").provider(MapRealmProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("role").provider(MapRoleProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(DeploymentStateSpi.NAME).provider(MapDeploymentStateProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(StoreFactorySpi.NAME).provider(MapAuthorizationStoreFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("user").provider(MapUserProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(UserLoginFailureSpi.NAME).provider(MapUserLoginFailureProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(SingleUseObjectSpi.NAME).provider(MapSingleUseObjectProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("publicKeyStorage").provider(MapPublicKeyStorageProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(UserSessionSpi.NAME).provider(MapUserSessionProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(EventStoreSpi.NAME).provider(MapEventStoreProviderFactory.PROVIDER_ID) .config("storage-admin-events.provider", JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("storage-auth-events.provider", JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(GlobalLockProviderSpi.GLOBAL_LOCK) .config("provider", MapGlobalLockProviderFactory.PROVIDER_ID)
|
||||
.spi(GlobalLockProviderSpi.GLOBAL_LOCK).provider(MapGlobalLockProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeSuite(Config cf) {
|
||||
if (START_CONTAINER) {
|
||||
COCKROACHDB_CONTAINER
|
||||
// Using the environment variables for now where using the withXXX() method is not supported, yet.
|
||||
// https://github.com/testcontainers/testcontainers-java/issues/6299
|
||||
.withEnv("COCKROACH_DATABASE", "keycloak")
|
||||
.withEnv("COCKROACH_USER", COCKROACHDB_DB_USER)
|
||||
// password is not used/supported in insecure mode
|
||||
.withCommand("start-single-node", "--insecure")
|
||||
.start();
|
||||
|
||||
COCKROACHDB_DB_JDBC_URL = COCKROACHDB_CONTAINER.getJdbcUrl();
|
||||
}
|
||||
System.setProperty(KeycloakModelTest.KEYCLOAK_MODELTESTS_RETRY_TRANSACTIONS, "true");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSuite() {
|
||||
if (START_CONTAINER) {
|
||||
COCKROACHDB_CONTAINER.stop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.parameters;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.keycloak.authorization.store.StoreFactorySpi;
|
||||
import org.keycloak.events.EventStoreSpi;
|
||||
import org.keycloak.models.DeploymentStateSpi;
|
||||
import org.keycloak.models.LDAPConstants;
|
||||
import org.keycloak.models.SingleUseObjectSpi;
|
||||
import org.keycloak.models.UserLoginFailureSpi;
|
||||
import org.keycloak.models.UserSessionSpi;
|
||||
import org.keycloak.models.map.storage.MapStorageSpi;
|
||||
import org.keycloak.models.map.storage.chm.ConcurrentHashMapStorageProviderFactory;
|
||||
import org.keycloak.models.map.storage.ldap.LdapMapStorageProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.testsuite.model.Config;
|
||||
import org.keycloak.testsuite.model.KeycloakModelParameters;
|
||||
import org.keycloak.testsuite.util.LDAPRule;
|
||||
import org.keycloak.util.ldap.LDAPEmbeddedServer;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Alexander Schwartz
|
||||
*/
|
||||
public class LdapMapStorage extends KeycloakModelParameters {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(LdapMapStorage.class.getName());
|
||||
|
||||
static final Set<Class<? extends Spi>> ALLOWED_SPIS = ImmutableSet.<Class<? extends Spi>>builder()
|
||||
.build();
|
||||
|
||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
.add(ConcurrentHashMapStorageProviderFactory.class)
|
||||
.add(LdapMapStorageProviderFactory.class)
|
||||
.build();
|
||||
|
||||
private final LDAPRule ldapRule = new LDAPRule();
|
||||
|
||||
public LdapMapStorage() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateConfig(Config cf) {
|
||||
cf.spi(MapStorageSpi.NAME)
|
||||
.provider(ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("dir", "${project.build.directory:target}");
|
||||
|
||||
cf.spi(MapStorageSpi.NAME)
|
||||
.provider(LdapMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("vendor", "other")
|
||||
.config("usernameLDAPAttribute", "uid")
|
||||
.config("rdnLDAPAttribute", "uid")
|
||||
.config("uuidLDAPAttribute", "entryUUID")
|
||||
.config("userObjectClasses", "inetOrgPerson, organizationalPerson")
|
||||
.config("connectionUrl", "ldap://localhost:10389")
|
||||
.config("usersDn", "ou=People,dc=keycloak,dc=org")
|
||||
.config("bindDn", "uid=admin,ou=system")
|
||||
.config("bindCredential", "secret")
|
||||
.config("roles.realm.dn", "ou=RealmRoles,dc=keycloak,dc=org")
|
||||
.config("roles.client.dn", "ou={0},dc=keycloak,dc=org")
|
||||
.config("roles.common.dn", "dc=keycloak,dc=org") // this is the top DN that finds both client and realm roles
|
||||
.config("membership.ldap.attribute", "member")
|
||||
.config("role.name.ldap.attribute", "cn")
|
||||
.config("role.object.classes", "groupOfNames")
|
||||
.config("role.attributes", "ou")
|
||||
.config("mode", "LDAP_ONLY")
|
||||
.config("use.realm.roles.mapping", "true")
|
||||
.config(LDAPConstants.CONNECTION_POOLING, "true");
|
||||
|
||||
cf.spi("client").config("map.storage.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("clientScope").config("map.storage.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("group").config("map.storage.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("realm").config("map.storage.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("role").config("map.storage.provider", LdapMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(DeploymentStateSpi.NAME).config("map.storage.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(StoreFactorySpi.NAME).config("map.storage.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("user").config("map.storage.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(UserSessionSpi.NAME).config("map.storage.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(UserLoginFailureSpi.NAME).config("map.storage.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("authorizationPersister").config("map.storage.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("authenticationSessions").config("map.storage.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(EventStoreSpi.NAME).config("map.storage-admin-events.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(EventStoreSpi.NAME).config("map.storage-auth-events.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(SingleUseObjectSpi.NAME).config("map.storage.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi("publicKeyStorage").config("map.storage.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID);
|
||||
|
||||
}
|
||||
|
||||
static {
|
||||
System.setProperty(LDAPEmbeddedServer.PROPERTY_ENABLE_SSL, "false");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement classRule(Statement base, Description description) {
|
||||
return ldapRule.apply(base, description);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.parameters;
|
||||
|
||||
import org.keycloak.authorization.store.StoreFactorySpi;
|
||||
import org.keycloak.events.EventStoreSpi;
|
||||
import org.keycloak.keys.PublicKeyStorageSpi;
|
||||
import org.keycloak.models.DeploymentStateSpi;
|
||||
import org.keycloak.models.SingleUseObjectProviderFactory;
|
||||
import org.keycloak.models.SingleUseObjectSpi;
|
||||
import org.keycloak.models.UserLoginFailureSpi;
|
||||
import org.keycloak.models.UserSessionSpi;
|
||||
import org.keycloak.models.locking.GlobalLockProviderSpi;
|
||||
import org.keycloak.models.locking.NoneGlobalLockProviderFactory;
|
||||
import org.keycloak.models.map.authSession.MapRootAuthenticationSessionProviderFactory;
|
||||
import org.keycloak.models.map.authorization.MapAuthorizationStoreFactory;
|
||||
import org.keycloak.models.map.events.MapEventStoreProviderFactory;
|
||||
import org.keycloak.models.map.keys.MapPublicKeyStorageProviderFactory;
|
||||
import org.keycloak.models.map.loginFailure.MapUserLoginFailureProviderFactory;
|
||||
import org.keycloak.models.map.singleUseObject.MapSingleUseObjectProviderFactory;
|
||||
import org.keycloak.models.map.storage.chm.ConcurrentHashMapStorageProviderFactory;
|
||||
import org.keycloak.models.map.userSession.MapUserSessionProviderFactory;
|
||||
import org.keycloak.sessions.AuthenticationSessionSpi;
|
||||
import org.keycloak.testsuite.model.KeycloakModelParameters;
|
||||
import org.keycloak.models.map.client.MapClientProviderFactory;
|
||||
import org.keycloak.models.map.clientscope.MapClientScopeProviderFactory;
|
||||
import org.keycloak.models.map.group.MapGroupProviderFactory;
|
||||
import org.keycloak.models.map.realm.MapRealmProviderFactory;
|
||||
import org.keycloak.models.map.role.MapRoleProviderFactory;
|
||||
import org.keycloak.models.map.deploymentState.MapDeploymentStateProviderFactory;
|
||||
import org.keycloak.models.map.storage.MapStorageSpi;
|
||||
import org.keycloak.models.map.user.MapUserProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.testsuite.model.Config;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class Map extends KeycloakModelParameters {
|
||||
|
||||
static final Set<Class<? extends Spi>> ALLOWED_SPIS = ImmutableSet.<Class<? extends Spi>>builder()
|
||||
.add(AuthenticationSessionSpi.class)
|
||||
.add(SingleUseObjectSpi.class)
|
||||
.add(PublicKeyStorageSpi.class)
|
||||
.add(MapStorageSpi.class)
|
||||
|
||||
.build();
|
||||
|
||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
.add(MapAuthorizationStoreFactory.class)
|
||||
.add(MapClientProviderFactory.class)
|
||||
.add(MapClientScopeProviderFactory.class)
|
||||
.add(MapGroupProviderFactory.class)
|
||||
.add(MapRealmProviderFactory.class)
|
||||
.add(MapRoleProviderFactory.class)
|
||||
.add(MapRootAuthenticationSessionProviderFactory.class)
|
||||
.add(MapDeploymentStateProviderFactory.class)
|
||||
.add(MapUserProviderFactory.class)
|
||||
.add(MapUserSessionProviderFactory.class)
|
||||
.add(MapUserLoginFailureProviderFactory.class)
|
||||
.add(NoneGlobalLockProviderFactory.class)
|
||||
.add(MapEventStoreProviderFactory.class)
|
||||
.add(SingleUseObjectProviderFactory.class)
|
||||
.add(MapPublicKeyStorageProviderFactory.class)
|
||||
.build();
|
||||
|
||||
public Map() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateConfig(Config cf) {
|
||||
cf.spi(AuthenticationSessionSpi.PROVIDER_ID).defaultProvider(MapRootAuthenticationSessionProviderFactory.PROVIDER_ID)
|
||||
.spi(SingleUseObjectSpi.NAME).defaultProvider(MapSingleUseObjectProviderFactory.PROVIDER_ID)
|
||||
.spi("client").defaultProvider(MapClientProviderFactory.PROVIDER_ID)
|
||||
.spi("clientScope").defaultProvider(MapClientScopeProviderFactory.PROVIDER_ID)
|
||||
.spi("group").defaultProvider(MapGroupProviderFactory.PROVIDER_ID)
|
||||
.spi("realm").defaultProvider(MapRealmProviderFactory.PROVIDER_ID)
|
||||
.spi("role").defaultProvider(MapRoleProviderFactory.PROVIDER_ID)
|
||||
.spi(DeploymentStateSpi.NAME).defaultProvider(MapDeploymentStateProviderFactory.PROVIDER_ID)
|
||||
.spi(StoreFactorySpi.NAME).defaultProvider(MapAuthorizationStoreFactory.PROVIDER_ID)
|
||||
.spi("user").defaultProvider(MapUserProviderFactory.PROVIDER_ID)
|
||||
.spi(UserSessionSpi.NAME).defaultProvider(MapUserSessionProviderFactory.PROVIDER_ID)
|
||||
.spi(UserLoginFailureSpi.NAME).defaultProvider(MapUserLoginFailureProviderFactory.PROVIDER_ID)
|
||||
.spi(GlobalLockProviderSpi.GLOBAL_LOCK).defaultProvider(NoneGlobalLockProviderFactory.PROVIDER_ID)
|
||||
.spi(EventStoreSpi.NAME).defaultProvider(MapEventStoreProviderFactory.PROVIDER_ID)
|
||||
.spi("publicKeyStorage").defaultProvider(MapPublicKeyStorageProviderFactory.PROVIDER_ID)
|
||||
;
|
||||
cf.spi(MapStorageSpi.NAME).provider(ConcurrentHashMapStorageProviderFactory.PROVIDER_ID).config("keyType.single-use-objects", "string");
|
||||
}
|
||||
}
|
|
@ -1,180 +0,0 @@
|
|||
/*
|
||||
* Copyright 2022 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.session;
|
||||
|
||||
import org.infinispan.client.hotrod.RemoteCache;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.AuthenticatedClientSessionModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.UserSessionProvider;
|
||||
import org.keycloak.models.map.storage.ModelEntityUtil;
|
||||
import org.keycloak.models.map.storage.hotRod.connections.DefaultHotRodConnectionProviderFactory;
|
||||
import org.keycloak.models.map.storage.hotRod.connections.HotRodConnectionProvider;
|
||||
import org.keycloak.models.map.storage.hotRod.userSession.HotRodUserSessionEntity;
|
||||
import org.keycloak.testsuite.model.KeycloakModelTest;
|
||||
import org.keycloak.testsuite.model.RequireProvider;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.aMapWithSize;
|
||||
import static org.hamcrest.Matchers.anEmptyMap;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.keycloak.protocol.oidc.OIDCConfigAttributes.CLIENT_SESSION_IDLE_TIMEOUT;
|
||||
import static org.keycloak.protocol.oidc.OIDCConfigAttributes.CLIENT_SESSION_MAX_LIFESPAN;
|
||||
|
||||
@RequireProvider(UserSessionProvider.class)
|
||||
@RequireProvider(value = HotRodConnectionProvider.class, only = DefaultHotRodConnectionProviderFactory.PROVIDER_ID)
|
||||
public class HotRodUserSessionClientSessionRelationshipTest extends KeycloakModelTest {
|
||||
|
||||
private String realmId;
|
||||
private String CLIENT0_CLIENT_ID = "client0";
|
||||
|
||||
@Override
|
||||
public void createEnvironment(KeycloakSession s) {
|
||||
RealmModel realm = createRealm(s, "test");
|
||||
realm.setDefaultRole(s.roles().addRealmRole(realm, Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + realm.getName()));
|
||||
realm.setSsoSessionIdleTimeout(1800);
|
||||
realm.setSsoSessionMaxLifespan(36000);
|
||||
this.realmId = realm.getId();
|
||||
s.clients().addClient(realm, CLIENT0_CLIENT_ID);
|
||||
|
||||
s.users().addUser(realm, "user1").setEmail("user1@localhost");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanEnvironment(KeycloakSession s) {
|
||||
if (realmId != null) {
|
||||
s.realms().removeRealm(realmId);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientSessionAreRemovedOnUserSessionRemoval() {
|
||||
AtomicReference<String> uSessionId = new AtomicReference<>();
|
||||
AtomicReference<String> cSessionId = new AtomicReference<>();
|
||||
prepareSessions(uSessionId, cSessionId);
|
||||
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
UserSessionModel uSession = session.sessions().getUserSession(realm, uSessionId.get());
|
||||
session.sessions().removeUserSession(realm, uSession);
|
||||
return null;
|
||||
});
|
||||
|
||||
assertCacheContains(remoteCache -> assertThat(remoteCache, anEmptyMap()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSessionsAreRemovedOnUserRemoval() {
|
||||
AtomicReference<String> uSessionId = new AtomicReference<>();
|
||||
AtomicReference<String> cSessionId = new AtomicReference<>();
|
||||
prepareSessions(uSessionId, cSessionId);
|
||||
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
session.users().removeUser(realm, session.users().getUserByUsername(realm, "user1"));
|
||||
return null;
|
||||
});
|
||||
|
||||
assertCacheContains(remoteCache -> {
|
||||
assertThat(remoteCache, anEmptyMap());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSessionsAreRemovedOnRealmRemoval() {
|
||||
AtomicReference<String> uSessionId = new AtomicReference<>();
|
||||
AtomicReference<String> cSessionId = new AtomicReference<>();
|
||||
prepareSessions(uSessionId, cSessionId);
|
||||
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
session.realms().removeRealm(realm.getId());
|
||||
return null;
|
||||
});
|
||||
|
||||
assertCacheContains(remoteCache -> {
|
||||
assertThat(remoteCache, anEmptyMap());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpiredClientSessionReferenceIsNotPresentInUserSession() {
|
||||
// Set lower client session timeouts
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
ClientModel client = realm.getClientByClientId(CLIENT0_CLIENT_ID);
|
||||
client.setAttribute(CLIENT_SESSION_IDLE_TIMEOUT, "60");
|
||||
client.setAttribute(CLIENT_SESSION_MAX_LIFESPAN, "65");
|
||||
return null;
|
||||
});
|
||||
|
||||
AtomicReference<String> uSessionId = new AtomicReference<>();
|
||||
AtomicReference<String> cSessionId = new AtomicReference<>();
|
||||
prepareSessions(uSessionId, cSessionId);
|
||||
|
||||
// Move in time when client session should be expired but user session not
|
||||
setTimeOffset(70);
|
||||
|
||||
// Try to create a new client session for the same user session
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
ClientModel client = realm.getClientByClientId(CLIENT0_CLIENT_ID);
|
||||
UserSessionModel uSession = session.sessions().getUserSession(realm, uSessionId.get());
|
||||
assertThat(uSession.getAuthenticatedClientSessions(), anEmptyMap());
|
||||
assertThat(session.sessions().createClientSession(realm, client, uSession), notNullValue());
|
||||
return null;
|
||||
});
|
||||
|
||||
// Check session does not contain a reference to expired client session
|
||||
assertCacheContains(remoteCache -> {
|
||||
HotRodUserSessionEntity hotRodUserSessionEntity = remoteCache.get(uSessionId.get());
|
||||
assertThat(hotRodUserSessionEntity.authenticatedClientSessions, hasSize(1));
|
||||
});
|
||||
}
|
||||
|
||||
private void assertCacheContains(Consumer<RemoteCache<String, HotRodUserSessionEntity>> checker) {
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
HotRodConnectionProvider provider = session.getProvider(HotRodConnectionProvider.class);
|
||||
RemoteCache<String, HotRodUserSessionEntity> remoteCache = provider.getRemoteCache(ModelEntityUtil.getModelName(UserSessionModel.class));
|
||||
checker.accept(remoteCache);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private void prepareSessions(AtomicReference<String> uSessionId, AtomicReference<String> cSessionId) {
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
UserSessionModel uSession = session.sessions().createUserSession(null, realm, session.users().getUserByUsername(realm, "user1"), "user1", "127.0.0.1", "form", true, null, null, UserSessionModel.SessionPersistenceState.PERSISTENT);
|
||||
ClientModel client = realm.getClientByClientId(CLIENT0_CLIENT_ID);
|
||||
|
||||
AuthenticatedClientSessionModel cSession = session.sessions().createClientSession(realm, client, uSession);
|
||||
|
||||
uSessionId.set(uSession.getId());
|
||||
cSessionId.set(cSession.getId());
|
||||
return null;
|
||||
});
|
||||
|
||||
assertCacheContains(remoteCache -> {
|
||||
assertThat(remoteCache, aMapWithSize(2));
|
||||
assertThat(remoteCache.keySet(), containsInAnyOrder(uSessionId.get(), cSessionId.get()));
|
||||
});
|
||||
}
|
||||
}
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
package org.keycloak.testsuite.model.session;
|
||||
|
||||
import org.infinispan.client.hotrod.RemoteCache;
|
||||
import org.infinispan.commons.CacheException;
|
||||
import org.keycloak.models.AuthenticatedClientSessionModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
|
@ -28,13 +27,8 @@ import org.keycloak.models.UserModel;
|
|||
import org.keycloak.models.UserProvider;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.UserSessionProvider;
|
||||
import org.keycloak.models.map.storage.ModelEntityUtil;
|
||||
import org.keycloak.models.map.storage.hotRod.connections.DefaultHotRodConnectionProviderFactory;
|
||||
import org.keycloak.models.map.storage.hotRod.connections.HotRodConnectionProvider;
|
||||
import org.keycloak.models.map.storage.hotRod.userSession.HotRodUserSessionEntity;
|
||||
import org.keycloak.models.session.UserSessionPersisterProvider;
|
||||
import org.keycloak.models.sessions.infinispan.InfinispanUserSessionProvider;
|
||||
import org.keycloak.models.sessions.infinispan.InfinispanUserSessionProviderFactory;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testsuite.model.KeycloakModelTest;
|
||||
import org.keycloak.testsuite.model.RequireProvider;
|
||||
|
@ -131,39 +125,6 @@ public class OfflineSessionPersistenceTest extends KeycloakModelTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequireProvider(value = HotRodConnectionProvider.class, only = DefaultHotRodConnectionProviderFactory.PROVIDER_ID)
|
||||
public void testOfflineSessionsRemovedAfterDeleteRealm() {
|
||||
String realmId2 = inComittedTransaction(session -> { return prepareRealm(session, "realm2").getId(); });
|
||||
List<String> userIds2 = withRealm(realmId2, (session, realm) -> IntStream.range(0, USER_COUNT)
|
||||
.mapToObj(i -> session.users().addUser(realm, "user2-" + i))
|
||||
.map(UserModel::getId)
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
|
||||
try {
|
||||
List<String> offlineSessionIds2 = createOfflineSessions(realmId2, userIds2);
|
||||
assertOfflineSessionsExist(realmId2, offlineSessionIds2);
|
||||
|
||||
// Simulate server restart
|
||||
reinitializeKeycloakSessionFactory();
|
||||
|
||||
assertOfflineSessionsExist(realmId2, offlineSessionIds2);
|
||||
|
||||
inComittedTransaction(session -> {
|
||||
session.realms().removeRealm(realmId2);
|
||||
});
|
||||
|
||||
inComittedTransaction(session -> {
|
||||
HotRodConnectionProvider provider = session.getProvider(HotRodConnectionProvider.class);
|
||||
RemoteCache<String, HotRodUserSessionEntity> remoteCache = provider.getRemoteCache(ModelEntityUtil.getModelName(UserSessionModel.class));
|
||||
assertThat(remoteCache, Matchers.anEmptyMap());
|
||||
});
|
||||
} finally {
|
||||
withRealm(realmId2, (session, realm) -> realm == null ? false : new RealmManager(session).removeRealm(realm));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersistenceSingleNode() {
|
||||
List<String> offlineSessionIds = createOfflineSessions(realmId, userIds);
|
||||
|
@ -176,7 +137,6 @@ public class OfflineSessionPersistenceTest extends KeycloakModelTest {
|
|||
|
||||
@Test(timeout = 90 * 1000)
|
||||
@RequireProvider(UserSessionPersisterProvider.class)
|
||||
@RequireProvider(value = UserSessionProvider.class, only = InfinispanUserSessionProviderFactory.PROVIDER_ID)
|
||||
public void testPersistenceMultipleNodesClientSessionAtSameNode() throws InterruptedException {
|
||||
int numClients = 2;
|
||||
List<String> clientIds = withRealm(realmId, (session, realm) -> IntStream.range(0, numClients)
|
||||
|
@ -233,7 +193,6 @@ public class OfflineSessionPersistenceTest extends KeycloakModelTest {
|
|||
|
||||
@Test(timeout = 90 * 1000)
|
||||
@RequireProvider(UserSessionPersisterProvider.class)
|
||||
@RequireProvider(value = UserSessionProvider.class, only = InfinispanUserSessionProviderFactory.PROVIDER_ID)
|
||||
public void testPersistenceMultipleNodesClientSessionsAtRandomNode() throws InterruptedException {
|
||||
List<String> clientIds = withRealm(realmId, (session, realm) -> IntStream.range(0, 5)
|
||||
.mapToObj(cid -> session.clients().addClient(realm, "client-" + cid))
|
||||
|
@ -286,7 +245,6 @@ public class OfflineSessionPersistenceTest extends KeycloakModelTest {
|
|||
|
||||
@Test
|
||||
@RequireProvider(UserSessionPersisterProvider.class)
|
||||
@RequireProvider(value = UserSessionProvider.class, only = InfinispanUserSessionProviderFactory.PROVIDER_ID)
|
||||
public void testOfflineSessionLoadingAfterCacheRemoval() {
|
||||
List<String> offlineSessionIds = createOfflineSessions(realmId, userIds);
|
||||
assertOfflineSessionsExist(realmId, offlineSessionIds);
|
||||
|
@ -311,7 +269,6 @@ public class OfflineSessionPersistenceTest extends KeycloakModelTest {
|
|||
|
||||
@Test
|
||||
@RequireProvider(UserSessionPersisterProvider.class)
|
||||
@RequireProvider(value = UserSessionProvider.class, only = InfinispanUserSessionProviderFactory.PROVIDER_ID)
|
||||
public void testLazyClientSessionStatsFetching() {
|
||||
List<String> clientIds = withRealm(realmId, (session, realm) -> IntStream.range(0, 5)
|
||||
.mapToObj(cid -> session.clients().addClient(realm, "client-" + cid))
|
||||
|
@ -346,7 +303,6 @@ public class OfflineSessionPersistenceTest extends KeycloakModelTest {
|
|||
|
||||
@Test
|
||||
@RequireProvider(UserSessionPersisterProvider.class)
|
||||
@RequireProvider(value = UserSessionProvider.class, only = InfinispanUserSessionProviderFactory.PROVIDER_ID)
|
||||
public void testLazyOfflineUserSessionFetching() {
|
||||
Map<String, Set<String>> offlineSessionIdsDetailed = createOfflineSessionsDetailed(realmId, userIds);
|
||||
Collection<String> offlineSessionIds = offlineSessionIdsDetailed.values().stream().flatMap(Set::stream).collect(Collectors.toCollection(TreeSet::new));
|
||||
|
@ -380,7 +336,6 @@ public class OfflineSessionPersistenceTest extends KeycloakModelTest {
|
|||
|
||||
@Test(timeout = 90 * 1000)
|
||||
@RequireProvider(UserSessionPersisterProvider.class)
|
||||
@RequireProvider(value = UserSessionProvider.class, only = InfinispanUserSessionProviderFactory.PROVIDER_ID)
|
||||
public void testPersistenceClientSessionsMultipleNodes() throws InterruptedException {
|
||||
// Create offline sessions
|
||||
List<String> offlineSessionIds = createOfflineSessions(realmId, userIds);
|
||||
|
|
|
@ -25,17 +25,10 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.UserSessionProvider;
|
||||
import org.keycloak.models.UserSessionSpi;
|
||||
import org.keycloak.models.map.storage.ModelEntityUtil;
|
||||
import org.keycloak.models.map.storage.file.FileMapStorageProviderFactory;
|
||||
import org.keycloak.models.map.storage.hotRod.HotRodMapStorageProviderFactory;
|
||||
import org.keycloak.models.map.storage.hotRod.connections.HotRodConnectionProvider;
|
||||
import org.keycloak.models.map.userSession.MapUserSessionProviderFactory;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.testsuite.model.KeycloakModelTest;
|
||||
import org.keycloak.testsuite.model.RequireProvider;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -43,9 +36,7 @@ import java.util.stream.IntStream;
|
|||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.aMapWithSize;
|
||||
import static org.hamcrest.Matchers.anEmptyMap;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification;
|
||||
|
||||
|
||||
|
@ -56,7 +47,6 @@ public class UserSessionConcurrencyTest extends KeycloakModelTest {
|
|||
private static final int CLIENTS_COUNT = 10;
|
||||
|
||||
private static final ThreadLocal<Boolean> wasWriting = ThreadLocal.withInitial(() -> false);
|
||||
private final boolean isHotRodStore = HotRodMapStorageProviderFactory.PROVIDER_ID.equals(CONFIG.getConfig().get("userSessions.map.storage.provider"));
|
||||
|
||||
@Override
|
||||
public void createEnvironment(KeycloakSession s) {
|
||||
|
@ -87,13 +77,6 @@ public class UserSessionConcurrencyTest extends KeycloakModelTest {
|
|||
|
||||
@Test
|
||||
public void testConcurrentNotesChange() throws InterruptedException {
|
||||
// Defer this one until file locking is available
|
||||
// Skip the test if EventProvider == File
|
||||
String evProvider = CONFIG.getConfig().get(UserSessionSpi.NAME + ".provider");
|
||||
String evMapStorageProvider = CONFIG.getConfig().get(UserSessionSpi.NAME + ".map.storage.provider");
|
||||
assumeFalse(MapUserSessionProviderFactory.PROVIDER_ID.equals(evProvider) &&
|
||||
(evMapStorageProvider == null || FileMapStorageProviderFactory.PROVIDER_ID.equals(evMapStorageProvider)));
|
||||
|
||||
// Create user session
|
||||
String uId = withRealm(this.realmId, (session, realm) -> session.sessions().createUserSession(null, realm, session.users().getUserByUsername(realm, "user1"), "user1", "127.0.0.1", "form", true, null, null, UserSessionModel.SessionPersistenceState.PERSISTENT)).getId();
|
||||
|
||||
|
@ -134,13 +117,5 @@ public class UserSessionConcurrencyTest extends KeycloakModelTest {
|
|||
});
|
||||
|
||||
inComittedTransaction((Consumer<KeycloakSession>) session -> session.realms().removeRealm(realmId));
|
||||
if (isHotRodStore) {
|
||||
inComittedTransaction(session -> {
|
||||
HotRodConnectionProvider provider = session.getProvider(HotRodConnectionProvider.class);
|
||||
Map<?,?> remoteCache = provider.getRemoteCache(ModelEntityUtil.getModelName(UserSessionModel.class));
|
||||
|
||||
assertThat(remoteCache, anEmptyMap());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* Copyright 2022 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.session;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.UserSessionProvider;
|
||||
import org.keycloak.models.map.userSession.MapUserSessionProviderFactory;
|
||||
import org.keycloak.testsuite.model.KeycloakModelTest;
|
||||
import org.keycloak.testsuite.model.RequireProvider;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
@RequireProvider(value = UserSessionProvider.class, only = MapUserSessionProviderFactory.PROVIDER_ID)
|
||||
@RequireProvider(RealmProvider.class)
|
||||
public class UserSessionExpirationTest extends KeycloakModelTest {
|
||||
|
||||
private String realmId;
|
||||
|
||||
@Override
|
||||
public void createEnvironment(KeycloakSession s) {
|
||||
RealmModel realm = createRealm(s, "test");
|
||||
realm.setDefaultRole(s.roles().addRealmRole(realm, Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + realm.getName()));
|
||||
|
||||
s.users().addUser(realm, "user1").setEmail("user1@localhost");
|
||||
this.realmId = realm.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanEnvironment(KeycloakSession s) {
|
||||
s.realms().removeRealm(realmId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSsoSessionIdleTimeout() {
|
||||
|
||||
// Set low ssoSessionIdleTimeout
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
realm.setSsoSessionIdleTimeout(5);
|
||||
realm.setSsoSessionMaxLifespan(36000);
|
||||
realm.setClientSessionIdleTimeout(5);
|
||||
return null;
|
||||
});
|
||||
|
||||
String uSId= withRealm(realmId, (session, realm) -> session.sessions().createUserSession(null, realm, session.users().getUserByUsername(realm, "user1"), "user1", "127.0.0.1", "form", true, null, null, UserSessionModel.SessionPersistenceState.PERSISTENT).getId());
|
||||
|
||||
assertThat(withRealm(realmId, (session, realm) -> session.sessions().getUserSession(realm, uSId)), notNullValue());
|
||||
|
||||
setTimeOffset(5);
|
||||
|
||||
assertThat(withRealm(realmId, (session, realm) -> session.sessions().getUserSession(realm, uSId)), nullValue());
|
||||
}
|
||||
}
|
|
@ -33,7 +33,6 @@ import org.keycloak.models.UserProvider;
|
|||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.UserSessionProvider;
|
||||
import org.keycloak.models.session.UserSessionPersisterProvider;
|
||||
import org.keycloak.models.sessions.infinispan.InfinispanUserSessionProviderFactory;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
@ -155,7 +154,6 @@ public class UserSessionInitializerTest extends KeycloakModelTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@RequireProvider(value = UserSessionProvider.class, only = InfinispanUserSessionProviderFactory.PROVIDER_ID)
|
||||
public void testUserSessionPropagationBetweenSites() throws InterruptedException {
|
||||
AtomicInteger index = new AtomicInteger();
|
||||
AtomicReference<String> userSessionId = new AtomicReference<>();
|
||||
|
|
|
@ -53,7 +53,6 @@ import static org.junit.Assert.assertEquals;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.sessions.infinispan.InfinispanUserSessionProviderFactory;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.keycloak.storage.client.ClientStorageProvider;
|
||||
import org.keycloak.storage.client.ClientStorageProviderModel;
|
||||
|
@ -67,7 +66,7 @@ import java.util.LinkedList;
|
|||
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
|
||||
*/
|
||||
@RequireProvider(UserSessionPersisterProvider.class)
|
||||
@RequireProvider(value = UserSessionProvider.class, only = InfinispanUserSessionProviderFactory.PROVIDER_ID)
|
||||
@RequireProvider(UserSessionProvider.class)
|
||||
@RequireProvider(UserProvider.class)
|
||||
@RequireProvider(RealmProvider.class)
|
||||
public class UserSessionPersisterProviderTest extends KeycloakModelTest {
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package org.keycloak.testsuite.model.session;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.infinispan.client.hotrod.RemoteCache;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.AuthenticatedClientSessionModel;
|
||||
|
@ -26,19 +25,10 @@ import org.keycloak.models.Constants;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.UserManager;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserProvider;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.UserSessionProvider;
|
||||
import org.keycloak.models.map.storage.ModelEntityUtil;
|
||||
import org.keycloak.models.map.storage.chm.ConcurrentHashMapStorageProviderFactory;
|
||||
import org.keycloak.models.map.storage.hotRod.connections.DefaultHotRodConnectionProviderFactory;
|
||||
import org.keycloak.models.map.storage.hotRod.connections.HotRodConnectionProvider;
|
||||
import org.keycloak.models.map.storage.hotRod.userSession.HotRodUserSessionEntity;
|
||||
import org.keycloak.models.map.userSession.MapUserSessionProvider;
|
||||
import org.keycloak.models.map.userSession.MapUserSessionProviderFactory;
|
||||
import org.keycloak.models.sessions.infinispan.InfinispanUserSessionProviderFactory;
|
||||
import org.keycloak.models.sessions.infinispan.changes.sessions.PersisterLastSessionRefreshStoreFactory;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.utils.ResetTimeOffsetEvent;
|
||||
|
@ -50,7 +40,6 @@ import org.keycloak.timer.TimerProvider;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
@ -59,7 +48,6 @@ import java.util.stream.Collectors;
|
|||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
import static org.keycloak.testsuite.model.session.UserSessionPersisterProviderTest.createClients;
|
||||
import static org.keycloak.testsuite.model.session.UserSessionPersisterProviderTest.createSessions;
|
||||
|
||||
|
@ -164,22 +152,8 @@ public class UserSessionProviderModelTest extends KeycloakModelTest {
|
|||
Assert.assertEquals(origSessions[1], userSession);
|
||||
});
|
||||
|
||||
|
||||
// not possible to expire client session without expiring user sessions with time offset in map storage because
|
||||
// expiration in map storage takes min of (clientSessionIdleExpiration, ssoSessionIdleTimeout)
|
||||
inComittedTransaction(session -> {
|
||||
if (session.getProvider(UserSessionProvider.class) instanceof MapUserSessionProvider) {
|
||||
RealmModel realm = session.realms().getRealm(realmId);
|
||||
|
||||
UserSessionModel userSession = session.sessions().getUserSession(realm, origSessions[0].getId());
|
||||
|
||||
userSession.getAuthenticatedClientSessions().values().stream().forEach(clientSession -> {
|
||||
// expire client sessions
|
||||
clientSession.setTimestamp(1);
|
||||
});
|
||||
} else {
|
||||
setTimeOffset(1000);
|
||||
}
|
||||
});
|
||||
|
||||
inComittedTransaction(session -> {
|
||||
|
@ -230,7 +204,6 @@ public class UserSessionProviderModelTest extends KeycloakModelTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@RequireProvider(value = UserSessionProvider.class, only = InfinispanUserSessionProviderFactory.PROVIDER_ID)
|
||||
public void testClientSessionIsNotPersistedForTransientUserSession() {
|
||||
Object[] transientUserSessionWithClientSessionId = inComittedTransaction(session -> {
|
||||
RealmModel realm = session.realms().getRealm(realmId);
|
||||
|
@ -255,33 +228,8 @@ public class UserSessionProviderModelTest extends KeycloakModelTest {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequireProvider(value = HotRodConnectionProvider.class, only = DefaultHotRodConnectionProviderFactory.PROVIDER_ID)
|
||||
public void testRemoteCachesParallel() throws InterruptedException {
|
||||
inIndependentFactories(4, 30, () -> inComittedTransaction(session -> {
|
||||
HotRodConnectionProvider provider = session.getProvider(HotRodConnectionProvider.class);
|
||||
RemoteCache<String, HotRodUserSessionEntity> remoteCache = provider.getRemoteCache(ModelEntityUtil.getModelName(UserSessionModel.class));
|
||||
HotRodUserSessionEntity userSessionEntity = new HotRodUserSessionEntity();
|
||||
userSessionEntity.id = UUID.randomUUID().toString();
|
||||
userSessionEntity.realmId = realmId;
|
||||
remoteCache.put(userSessionEntity.id, userSessionEntity);
|
||||
}));
|
||||
|
||||
inComittedTransaction(session -> {
|
||||
HotRodConnectionProvider provider = session.getProvider(HotRodConnectionProvider.class);
|
||||
RemoteCache<String, HotRodUserSessionEntity> remoteCache = provider.getRemoteCache(ModelEntityUtil.getModelName(UserSessionModel.class));
|
||||
assertThat(remoteCache.size(), Matchers.is(4));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateUserSessionsParallel() throws InterruptedException {
|
||||
// Skip the test if MapUserSessionProvider == CHM
|
||||
String usProvider = CONFIG.getConfig().get("userSessions.provider");
|
||||
String usMapStorageProvider = CONFIG.getConfig().get("userSessions.map.storage.provider");
|
||||
assumeFalse(MapUserSessionProviderFactory.PROVIDER_ID.equals(usProvider) &&
|
||||
(usMapStorageProvider == null || ConcurrentHashMapStorageProviderFactory.PROVIDER_ID.equals(usMapStorageProvider)));
|
||||
|
||||
Set<String> userSessionIds = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
CountDownLatch latch = new CountDownLatch(4);
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
|
||||
*/
|
||||
@RequireProvider(UserSessionPersisterProvider.class)
|
||||
@RequireProvider(value=UserSessionProvider.class, only={"infinispan"})
|
||||
@RequireProvider(UserSessionProvider.class)
|
||||
@RequireProvider(UserProvider.class)
|
||||
@RequireProvider(RealmProvider.class)
|
||||
public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
|
||||
|
|
|
@ -26,12 +26,7 @@ import org.keycloak.models.Constants;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.SingleUseObjectProvider;
|
||||
import org.keycloak.models.SingleUseObjectProviderFactory;
|
||||
import org.keycloak.models.SingleUseObjectSpi;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.map.singleUseObject.MapSingleUseObjectProviderFactory;
|
||||
import org.keycloak.models.map.storage.chm.ConcurrentHashMapStorageProviderFactory;
|
||||
import org.keycloak.models.map.userSession.MapUserSessionProviderFactory;
|
||||
import org.keycloak.testsuite.model.KeycloakModelTest;
|
||||
import org.keycloak.testsuite.model.RequireProvider;
|
||||
|
||||
|
@ -43,7 +38,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
|
||||
@RequireProvider(SingleUseObjectProvider.class)
|
||||
public class SingleUseObjectModelTest extends KeycloakModelTest {
|
||||
|
@ -171,12 +165,6 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
|
|||
|
||||
@Test
|
||||
public void testCluster() throws InterruptedException {
|
||||
// Skip the test if SingleUseObjectProvider == CHM
|
||||
String suProvider = CONFIG.getConfig().get(SingleUseObjectSpi.NAME + ".provider");
|
||||
String suMapStorageProvider = CONFIG.getConfig().get(SingleUseObjectSpi.NAME + ".map.storage.provider");
|
||||
assumeFalse(MapSingleUseObjectProviderFactory.PROVIDER_ID.equals(suProvider) &&
|
||||
(suMapStorageProvider == null || ConcurrentHashMapStorageProviderFactory.PROVIDER_ID.equals(suMapStorageProvider)));
|
||||
|
||||
AtomicInteger index = new AtomicInteger();
|
||||
CountDownLatch afterFirstNodeLatch = new CountDownLatch(1);
|
||||
CountDownLatch afterDeleteLatch = new CountDownLatch(1);
|
||||
|
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 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.storage.tree.sample;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.keycloak.models.map.client.MapClientEntity;
|
||||
import org.keycloak.models.map.client.MapClientEntityFields;
|
||||
import org.keycloak.models.map.common.DeepCloner;
|
||||
import org.keycloak.models.map.common.EntityField;
|
||||
import org.keycloak.models.map.common.UpdatableEntity;
|
||||
import org.keycloak.models.map.common.delegate.EntityFieldDelegate;
|
||||
import org.keycloak.models.map.common.delegate.HasEntityFieldDelegate;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class Dict<E> extends UpdatableEntity.Impl implements EntityFieldDelegate<E> {
|
||||
|
||||
public static final String CLIENT_FIELD_LOGO = "LOGO";
|
||||
public static final String CLIENT_FIELD_ENABLED = "ENABLED";
|
||||
public static final String CLIENT_FIELD_NAME = "NAME";
|
||||
|
||||
private static final Set<String> CLIENT_ALLOWED_KEYS = new HashSet<>(Arrays.asList(CLIENT_FIELD_NAME, CLIENT_FIELD_ENABLED, CLIENT_FIELD_LOGO));
|
||||
|
||||
public static MapClientEntity clientDelegate() {
|
||||
// To be replaced by dynamic mapper config
|
||||
Map<String, String> fieldName2key = new HashMap<>();
|
||||
fieldName2key.put(MapClientEntityFields.ID.getName(), CLIENT_FIELD_NAME);
|
||||
fieldName2key.put(MapClientEntityFields.CLIENT_ID.getName(), CLIENT_FIELD_NAME);
|
||||
fieldName2key.put(MapClientEntityFields.ENABLED.getName(), CLIENT_FIELD_ENABLED);
|
||||
|
||||
Map<String, String> attributeName2key = new HashMap<>();
|
||||
attributeName2key.put("logo", CLIENT_FIELD_LOGO);
|
||||
|
||||
Dict<MapClientEntity> dict = new Dict<>(CLIENT_ALLOWED_KEYS, fieldName2key, attributeName2key);
|
||||
return DeepCloner.DUMB_CLONER.entityFieldDelegate(MapClientEntity.class, dict);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <E> Dict<E> asDict(E entity) {
|
||||
return (entity instanceof HasEntityFieldDelegate && ((HasEntityFieldDelegate<?>) entity).getEntityFieldDelegate() instanceof Dict)
|
||||
? (Dict<E>) ((HasEntityFieldDelegate<E>) entity).getEntityFieldDelegate()
|
||||
: null;
|
||||
}
|
||||
|
||||
private final Set<String> allowedKeys;
|
||||
private final Map<String, Object> contents = new HashMap<>();
|
||||
private final Map<String, String> fieldName2key;
|
||||
private final Map<String, String> attributeName2key;
|
||||
|
||||
public Dict(Set<String> allowedKeys, Map<String, String> fieldName2key, Map<String, String> attributeName2key) {
|
||||
this.allowedKeys = allowedKeys;
|
||||
this.fieldName2key = fieldName2key;
|
||||
this.attributeName2key = attributeName2key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <EF extends Enum<? extends EntityField<E>> & EntityField<E>> Object get(EF field) {
|
||||
if ("Attributes".equals(field.getName())) {
|
||||
return attributeName2key.entrySet().stream()
|
||||
.filter(me -> get(me.getValue()) != null)
|
||||
.collect(Collectors.toMap(me -> me.getKey(), me -> Collections.singletonList(get(me.getValue()))));
|
||||
}
|
||||
String key = fieldName2key.get(field.getName());
|
||||
if (key != null) {
|
||||
return get(key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, EF extends Enum<? extends EntityField<E>> & EntityField<E>> void set(EF field, T value) {
|
||||
String key = fieldName2key.get(field.getName());
|
||||
if (key != null) {
|
||||
put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, EF extends Enum<? extends EntityField<E>> & EntityField<E>> Object mapGet(EF field, K key) {
|
||||
if ("Attributes".equals(field.getName()) && attributeName2key.containsKey(key)) {
|
||||
Object v = get(attributeName2key.get(key));
|
||||
return v == null ? null : Collections.singletonList(get(attributeName2key.get(key)));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, T, EF extends Enum<? extends EntityField<E>> & EntityField<E>> void mapPut(EF field, K key, T value) {
|
||||
if ("Attributes".equals(field.getName()) && attributeName2key.containsKey(key) && (value instanceof List)) {
|
||||
List<?> l = (List<?>) value;
|
||||
if (l.isEmpty()) {
|
||||
remove(attributeName2key.get(key));
|
||||
} else {
|
||||
put(attributeName2key.get(key), l.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, EF extends Enum<? extends EntityField<E>> & EntityField<E>> Object mapRemove(EF field, K key) {
|
||||
if ("Attributes".equals(field.getName()) && attributeName2key.containsKey(key)) {
|
||||
Object o = remove(attributeName2key.get(key));
|
||||
return o == null ? null : Collections.singletonList(o);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T, EF extends java.lang.Enum<? extends org.keycloak.models.map.common.EntityField<E>> & org.keycloak.models.map.common.EntityField<E>> void collectionAdd(EF field, T value) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, EF extends java.lang.Enum<? extends org.keycloak.models.map.common.EntityField<E>> & org.keycloak.models.map.common.EntityField<E>> Object collectionRemove(EF field, T value) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
protected boolean isKeyAllowed(String key) {
|
||||
return allowedKeys.contains(key);
|
||||
}
|
||||
|
||||
public Object get(String key) {
|
||||
return isKeyAllowed(key) ? contents.get(key) : null;
|
||||
}
|
||||
|
||||
public void put(String key, Object value) {
|
||||
if (isKeyAllowed(key)) {
|
||||
updated |= ! Objects.equals(contents.put(key, value), value);
|
||||
}
|
||||
}
|
||||
|
||||
public Object remove(String key) {
|
||||
key = key == null ? null : key.toUpperCase();
|
||||
if (isKeyAllowed(key)) {
|
||||
Object res = contents.remove(key);
|
||||
updated |= res != null;
|
||||
return res;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 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.storage.tree.sample;
|
||||
|
||||
import org.keycloak.models.map.common.AbstractEntity;
|
||||
import org.keycloak.models.map.common.DeepCloner;
|
||||
import org.keycloak.models.map.storage.MapStorage;
|
||||
import org.keycloak.models.map.storage.QueryParameters;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class DictStorage<V extends AbstractEntity, M> implements MapStorage<V, M> {
|
||||
|
||||
private final DeepCloner cloner;
|
||||
|
||||
private final List<V> store;
|
||||
|
||||
public DictStorage(DeepCloner cloner, List<V> store) {
|
||||
this.cloner = cloner;
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
List<V> getStore() {
|
||||
return store;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V create(V value) {
|
||||
V res = cloner.from(value);
|
||||
store.add(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V read(String key) {
|
||||
return store.stream()
|
||||
.filter(e -> Objects.equals(e.getId(), key))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<V> read(QueryParameters<M> queryParameters) {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCount(QueryParameters<M> queryParameters) {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(String key) {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public long delete(QueryParameters<M> queryParameters) {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
package org.keycloak.testsuite.model.storage.tree.sample;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.hasItems;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.map.client.MapClientEntity;
|
||||
|
||||
public class DictTest {
|
||||
@Test
|
||||
public void testDictClientFromMap() {
|
||||
MapClientEntity mce = Dict.clientDelegate();
|
||||
assertThat(mce.getClientId(), nullValue());
|
||||
assertThat(mce.isEnabled(), nullValue());
|
||||
assertThat(mce.getAttribute("logo"), nullValue());
|
||||
assertThat(mce.getAttributes().keySet(), is(empty()));
|
||||
|
||||
Dict.asDict(mce).put(Dict.CLIENT_FIELD_NAME, "name");
|
||||
Dict.asDict(mce).put(Dict.CLIENT_FIELD_ENABLED, false);
|
||||
Dict.asDict(mce).put(Dict.CLIENT_FIELD_LOGO, "thisShouldBeBase64Logo");
|
||||
Dict.asDict(mce).put("nonexistent", "nonexistent");
|
||||
|
||||
assertThat(mce.getId(), is("name"));
|
||||
assertThat(mce.getClientId(), is("name"));
|
||||
assertThat(mce.isEnabled(), is(false));
|
||||
assertThat(mce.getAttribute("logo"), hasItems("thisShouldBeBase64Logo"));
|
||||
assertThat(mce.getAttributes().keySet(), hasItems("logo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDictClientFromEntity() {
|
||||
MapClientEntity mce = Dict.clientDelegate();
|
||||
|
||||
assertThat(Dict.asDict(mce).get(Dict.CLIENT_FIELD_NAME), nullValue());
|
||||
assertThat(Dict.asDict(mce).get(Dict.CLIENT_FIELD_ENABLED), nullValue());
|
||||
assertThat(Dict.asDict(mce).get(Dict.CLIENT_FIELD_LOGO), nullValue());
|
||||
|
||||
mce.setClientId("name");
|
||||
mce.setEnabled(false);
|
||||
mce.setAttribute("logo", Arrays.asList("thisShouldBeBase64Logo"));
|
||||
mce.setAttribute("blah", Arrays.asList("thisShouldBeBase64Logofdas"));
|
||||
|
||||
assertThat(mce.getAttributes().keySet(), hasItems("logo"));
|
||||
|
||||
assertThat(Dict.asDict(mce).get(Dict.CLIENT_FIELD_NAME), is("name"));
|
||||
assertThat(Dict.asDict(mce).get(Dict.CLIENT_FIELD_ENABLED), is(false));
|
||||
assertThat(Dict.asDict(mce).get(Dict.CLIENT_FIELD_LOGO), is("thisShouldBeBase64Logo"));
|
||||
|
||||
mce.setAttribute("logo", Arrays.asList("thisShouldBeAnotherBase64Logo"));
|
||||
assertThat(Dict.asDict(mce).get(Dict.CLIENT_FIELD_LOGO), is("thisShouldBeAnotherBase64Logo"));
|
||||
|
||||
mce.removeAttribute("logo");
|
||||
assertThat(Dict.asDict(mce).get(Dict.CLIENT_FIELD_LOGO), nullValue());
|
||||
}
|
||||
}
|
|
@ -20,43 +20,18 @@ package org.keycloak.testsuite.model.transaction;
|
|||
import org.junit.Test;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.locking.LockAcquiringTimeoutException;
|
||||
import org.keycloak.models.map.storage.MapStorageProvider;
|
||||
import org.keycloak.models.map.storage.hotRod.HotRodMapStorageProviderFactory;
|
||||
import org.keycloak.models.map.storage.jpa.JpaMapStorageProviderFactory;
|
||||
import org.keycloak.testsuite.model.KeycloakModelTest;
|
||||
import org.keycloak.testsuite.model.RequireProvider;
|
||||
import org.keycloak.testsuite.model.util.TransactionController;
|
||||
import org.keycloak.utils.LockObjectsForModification;
|
||||
|
||||
import jakarta.persistence.OptimisticLockException;
|
||||
import jakarta.persistence.PessimisticLockException;
|
||||
import jakarta.transaction.RollbackException;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.CoreMatchers.anyOf;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.internal.matchers.ThrowableCauseMatcher.hasCause;
|
||||
import static org.keycloak.testsuite.model.util.KeycloakAssertions.assertException;
|
||||
|
||||
@RequireProvider(RealmProvider.class)
|
||||
public class StorageTransactionTest extends KeycloakModelTest {
|
||||
|
||||
// System variable is used to simplify configuration for more storages that support pessimistic locking.
|
||||
// Instead of searching which storage is used and then configure its factory, we can just configure
|
||||
// lockTimeout like this: .config("lockTimeout", "${keycloak.model.tests.lockTimeout:}") and
|
||||
// system property will be picked when factory is reinitialized.
|
||||
public static final String LOCK_TIMEOUT_SYSTEM_PROPERTY = "keycloak.model.tests.lockTimeout";
|
||||
private String realmId;
|
||||
|
||||
@Override
|
||||
|
@ -135,235 +110,4 @@ public class StorageTransactionTest extends KeycloakModelTest {
|
|||
tx3.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
// LockObjectForModification currently works only in map-jpa and map-hotrod
|
||||
@RequireProvider(value = MapStorageProvider.class, only = {JpaMapStorageProviderFactory.PROVIDER_ID, HotRodMapStorageProviderFactory.PROVIDER_ID})
|
||||
public void testLockObjectForModificationById() throws Exception {
|
||||
testLockObjectForModification(session -> LockObjectsForModification.lockRealmsForModification(session, () -> session.realms().getRealm(realmId)));
|
||||
}
|
||||
|
||||
@Test
|
||||
// LockObjectForModification currently works only in map-jpa and map-hotrod
|
||||
@RequireProvider(value = MapStorageProvider.class, only = {JpaMapStorageProviderFactory.PROVIDER_ID, HotRodMapStorageProviderFactory.PROVIDER_ID})
|
||||
public void testLockUserSessionForModificationByQuery() throws Exception {
|
||||
// Create user session
|
||||
final String sessionId = withRealm(realmId, (session, realm) -> {
|
||||
UserModel myUser = session.users().addUser(realm, "myUser");
|
||||
return session.sessions().createUserSession(realm, myUser, "myUser", "127.0.0.1", "form", true, null, null).getId();
|
||||
});
|
||||
|
||||
testLockObjectForModification(session -> LockObjectsForModification.lockUserSessionsForModification(session, readUserSessionByIdUsingQueryParameters(session, sessionId)));
|
||||
}
|
||||
|
||||
private <R> void testLockObjectForModification(Function<KeycloakSession, R> lockedExecution) throws Exception {
|
||||
String originalTimeoutValue = System.getProperty(LOCK_TIMEOUT_SYSTEM_PROPERTY);
|
||||
try {
|
||||
System.setProperty(LOCK_TIMEOUT_SYSTEM_PROPERTY, "300");
|
||||
reinitializeKeycloakSessionFactory();
|
||||
try (TransactionController tx1 = new TransactionController(getFactory());
|
||||
TransactionController tx2 = new TransactionController(getFactory());
|
||||
TransactionController tx3 = new TransactionController(getFactory())) {
|
||||
|
||||
tx1.begin();
|
||||
tx2.begin();
|
||||
|
||||
// tx1 acquires lock
|
||||
tx1.runStep(lockedExecution);
|
||||
|
||||
// tx2 should fail as tx1 locked the realm
|
||||
assertException(() -> tx2.runStep(lockedExecution),
|
||||
anyOf(allOf(instanceOf(ModelException.class), hasCause(anyOf(instanceOf(PessimisticLockException.class), instanceOf(org.hibernate.PessimisticLockException.class)))),
|
||||
instanceOf(LockAcquiringTimeoutException.class)));
|
||||
|
||||
// end both transactions
|
||||
tx2.rollback();
|
||||
tx1.commit();
|
||||
|
||||
// start new transaction and read again, it should be successful
|
||||
tx3.begin();
|
||||
tx3.runStep(lockedExecution);
|
||||
tx3.commit();
|
||||
}
|
||||
} finally {
|
||||
if (originalTimeoutValue == null) {
|
||||
System.clearProperty(LOCK_TIMEOUT_SYSTEM_PROPERTY);
|
||||
} else {
|
||||
System.setProperty(LOCK_TIMEOUT_SYSTEM_PROPERTY, originalTimeoutValue);
|
||||
}
|
||||
reinitializeKeycloakSessionFactory();
|
||||
}
|
||||
}
|
||||
|
||||
private LockObjectsForModification.CallableWithoutThrowingAnException<UserSessionModel> readUserSessionByIdUsingQueryParameters(KeycloakSession session, String sessionId) {
|
||||
RealmModel realm = session.realms().getRealm(realmId);
|
||||
return () -> session.sessions().getUserSession(realm, sessionId);
|
||||
}
|
||||
|
||||
@Test
|
||||
// Optimistic locking works only with map-jpa and map-hotrod
|
||||
@RequireProvider(value = MapStorageProvider.class, only = {JpaMapStorageProviderFactory.PROVIDER_ID,
|
||||
HotRodMapStorageProviderFactory.PROVIDER_ID})
|
||||
public void testOptimisticLockingExceptionReadById() throws Exception {
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
realm.setDisplayName("displayName1");
|
||||
return null;
|
||||
});
|
||||
|
||||
try (TransactionController tx1 = new TransactionController(getFactory());
|
||||
TransactionController tx2 = new TransactionController(getFactory())) {
|
||||
|
||||
// tx1 acquires lock
|
||||
tx1.begin();
|
||||
tx2.begin();
|
||||
|
||||
// both transactions touch the same entity
|
||||
tx1.runStep(session -> {
|
||||
session.realms().getRealm(realmId).setDisplayName("displayName2");
|
||||
return null;
|
||||
});
|
||||
tx2.runStep(session -> {
|
||||
session.realms().getRealm(realmId).setDisplayName("displayName3");
|
||||
return null;
|
||||
});
|
||||
|
||||
// tx1 transaction should be successful
|
||||
tx1.commit();
|
||||
|
||||
// tx2 should fail as tx1 already changed the value
|
||||
assertException(tx2::commit,
|
||||
anyOf(
|
||||
allOf(instanceOf(RuntimeException.class), hasCause(instanceOf(RollbackException.class))),
|
||||
allOf(instanceOf(ModelException.class), hasCause(instanceOf(OptimisticLockException.class))),
|
||||
allOf(instanceOf(OptimisticLockException.class))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
// Optimistic locking works only with map-jpa and map-hotrod
|
||||
@RequireProvider(value = MapStorageProvider.class, only = {JpaMapStorageProviderFactory.PROVIDER_ID,
|
||||
HotRodMapStorageProviderFactory.PROVIDER_ID})
|
||||
public void testOptimisticLockingExceptionReadByQuery() throws Exception {
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
realm.setDisplayName("displayName1");
|
||||
return null;
|
||||
});
|
||||
|
||||
try (TransactionController tx1 = new TransactionController(getFactory());
|
||||
TransactionController tx2 = new TransactionController(getFactory())) {
|
||||
|
||||
// tx1 acquires lock
|
||||
tx1.begin();
|
||||
tx2.begin();
|
||||
|
||||
// both transactions touch the same entity
|
||||
tx1.runStep(session -> {
|
||||
session.realms().getRealmByName("1").setDisplayName("displayName2");
|
||||
return null;
|
||||
});
|
||||
tx2.runStep(session -> {
|
||||
session.realms().getRealmByName("1").setDisplayName("displayName3");
|
||||
return null;
|
||||
});
|
||||
|
||||
// tx1 transaction should be successful
|
||||
tx1.commit();
|
||||
|
||||
// tx2 should fail as tx1 already changed the value
|
||||
assertException(tx2::commit,
|
||||
anyOf(
|
||||
allOf(instanceOf(RuntimeException.class), hasCause(instanceOf(RollbackException.class))),
|
||||
allOf(instanceOf(ModelException.class), hasCause(instanceOf(OptimisticLockException.class))),
|
||||
allOf(instanceOf(OptimisticLockException.class))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
// Optimistic locking works only with map-jpa and map-hotrod
|
||||
@RequireProvider(value = MapStorageProvider.class, only = {JpaMapStorageProviderFactory.PROVIDER_ID,
|
||||
HotRodMapStorageProviderFactory.PROVIDER_ID})
|
||||
public void testOptimisticLockingDeleteWhenReadingByQuery() throws Exception {
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
session.users().addUser(realm, "user", "user", false, false);
|
||||
return null;
|
||||
});
|
||||
|
||||
try (TransactionController tx1 = new TransactionController(getFactory());
|
||||
TransactionController tx2 = new TransactionController(getFactory())) {
|
||||
|
||||
tx1.begin();
|
||||
tx2.begin();
|
||||
|
||||
// both transactions touch the same entity
|
||||
tx1.runStep(session -> {
|
||||
// read by criteria
|
||||
session.users().getUserByUsername(session.realms().getRealm(realmId), "user").setFirstName("firstName");
|
||||
return null;
|
||||
});
|
||||
tx2.runStep(session -> {
|
||||
RealmModel realm = session.realms().getRealm(realmId);
|
||||
|
||||
// remove by id
|
||||
session.users().removeUser(realm, session.users().getUserByUsername(realm, "user"));
|
||||
return null;
|
||||
});
|
||||
|
||||
// tx1 transaction should be successful
|
||||
tx1.commit();
|
||||
|
||||
// tx2 should fail as tx1 already changed the value
|
||||
assertException(tx2::commit,
|
||||
anyOf(
|
||||
allOf(instanceOf(RuntimeException.class), hasCause(instanceOf(RollbackException.class))),
|
||||
allOf(instanceOf(ModelException.class), hasCause(instanceOf(OptimisticLockException.class))),
|
||||
allOf(instanceOf(OptimisticLockException.class))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
// Optimistic locking works only with map-jpa and map-hotrod
|
||||
@RequireProvider(value = MapStorageProvider.class, only = {JpaMapStorageProviderFactory.PROVIDER_ID,
|
||||
HotRodMapStorageProviderFactory.PROVIDER_ID})
|
||||
public void testOptimisticLockingDeleteWhenReadingById() throws Exception {
|
||||
String userId = UUID.randomUUID().toString();
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
session.users().addUser(realm, userId, "user", false, false);
|
||||
return null;
|
||||
});
|
||||
|
||||
try (TransactionController tx1 = new TransactionController(getFactory());
|
||||
TransactionController tx2 = new TransactionController(getFactory())) {
|
||||
|
||||
tx1.begin();
|
||||
tx2.begin();
|
||||
|
||||
// both transactions touch the same entity
|
||||
tx1.runStep(session -> {
|
||||
// read by id
|
||||
session.users().getUserById(session.realms().getRealm(realmId), userId).setFirstName("firstName");
|
||||
return null;
|
||||
});
|
||||
tx2.runStep(session -> {
|
||||
RealmModel realm = session.realms().getRealm(realmId);
|
||||
|
||||
// remove by id after read by id
|
||||
session.users().removeUser(realm, session.users().getUserById(realm, userId));
|
||||
return null;
|
||||
});
|
||||
|
||||
// tx1 transaction should be successful
|
||||
tx1.commit();
|
||||
|
||||
// tx2 should fail as tx1 already changed the value
|
||||
assertException(tx2::commit,
|
||||
anyOf(
|
||||
allOf(instanceOf(RuntimeException.class), hasCause(instanceOf(RollbackException.class))),
|
||||
allOf(instanceOf(ModelException.class), hasCause(instanceOf(OptimisticLockException.class))),
|
||||
allOf(instanceOf(OptimisticLockException.class))
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,17 +16,16 @@
|
|||
*/
|
||||
package org.keycloak.testsuite.model.user;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserProvider;
|
||||
import org.keycloak.models.map.realm.MapRealmProviderFactory;
|
||||
import org.keycloak.models.map.user.MapUserProviderFactory;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.UserStorageProviderFactory;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
|
@ -34,29 +33,23 @@ import org.keycloak.storage.UserStorageUtil;
|
|||
import org.keycloak.storage.user.UserRegistrationProvider;
|
||||
import org.keycloak.testsuite.model.KeycloakModelTest;
|
||||
import org.keycloak.testsuite.model.RequireProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assume.assumeThat;
|
||||
|
||||
/**
|
||||
|
@ -73,8 +66,6 @@ public class UserModelTest extends KeycloakModelTest {
|
|||
private static final int DELETED_USER_COUNT = LAST_DELETED_USER_INDEX - FIRST_DELETED_USER_INDEX;
|
||||
|
||||
private String realmId;
|
||||
private String realm1Id;
|
||||
private String realm2Id;
|
||||
private final List<String> groupIds = new ArrayList<>(NUM_GROUPS);
|
||||
private String userFederationId;
|
||||
|
||||
|
@ -92,8 +83,6 @@ public class UserModelTest extends KeycloakModelTest {
|
|||
@Override
|
||||
public void cleanEnvironment(KeycloakSession s) {
|
||||
s.realms().removeRealm(realmId);
|
||||
if (realm1Id != null) s.realms().removeRealm(realm1Id);
|
||||
if (realm2Id != null) s.realms().removeRealm(realm2Id);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -126,67 +115,6 @@ public class UserModelTest extends KeycloakModelTest {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequireProvider(value = UserProvider.class, only = {MapUserProviderFactory.PROVIDER_ID})
|
||||
@RequireProvider(value = RealmProvider.class, only = {MapRealmProviderFactory.PROVIDER_ID})
|
||||
public void testCaseSensitivityGetUserByUsername() {
|
||||
|
||||
realm1Id = inComittedTransaction((Function<KeycloakSession, String>) session -> {
|
||||
RealmModel realm = session.realms().createRealm("realm1");
|
||||
realm.setDefaultRole(session.roles().addRealmRole(realm, Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + realm.getName()));
|
||||
realm.setAttribute(Constants.REALM_ATTR_USERNAME_CASE_SENSITIVE, true);
|
||||
return realm.getId();
|
||||
});
|
||||
|
||||
withRealm(realm1Id, (session, realm) -> {
|
||||
UserModel user1 = session.users().addUser(realm, "user");
|
||||
UserModel user2 = session.users().addUser(realm, "USER");
|
||||
|
||||
assertThat(user1, not(nullValue()));
|
||||
assertThat(user2, not(nullValue()));
|
||||
|
||||
assertThat(user1.getUsername(), equalTo("user"));
|
||||
assertThat(user2.getUsername(), equalTo("USER"));
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
// try to query storage in a separate transaction to make sure that storage can handle case-sensitive usernames
|
||||
withRealm(realm1Id, (session, realm) -> {
|
||||
UserModel user1 = session.users().getUserByUsername(realm, "user");
|
||||
UserModel user2 = session.users().getUserByUsername(realm, "USER");
|
||||
|
||||
assertThat(user1, not(nullValue()));
|
||||
assertThat(user2, not(nullValue()));
|
||||
|
||||
assertThat(user1.getUsername(), equalTo("user"));
|
||||
assertThat(user2.getUsername(), equalTo("USER"));
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
realm2Id = inComittedTransaction((Function<KeycloakSession, String>) session -> {
|
||||
RealmModel realm = session.realms().createRealm("realm2");
|
||||
realm.setDefaultRole(session.roles().addRealmRole(realm, Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + realm.getName()));
|
||||
realm.setAttribute(Constants.REALM_ATTR_USERNAME_CASE_SENSITIVE, false);
|
||||
return realm.getId();
|
||||
});
|
||||
|
||||
withRealm(realm2Id, (session, realm) -> {
|
||||
UserModel user1 = session.users().addUser(realm, "user");
|
||||
assertThat(user1, not(nullValue()));
|
||||
|
||||
try {
|
||||
session.users().addUser(realm, "USER");
|
||||
} catch (ModelDuplicateException e) {
|
||||
return null; // expected
|
||||
}
|
||||
|
||||
fail("ModelDuplicateException expected");
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRemoveUser() {
|
||||
inRolledBackTransaction(1, this::addRemoveUser);
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023 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.util;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
public class KeycloakAssertions {
|
||||
|
||||
/**
|
||||
* Runs {@code task} and checks whether the execution resulted in
|
||||
* an exception that matches {@code matcher}. The method fails also
|
||||
* when no exception is thrown.
|
||||
*
|
||||
* @param task task
|
||||
* @param matcher matcher that the exception should match
|
||||
*/
|
||||
public static void assertException(Runnable task, Matcher<? super Throwable> matcher) {
|
||||
Throwable ex = catchException(task);
|
||||
assertThat(ex, allOf(notNullValue(), matcher));
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the {@code task} and returns any throwable that is thrown.
|
||||
* If not exception is thrown, the method returns {@code null}
|
||||
*
|
||||
* @param task task
|
||||
*/
|
||||
public static Throwable catchException(Runnable task) {
|
||||
try {
|
||||
task.run();
|
||||
return null;
|
||||
} catch (Throwable ex) {
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -42,9 +42,6 @@ log4j.logger.org.keycloak.connections.jpa.updater.liquibase=${keycloak.liquibase
|
|||
log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=debug
|
||||
|
||||
# Enable to log short stack traces for log entries enabled with StackUtil.getShortStackTrace() calls
|
||||
#log4j.logger.org.keycloak.models.map=trace
|
||||
#log4j.logger.org.keycloak.models.map.transaction=debug
|
||||
#
|
||||
#log4j.logger.org.keycloak.STACK_TRACE=trace
|
||||
|
||||
#log4j.logger.org.keycloak.models.sessions.infinispan=trace
|
||||
|
|
Loading…
Reference in a new issue