KEYCLOAK-16489 Add ability to run model tests with LDAP
This commit is contained in:
parent
f6be378eca
commit
8c0c542f09
25 changed files with 475 additions and 100 deletions
39
.github/workflows/ci.yml
vendored
39
.github/workflows/ci.yml
vendored
|
@ -82,6 +82,45 @@ jobs:
|
|||
path: reports-unit-tests.zip
|
||||
if-no-files-found: ignore
|
||||
|
||||
model-tests:
|
||||
name: Model Tests
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
- name: Cache Maven packages
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: cache-1-${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: cache-1-${{ runner.os }}-m2
|
||||
- name: Cleanup org.keycloak artifacts
|
||||
run: rm -rf ~/.m2/repository/org/keycloak >/dev/null || true
|
||||
- name: Download built keycloak
|
||||
id: download-keycloak
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
path: ~/.m2/repository/org/keycloak/
|
||||
name: keycloak-artifacts.zip
|
||||
- name: Run model tests
|
||||
run: |
|
||||
if ! testsuite/model/test-all-profiles.sh; then
|
||||
find . -path '*/target/surefire-reports*/*.xml' | zip -q reports-model-tests.zip -@
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Model test reports
|
||||
uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: reports-model-tests
|
||||
retention-days: 14
|
||||
path: reports-model-tests.zip
|
||||
if-no-files-found: ignore
|
||||
|
||||
test:
|
||||
name: Base testsuite
|
||||
needs: build
|
||||
|
|
|
@ -171,8 +171,11 @@ public class UserStorageSyncManager {
|
|||
return;
|
||||
|
||||
}
|
||||
final ClusterProvider cp = session.getProvider(ClusterProvider.class);
|
||||
if (cp != null) {
|
||||
UserStorageProviderClusterEvent event = UserStorageProviderClusterEvent.createEvent(removed, realm.getId(), provider);
|
||||
session.getProvider(ClusterProvider.class).notify(USER_STORAGE_TASK_KEY, event, false, ClusterProvider.DCNotify.ALL_DCS);
|
||||
cp.notify(USER_STORAGE_TASK_KEY, event, false, ClusterProvider.DCNotify.ALL_DCS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -74,12 +74,15 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us
|
|||
this.users = users;
|
||||
}
|
||||
|
||||
private static String translateUserName(String userName) {
|
||||
return userName == null ? null : userName.toLowerCase();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModel getUserById(String id, RealmModel realm) {
|
||||
StorageId storageId = new StorageId(id);
|
||||
final String username = storageId.getExternalId();
|
||||
if (!users.containsKey(username)) return null;
|
||||
if (!users.containsKey(translateUserName(username))) return null;
|
||||
|
||||
return createUser(realm, username);
|
||||
}
|
||||
|
@ -152,7 +155,7 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us
|
|||
assertNotNull(newPassword.getValue());
|
||||
assertNotNull(newPassword.getSalt());
|
||||
|
||||
users.get(user.getUsername()).hashedPassword = newPassword;
|
||||
users.get(translateUserName(user.getUsername())).hashedPassword = newPassword;
|
||||
|
||||
UserCache userCache = session.userCache();
|
||||
if (userCache != null) {
|
||||
|
@ -179,7 +182,7 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us
|
|||
newOTP.setAlgorithm(otpPolicy.getAlgorithm());
|
||||
newOTP.setPeriod(otpPolicy.getPeriod());
|
||||
|
||||
users.get(user.getUsername()).otp = newOTP;
|
||||
users.get(translateUserName(user.getUsername())).otp = newOTP;
|
||||
|
||||
return true;
|
||||
} else {
|
||||
|
@ -208,7 +211,7 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us
|
|||
}
|
||||
|
||||
private MyUser getMyUser(UserModel user) {
|
||||
return users.get(user.getUsername());
|
||||
return users.get(translateUserName(user.getUsername()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -240,7 +243,7 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us
|
|||
|
||||
@Override
|
||||
public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) {
|
||||
MyUser myUser = users.get(user.getUsername());
|
||||
MyUser myUser = users.get(translateUserName(user.getUsername()));
|
||||
if (myUser == null) return false;
|
||||
|
||||
if (input.getType().equals(UserCredentialModel.PASSWORD)) {
|
||||
|
@ -289,7 +292,7 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us
|
|||
|
||||
@Override
|
||||
public UserModel getUserByUsername(String username, RealmModel realm) {
|
||||
if (!users.containsKey(username)) return null;
|
||||
if (!users.containsKey(translateUserName(username))) return null;
|
||||
|
||||
return createUser(realm, username);
|
||||
}
|
||||
|
@ -301,13 +304,13 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us
|
|||
|
||||
@Override
|
||||
public UserModel addUser(RealmModel realm, String username) {
|
||||
users.put(username, new MyUser(username));
|
||||
users.put(translateUserName(username), new MyUser(username));
|
||||
return createUser(realm, username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeUser(RealmModel realm, UserModel user) {
|
||||
return users.remove(user.getUsername()) != null;
|
||||
return users.remove(translateUserName(user.getUsername())) != null;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
|||
public UserModel getUserById(String id, RealmModel realm) {
|
||||
StorageId storageId = new StorageId(id);
|
||||
final String username = storageId.getExternalId();
|
||||
if (!userPasswords.containsKey(username)) {
|
||||
if (!userPasswords.containsKey(translateUserName(username))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -159,7 +159,7 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
|||
return false;
|
||||
}
|
||||
if (input.getType().equals(PasswordCredentialModel.TYPE)) {
|
||||
userPasswords.put(user.getUsername(), input.getChallengeResponse());
|
||||
userPasswords.put(translateUserName(user.getUsername()), input.getChallengeResponse());
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
@ -189,7 +189,7 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
|||
return false;
|
||||
}
|
||||
if (input.getType().equals(PasswordCredentialModel.TYPE)) {
|
||||
String pw = userPasswords.get(user.getUsername());
|
||||
String pw = userPasswords.get(translateUserName(user.getUsername()));
|
||||
|
||||
// Using "getValue" on purpose here, to test that backwards compatibility works as expected
|
||||
return pw != null && pw.equals(((UserCredentialModel) input).getValue());
|
||||
|
@ -200,7 +200,7 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
|||
|
||||
@Override
|
||||
public UserModel getUserByUsername(String username, RealmModel realm) {
|
||||
if (!userPasswords.containsKey(username)) {
|
||||
if (!userPasswords.containsKey(translateUserName(username))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -218,7 +218,7 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
|||
throw new ReadOnlyException("Federated storage is not writable");
|
||||
}
|
||||
|
||||
userPasswords.put(username, "");
|
||||
userPasswords.put(translateUserName(username), "");
|
||||
return createUser(realm, username);
|
||||
}
|
||||
|
||||
|
@ -226,21 +226,21 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
|||
public boolean removeUser(RealmModel realm, UserModel user) {
|
||||
if (editMode == UserStorageProvider.EditMode.READ_ONLY || editMode == UserStorageProvider.EditMode.UNSYNCED) {
|
||||
log.warnf("User '%s' can't be deleted in LDAP as editMode is '%s'. Deleting user just from Keycloak DB, but he will be re-imported from LDAP again once searched in Keycloak", user.getUsername(), editMode.toString());
|
||||
userPasswords.remove(user.getUsername());
|
||||
userPasswords.remove(translateUserName(user.getUsername()));
|
||||
return true;
|
||||
}
|
||||
|
||||
return userPasswords.remove(user.getUsername()) != null;
|
||||
return userPasswords.remove(translateUserName(user.getUsername())) != null;
|
||||
}
|
||||
|
||||
public boolean removeUserByName(String userName) {
|
||||
if (editMode == UserStorageProvider.EditMode.READ_ONLY || editMode == UserStorageProvider.EditMode.UNSYNCED) {
|
||||
log.warnf("User '%s' can't be deleted in LDAP as editMode is '%s'. Deleting user just from Keycloak DB, but he will be re-imported from LDAP again once searched in Keycloak", userName, editMode.toString());
|
||||
userPasswords.remove(userName);
|
||||
userPasswords.remove(translateUserName(userName));
|
||||
return true;
|
||||
}
|
||||
|
||||
return userPasswords.remove(userName) != null;
|
||||
return userPasswords.remove(translateUserName(userName)) != null;
|
||||
}
|
||||
|
||||
public boolean isImportEnabled() {
|
||||
|
@ -307,17 +307,19 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
|||
|
||||
@Override
|
||||
public Stream<UserModel> searchForUserStream(String search, RealmModel realm) {
|
||||
String tSearch = translateUserName(search);
|
||||
return userPasswords.keySet().stream()
|
||||
.sorted()
|
||||
.filter(userName -> userName.contains(search))
|
||||
.filter(userName -> translateUserName(userName).contains(tSearch))
|
||||
.map(userName -> createUser(realm, userName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<UserModel> searchForUserStream(String search, RealmModel realm, int firstResult, int maxResults) {
|
||||
String tSearch = translateUserName(search);
|
||||
Stream<String> userStream = userPasswords.keySet().stream()
|
||||
.sorted()
|
||||
.filter(userName -> userName.contains(search));
|
||||
.filter(userName -> translateUserName(userName).contains(search));
|
||||
if (firstResult > 0)
|
||||
userStream = userStream.skip(firstResult);
|
||||
if (maxResults >= 0)
|
||||
|
@ -421,11 +423,15 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
|||
|
||||
@Override
|
||||
public UserModel validate(RealmModel realm, UserModel local) {
|
||||
final boolean userExists = userPasswords.containsKey(local.getUsername());
|
||||
final boolean userExists = userPasswords.containsKey(translateUserName(local.getUsername()));
|
||||
if (! userExists) {
|
||||
userGroups.remove(getUserIdInMap(realm, local.getUsername()));
|
||||
}
|
||||
return userExists ? local : null;
|
||||
}
|
||||
|
||||
private static String translateUserName(String userName) {
|
||||
return userName == null ? null : userName.toLowerCase();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -266,6 +266,10 @@ public class LDAPRule extends ExternalResource {
|
|||
return ldapTestConfiguration.getSleepTime();
|
||||
}
|
||||
|
||||
public LDAPEmbeddedServer getLdapEmbeddedServer() {
|
||||
return ldapEmbeddedServer;
|
||||
}
|
||||
|
||||
/** Allows to run particular LDAP test just under specific conditions (eg. some test running just on Active Directory) **/
|
||||
public interface LDAPAssume {
|
||||
|
||||
|
|
|
@ -61,6 +61,11 @@
|
|||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-server-spi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<artifactId>integration-arquillian-tests-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${jdbc.mvn.groupId}</groupId>
|
||||
<artifactId>${jdbc.mvn.artifactId}</artifactId>
|
||||
|
@ -127,14 +132,28 @@
|
|||
<profile>
|
||||
<id>jpa-federation+infinispan</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>Infinispan,JpaFederation,BackwardsCompatibilityUserStorage</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>Infinispan,JpaFederation,TestsuiteUserMapStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa-federation</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>JpaFederation,BackwardsCompatibilityUserStorage</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>JpaFederation,TestsuiteUserMapStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa-federation+ldap</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>JpaFederation,LdapUserStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa-federation+ldap+infinispan</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>JpaFederation,LdapUserStorage,Infinispan</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
|
|
|
@ -14,11 +14,14 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.model;
|
||||
package org.keycloak.testsuite.model;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -42,4 +45,23 @@ public class KeycloakModelParameters {
|
|||
return allowedFactories.stream().anyMatch((c) -> c.isAssignableFrom(factory.getClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns stream of parameters of the given type, or an empty stream if no parameters of the given type are supplied
|
||||
* by this clazz.
|
||||
* @param <T>
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public <T> Stream<T> getParameters(Class<T> clazz) {
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
public Statement classRule(Statement base, Description description) {
|
||||
return base;
|
||||
}
|
||||
|
||||
public Statement instanceRule(Statement base, Description description) {
|
||||
return base;
|
||||
}
|
||||
|
||||
}
|
|
@ -14,14 +14,13 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.model;
|
||||
package org.keycloak.testsuite.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;
|
||||
|
@ -30,7 +29,6 @@ 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;
|
||||
|
@ -41,28 +39,29 @@ 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.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
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.AssumptionViolatedException;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
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
|
||||
|
@ -87,13 +86,56 @@ public abstract class KeycloakModelTest {
|
|||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
Class<?> testClass = description.getTestClass();
|
||||
Stream<RequireProvider> st = Stream.empty();
|
||||
while (testClass != Object.class) {
|
||||
for (RequireProvider ann : testClass.getAnnotationsByType(RequireProvider.class)) {
|
||||
Assume.assumeThat("Provider must exist: " + ann.value(), FACTORY.getProviderFactory(ann.value()), Matchers.notNullValue());
|
||||
}
|
||||
st = Stream.concat(Stream.of(testClass.getAnnotationsByType(RequireProvider.class)), st);
|
||||
testClass = testClass.getSuperclass();
|
||||
}
|
||||
return base;
|
||||
List<Class<? extends Provider>> notFound = st.map(RequireProvider::value)
|
||||
.filter(pClass -> FACTORY.getProviderFactory(pClass) == null)
|
||||
.collect(Collectors.toList());
|
||||
Assume.assumeThat("Some required providers not found", notFound, Matchers.empty());
|
||||
|
||||
Statement res = base;
|
||||
for (KeycloakModelParameters kmp : KeycloakModelTest.MODEL_PARAMETERS) {
|
||||
res = kmp.classRule(res, description);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
@Rule
|
||||
public final TestRule guaranteeRequiredFactoryOnMethod = new TestRule() {
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
Stream<RequireProvider> st = Optional.ofNullable(description.getAnnotation(RequireProviders.class))
|
||||
.map(RequireProviders::value)
|
||||
.map(Stream::of)
|
||||
.orElseGet(Stream::empty);
|
||||
|
||||
RequireProvider rp = description.getAnnotation(RequireProvider.class);
|
||||
if (rp != null) {
|
||||
st = Stream.concat(st, Stream.of(rp));
|
||||
}
|
||||
|
||||
for (Iterator<Class<? extends Provider>> iterator = st.map(RequireProvider::value).iterator(); iterator.hasNext();) {
|
||||
Class<? extends Provider> providerClass = iterator.next();
|
||||
|
||||
if (FACTORY.getProviderFactory(providerClass) == null) {
|
||||
return new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
throw new AssumptionViolatedException("Provider must exist: " + providerClass);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Statement res = base;
|
||||
for (KeycloakModelParameters kmp : KeycloakModelTest.MODEL_PARAMETERS) {
|
||||
res = kmp.instanceRule(res, description);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -124,7 +166,7 @@ public abstract class KeycloakModelTest {
|
|||
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; }})
|
||||
.map(cn -> { try { return Class.forName(cn.indexOf('.') >= 0 ? cn : ("org.keycloak.testsuite.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)
|
||||
|
@ -176,21 +218,12 @@ public abstract class KeycloakModelTest {
|
|||
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();
|
||||
protected <T> Stream<T> getParameters(Class<T> clazz) {
|
||||
return MODEL_PARAMETERS.stream().flatMap(mp -> mp.getParameters(clazz)).filter(Objects::nonNull);
|
||||
}
|
||||
return null;
|
||||
|
||||
protected <T> void withEach(Class<T> parameterClazz, Consumer<T> what) {
|
||||
getParameters(parameterClazz).forEach(what);
|
||||
}
|
||||
|
||||
protected <T> void inRolledBackTransaction(T parameter, BiConsumer<KeycloakSession, T> what) {
|
|
@ -14,7 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.model;
|
||||
package org.keycloak.testsuite.model;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import java.lang.annotation.ElementType;
|
||||
|
@ -30,7 +30,7 @@ import java.lang.annotation.Target;
|
|||
* @author hmlnarik
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Repeatable(RequireProviders.class)
|
||||
public @interface RequireProvider {
|
||||
Class<? extends Provider> value() default Provider.class;
|
|
@ -14,7 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.model;
|
||||
package org.keycloak.testsuite.model;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
|
@ -26,7 +26,7 @@ import java.lang.annotation.Target;
|
|||
* @author hmlnarik
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
public @interface RequireProviders {
|
||||
RequireProvider[] value();
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.model;
|
||||
package org.keycloak.testsuite.model;
|
||||
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
|
@ -26,7 +26,6 @@ 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;
|
||||
|
@ -55,6 +54,9 @@ import static org.junit.Assume.assumeThat;
|
|||
public class UserModelTest extends KeycloakModelTest {
|
||||
|
||||
protected static final int NUM_GROUPS = 100;
|
||||
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;
|
||||
|
||||
private String realmId;
|
||||
private final List<String> groupIds = new ArrayList<>(NUM_GROUPS);
|
||||
|
@ -65,8 +67,6 @@ public class UserModelTest extends KeycloakModelTest {
|
|||
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());
|
||||
});
|
||||
|
@ -150,12 +150,42 @@ public class UserModelTest extends KeycloakModelTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testAddDirtyRemoveFederationUsersInTheSameGroupConcurrent() {
|
||||
assumeThat("Test for federated providers only", userFederationId, Matchers.notNullValue());
|
||||
@RequireProvider(UserStorageProvider.class)
|
||||
public void testAddDirtyRemoveFederationUser() {
|
||||
registerUserFederationWithRealm();
|
||||
|
||||
inComittedTransaction(1, (session, i) -> {
|
||||
final RealmModel realm = session.realms().getRealm(realmId);
|
||||
final UserModel user = session.users().addUser(realm, "user-A");
|
||||
});
|
||||
|
||||
// Remove user _from the federation_, simulates eg. user being removed from LDAP without Keycloak knowing
|
||||
inComittedTransaction(1, (session, i) -> {
|
||||
final RealmModel realm = session.realms().getRealm(realmId);
|
||||
final UserStorageProvider instance = getUserFederationInstance(session, realm);
|
||||
log.debugf("Removing selected users from backend");
|
||||
final UserModel user = session.users().getUserByUsername("user-A", realm);
|
||||
((UserRegistrationProvider) instance).removeUser(realm, user);
|
||||
});
|
||||
|
||||
inComittedTransaction(1, (session, i) -> {
|
||||
final RealmModel realm = session.realms().getRealm(realmId);
|
||||
if (session.userCache() != null) {
|
||||
session.userCache().clear();
|
||||
}
|
||||
final UserModel user = session.users().getUserByUsername("user-A", realm);
|
||||
assertThat("User should not be found in the main store", user, Matchers.nullValue());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequireProvider(UserStorageProvider.class)
|
||||
public void testAddDirtyRemoveFederationUsersInTheSameGroupConcurrent() {
|
||||
final ConcurrentSkipListSet<String> userIds = new ConcurrentSkipListSet<>();
|
||||
String groupId = groupIds.get(0);
|
||||
|
||||
registerUserFederationWithRealm();
|
||||
|
||||
// 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);
|
||||
|
@ -167,25 +197,11 @@ public class UserModelTest extends KeycloakModelTest {
|
|||
// 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;
|
||||
UserStorageProvider instance = getUserFederationInstance(session, realm);
|
||||
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);
|
||||
final UserModel user = session.users().getUserByUsername("user-" + j, realm);
|
||||
((UserRegistrationProvider) instance).removeUser(realm, user);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -229,7 +245,34 @@ public class UserModelTest extends KeycloakModelTest {
|
|||
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;
|
||||
|
||||
private void registerUserFederationWithRealm() {
|
||||
getParameters(UserStorageProviderModel.class).forEach(fs -> inComittedTransaction(fs, (session, federatedStorage) -> {
|
||||
assumeThat("Cannot handle more than 1 user federation provider", userFederationId, Matchers.nullValue());
|
||||
RealmModel realm = session.realms().getRealm(realmId);
|
||||
federatedStorage.setParentId(realmId);
|
||||
federatedStorage.setImportEnabled(true);
|
||||
ComponentModel res = realm.addComponentModel(federatedStorage);
|
||||
userFederationId = res.getId();
|
||||
log.infof("Added %s user federation provider: %s", federatedStorage.getName(), userFederationId);
|
||||
}));
|
||||
}
|
||||
|
||||
private UserStorageProvider getUserFederationInstance(KeycloakSession session, final RealmModel realm) throws RuntimeException {
|
||||
UserStorageProvider instance = (UserStorageProvider)session.getAttribute(userFederationId);
|
||||
|
||||
if (instance == null) {
|
||||
ComponentModel model = realm.getComponent(userFederationId);
|
||||
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);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
}
|
|
@ -14,14 +14,14 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.model.events;
|
||||
package org.keycloak.testsuite.model.events;
|
||||
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.events.EventStoreProvider;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.model.KeycloakModelTest;
|
||||
import org.keycloak.model.RequireProvider;
|
||||
import org.keycloak.testsuite.model.KeycloakModelTest;
|
||||
import org.keycloak.testsuite.model.RequireProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import java.util.stream.Collectors;
|
|
@ -14,17 +14,18 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.model.parameters;
|
||||
package org.keycloak.testsuite.model.parameters;
|
||||
|
||||
import org.keycloak.model.KeycloakModelParameters;
|
||||
import org.keycloak.testsuite.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.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
import org.keycloak.testsuite.federation.BackwardsCompatibilityUserStorageFactory;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -39,7 +40,22 @@ public class BackwardsCompatibilityUserStorage extends KeycloakModelParameters {
|
|||
.add(BackwardsCompatibilityUserStorageFactory.class)
|
||||
.build();
|
||||
|
||||
private final AtomicInteger counter = new AtomicInteger();
|
||||
|
||||
public BackwardsCompatibilityUserStorage() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Stream<T> getParameters(Class<T> clazz) {
|
||||
if (UserStorageProviderModel.class.isAssignableFrom(clazz)) {
|
||||
UserStorageProviderModel federatedStorage = new UserStorageProviderModel();
|
||||
federatedStorage.setName(BackwardsCompatibilityUserStorageFactory.PROVIDER_ID + ":" + counter.getAndIncrement());
|
||||
federatedStorage.setProviderId(BackwardsCompatibilityUserStorageFactory.PROVIDER_ID);
|
||||
federatedStorage.setProviderType(UserStorageProvider.class.getName());
|
||||
return Stream.of((T) federatedStorage);
|
||||
} else {
|
||||
return super.getParameters(clazz);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,9 +14,9 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.model.parameters;
|
||||
package org.keycloak.testsuite.model.parameters;
|
||||
|
||||
import org.keycloak.model.KeycloakModelParameters;
|
||||
import org.keycloak.testsuite.model.KeycloakModelParameters;
|
||||
import org.keycloak.models.map.client.MapClientProviderFactory;
|
||||
import org.keycloak.models.map.group.MapGroupProviderFactory;
|
||||
import org.keycloak.models.map.role.MapRoleProviderFactory;
|
|
@ -14,12 +14,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.model.parameters;
|
||||
package org.keycloak.testsuite.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.testsuite.model.KeycloakModelParameters;
|
||||
import org.keycloak.models.cache.CacheRealmProviderSpi;
|
||||
import org.keycloak.models.cache.CacheUserProviderSpi;
|
||||
import org.keycloak.models.cache.infinispan.InfinispanCacheRealmProviderFactory;
|
|
@ -14,7 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.model.parameters;
|
||||
package org.keycloak.testsuite.model.parameters;
|
||||
|
||||
import org.keycloak.authorization.jpa.store.JPAAuthorizationStoreFactory;
|
||||
import org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory;
|
||||
|
@ -25,7 +25,7 @@ import org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionPr
|
|||
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.testsuite.model.KeycloakModelParameters;
|
||||
import org.keycloak.models.dblock.DBLockSpi;
|
||||
import org.keycloak.models.jpa.JpaClientProviderFactory;
|
||||
import org.keycloak.models.jpa.JpaGroupProviderFactory;
|
|
@ -14,9 +14,9 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.model.parameters;
|
||||
package org.keycloak.testsuite.model.parameters;
|
||||
|
||||
import org.keycloak.model.KeycloakModelParameters;
|
||||
import org.keycloak.testsuite.model.KeycloakModelParameters;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.storage.UserStorageProviderSpi;
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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.util.MultivaluedHashMap;
|
||||
import org.keycloak.testsuite.model.KeycloakModelParameters;
|
||||
import org.keycloak.models.LDAPConstants;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
import org.keycloak.storage.UserStorageProviderSpi;
|
||||
import org.keycloak.storage.federated.UserFederatedStorageProviderSpi;
|
||||
import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
|
||||
import org.keycloak.storage.ldap.mappers.LDAPStorageMapperFactory;
|
||||
import org.keycloak.storage.ldap.mappers.LDAPStorageMapperSpi;
|
||||
import org.keycloak.testsuite.util.LDAPRule;
|
||||
import org.keycloak.util.ldap.LDAPEmbeddedServer;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class LdapUserStorage extends KeycloakModelParameters {
|
||||
|
||||
static final Set<Class<? extends Spi>> ALLOWED_SPIS = ImmutableSet.<Class<? extends Spi>>builder()
|
||||
.add(UserStorageProviderSpi.class)
|
||||
.add(UserFederatedStorageProviderSpi.class)
|
||||
.add(LDAPStorageMapperSpi.class)
|
||||
|
||||
.build();
|
||||
|
||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
.add(LDAPStorageMapperFactory.class)
|
||||
.add(LDAPStorageProviderFactory.class)
|
||||
|
||||
.build();
|
||||
|
||||
private final AtomicInteger counter = new AtomicInteger();
|
||||
|
||||
private final LDAPRule ldapRule = new LDAPRule();
|
||||
|
||||
public LdapUserStorage() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Stream<T> getParameters(Class<T> clazz) {
|
||||
if (UserStorageProviderModel.class.isAssignableFrom(clazz)) {
|
||||
MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
|
||||
for (java.util.Map.Entry<String, String> entry : ldapRule.getConfig().entrySet()) {
|
||||
config.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
config.putSingle(LDAPConstants.SYNC_REGISTRATIONS, "true");
|
||||
config.putSingle(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.WRITABLE.toString());
|
||||
|
||||
UserStorageProviderModel federatedStorage = new UserStorageProviderModel();
|
||||
federatedStorage.setName(LDAPStorageProviderFactory.PROVIDER_NAME + ":" + counter.getAndIncrement());
|
||||
federatedStorage.setProviderId(LDAPStorageProviderFactory.PROVIDER_NAME);
|
||||
federatedStorage.setProviderType(UserStorageProvider.class.getName());
|
||||
federatedStorage.setLastSync(0);
|
||||
federatedStorage.setChangedSyncPeriod(-1);
|
||||
federatedStorage.setFullSyncPeriod(-1);
|
||||
federatedStorage.setPriority(0);
|
||||
federatedStorage.setConfig(config);
|
||||
return Stream.of((T) federatedStorage);
|
||||
} else {
|
||||
return super.getParameters(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
System.setProperty(LDAPEmbeddedServer.PROPERTY_ENABLE_SSL, "false");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement classRule(Statement base, Description description) {
|
||||
return ldapRule.apply(base, description);
|
||||
}
|
||||
|
||||
}
|
|
@ -14,9 +14,9 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.model.parameters;
|
||||
package org.keycloak.testsuite.model.parameters;
|
||||
|
||||
import org.keycloak.model.KeycloakModelParameters;
|
||||
import org.keycloak.testsuite.model.KeycloakModelParameters;
|
||||
import org.keycloak.models.map.client.MapClientProviderFactory;
|
||||
import org.keycloak.models.map.group.MapGroupProviderFactory;
|
||||
import org.keycloak.models.map.role.MapRoleProviderFactory;
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.testsuite.model.KeycloakModelParameters;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
import org.keycloak.testsuite.federation.BackwardsCompatibilityUserStorageFactory;
|
||||
import org.keycloak.testsuite.federation.UserMapStorageFactory;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class TestsuiteUserMapStorage 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(UserMapStorageFactory.class)
|
||||
.build();
|
||||
|
||||
private final AtomicInteger counter = new AtomicInteger();
|
||||
|
||||
public TestsuiteUserMapStorage() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Stream<T> getParameters(Class<T> clazz) {
|
||||
if (UserStorageProviderModel.class.isAssignableFrom(clazz)) {
|
||||
UserStorageProviderModel federatedStorage = new UserStorageProviderModel();
|
||||
federatedStorage.setName(UserMapStorageFactory.PROVIDER_ID + ":" + counter.getAndIncrement());
|
||||
federatedStorage.setProviderId(UserMapStorageFactory.PROVIDER_ID);
|
||||
federatedStorage.setProviderType(UserStorageProvider.class.getName());
|
||||
return Stream.of((T) federatedStorage);
|
||||
} else {
|
||||
return super.getParameters(clazz);
|
||||
}
|
||||
}
|
||||
}
|
1
testsuite/model/src/test/resources/kerberos
Symbolic link
1
testsuite/model/src/test/resources/kerberos
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../../integration-arquillian/tests/base/src/test/resources/kerberos
|
1
testsuite/model/src/test/resources/keystore
Symbolic link
1
testsuite/model/src/test/resources/keystore
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../../integration-arquillian/tests/base/src/test/resources/keystore
|
1
testsuite/model/src/test/resources/ldap
Symbolic link
1
testsuite/model/src/test/resources/ldap
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../../integration-arquillian/tests/base/src/test/resources/ldap
|
|
@ -23,7 +23,12 @@ 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.models=debug
|
||||
log4j.logger.org.keycloak=${keycloak.logging.level:info}
|
||||
|
||||
keycloak.testsuite.logging.level=debug
|
||||
log4j.logger.org.keycloak.testsuite=${keycloak.testsuite.logging.level}
|
||||
|
||||
# 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.hibernate=debug
|
||||
|
||||
# Enable to view loaded SPI and Providers
|
||||
|
|
16
testsuite/model/test-all-profiles.sh
Executable file
16
testsuite/model/test-all-profiles.sh
Executable file
|
@ -0,0 +1,16 @@
|
|||
#!/bin/bash
|
||||
|
||||
cd "$(dirname $0)"
|
||||
|
||||
EXIT_CODE=0
|
||||
mvn clean
|
||||
for I in `perl -ne 'print "$1\n" if (m,<id>([^<]+)</id>,)' pom.xml`; do
|
||||
echo "========"
|
||||
echo "======== Profile $I"
|
||||
echo "========"
|
||||
mvn test "-P$I" "$@"
|
||||
EXIT_CODE=$[$EXIT_CODE + $?]
|
||||
mv target/surefire-reports "target/surefire-reports-$I"
|
||||
done
|
||||
|
||||
exit $EXIT_CODE
|
Loading…
Reference in a new issue