From 5da05aa62ac088d61bfb78b1c651e2251907746f Mon Sep 17 00:00:00 2001 From: mposolda Date: Fri, 13 Feb 2015 21:05:17 +0100 Subject: [PATCH] LDAP testing improvements. Support for embedded Kerberos server in testsuite --- pom.xml | 36 ++-- .../managers/LDAPConnectionTestManager.java | 3 +- testsuite/integration/README.md | 30 +++ testsuite/integration/pom.xml | 64 +++++- .../keycloak/testutils/KeycloakServer.java | 19 -- .../ldap/EmbeddedServersFactory.java | 82 ++++++++ .../ldap/InMemoryDirectoryServiceFactory.java | 144 ++++++++++++++ .../ldap/InMemorySchemaPartition.java | 75 +++++++ .../ldap/KerberosEmbeddedServer.java | 183 +++++++++++++++++ .../testutils/ldap/KerberosKeytabCreator.java | 70 +++++++ .../LDAPConfiguration.java} | 117 +---------- .../testutils/ldap/LDAPEmbeddedServer.java | 186 ++++++++++++++++++ .../src/main/resources/kerberos/http.keytab | Bin 0 -> 266 bytes .../resources/kerberos/users-kerberos.ldif | 88 +++++++++ .../src/main/resources/log4j.properties | 7 +- .../FederationProvidersIntegrationTest.java | 4 +- .../testsuite/forms/SyncProvidersTest.java | 4 +- .../org/keycloak/testsuite/rule/LDAPRule.java | 33 ++-- 18 files changed, 976 insertions(+), 169 deletions(-) create mode 100644 testsuite/integration/src/main/java/org/keycloak/testutils/ldap/EmbeddedServersFactory.java create mode 100644 testsuite/integration/src/main/java/org/keycloak/testutils/ldap/InMemoryDirectoryServiceFactory.java create mode 100644 testsuite/integration/src/main/java/org/keycloak/testutils/ldap/InMemorySchemaPartition.java create mode 100644 testsuite/integration/src/main/java/org/keycloak/testutils/ldap/KerberosEmbeddedServer.java create mode 100644 testsuite/integration/src/main/java/org/keycloak/testutils/ldap/KerberosKeytabCreator.java rename testsuite/integration/src/main/java/org/keycloak/testutils/{LDAPEmbeddedServer.java => ldap/LDAPConfiguration.java} (66%) mode change 100755 => 100644 create mode 100644 testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPEmbeddedServer.java create mode 100644 testsuite/integration/src/main/resources/kerberos/http.keytab create mode 100644 testsuite/integration/src/main/resources/kerberos/users-kerberos.ldif diff --git a/pom.xml b/pom.xml index 4aada1a49c..d43ce03c7d 100755 --- a/pom.xml +++ b/pom.xml @@ -13,6 +13,8 @@ 0.33.12 + 2.0.0-M17 + 1.0.0-M23 2.3.8 1.50 1.50 @@ -23,7 +25,6 @@ 1.1.1.Final 2.7.0.CR3 - 1.0.2.Final 2.11.3 3.1.4.GA 0.9.30 @@ -307,17 +308,6 @@ picketlink-impl ${picketlink.version} - - org.picketbox - picketbox-ldap - ${picketbox.ldap.version} - - - org.picketbox - picketbox-ldap - ${picketbox.ldap.version} - test-jar - org.jboss.logging jboss-logging @@ -422,6 +412,28 @@ ${winzipaes.version} + + + org.apache.directory.server + apacheds-core-annotations + ${apacheds.version} + + + org.apache.directory.server + apacheds-interceptor-kerberos + ${apacheds.version} + + + org.apache.directory.server + apacheds-server-annotations + ${apacheds.version} + + + org.apache.directory.api + api-ldap-codec-standalone + ${apacheds.codec.version} + + org.seleniumhq.selenium diff --git a/services/src/main/java/org/keycloak/services/managers/LDAPConnectionTestManager.java b/services/src/main/java/org/keycloak/services/managers/LDAPConnectionTestManager.java index 2b78406e8c..fff0bfb3b1 100755 --- a/services/src/main/java/org/keycloak/services/managers/LDAPConnectionTestManager.java +++ b/services/src/main/java/org/keycloak/services/managers/LDAPConnectionTestManager.java @@ -27,11 +27,10 @@ public class LDAPConnectionTestManager { try { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); - env.put(Context.SECURITY_AUTHENTICATION, "simple"); - env.put(Context.PROVIDER_URL, connectionUrl); if (TEST_AUTHENTICATION.equals(action)) { + env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, bindDn); char[] bindCredentialChar = null; diff --git a/testsuite/integration/README.md b/testsuite/integration/README.md index 9de055c154..a8d06711ce 100644 --- a/testsuite/integration/README.md +++ b/testsuite/integration/README.md @@ -90,4 +90,34 @@ To configure Keycloak to use the above server add the following system propertie For example if using the test utils Keycloak server start it with: mvn exec:java -Pkeycloak-server -Dkeycloak.mail.smtp.from=auto@keycloak.org -Dkeycloak.mail.smtp.host=localhost -Dkeycloak.mail.smtp.port=3025 + +LDAP server +----------- + +To start a ApacheDS based LDAP server for testing LDAP sending run: + + mvn exec:java -Pldap + +There are additional system properties you can use to configure (See EmbeddedServersFactory class for details). Once done, you can create LDAP Federation provider +in Keycloak admin console with the settings like: +Vendor: Other +Connection URL: ldap://localhost:10389 +Base DN: dc=keycloak,dc=org +User DN Suffix: ou=People,dc=keycloak,dc=org +Bind DN: uid=admin,ou=system +Bind credential: secret + +Kerberos server +--------------- + +To start a ApacheDS based Kerberos server for testing Kerberos + LDAP sending run: + + mvn exec:java -Pkerberos + +There are additional system properties you can use to configure (See EmbeddedServersFactory class for details). Once done, you can create LDAP Federation provider +in Keycloak admin console with same settings like mentioned in previous LDAP section. And you can enable Kerberos with the settings like: + +Server Principal: HTTP/localhost@KEYCLOAK.ORG +KeyTab: $KEYCLOAK_SOURCES/testsuite/integration/src/main/resources/kerberos/http.keytab + diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml index 5800d98df6..98697e5497 100755 --- a/testsuite/integration/pom.xml +++ b/testsuite/integration/pom.xml @@ -113,10 +113,6 @@ com.google.zxing javase - - org.bouncycastle - bcprov-jdk15on - org.apache.httpcomponents httpclient @@ -212,15 +208,31 @@ org.seleniumhq.selenium selenium-chrome-driver + + - org.picketbox - picketbox-ldap - test-jar + org.apache.directory.server + apacheds-core-annotations + + + org.slf4j + slf4j-log4j12 + + - org.picketbox - picketbox-ldap + org.apache.directory.server + apacheds-interceptor-kerberos + + org.apache.directory.server + apacheds-server-annotations + + + org.apache.directory.api + api-ldap-codec-standalone + + org.picketlink picketlink-wildfly-common @@ -270,6 +282,12 @@ ${project.basedir} + + org.apache.felix + maven-bundle-plugin + true + true + @@ -316,6 +334,34 @@ + + ldap + + + + org.codehaus.mojo + exec-maven-plugin + + org.keycloak.testutils.ldap.LDAPEmbeddedServer + + + + + + + kerberos + + + + org.codehaus.mojo + exec-maven-plugin + + org.keycloak.testutils.ldap.KerberosEmbeddedServer + + + + + jpa diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java b/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java index 9b0c200e20..d5e1c375a6 100755 --- a/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java +++ b/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java @@ -104,27 +104,8 @@ public class KeycloakServer { } public static void main(String[] args) throws Throwable { - //bootstrapLdap(); Can't seem to get this to work. bootstrapKeycloakServer(args); } - /*private static LDAPEmbeddedServer embeddedServer; - public static void bootstrapLdap() throws Exception { - embeddedServer = new LDAPEmbeddedServer(); - embeddedServer.setup(); - embeddedServer.importLDIF("ldap/users.ldif"); - Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public void run() { - try { - embeddedServer.tearDown(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - }); - - - } */ public static KeycloakServer bootstrapKeycloakServer(String[] args) throws Throwable { KeycloakServerConfig config = new KeycloakServerConfig(); diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/EmbeddedServersFactory.java b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/EmbeddedServersFactory.java new file mode 100644 index 0000000000..a377d9b954 --- /dev/null +++ b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/EmbeddedServersFactory.java @@ -0,0 +1,82 @@ +package org.keycloak.testutils.ldap; + +/** + * Factory for ApacheDS based LDAP and Kerberos servers + * + * @author Marek Posolda + */ +public class EmbeddedServersFactory { + + private static final String DEFAULT_BASE_DN = "dc=keycloak,dc=org"; + private static final String DEFAULT_BIND_HOST = "localhost"; + private static final int DEFAULT_BIND_PORT = 10389; + private static final String DEFAULT_LDIF_FILE = "ldap/users.ldif"; + + private static final String DEFAULT_KERBEROS_LDIF_FILE = "kerberos/users-kerberos.ldif"; + + private static final String DEFAULT_KERBEROS_REALM = "KEYCLOAK.ORG"; + private static final int DEFAULT_KDC_PORT = 6088; + + private String baseDN; + private String bindHost; + private int bindPort; + private String ldifFile; + private String kerberosRealm; + private int kdcPort; + + + public static EmbeddedServersFactory readConfiguration() { + EmbeddedServersFactory factory = new EmbeddedServersFactory(); + factory.readProperties(); + return factory; + } + + + protected void readProperties() { + this.baseDN = System.getProperty("ldap.baseDN"); + this.bindHost = System.getProperty("ldap.host"); + String bindPort = System.getProperty("ldap.port"); + this.ldifFile = System.getProperty("ldap.ldif"); + + this.kerberosRealm = System.getProperty("kerberos.realm"); + String kdcPort = System.getProperty("kerberos.port"); + + if (baseDN == null || baseDN.isEmpty()) { + baseDN = DEFAULT_BASE_DN; + } + if (bindHost == null || bindHost.isEmpty()) { + bindHost = DEFAULT_BIND_HOST; + } + this.bindPort = (bindPort == null || bindPort.isEmpty()) ? DEFAULT_BIND_PORT : Integer.parseInt(bindPort); + if (ldifFile == null || ldifFile.isEmpty()) { + ldifFile = DEFAULT_LDIF_FILE; + } + + if (kerberosRealm == null || kerberosRealm.isEmpty()) { + kerberosRealm = DEFAULT_KERBEROS_REALM; + } + this.kdcPort = (kdcPort == null || kdcPort.isEmpty()) ? DEFAULT_KDC_PORT : Integer.parseInt(kdcPort); + } + + + public LDAPEmbeddedServer createLdapServer() { + + // Override LDIF file with default for embedded LDAP + if (ldifFile.equals(DEFAULT_KERBEROS_LDIF_FILE)) { + ldifFile = DEFAULT_LDIF_FILE; + } + + return new LDAPEmbeddedServer(baseDN, bindHost, bindPort, ldifFile); + } + + + public KerberosEmbeddedServer createKerberosServer() { + + // Override LDIF file with default for embedded Kerberos + if (ldifFile.equals(DEFAULT_LDIF_FILE)) { + ldifFile = DEFAULT_KERBEROS_LDIF_FILE; + } + + return new KerberosEmbeddedServer(baseDN, bindHost, bindPort, ldifFile, kerberosRealm, kdcPort); + } +} diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/InMemoryDirectoryServiceFactory.java b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/InMemoryDirectoryServiceFactory.java new file mode 100644 index 0000000000..bba4954a3f --- /dev/null +++ b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/InMemoryDirectoryServiceFactory.java @@ -0,0 +1,144 @@ +package org.keycloak.testutils.ldap; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import net.sf.ehcache.CacheManager; +import net.sf.ehcache.config.CacheConfiguration; +import net.sf.ehcache.config.Configuration; +import org.apache.commons.io.FileUtils; +import org.apache.directory.api.ldap.model.constants.SchemaConstants; +import org.apache.directory.api.ldap.model.schema.LdapComparator; +import org.apache.directory.api.ldap.model.schema.SchemaManager; +import org.apache.directory.api.ldap.model.schema.comparators.NormalizingComparator; +import org.apache.directory.api.ldap.model.schema.registries.ComparatorRegistry; +import org.apache.directory.api.ldap.model.schema.registries.SchemaLoader; +import org.apache.directory.api.ldap.schemaloader.JarLdifSchemaLoader; +import org.apache.directory.api.ldap.schemamanager.impl.DefaultSchemaManager; +import org.apache.directory.api.util.exception.Exceptions; +import org.apache.directory.server.constants.ServerDNConstants; +import org.apache.directory.server.core.DefaultDirectoryService; +import org.apache.directory.server.core.api.CacheService; +import org.apache.directory.server.core.api.DirectoryService; +import org.apache.directory.server.core.api.InstanceLayout; +import org.apache.directory.server.core.api.partition.Partition; +import org.apache.directory.server.core.api.schema.SchemaPartition; +import org.apache.directory.server.core.factory.AvlPartitionFactory; +import org.apache.directory.server.core.factory.DirectoryServiceFactory; +import org.apache.directory.server.core.factory.PartitionFactory; +import org.apache.directory.server.i18n.I18n; +import org.jboss.logging.Logger; + +/** + * Factory for a fast (mostly in-memory-only) ApacheDS DirectoryService. Use only for tests!! + * + * @author Josef Cacek + */ +class InMemoryDirectoryServiceFactory implements DirectoryServiceFactory { + + private static final Logger log = Logger.getLogger(InMemoryDirectoryServiceFactory.class); + + private final DirectoryService directoryService; + private final PartitionFactory partitionFactory; + + /** + * Default constructor which creates {@link DefaultDirectoryService} instance and configures {@link AvlPartitionFactory} as + * the {@link PartitionFactory} implementation. + */ + public InMemoryDirectoryServiceFactory() { + try { + directoryService = new DefaultDirectoryService(); + } catch (Exception e) { + throw new RuntimeException(e); + } + directoryService.setShutdownHookEnabled(false); + partitionFactory = new AvlPartitionFactory(); + } + + /** + * Constructor which uses provided {@link DirectoryService} and {@link PartitionFactory} implementations. + * + * @param directoryService must be not-null + * @param partitionFactory must be not-null + */ + public InMemoryDirectoryServiceFactory(DirectoryService directoryService, PartitionFactory partitionFactory) { + this.directoryService = directoryService; + this.partitionFactory = partitionFactory; + } + + /** + * {@inheritDoc} + */ + public void init(String name) throws Exception { + if ((directoryService != null) && directoryService.isStarted()) { + return; + } + directoryService.setInstanceId(name); + + // instance layout + InstanceLayout instanceLayout = new InstanceLayout(System.getProperty("java.io.tmpdir") + "/server-work-" + name); + if (instanceLayout.getInstanceDirectory().exists()) { + try { + FileUtils.deleteDirectory(instanceLayout.getInstanceDirectory()); + } catch (IOException e) { + log.warn("couldn't delete the instance directory before initializing the DirectoryService", e); + } + } + directoryService.setInstanceLayout(instanceLayout); + + // EhCache in disabled-like-mode + Configuration ehCacheConfig = new Configuration(); + CacheConfiguration defaultCache = new CacheConfiguration("default", 1).eternal(false).timeToIdleSeconds(30) + .timeToLiveSeconds(30).overflowToDisk(false); + ehCacheConfig.addDefaultCache(defaultCache); + CacheService cacheService = new CacheService(new CacheManager(ehCacheConfig)); + directoryService.setCacheService(cacheService); + + // Init the schema + // SchemaLoader loader = new SingleLdifSchemaLoader(); + SchemaLoader loader = new JarLdifSchemaLoader(); + SchemaManager schemaManager = new DefaultSchemaManager(loader); + schemaManager.loadAllEnabled(); + ComparatorRegistry comparatorRegistry = schemaManager.getComparatorRegistry(); + for (LdapComparator comparator : comparatorRegistry) { + if (comparator instanceof NormalizingComparator) { + ((NormalizingComparator) comparator).setOnServer(); + } + } + directoryService.setSchemaManager(schemaManager); + InMemorySchemaPartition inMemorySchemaPartition = new InMemorySchemaPartition(schemaManager); + SchemaPartition schemaPartition = new SchemaPartition(schemaManager); + schemaPartition.setWrappedPartition(inMemorySchemaPartition); + directoryService.setSchemaPartition(schemaPartition); + List errors = schemaManager.getErrors(); + if (errors.size() != 0) { + throw new Exception(I18n.err(I18n.ERR_317, Exceptions.printErrors(errors))); + } + + // Init system partition + Partition systemPartition = partitionFactory.createPartition(directoryService.getSchemaManager(), + directoryService.getDnFactory(), "system", + ServerDNConstants.SYSTEM_DN, 500, + new File(directoryService.getInstanceLayout().getPartitionsDirectory(), + "system")); + + systemPartition.setSchemaManager(directoryService.getSchemaManager()); + partitionFactory.addIndex(systemPartition, SchemaConstants.OBJECT_CLASS_AT, 100); + directoryService.setSystemPartition(systemPartition); + directoryService.startup(); + } + + /** + * {@inheritDoc} + */ + public DirectoryService getDirectoryService() throws Exception { + return directoryService; + } + + /** + * {@inheritDoc} + */ + public PartitionFactory getPartitionFactory() throws Exception { + return partitionFactory; + } +} \ No newline at end of file diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/InMemorySchemaPartition.java b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/InMemorySchemaPartition.java new file mode 100644 index 0000000000..a5fed44ec7 --- /dev/null +++ b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/InMemorySchemaPartition.java @@ -0,0 +1,75 @@ +package org.keycloak.testutils.ldap; + +import java.net.URL; +import java.util.Map; +import java.util.TreeSet; +import java.util.UUID; +import java.util.regex.Pattern; +import javax.naming.InvalidNameException; +import org.apache.directory.api.ldap.model.constants.SchemaConstants; +import org.apache.directory.api.ldap.model.entry.DefaultEntry; +import org.apache.directory.api.ldap.model.entry.Entry; +import org.apache.directory.api.ldap.model.ldif.LdifEntry; +import org.apache.directory.api.ldap.model.ldif.LdifReader; +import org.apache.directory.api.ldap.model.schema.SchemaManager; +import org.apache.directory.api.ldap.schemaextractor.impl.DefaultSchemaLdifExtractor; +import org.apache.directory.api.ldap.schemaextractor.impl.ResourceMap; +import org.apache.directory.server.core.api.interceptor.context.AddOperationContext; +import org.apache.directory.server.core.partition.ldif.AbstractLdifPartition; +import org.jboss.logging.Logger; + +/** + * In-memory schema-only partition which loads the data in the similar way as the + * {@link org.apache.directory.api.ldap.schemaloader.JarLdifSchemaLoader}. + * + * @author Josef Cacek + */ +class InMemorySchemaPartition extends AbstractLdifPartition { + + private static final Logger log = Logger.getLogger(InMemorySchemaPartition.class); + + /** + * Filesystem path separator pattern, either forward slash or backslash. java.util.regex.Pattern is immutable so only one + * instance is needed for all uses. + */ + public InMemorySchemaPartition(SchemaManager schemaManager) { + super(schemaManager); + } + + /** + * Partition initialization - loads schema entries from the files on classpath. + * + * @see org.apache.directory.server.core.partition.impl.avl.AvlPartition#doInit() + */ + @Override + protected void doInit() throws InvalidNameException, Exception { + if (initialized) + return; + log.debug("Initializing schema partition " + getId()); + suffixDn.apply(schemaManager); + super.doInit(); + + // load schema + final Map resMap = ResourceMap.getResources(Pattern.compile("schema[/\\Q\\\\E]ou=schema.*")); + for (String resourcePath : new TreeSet(resMap.keySet())) { + if (resourcePath.endsWith(".ldif")) { + URL resource = DefaultSchemaLdifExtractor.getUniqueResource(resourcePath, "Schema LDIF file"); + LdifReader reader = new LdifReader(resource.openStream()); + LdifEntry ldifEntry = reader.next(); + reader.close(); + Entry entry = new DefaultEntry(schemaManager, ldifEntry.getEntry()); + + // add mandatory attributes + if (entry.get(SchemaConstants.ENTRY_CSN_AT) == null) { + entry.add(SchemaConstants.ENTRY_CSN_AT, defaultCSNFactory.newInstance().toString()); + } + if (entry.get(SchemaConstants.ENTRY_UUID_AT) == null) { + entry.add(SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString()); + } + AddOperationContext addContext = new AddOperationContext(null, entry); + super.add(addContext); + } + } + } + +} diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/KerberosEmbeddedServer.java b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/KerberosEmbeddedServer.java new file mode 100644 index 0000000000..635c81764c --- /dev/null +++ b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/KerberosEmbeddedServer.java @@ -0,0 +1,183 @@ +package org.keycloak.testutils.ldap; + +import java.io.IOException; +import java.lang.reflect.Field; + +import javax.security.auth.kerberos.KerberosPrincipal; + +import org.apache.directory.api.ldap.model.constants.SupportedSaslMechanisms; +import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException; +import org.apache.directory.server.core.api.DirectoryService; +import org.apache.directory.server.core.kerberos.KeyDerivationInterceptor; +import org.apache.directory.server.kerberos.KerberosConfig; +import org.apache.directory.server.kerberos.kdc.KdcServer; +import org.apache.directory.server.kerberos.shared.replay.ReplayCache; +import org.apache.directory.server.ldap.LdapServer; +import org.apache.directory.server.ldap.handlers.sasl.cramMD5.CramMd5MechanismHandler; +import org.apache.directory.server.ldap.handlers.sasl.digestMD5.DigestMd5MechanismHandler; +import org.apache.directory.server.ldap.handlers.sasl.gssapi.GssapiMechanismHandler; +import org.apache.directory.server.ldap.handlers.sasl.ntlm.NtlmMechanismHandler; +import org.apache.directory.server.ldap.handlers.sasl.plain.PlainMechanismHandler; +import org.apache.directory.server.protocol.shared.transport.UdpTransport; +import org.apache.directory.shared.kerberos.KerberosTime; +import org.jboss.logging.Logger; + +/** + * @author Marek Posolda + */ +public class KerberosEmbeddedServer extends LDAPEmbeddedServer { + + private static final Logger log = Logger.getLogger(LDAPEmbeddedServer.class); + + private final String kerberosRealm; + private final int kdcPort; + + private KdcServer kdcServer; + + + public static void main(String[] args) throws Exception { + EmbeddedServersFactory factory = EmbeddedServersFactory.readConfiguration(); + KerberosEmbeddedServer kerberosEmbeddedServer = factory.createKerberosServer(); + kerberosEmbeddedServer.init(); + kerberosEmbeddedServer.start(); + } + + + protected KerberosEmbeddedServer(String baseDN, String bindHost, int bindPort, String ldifFile, String kerberosRealm, int kdcPort) { + super(baseDN, bindHost, bindPort, ldifFile); + this.kerberosRealm = kerberosRealm; + this.kdcPort = kdcPort; + } + + + @Override + public void init() throws Exception { + super.init(); + + log.info("Creating KDC server"); + createAndStartKdcServer(); + } + + + @Override + protected DirectoryService createDirectoryService() throws Exception { + DirectoryService directoryService = super.createDirectoryService(); + + directoryService.addLast(new KeyDerivationInterceptor()); + return directoryService; + } + + + @Override + protected LdapServer createLdapServer() { + LdapServer ldapServer = super.createLdapServer(); + + ldapServer.setSaslHost( this.bindHost ); + ldapServer.setSaslPrincipal( "ldap/" + this.bindHost + "@" + this.kerberosRealm); + + ldapServer.addSaslMechanismHandler(SupportedSaslMechanisms.PLAIN, new PlainMechanismHandler()); + ldapServer.addSaslMechanismHandler(SupportedSaslMechanisms.CRAM_MD5, new CramMd5MechanismHandler()); + ldapServer.addSaslMechanismHandler(SupportedSaslMechanisms.DIGEST_MD5, new DigestMd5MechanismHandler()); + ldapServer.addSaslMechanismHandler(SupportedSaslMechanisms.GSSAPI, new GssapiMechanismHandler()); + ldapServer.addSaslMechanismHandler(SupportedSaslMechanisms.NTLM, new NtlmMechanismHandler()); + ldapServer.addSaslMechanismHandler(SupportedSaslMechanisms.GSS_SPNEGO, new NtlmMechanismHandler()); + + return ldapServer; + } + + + protected KdcServer createAndStartKdcServer() throws Exception { + KerberosConfig kdcConfig = new KerberosConfig(); + kdcConfig.setServicePrincipal("krbtgt/" + this.kerberosRealm + "@" + this.kerberosRealm); + kdcConfig.setPrimaryRealm(this.kerberosRealm); + kdcConfig.setMaximumTicketLifetime(60000 * 1440); + kdcConfig.setMaximumRenewableLifetime(60000 * 10080); + kdcConfig.setPaEncTimestampRequired(false); + + kdcServer = new NoReplayKdcServer(kdcConfig); + kdcServer.setSearchBaseDn(this.baseDN); + + UdpTransport udp = new UdpTransport(this.bindHost, this.kdcPort); + kdcServer.addTransports(udp); + + kdcServer.setDirectoryService(directoryService); + + // Launch the server + kdcServer.start(); + + return kdcServer; + } + + + public void stop() throws Exception { + stopLdapServer(); + stopKerberosServer(); + shutdownDirectoryService(); + } + + + protected void stopKerberosServer() { + log.info("Stoping Kerberos server."); + kdcServer.stop(); + } + + + /** + * Replacement of apacheDS KdcServer class with disabled ticket replay cache. + * + * @author Dominik Pospisil + */ + class NoReplayKdcServer extends KdcServer { + + NoReplayKdcServer(KerberosConfig kdcConfig) { + super(kdcConfig); + } + + /** + * + * Dummy implementation of the ApacheDS kerberos replay cache. Essentially disables kerbores ticket replay checks. + * https://issues.jboss.org/browse/JBPAPP-10974 + * + * @author Dominik Pospisil + */ + private class DummyReplayCache implements ReplayCache { + + @Override + public boolean isReplay(KerberosPrincipal serverPrincipal, KerberosPrincipal clientPrincipal, KerberosTime clientTime, + int clientMicroSeconds) { + return false; + } + + @Override + public void save(KerberosPrincipal serverPrincipal, KerberosPrincipal clientPrincipal, KerberosTime clientTime, + int clientMicroSeconds) { + return; + } + + @Override + public void clear() { + return; + } + + } + + /** + * @throws java.io.IOException if we cannot bind to the sockets + */ + @Override + public void start() throws IOException, LdapInvalidDnException { + super.start(); + + try { + + // override initialized replay cache with a dummy implementation + Field replayCacheField = KdcServer.class.getDeclaredField("replayCache"); + replayCacheField.setAccessible(true); + replayCacheField.set(this, new DummyReplayCache()); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + } +} diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/KerberosKeytabCreator.java b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/KerberosKeytabCreator.java new file mode 100644 index 0000000000..aa26153fb1 --- /dev/null +++ b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/KerberosKeytabCreator.java @@ -0,0 +1,70 @@ +package org.keycloak.testutils.ldap; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.directory.server.kerberos.shared.crypto.encryption.KerberosKeyFactory; +import org.apache.directory.server.kerberos.shared.keytab.Keytab; +import org.apache.directory.server.kerberos.shared.keytab.KeytabEntry; +import org.apache.directory.shared.kerberos.KerberosTime; +import org.apache.directory.shared.kerberos.codec.types.EncryptionType; +import org.apache.directory.shared.kerberos.components.EncryptionKey; + +/** + * Helper utility for creating Keytab files. + * + * @author Josef Cacek + */ +public class KerberosKeytabCreator { + + // Public methods -------------------------------------------------------- + + /** + * The main. + * + * @param args + * @throws java.io.IOException + */ + public static void main(String[] args) throws IOException { + if (args == null || args.length != 3) { + System.out.println("Kerberos keytab generator"); + System.out.println("-------------------------"); + System.out.println("Arguments missing or invalid. Required arguments are: "); + System.out.println("Example of usage:"); + System.out.println("mvn exec:java -Dexec.mainClass=\"org.keycloak.testutils.ldap.KerberosKeytabCreator\" -Dexec.args=\"HTTP/localhost@KEYCLOAK.ORG httppwd src/main/resources/kerberos/http.keytab\""); + } else { + final File keytabFile = new File(args[2]); + createKeytab(args[0], args[1], keytabFile); + System.out.println("Keytab file was created: " + keytabFile.getAbsolutePath() + ", principal: " + args[0] + ", passphrase: " + args[1]); + } + } + + /** + * Creates a keytab file for given principal. + * + * @param principalName + * @param passPhrase + * @param keytabFile + * @throws IOException + */ + public static void createKeytab(final String principalName, final String passPhrase, final File keytabFile) + throws IOException { + final KerberosTime timeStamp = new KerberosTime(); + final int principalType = 1; // KRB5_NT_PRINCIPAL + + final Keytab keytab = Keytab.getInstance(); + final List entries = new ArrayList(); + for (Map.Entry keyEntry : KerberosKeyFactory.getKerberosKeys(principalName, passPhrase) + .entrySet()) { + System.out.println("Adding keytab entry of type: " + keyEntry.getKey().getName()); + final EncryptionKey key = keyEntry.getValue(); + final byte keyVersion = (byte) key.getKeyVersion(); + entries.add(new KeytabEntry(principalName, principalType, timeStamp, keyVersion, key)); + } + keytab.setEntries(entries); + keytab.write(keytabFile); + } +} diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/LDAPEmbeddedServer.java b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPConfiguration.java old mode 100755 new mode 100644 similarity index 66% rename from testsuite/integration/src/main/java/org/keycloak/testutils/LDAPEmbeddedServer.java rename to testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPConfiguration.java index bbf932c3da..1312143306 --- a/testsuite/integration/src/main/java/org/keycloak/testutils/LDAPEmbeddedServer.java +++ b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPConfiguration.java @@ -1,32 +1,16 @@ -package org.keycloak.testutils; +package org.keycloak.testutils.ldap; -import org.keycloak.models.LDAPConstants; -import org.picketbox.test.ldap.AbstractLDAPTest; - -import javax.naming.CompositeName; -import javax.naming.Context; -import javax.naming.ContextNotEmptyException; -import javax.naming.Name; -import javax.naming.NameClassPair; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.DirContext; -import javax.naming.directory.InitialDirContext; -import java.io.File; import java.io.InputStream; import java.util.HashMap; -import java.util.Hashtable; import java.util.Map; import java.util.Properties; +import org.keycloak.models.LDAPConstants; + /** - * Forked from Picketlink project - * - * Abstract base for all LDAP test suites. It handles - * @author Peter Skopek: pskopek at redhat dot com - * + * @author Marek Posolda */ -public class LDAPEmbeddedServer extends AbstractLDAPTest { +public class LDAPConfiguration { public static final String CONNECTION_PROPERTIES = "ldap/ldap-connection.properties"; @@ -64,10 +48,10 @@ public class LDAPEmbeddedServer extends AbstractLDAPTest { public static String IDM_TEST_LDAP_USER_OBJECT_CLASSES = "idm.test.ldap.user.object.classes"; public static String IDM_TEST_LDAP_USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE = "idm.test.ldap.user.account.controls.after.password.update"; - - public LDAPEmbeddedServer() { - super(); - loadConnectionProperties(); + public static LDAPConfiguration readConfiguration() { + LDAPConfiguration ldapConfiguration = new LDAPConfiguration(); + ldapConfiguration.loadConnectionProperties(); + return ldapConfiguration; } protected void loadConnectionProperties() { @@ -98,44 +82,6 @@ public class LDAPEmbeddedServer extends AbstractLDAPTest { userAccountControlsAfterPasswordUpdate = Boolean.parseBoolean(p.getProperty(IDM_TEST_LDAP_USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE)); } - @Override - public void setup() throws Exception { - // suppress emb. LDAP server start - if (isStartEmbeddedLdapLerver()) { - // On Windows, the directory may not be fully deleted from previous test - String tempDir = System.getProperty("java.io.tmpdir"); - File workDir = new File(tempDir + File.separator + "server-work"); - if (workDir.exists()) { - recursiveDeleteDir(workDir); - } - - super.setup(); - } - } - - @Override - public void tearDown() throws Exception { - // suppress emb. LDAP server stop - if (isStartEmbeddedLdapLerver()) { - - // clear data left in LDAP - DirContext ctx = getDirContext(); - clearSubContexts(ctx, new CompositeName(baseDn)); - - super.tearDown(); - } - } - - private DirContext getDirContext() throws NamingException { - Hashtable env = new Hashtable(); - env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); - env.put(Context.PROVIDER_URL, connectionUrl); - env.put(Context.SECURITY_PRINCIPAL, bindDn); - env.put(Context.SECURITY_CREDENTIALS, bindCredential); - DirContext ctx = new InitialDirContext(env); - return ctx; - } - public Map getLDAPConfig() { Map ldapConfig = new HashMap(); ldapConfig.put(LDAPConstants.CONNECTION_URL, getConnectionUrl()); @@ -153,37 +99,6 @@ public class LDAPEmbeddedServer extends AbstractLDAPTest { return ldapConfig; } - - public static void clearSubContexts(DirContext ctx, Name name) throws NamingException { - - NamingEnumeration enumeration = null; - try { - enumeration = ctx.list(name); - while (enumeration.hasMore()) { - NameClassPair pair = enumeration.next(); - Name childName = ctx.composeName(new CompositeName(pair.getName()), name); - try { - ctx.destroySubcontext(childName); - } - catch (ContextNotEmptyException e) { - clearSubContexts(ctx, childName); - ctx.destroySubcontext(childName); - } - } - } - catch (NamingException e) { - e.printStackTrace(); - } - finally { - try { - enumeration.close(); - } - catch (Exception e) { - // Never mind this - } - } - } - public String getConnectionUrl() { return connectionUrl; } @@ -247,18 +162,4 @@ public class LDAPEmbeddedServer extends AbstractLDAPTest { public boolean isUserAccountControlsAfterPasswordUpdate() { return userAccountControlsAfterPasswordUpdate; } - - @Override - public void importLDIF(String fileName) throws Exception { - // import LDIF only in case we are running against embedded LDAP server - if (isStartEmbeddedLdapLerver()) { - super.importLDIF(fileName); - } - } - - @Override - protected void createBaseDN() throws Exception { - ds.createBaseDN("keycloak", "dc=keycloak,dc=org"); - } - } diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPEmbeddedServer.java b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPEmbeddedServer.java new file mode 100644 index 0000000000..9c18288ebf --- /dev/null +++ b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPEmbeddedServer.java @@ -0,0 +1,186 @@ +package org.keycloak.testutils.ldap; + +import java.io.File; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.text.StrSubstitutor; +import org.apache.directory.api.ldap.model.entry.DefaultEntry; +import org.apache.directory.api.ldap.model.exception.LdapEntryAlreadyExistsException; +import org.apache.directory.api.ldap.model.ldif.LdifEntry; +import org.apache.directory.api.ldap.model.ldif.LdifReader; +import org.apache.directory.api.ldap.model.schema.SchemaManager; +import org.apache.directory.server.core.api.DirectoryService; +import org.apache.directory.server.core.api.partition.Partition; +import org.apache.directory.server.core.factory.DSAnnotationProcessor; +import org.apache.directory.server.core.factory.PartitionFactory; +import org.apache.directory.server.ldap.LdapServer; +import org.apache.directory.server.protocol.shared.transport.TcpTransport; +import org.apache.directory.server.protocol.shared.transport.Transport; +import org.jboss.logging.Logger; +import org.keycloak.util.StreamUtil; + +/** + * @author Marek Posolda + */ +public class LDAPEmbeddedServer { + + private static final Logger log = Logger.getLogger(LDAPEmbeddedServer.class); + + protected final String baseDN; + protected final String bindHost; + protected final int bindPort; + protected final String ldifFile; + + protected DirectoryService directoryService; + protected LdapServer ldapServer; + + + public static void main(String[] args) throws Exception { + EmbeddedServersFactory factory = EmbeddedServersFactory.readConfiguration(); + LDAPEmbeddedServer ldapEmbeddedServer = factory.createLdapServer(); + ldapEmbeddedServer.init(); + ldapEmbeddedServer.start(); + } + + public LDAPEmbeddedServer(String baseDN, String bindHost, int bindPort, String ldifFile) { + this.baseDN = baseDN; + this.bindHost = bindHost; + this.bindPort = bindPort; + this.ldifFile = ldifFile; + } + + + public void init() throws Exception { + log.info("Creating LDAP Directory Service. Config: baseDN=" + baseDN + ", bindHost=" + bindHost + ", bindPort=" + bindPort); + this.directoryService = createDirectoryService(); + + log.info("Importing LDIF: " + ldifFile); + importLdif(); + + log.info("Creating LDAP Server"); + this.ldapServer = createLdapServer(); + } + + + public void start() throws Exception { + log.info("Starting LDAP Server"); + ldapServer.start(); + log.info("LDAP Server started"); + } + + + protected DirectoryService createDirectoryService() throws Exception { + // Parse "keycloak" from "dc=keycloak,dc=org" + String dcName = baseDN.split(",")[0].substring(3); + + InMemoryDirectoryServiceFactory dsf = new InMemoryDirectoryServiceFactory(); + + DirectoryService service = dsf.getDirectoryService(); + service.setAccessControlEnabled(false); + service.setAllowAnonymousAccess(false); + service.getChangeLog().setEnabled(false); + + dsf.init(dcName + "DS"); + + SchemaManager schemaManager = service.getSchemaManager(); + + PartitionFactory partitionFactory = dsf.getPartitionFactory(); + Partition partition = partitionFactory.createPartition( + schemaManager, + service.getDnFactory(), + dcName, + this.baseDN, + 1000, + new File(service.getInstanceLayout().getPartitionsDirectory(), dcName)); + partition.setCacheService( service.getCacheService() ); + partition.initialize(); + + partition.setSchemaManager( schemaManager ); + + // Inject the partition into the DirectoryService + service.addPartition( partition ); + + // Last, process the context entry + String entryLdif = + "dn: " + baseDN + "\n" + + "dc: " + dcName + "\n" + + "objectClass: top\n" + + "objectClass: domain\n\n"; + DSAnnotationProcessor.injectEntries(service, entryLdif); + + return service; + } + + + protected LdapServer createLdapServer() { + LdapServer ldapServer = new LdapServer(); + + ldapServer.setServiceName("DefaultLdapServer"); + + // Read the transports + Transport ldap = new TcpTransport(this.bindHost, this.bindPort, 3, 50); + ldapServer.addTransports( ldap ); + + // Associate the DS to this LdapServer + ldapServer.setDirectoryService( directoryService ); + + // Propagate the anonymous flag to the DS + directoryService.setAllowAnonymousAccess(false); + + ldapServer.setSaslHost( this.bindHost ); + ldapServer.setSaslPrincipal( "ldap/" + this.bindHost + "@KEYCLOAK.ORG"); + ldapServer.setSaslRealms(new ArrayList()); + return ldapServer; + } + + + private void importLdif() throws Exception { + Map map = new HashMap(); + map.put("hostname", this.bindHost); + + // For now, assume that LDIF file is on classpath + InputStream is = getClass().getClassLoader().getResourceAsStream(ldifFile); + if (is == null) { + throw new IllegalStateException("LDIF file not found on classpath. Location was: " + ldifFile); + } + + final String ldifContent = StrSubstitutor.replace(StreamUtil.readString(is), map); + log.info("Importing LDIF: " + ldifContent); + final SchemaManager schemaManager = directoryService.getSchemaManager(); + + for (LdifEntry ldifEntry : new LdifReader(IOUtils.toInputStream(ldifContent))) { + try { + directoryService.getAdminSession().add(new DefaultEntry(schemaManager, ldifEntry.getEntry())); + } catch (LdapEntryAlreadyExistsException ignore) { + log.debug("Entry " + ldifEntry.getNewRdn() + " already exists. Ignoring"); + } + } + } + + + public void stop() throws Exception { + stopLdapServer(); + shutdownDirectoryService(); + } + + + protected void stopLdapServer() { + log.info("Stoping LDAP server."); + ldapServer.stop(); + } + + + protected void shutdownDirectoryService() throws Exception { + log.info("Stoping Directory service."); + directoryService.shutdown(); + + log.info("Removing Directory service workfiles."); + FileUtils.deleteDirectory(directoryService.getInstanceLayout().getInstanceDirectory()); + } + +} diff --git a/testsuite/integration/src/main/resources/kerberos/http.keytab b/testsuite/integration/src/main/resources/kerberos/http.keytab new file mode 100644 index 0000000000000000000000000000000000000000..c156500feef4b8d9ef7abaa0275263bba600244a GIT binary patch literal 266 zcmZQ&VqjpfV_;(7@pg@L_VIW0*7FZ?XJGLN2?=1}%*jtq%*n_vE&(cH40(7|mw`c$ zL4g1HK9N~r>sNh0AIWRKXG$iCCWtc#ut)GOJoM-K%#~$zxz3^YmHxKF99)4q-AK?Wz#w6?dAa`m%Vp`0Ir54>eZRlrtUT|_Xv6eM0Q%ERZ2$lO literal 0 HcmV?d00001 diff --git a/testsuite/integration/src/main/resources/kerberos/users-kerberos.ldif b/testsuite/integration/src/main/resources/kerberos/users-kerberos.ldif new file mode 100644 index 0000000000..fcde10e462 --- /dev/null +++ b/testsuite/integration/src/main/resources/kerberos/users-kerberos.ldif @@ -0,0 +1,88 @@ +dn: dc=keycloak,dc=org +objectclass: dcObject +objectclass: organization +o: Keycloak +dc: Keycloak + +dn: ou=People,dc=keycloak,dc=org +objectClass: organizationalUnit +objectClass: top +ou: People + +dn: uid=krbtgt,ou=People,dc=keycloak,dc=org +objectClass: top +objectClass: person +objectClass: inetOrgPerson +objectClass: krb5principal +objectClass: krb5kdcentry +cn: KDC Service +sn: Service +uid: krbtgt +userPassword: secret +krb5PrincipalName: krbtgt/KEYCLOAK.ORG@KEYCLOAK.ORG +krb5KeyVersionNumber: 0 + +dn: uid=ldap,ou=People,dc=keycloak,dc=org +objectClass: top +objectClass: person +objectClass: inetOrgPerson +objectClass: krb5principal +objectClass: krb5kdcentry +cn: LDAP +sn: Service +uid: ldap +userPassword: randall +krb5PrincipalName: ldap/${hostname}@KEYCLOAK.ORG +krb5KeyVersionNumber: 0 + +dn: uid=HTTP,ou=People,dc=keycloak,dc=org +objectClass: top +objectClass: person +objectClass: inetOrgPerson +objectClass: krb5principal +objectClass: krb5kdcentry +cn: HTTP +sn: Service +uid: HTTP +userPassword: httppwd +krb5PrincipalName: HTTP/${hostname}@KEYCLOAK.ORG +krb5KeyVersionNumber: 0 + +dn: uid=hnelson,ou=People,dc=keycloak,dc=org +objectClass: top +objectClass: person +objectClass: inetOrgPerson +objectClass: krb5principal +objectClass: krb5kdcentry +cn: Horatio Nelson +sn: Nelson +uid: hnelson +userPassword: secret +krb5PrincipalName: hnelson@KEYCLOAK.ORG +krb5KeyVersionNumber: 0 + +dn: uid=jduke,ou=People,dc=keycloak,dc=org +objectClass: top +objectClass: person +objectClass: inetOrgPerson +objectClass: krb5principal +objectClass: krb5kdcentry +cn: Java Duke +sn: duke +uid: jduke +userPassword: theduke +krb5PrincipalName: jduke@KEYCLOAK.ORG +krb5KeyVersionNumber: 0 + +dn: uid=gsstestserver,ou=People,dc=keycloak,dc=org +objectClass: top +objectClass: person +objectClass: inetOrgPerson +objectClass: krb5principal +objectClass: krb5kdcentry +cn: gsstestserver +sn: Service +uid: gsstestserver +userPassword: gsstestpwd +krb5PrincipalName: gsstestserver/xxx@KEYCLOAK.ORG +krb5KeyVersionNumber: 0 diff --git a/testsuite/integration/src/main/resources/log4j.properties b/testsuite/integration/src/main/resources/log4j.properties index 573c238f3c..5e78b310ff 100755 --- a/testsuite/integration/src/main/resources/log4j.properties +++ b/testsuite/integration/src/main/resources/log4j.properties @@ -19,6 +19,11 @@ log4j.logger.org.keycloak=info # Enable to view kerberos/spnego logging # log4j.logger.org.keycloak.broker.kerberos=trace +# Enable to view detailed AS REQ and TGS REQ requests to embedded Kerberos server +log4j.logger.org.apache.directory.server.kerberos=debug + log4j.logger.org.xnio=off log4j.logger.org.hibernate=off -log4j.logger.org.jboss.resteasy=warn \ No newline at end of file +log4j.logger.org.jboss.resteasy=warn +log4j.logger.org.apache.directory.api=warn +log4j.logger.org.apache.directory.server.core=warn \ No newline at end of file diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/FederationProvidersIntegrationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/FederationProvidersIntegrationTest.java index 1146257e7b..833e56c664 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/FederationProvidersIntegrationTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/FederationProvidersIntegrationTest.java @@ -33,7 +33,6 @@ import org.keycloak.testsuite.rule.KeycloakRule; import org.keycloak.testsuite.rule.LDAPRule; import org.keycloak.testsuite.rule.WebResource; import org.keycloak.testsuite.rule.WebRule; -import org.keycloak.testutils.LDAPEmbeddedServer; import org.openqa.selenium.WebDriver; import org.picketlink.idm.PartitionManager; import org.picketlink.idm.model.basic.User; @@ -56,8 +55,7 @@ public class FederationProvidersIntegrationTest { public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { addUser(manager.getSession(), appRealm, "mary", "mary@test.com", "password-app"); - LDAPEmbeddedServer ldapServer = ldapRule.getEmbeddedServer(); - Map ldapConfig = ldapServer.getLDAPConfig(); + Map ldapConfig = ldapRule.getLdapConfig(); ldapConfig.put(LDAPFederationProvider.SYNC_REGISTRATIONS, "true"); ldapConfig.put(LDAPFederationProvider.EDIT_MODE, UserFederationProvider.EditMode.WRITABLE.toString()); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/SyncProvidersTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/SyncProvidersTest.java index f256ee008c..917a544e8a 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/SyncProvidersTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/SyncProvidersTest.java @@ -22,7 +22,6 @@ import org.keycloak.services.managers.UsersSyncManager; import org.keycloak.testsuite.rule.KeycloakRule; import org.keycloak.testsuite.rule.LDAPRule; import org.keycloak.testutils.DummyUserFederationProviderFactory; -import org.keycloak.testutils.LDAPEmbeddedServer; import org.keycloak.timer.TimerProvider; import org.keycloak.util.Time; import org.picketlink.idm.PartitionManager; @@ -49,8 +48,7 @@ public class SyncProvidersTest { // Other tests may left Time offset uncleared, which could cause issues Time.setOffset(0); - LDAPEmbeddedServer ldapServer = ldapRule.getEmbeddedServer(); - Map ldapConfig = ldapServer.getLDAPConfig(); + Map ldapConfig = ldapRule.getLdapConfig(); ldapConfig.put(LDAPFederationProvider.SYNC_REGISTRATIONS, "false"); ldapConfig.put(LDAPFederationProvider.EDIT_MODE, UserFederationProvider.EditMode.UNSYNCED.toString()); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/LDAPRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/LDAPRule.java index 1c631bb9ad..5b120377cb 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/LDAPRule.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/LDAPRule.java @@ -1,37 +1,46 @@ package org.keycloak.testsuite.rule; +import java.util.Map; + import org.junit.rules.ExternalResource; -import org.keycloak.testutils.LDAPEmbeddedServer; +import org.keycloak.testutils.ldap.EmbeddedServersFactory; +import org.keycloak.testutils.ldap.LDAPConfiguration; +import org.keycloak.testutils.ldap.LDAPEmbeddedServer; /** * @author Marek Posolda */ public class LDAPRule extends ExternalResource { - private LDAPEmbeddedServer embeddedServer; + private LDAPConfiguration ldapConfiguration; + private LDAPEmbeddedServer ldapEmbeddedServer; @Override protected void before() throws Throwable { - try { - embeddedServer = new LDAPEmbeddedServer(); - embeddedServer.setup(); - embeddedServer.importLDIF("ldap/users.ldif"); - } catch (Exception e) { - throw new RuntimeException("Error starting Embedded LDAP server.", e); + ldapConfiguration = LDAPConfiguration.readConfiguration(); + + if (ldapConfiguration.isStartEmbeddedLdapLerver()) { + EmbeddedServersFactory factory = EmbeddedServersFactory.readConfiguration(); + ldapEmbeddedServer = factory.createLdapServer(); + ldapEmbeddedServer.init(); + ldapEmbeddedServer.start(); } } @Override protected void after() { try { - embeddedServer.tearDown(); - embeddedServer = null; + if (ldapEmbeddedServer != null) { + ldapEmbeddedServer.stop(); + ldapEmbeddedServer = null; + ldapConfiguration = null; + } } catch (Exception e) { throw new RuntimeException("Error tearDown Embedded LDAP server.", e); } } - public LDAPEmbeddedServer getEmbeddedServer() { - return embeddedServer; + public Map getLdapConfig() { + return ldapConfiguration.getLDAPConfig(); } }