KEYCLOAK-16405 Tests for storage logical layer
This commit is contained in:
parent
4f330f4a57
commit
363df6cab4
18 changed files with 1080 additions and 75 deletions
|
@ -117,10 +117,6 @@
|
|||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-saml-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${jdbc.mvn.groupId}</groupId>
|
||||
<artifactId>${jdbc.mvn.artifactId}</artifactId>
|
||||
|
|
|
@ -56,6 +56,11 @@ public abstract class UserModelDefaultMethods implements UserModel {
|
|||
setSingleAttribute(EMAIL, email);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + "@" + getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link UserModelDefaultMethods.Streams} class extends the {@link UserModelDefaultMethods} abstract class and
|
||||
* implements the {@link UserModel.Streams} interface, allowing subclasses to focus on the implementation of the
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
|
||||
package org.keycloak.testsuite.federation;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.storage.UserStorageProviderFactory;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
|
@ -32,7 +32,7 @@ public class BackwardsCompatibilityUserStorageFactory implements UserStorageProv
|
|||
|
||||
public static final String PROVIDER_ID = "backwards-compatibility-storage";
|
||||
|
||||
protected Map<String, BackwardsCompatibilityUserStorage.MyUser> userPasswords = new Hashtable<>();
|
||||
private final Map<String, BackwardsCompatibilityUserStorage.MyUser> userPasswords = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public BackwardsCompatibilityUserStorage create(KeycloakSession session, ComponentModel model) {
|
||||
|
|
149
testsuite/model/pom.xml
Normal file
149
testsuite/model/pom.xml
Normal file
|
@ -0,0 +1,149 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-testsuite-pom</artifactId>
|
||||
<version>12.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<artifactId>keycloak-model-test</artifactId>
|
||||
<name>Tests for logical storage layer</name>
|
||||
<description>Tests for storage layer functionality targetting logical layer, i.e. models</description>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<keycloak.connectionsJpa.driver>org.h2.Driver</keycloak.connectionsJpa.driver>
|
||||
<keycloak.connectionsJpa.database>keycloak</keycloak.connectionsJpa.database>
|
||||
<keycloak.connectionsJpa.user>sa</keycloak.connectionsJpa.user>
|
||||
<keycloak.connectionsJpa.password></keycloak.connectionsJpa.password>
|
||||
<keycloak.connectionsJpa.url>jdbc:h2:mem:test;MVCC=TRUE;DB_CLOSE_DELAY=-1</keycloak.connectionsJpa.url>
|
||||
<jdbc.mvn.groupId>com.h2database</jdbc.mvn.groupId>
|
||||
<jdbc.mvn.artifactId>h2</jdbc.mvn.artifactId>
|
||||
<jdbc.mvn.version>${h2.version}</jdbc.mvn.version>
|
||||
<log4j.configuration>file:${project.build.directory}/dependency/log4j.properties</log4j.configuration>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-all</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-services</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-server-spi-private</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-server-spi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${jdbc.mvn.groupId}</groupId>
|
||||
<artifactId>${jdbc.mvn.artifactId}</artifactId>
|
||||
<version>${jdbc.mvn.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<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>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<!-- keycloak.model.parameters lists parameter classes from
|
||||
org.keycloak.model.parameters package and determine enabled providers -->
|
||||
<keycloak.model.parameters>${keycloak.model.parameters}</keycloak.model.parameters>
|
||||
<keycloak.connectionsJpa.default.driver>${keycloak.connectionsJpa.driver}</keycloak.connectionsJpa.default.driver>
|
||||
<keycloak.connectionsJpa.default.database>${keycloak.connectionsJpa.database}</keycloak.connectionsJpa.default.database>
|
||||
<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>
|
||||
<log4j.configuration>file:${project.build.directory}/test-classes/log4j.properties</log4j.configuration> <!-- for the logging to properly work with tests in the 'other' module -->
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>jpa</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>Jpa</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa+infinispan</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>Infinispan,Jpa</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa-federation+infinispan</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>Infinispan,JpaFederation,BackwardsCompatibilityUserStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa-federation</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>JpaFederation,BackwardsCompatibilityUserStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>map+infinispan</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>Infinispan,Map,ConcurrentHashMapStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.model;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class KeycloakModelParameters {
|
||||
|
||||
private final Set<Class<? extends Spi>> allowedSpis;
|
||||
private final Set<Class<? extends ProviderFactory>> allowedFactories;
|
||||
|
||||
public KeycloakModelParameters(Set<Class<? extends Spi>> allowedSpis, Set<Class<? extends ProviderFactory>> allowedFactories) {
|
||||
this.allowedSpis = allowedSpis;
|
||||
this.allowedFactories = allowedFactories;
|
||||
}
|
||||
|
||||
boolean isSpiAllowed(Spi s) {
|
||||
return allowedSpis.contains(s.getClass());
|
||||
}
|
||||
|
||||
boolean isFactoryAllowed(ProviderFactory factory) {
|
||||
return allowedFactories.stream().anyMatch((c) -> c.isAssignableFrom(factory.getClass()));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* 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.model;
|
||||
|
||||
import org.keycloak.Config.Scope;
|
||||
import org.keycloak.authorization.AuthorizationSpi;
|
||||
import org.keycloak.authorization.DefaultAuthorizationProviderFactory;
|
||||
import org.keycloak.authorization.store.StoreFactorySpi;
|
||||
import org.keycloak.cluster.ClusterSpi;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.events.EventStoreSpi;
|
||||
import org.keycloak.executors.DefaultExecutorsProviderFactory;
|
||||
import org.keycloak.executors.ExecutorsSpi;
|
||||
import org.keycloak.models.AbstractKeycloakTransaction;
|
||||
import org.keycloak.models.ClientSpi;
|
||||
import org.keycloak.models.GroupSpi;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmSpi;
|
||||
import org.keycloak.models.RoleSpi;
|
||||
import org.keycloak.models.UserSpi;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.ProviderManager;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.services.DefaultKeycloakSession;
|
||||
import org.keycloak.services.DefaultKeycloakSessionFactory;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.After;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Base of testcases that operate on session level. The tests derived from this class
|
||||
* will have access to a shared {@link KeycloakSessionFactory} in the {@link #FACTORY}
|
||||
* field that can be used to obtain a session and e.g. start / stop transaction.
|
||||
* <p>
|
||||
* This class expects {@code keycloak.model.parameters} system property to contain
|
||||
* comma-separated class names that implement {@link KeycloakModelParameters} interface
|
||||
* to provide list of factories and SPIs that are visible to the {@link KeycloakSessionFactory}
|
||||
* that is offered to the tests.
|
||||
* <p>
|
||||
* If no parameters are set via this property, the tests derived from this class are skipped.
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public abstract class KeycloakModelTest {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(KeycloakModelParameters.class);
|
||||
protected final Logger log = Logger.getLogger(getClass());
|
||||
|
||||
@ClassRule
|
||||
public static final TestRule GUARANTEE_REQUIRED_FACTORY = new TestRule() {
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
Class<?> testClass = description.getTestClass();
|
||||
while (testClass != Object.class) {
|
||||
for (RequireProvider ann : testClass.getAnnotationsByType(RequireProvider.class)) {
|
||||
Assume.assumeThat("Provider must exist: " + ann.value(), FACTORY.getProviderFactory(ann.value()), Matchers.notNullValue());
|
||||
}
|
||||
testClass = testClass.getSuperclass();
|
||||
}
|
||||
return base;
|
||||
}
|
||||
};
|
||||
|
||||
private static final Set<Class<? extends Spi>> ALLOWED_SPIS = ImmutableSet.<Class<? extends Spi>>builder()
|
||||
.add(AuthorizationSpi.class)
|
||||
.add(ClientSpi.class)
|
||||
.add(ClusterSpi.class)
|
||||
.add(EventStoreSpi.class)
|
||||
.add(ExecutorsSpi.class)
|
||||
.add(GroupSpi.class)
|
||||
.add(RealmSpi.class)
|
||||
.add(RoleSpi.class)
|
||||
.add(StoreFactorySpi.class)
|
||||
.add(UserSpi.class)
|
||||
.build();
|
||||
|
||||
private static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
.add(DefaultAuthorizationProviderFactory.class)
|
||||
.add(DefaultExecutorsProviderFactory.class)
|
||||
.build();
|
||||
|
||||
protected static final List<KeycloakModelParameters> MODEL_PARAMETERS;
|
||||
protected static final DefaultKeycloakSessionFactory FACTORY;
|
||||
|
||||
static {
|
||||
KeycloakModelParameters basicParameters = new KeycloakModelParameters(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
MODEL_PARAMETERS = Stream.concat(
|
||||
Stream.of(basicParameters),
|
||||
Stream.of(System.getProperty("keycloak.model.parameters", "").split("\\s*,\\s*"))
|
||||
.filter(s -> s != null && ! s.trim().isEmpty())
|
||||
.map(cn -> { try { return Class.forName(cn.indexOf('.') >= 0 ? cn : ("org.keycloak.model.parameters." + cn)); } catch (Exception e) { LOG.error("Cannot find " + cn); return null; }})
|
||||
.filter(Objects::nonNull)
|
||||
.map(c -> { try { return c.newInstance(); } catch (Exception e) { LOG.error("Cannot instantiate " + c); return null; }} )
|
||||
.filter(KeycloakModelParameters.class::isInstance)
|
||||
.map(KeycloakModelParameters.class::cast)
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
FACTORY = new DefaultKeycloakSessionFactory() {
|
||||
@Override
|
||||
protected boolean isEnabled(ProviderFactory factory, Scope scope) {
|
||||
return super.isEnabled(factory, scope) && isFactoryAllowed(factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Class<? extends Provider>, Map<String, ProviderFactory>> loadFactories(ProviderManager pm) {
|
||||
spis.removeIf(s -> ! isSpiAllowed(s));
|
||||
return super.loadFactories(pm);
|
||||
}
|
||||
|
||||
private boolean isSpiAllowed(Spi s) {
|
||||
return MODEL_PARAMETERS.stream().anyMatch(p -> p.isSpiAllowed(s));
|
||||
}
|
||||
|
||||
private boolean isFactoryAllowed(ProviderFactory factory) {
|
||||
return MODEL_PARAMETERS.stream().anyMatch(p -> p.isFactoryAllowed(factory));
|
||||
}
|
||||
};
|
||||
FACTORY.init();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void checkValidParameters() {
|
||||
Assume.assumeTrue("keycloak.model.parameters property must be set", MODEL_PARAMETERS.size() > 1); // Additional parameters have to be set
|
||||
}
|
||||
|
||||
protected void createEnvironment(KeycloakSession s) {
|
||||
}
|
||||
|
||||
protected void cleanEnvironment(KeycloakSession s) {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createEnvironment() {
|
||||
KeycloakModelUtils.runJobInTransaction(FACTORY, this::createEnvironment);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanEnvironment() {
|
||||
KeycloakModelUtils.runJobInTransaction(FACTORY, this::cleanEnvironment);
|
||||
}
|
||||
|
||||
protected String registerUserFederationIfAvailable(RealmModel realm) {
|
||||
final List<ProviderFactory> userFedProviders = FACTORY.getProviderFactories(UserStorageProvider.class);
|
||||
|
||||
if (! userFedProviders.isEmpty() && realm != null) {
|
||||
assertThat("Cannot handle more than 1 user federation provider", userFedProviders, hasSize(1));
|
||||
UserStorageProviderModel federatedStorage = new UserStorageProviderModel();
|
||||
federatedStorage.setName(userFedProviders.get(0).getId());
|
||||
federatedStorage.setProviderId(userFedProviders.get(0).getId());
|
||||
federatedStorage.setProviderType(UserStorageProvider.class.getName());
|
||||
federatedStorage.setParentId(realm.getId());
|
||||
ComponentModel res = realm.addComponentModel(federatedStorage);
|
||||
log.infof("Added %s user federation provider: %s", federatedStorage.getName(), res.getId());
|
||||
return res.getId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected <T> void inRolledBackTransaction(T parameter, BiConsumer<KeycloakSession, T> what) {
|
||||
KeycloakSession session = new DefaultKeycloakSession(FACTORY);
|
||||
session.getTransactionManager().begin();
|
||||
|
||||
what.accept(session, parameter);
|
||||
|
||||
session.getTransactionManager().rollback();
|
||||
}
|
||||
|
||||
protected <T> void inComittedTransaction(T parameter, BiConsumer<KeycloakSession, T> what) {
|
||||
inComittedTransaction(parameter, what, (a,b) -> {}, (a,b) -> {});
|
||||
}
|
||||
|
||||
protected <T> void inComittedTransaction(T parameter, BiConsumer<KeycloakSession, T> what, BiConsumer<KeycloakSession, T> onCommit, BiConsumer<KeycloakSession, T> onRollback) {
|
||||
KeycloakModelUtils.runJobInTransaction(FACTORY, session -> {
|
||||
session.getTransactionManager().enlistAfterCompletion(new AbstractKeycloakTransaction() {
|
||||
@Override
|
||||
protected void commitImpl() {
|
||||
if (onCommit != null) { onCommit.accept(session, parameter); }
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void rollbackImpl() {
|
||||
if (onRollback != null) { onRollback.accept(session, parameter); }
|
||||
}
|
||||
});
|
||||
what.accept(session, parameter);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.model;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Identifies a requirement for a given provider to be present in the session factory.
|
||||
* If the provider is not available, the test is skipped.
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Repeatable(RequireProviders.class)
|
||||
public @interface RequireProvider {
|
||||
Class<? extends Provider> value() default Provider.class;
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.model;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface RequireProviders {
|
||||
RequireProvider[] value();
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* 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.model;
|
||||
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserProvider;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.UserStorageProviderFactory;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
import org.keycloak.storage.user.UserLookupProvider;
|
||||
import org.keycloak.storage.user.UserRegistrationProvider;
|
||||
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.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assume.assumeThat;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
@RequireProvider(UserProvider.class)
|
||||
@RequireProvider(RealmProvider.class)
|
||||
public class UserModelTest extends KeycloakModelTest {
|
||||
|
||||
protected static final int NUM_GROUPS = 100;
|
||||
|
||||
private String realmId;
|
||||
private final List<String> groupIds = new ArrayList<>(NUM_GROUPS);
|
||||
private String userFederationId;
|
||||
|
||||
@Override
|
||||
public void createEnvironment(KeycloakSession s) {
|
||||
RealmModel realm = s.realms().createRealm("realm");
|
||||
this.realmId = realm.getId();
|
||||
|
||||
this.userFederationId = registerUserFederationIfAvailable(realm);
|
||||
|
||||
IntStream.range(0, NUM_GROUPS).forEach(i -> {
|
||||
groupIds.add(s.groups().createGroup(realm, "group-" + i).getId());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanEnvironment(KeycloakSession s) {
|
||||
s.realms().removeRealm(realmId);
|
||||
}
|
||||
|
||||
private void addRemoveUser(KeycloakSession session, int i) {
|
||||
RealmModel realm = session.realms().getRealmByName("realm");
|
||||
|
||||
UserModel user = session.users().addUser(realm, "user-" + i);
|
||||
|
||||
IntStream.range(0, NUM_GROUPS / 20).forEach(gIndex -> {
|
||||
user.joinGroup(session.groups().getGroupById(realm, groupIds.get((i + gIndex) % NUM_GROUPS)));
|
||||
});
|
||||
|
||||
final UserModel obtainedUser = session.users().getUserById(user.getId(), realm);
|
||||
|
||||
assertThat(obtainedUser, Matchers.notNullValue());
|
||||
assertThat(obtainedUser.getUsername(), is("user-" + i));
|
||||
Set<String> userGroupIds = obtainedUser.getGroupsStream().map(GroupModel::getName).collect(Collectors.toSet());
|
||||
assertThat(userGroupIds, hasSize(NUM_GROUPS / 20));
|
||||
assertThat(userGroupIds, hasItem("group-" + i));
|
||||
assertThat(userGroupIds, hasItem("group-" + (i - 1 + (NUM_GROUPS / 20)) % NUM_GROUPS));
|
||||
|
||||
assertTrue(session.users().removeUser(realm, user));
|
||||
assertFalse(session.users().removeUser(realm, user));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRemoveUser() {
|
||||
inRolledBackTransaction(1, this::addRemoveUser);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRemoveUserConcurrent() {
|
||||
IntStream.range(0,100).parallel().forEach(i -> inComittedTransaction(i, this::addRemoveUser));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRemoveUsersInTheSameGroupConcurrent() {
|
||||
final ConcurrentSkipListSet<String> userIds = new ConcurrentSkipListSet<>();
|
||||
String groupId = groupIds.get(0);
|
||||
|
||||
// Create users and let them join first group
|
||||
IntStream.range(0, 100).parallel().forEach(index -> inComittedTransaction(index, (session, i) -> {
|
||||
final RealmModel realm = session.realms().getRealm(realmId);
|
||||
final UserModel user = session.users().addUser(realm, "user-" + i);
|
||||
user.joinGroup(session.groups().getGroupById(realm, groupId));
|
||||
userIds.add(user.getId());
|
||||
}));
|
||||
|
||||
inComittedTransaction(1, (session, i) -> {
|
||||
final RealmModel realm = session.realms().getRealm(realmId);
|
||||
final GroupModel group = session.groups().getGroupById(realm, groupId);
|
||||
assertThat(session.users().getGroupMembersStream(realm, group).count(), is(100L));
|
||||
});
|
||||
|
||||
// Some of the transactions may fail due to conflicts as there are many parallel request, so repeat until all users are removed
|
||||
Set<String> remainingUserIds = new HashSet<>();
|
||||
do {
|
||||
userIds.stream().parallel().forEach(index -> inComittedTransaction(index, (session, userId) -> {
|
||||
final RealmModel realm = session.realms().getRealm(realmId);
|
||||
final UserModel user = session.users().getUserById(userId, realm);
|
||||
log.debugf("Remove user %s: %s", userId, session.users().removeUser(realm, user));
|
||||
}, null, (session, userId) -> remainingUserIds.add(userId) ));
|
||||
|
||||
userIds.clear();
|
||||
userIds.addAll(remainingUserIds);
|
||||
remainingUserIds.clear();
|
||||
} while (! userIds.isEmpty());
|
||||
|
||||
inComittedTransaction(1, (session, i) -> {
|
||||
final RealmModel realm = session.realms().getRealm(realmId);
|
||||
final GroupModel group = session.groups().getGroupById(realm, groupId);
|
||||
assertThat(session.users().getGroupMembersStream(realm, group).collect(Collectors.toList()), Matchers.empty());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddDirtyRemoveFederationUsersInTheSameGroupConcurrent() {
|
||||
assumeThat("Test for federated providers only", userFederationId, Matchers.notNullValue());
|
||||
|
||||
final ConcurrentSkipListSet<String> userIds = new ConcurrentSkipListSet<>();
|
||||
String groupId = groupIds.get(0);
|
||||
|
||||
// Create users and let them join first group
|
||||
IntStream.range(0, 100).parallel().forEach(index -> inComittedTransaction(index, (session, i) -> {
|
||||
final RealmModel realm = session.realms().getRealm(realmId);
|
||||
final UserModel user = session.users().addUser(realm, "user-" + i);
|
||||
user.joinGroup(session.groups().getGroupById(realm, groupId));
|
||||
userIds.add(user.getId());
|
||||
}));
|
||||
|
||||
// Remove users _from the federation_, simulates eg. user being removed from LDAP without Keycloak knowing
|
||||
inComittedTransaction(1, (session, i) -> {
|
||||
final RealmModel realm = session.realms().getRealm(realmId);
|
||||
UserStorageProvider instance = (UserStorageProvider)session.getAttribute(userFederationId);
|
||||
|
||||
if (instance == null) {
|
||||
ComponentModel model = realm.getComponent(userFederationId);
|
||||
UserStorageProviderModel storageModel = new UserStorageProviderModel(model);
|
||||
UserStorageProviderFactory factory = (UserStorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, model.getProviderId());
|
||||
instance = factory.create(session, model);
|
||||
if (instance == null) {
|
||||
throw new RuntimeException("UserStorageProvideFactory (of type " + factory.getClass().getName() + ") produced a null instance");
|
||||
}
|
||||
session.enlistForClose(instance);
|
||||
session.setAttribute(userFederationId, instance);
|
||||
}
|
||||
|
||||
final UserStorageProvider lambdaInstance = instance;
|
||||
log.debugf("Removing selected users from backend");
|
||||
IntStream.range(FIRST_DELETED_USER_INDEX, LAST_DELETED_USER_INDEX).forEach(j -> {
|
||||
final UserModel user = ((UserLookupProvider) lambdaInstance).getUserByUsername("user-" + j, realm);
|
||||
((UserRegistrationProvider) lambdaInstance).removeUser(realm, user);
|
||||
});
|
||||
});
|
||||
|
||||
inComittedTransaction(1, (session, i) -> {
|
||||
final RealmModel realm = session.realms().getRealm(realmId);
|
||||
final GroupModel group = session.groups().getGroupById(realm, groupId);
|
||||
assertThat(session.users().getGroupMembersStream(realm, group).count(), is(100L - DELETED_USER_COUNT));
|
||||
});
|
||||
|
||||
// Now delete the users, and count those that were not found to be deleted. This should be equal to the number
|
||||
// of users removed directly in the user federation.
|
||||
// Some of the transactions may fail due to conflicts as there are many parallel request, so repeat until all users are removed
|
||||
AtomicInteger notFoundUsers = new AtomicInteger();
|
||||
Set<String> remainingUserIds = new HashSet<>();
|
||||
do {
|
||||
userIds.stream().parallel().forEach(index -> inComittedTransaction(index, (session, userId) -> {
|
||||
final RealmModel realm = session.realms().getRealm(realmId);
|
||||
final UserModel user = session.users().getUserById(userId, realm);
|
||||
if (user != null) {
|
||||
log.debugf("Deleting user: %s", userId);
|
||||
session.users().removeUser(realm, user);
|
||||
} else {
|
||||
log.debugf("Failed deleting user: %s", userId);
|
||||
notFoundUsers.incrementAndGet();
|
||||
}
|
||||
}, null, (session, userId) -> {
|
||||
log.debugf("Could not delete user %s", userId);
|
||||
remainingUserIds.add(userId);
|
||||
}));
|
||||
|
||||
userIds.clear();
|
||||
userIds.addAll(remainingUserIds);
|
||||
remainingUserIds.clear();
|
||||
} while (! userIds.isEmpty());
|
||||
|
||||
assertThat(notFoundUsers.get(), is(DELETED_USER_COUNT));
|
||||
|
||||
inComittedTransaction(1, (session, i) -> {
|
||||
final RealmModel realm = session.realms().getRealm(realmId);
|
||||
final GroupModel group = session.groups().getGroupById(realm, groupId);
|
||||
assertThat(session.users().getGroupMembersStream(realm, group).collect(Collectors.toList()), Matchers.empty());
|
||||
});
|
||||
}
|
||||
private static final int FIRST_DELETED_USER_INDEX = 10;
|
||||
private static final int LAST_DELETED_USER_INDEX = 90;
|
||||
private static final int DELETED_USER_COUNT = LAST_DELETED_USER_INDEX - FIRST_DELETED_USER_INDEX;
|
||||
}
|
|
@ -14,36 +14,16 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.events.jpa;
|
||||
package org.keycloak.model.events;
|
||||
|
||||
import org.keycloak.Config.Scope;
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory;
|
||||
import org.keycloak.connections.jpa.JpaConnectionSpi;
|
||||
import org.keycloak.connections.jpa.updater.JpaUpdaterProviderFactory;
|
||||
import org.keycloak.connections.jpa.updater.JpaUpdaterSpi;
|
||||
import org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionProviderFactory;
|
||||
import org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionSpi;
|
||||
import org.keycloak.connections.jpa.updater.liquibase.lock.LiquibaseDBLockProviderFactory;
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.events.EventStoreProvider;
|
||||
import org.keycloak.events.EventStoreProviderFactory;
|
||||
import org.keycloak.events.EventStoreSpi;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.model.KeycloakModelTest;
|
||||
import org.keycloak.model.RequireProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmSpi;
|
||||
import org.keycloak.models.dblock.DBLockSpi;
|
||||
import org.keycloak.models.jpa.JpaRealmProviderFactory;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.ProviderManager;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.services.DefaultKeycloakSession;
|
||||
import org.keycloak.services.DefaultKeycloakSessionFactory;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
@ -55,43 +35,17 @@ import static org.junit.Assert.assertThat;
|
|||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class JpaAdminEventQueryTest {
|
||||
@RequireProvider(EventStoreProvider.class)
|
||||
public class AdminEventQueryTest extends KeycloakModelTest {
|
||||
|
||||
private static final Set<Class<? extends Spi>> ALLOWED_SPIS = ImmutableSet.<Class<? extends Spi>>builder()
|
||||
.add(DBLockSpi.class)
|
||||
.add(EventStoreSpi.class)
|
||||
.add(JpaConnectionSpi.class)
|
||||
.add(JpaUpdaterSpi.class)
|
||||
.add(LiquibaseConnectionSpi.class)
|
||||
.add(RealmSpi.class)
|
||||
.build();
|
||||
|
||||
private static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
.add(DefaultJpaConnectionProviderFactory.class)
|
||||
.add(EventStoreProviderFactory.class)
|
||||
.add(JpaUpdaterProviderFactory.class)
|
||||
.add(JpaRealmProviderFactory.class)
|
||||
.add(LiquibaseConnectionProviderFactory.class)
|
||||
.add(LiquibaseDBLockProviderFactory.class)
|
||||
.build();
|
||||
|
||||
private static final DefaultKeycloakSessionFactory factory = new DefaultKeycloakSessionFactory() {
|
||||
@Override
|
||||
protected boolean isEnabled(ProviderFactory factory, Scope scope) {
|
||||
return super.isEnabled(factory, scope) && ALLOWED_FACTORIES.stream().filter(c -> c.isAssignableFrom(factory.getClass())).findAny().isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Class<? extends Provider>, Map<String, ProviderFactory>> loadFactories(ProviderManager pm) {
|
||||
spis.removeIf(s -> ! ALLOWED_SPIS.contains(s.getClass()));
|
||||
return super.loadFactories(pm);
|
||||
}
|
||||
};
|
||||
static { factory.init(); }
|
||||
|
||||
private final KeycloakSession session = new DefaultKeycloakSession(factory);
|
||||
private final KeycloakSession session = FACTORY.create();
|
||||
private final EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
|
||||
|
||||
@Test
|
||||
public void testClear() {
|
||||
eventStore.clear();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void startTransaction() {
|
||||
session.getTransactionManager().begin();
|
||||
|
@ -102,11 +56,6 @@ public class JpaAdminEventQueryTest {
|
|||
session.getTransactionManager().rollback();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClear() {
|
||||
eventStore.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuery() {
|
||||
RealmModel realm = session.realms().createRealm("realm");
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.model.parameters;
|
||||
|
||||
import org.keycloak.model.KeycloakModelParameters;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.storage.UserStorageProviderSpi;
|
||||
import org.keycloak.storage.federated.UserFederatedStorageProviderSpi;
|
||||
import org.keycloak.storage.jpa.JpaUserFederatedStorageProviderFactory;
|
||||
import org.keycloak.testsuite.federation.BackwardsCompatibilityUserStorageFactory;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class BackwardsCompatibilityUserStorage 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(BackwardsCompatibilityUserStorageFactory.class)
|
||||
.build();
|
||||
|
||||
public BackwardsCompatibilityUserStorage() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.model.parameters;
|
||||
|
||||
import org.keycloak.model.KeycloakModelParameters;
|
||||
import org.keycloak.models.map.client.MapClientProviderFactory;
|
||||
import org.keycloak.models.map.group.MapGroupProviderFactory;
|
||||
import org.keycloak.models.map.role.MapRoleProviderFactory;
|
||||
import org.keycloak.models.map.storage.ConcurrentHashMapStorageProvider;
|
||||
import org.keycloak.models.map.storage.MapStorageProvider;
|
||||
import org.keycloak.models.map.storage.MapStorageSpi;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
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()
|
||||
.build();
|
||||
|
||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
.add(ConcurrentHashMapStorageProvider.class)
|
||||
.build();
|
||||
|
||||
static {
|
||||
System.setProperty("keycloak.mapStorage.concurrenthashmap.dir", System.getProperty("keycloak.mapStorage.concurrenthashmap.dir", "${project.build.directory:target}"));
|
||||
}
|
||||
|
||||
public ConcurrentHashMapStorage() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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.model.parameters;
|
||||
|
||||
import org.keycloak.cluster.infinispan.InfinispanClusterProviderFactory;
|
||||
import org.keycloak.connections.infinispan.InfinispanConnectionProviderFactory;
|
||||
import org.keycloak.connections.infinispan.InfinispanConnectionSpi;
|
||||
import org.keycloak.model.KeycloakModelParameters;
|
||||
import org.keycloak.models.cache.CacheRealmProviderSpi;
|
||||
import org.keycloak.models.cache.CacheUserProviderSpi;
|
||||
import org.keycloak.models.cache.infinispan.InfinispanCacheRealmProviderFactory;
|
||||
import org.keycloak.models.cache.infinispan.InfinispanUserCacheProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class Infinispan extends KeycloakModelParameters {
|
||||
|
||||
static final Set<Class<? extends Spi>> ALLOWED_SPIS = ImmutableSet.<Class<? extends Spi>>builder()
|
||||
.add(CacheRealmProviderSpi.class)
|
||||
.add(CacheUserProviderSpi.class)
|
||||
.add(InfinispanConnectionSpi.class)
|
||||
|
||||
.build();
|
||||
|
||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
.add(InfinispanCacheRealmProviderFactory.class)
|
||||
.add(InfinispanClusterProviderFactory.class)
|
||||
.add(InfinispanConnectionProviderFactory.class)
|
||||
.add(InfinispanUserCacheProviderFactory.class)
|
||||
.build();
|
||||
|
||||
static {
|
||||
System.setProperty("keycloak.connectionsInfinispan.default.embedded", System.getProperty("keycloak.connectionsInfinispan.default.embedded", "true"));
|
||||
}
|
||||
|
||||
public Infinispan() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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.model.parameters;
|
||||
|
||||
import org.keycloak.authorization.jpa.store.JPAAuthorizationStoreFactory;
|
||||
import org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory;
|
||||
import org.keycloak.connections.jpa.JpaConnectionSpi;
|
||||
import org.keycloak.connections.jpa.updater.JpaUpdaterProviderFactory;
|
||||
import org.keycloak.connections.jpa.updater.JpaUpdaterSpi;
|
||||
import org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionProviderFactory;
|
||||
import org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionSpi;
|
||||
import org.keycloak.connections.jpa.updater.liquibase.lock.LiquibaseDBLockProviderFactory;
|
||||
import org.keycloak.events.jpa.JpaEventStoreProviderFactory;
|
||||
import org.keycloak.model.KeycloakModelParameters;
|
||||
import org.keycloak.models.dblock.DBLockSpi;
|
||||
import org.keycloak.models.jpa.JpaClientProviderFactory;
|
||||
import org.keycloak.models.jpa.JpaGroupProviderFactory;
|
||||
import org.keycloak.models.jpa.JpaRealmProviderFactory;
|
||||
import org.keycloak.models.jpa.JpaRoleProviderFactory;
|
||||
import org.keycloak.models.jpa.JpaUserProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class Jpa extends KeycloakModelParameters {
|
||||
|
||||
static final Set<Class<? extends Spi>> ALLOWED_SPIS = ImmutableSet.<Class<? extends Spi>>builder()
|
||||
// jpa-specific
|
||||
.add(DBLockSpi.class)
|
||||
.add(JpaConnectionSpi.class)
|
||||
.add(JpaUpdaterSpi.class)
|
||||
.add(LiquibaseConnectionSpi.class)
|
||||
|
||||
.build();
|
||||
|
||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
// jpa-specific
|
||||
.add(DefaultJpaConnectionProviderFactory.class)
|
||||
.add(JPAAuthorizationStoreFactory.class)
|
||||
.add(JpaClientProviderFactory.class)
|
||||
.add(JpaEventStoreProviderFactory.class)
|
||||
.add(JpaGroupProviderFactory.class)
|
||||
.add(JpaRealmProviderFactory.class)
|
||||
.add(JpaRoleProviderFactory.class)
|
||||
.add(JpaUpdaterProviderFactory.class)
|
||||
.add(JpaUserProviderFactory.class)
|
||||
.add(LiquibaseConnectionProviderFactory.class)
|
||||
.add(LiquibaseDBLockProviderFactory.class)
|
||||
.build();
|
||||
|
||||
public Jpa() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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.model.parameters;
|
||||
|
||||
import org.keycloak.model.KeycloakModelParameters;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.storage.UserStorageProviderSpi;
|
||||
import org.keycloak.storage.federated.UserFederatedStorageProviderSpi;
|
||||
import org.keycloak.storage.jpa.JpaUserFederatedStorageProviderFactory;
|
||||
import org.keycloak.testsuite.federation.BackwardsCompatibilityUserStorageFactory;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class JpaFederation extends KeycloakModelParameters {
|
||||
|
||||
static final Set<Class<? extends Spi>> ALLOWED_SPIS = ImmutableSet.<Class<? extends Spi>>builder()
|
||||
.addAll(Jpa.ALLOWED_SPIS)
|
||||
.add(UserStorageProviderSpi.class)
|
||||
.add(UserFederatedStorageProviderSpi.class)
|
||||
|
||||
.build();
|
||||
|
||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
.addAll(Jpa.ALLOWED_FACTORIES)
|
||||
.add(JpaUserFederatedStorageProviderFactory.class)
|
||||
.build();
|
||||
|
||||
public JpaFederation() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.model.parameters;
|
||||
|
||||
import org.keycloak.model.KeycloakModelParameters;
|
||||
import org.keycloak.models.map.client.MapClientProviderFactory;
|
||||
import org.keycloak.models.map.group.MapGroupProviderFactory;
|
||||
import org.keycloak.models.map.role.MapRoleProviderFactory;
|
||||
import org.keycloak.models.map.storage.MapStorageProvider;
|
||||
import org.keycloak.models.map.storage.MapStorageSpi;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
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(MapStorageSpi.class)
|
||||
|
||||
.build();
|
||||
|
||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
.add(MapClientProviderFactory.class)
|
||||
.add(MapGroupProviderFactory.class)
|
||||
.add(MapRoleProviderFactory.class)
|
||||
.add(MapStorageProvider.class)
|
||||
.build();
|
||||
|
||||
public Map() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
}
|
|
@ -19,18 +19,16 @@ log4j.rootLogger=info, keycloak
|
|||
|
||||
log4j.appender.keycloak=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.keycloak.layout=org.apache.log4j.EnhancedPatternLayout
|
||||
keycloak.testsuite.logging.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %m%n
|
||||
keycloak.testsuite.logging.pattern=%d{HH:mm:ss,SSS} %-5p %t [%c] %m%n
|
||||
log4j.appender.keycloak.layout.ConversionPattern=${keycloak.testsuite.logging.pattern}
|
||||
|
||||
# Logging with "info" when running test from IDE, but disabled when running test with "mvn" . Both cases can be overriden by use system property "keycloak.logging.level" (eg. -Dkeycloak.logging.level=debug )
|
||||
log4j.logger.org.keycloak=${keycloak.logging.level:debug}
|
||||
|
||||
keycloak.testsuite.logging.level=debug
|
||||
log4j.logger.org.keycloak.testsuite=${keycloak.testsuite.logging.level}
|
||||
log4j.logger.org.keycloak.models=debug
|
||||
# log4j.logger.org.hibernate=debug
|
||||
|
||||
# Enable to view loaded SPI and Providers
|
||||
log4j.logger.org.keycloak.services.DefaultKeycloakSessionFactory=debug
|
||||
log4j.logger.org.keycloak.provider.ProviderManager=debug
|
||||
# log4j.logger.org.keycloak.services.DefaultKeycloakSessionFactory=debug
|
||||
# log4j.logger.org.keycloak.provider.ProviderManager=debug
|
||||
# log4j.logger.org.keycloak.provider.FileSystemProviderLoaderFactory=debug
|
||||
|
||||
# Liquibase updates logged with "info" by default. Logging level can be changed by system property "keycloak.liquibase.logging.level"
|
|
@ -45,6 +45,7 @@
|
|||
<modules>
|
||||
<module>db-allocator-plugin</module>
|
||||
<module>integration-arquillian</module>
|
||||
<module>model</module>
|
||||
<module>utils</module>
|
||||
</modules>
|
||||
|
||||
|
|
Loading…
Reference in a new issue