LDAP testing improvements. Support for embedded Kerberos server in testsuite
This commit is contained in:
parent
6097ecb53f
commit
5da05aa62a
18 changed files with 976 additions and 169 deletions
36
pom.xml
36
pom.xml
|
@ -13,6 +13,8 @@
|
|||
|
||||
<properties>
|
||||
<aesh.version>0.33.12</aesh.version>
|
||||
<apacheds.version>2.0.0-M17</apacheds.version>
|
||||
<apacheds.codec.version>1.0.0-M23</apacheds.codec.version>
|
||||
<base64.version>2.3.8</base64.version>
|
||||
<bouncycastle.crypto.version>1.50</bouncycastle.crypto.version>
|
||||
<bouncycastle.mail.version>1.50</bouncycastle.mail.version>
|
||||
|
@ -23,7 +25,6 @@
|
|||
<!-- <undertow.version>1.1.0.Final</undertow.version> -->
|
||||
<undertow.version>1.1.1.Final</undertow.version>
|
||||
<picketlink.version>2.7.0.CR3</picketlink.version>
|
||||
<picketbox.ldap.version>1.0.2.Final</picketbox.ldap.version>
|
||||
<mongo.driver.version>2.11.3</mongo.driver.version>
|
||||
<jboss.logging.version>3.1.4.GA</jboss.logging.version>
|
||||
<syslog4j.version>0.9.30</syslog4j.version>
|
||||
|
@ -307,17 +308,6 @@
|
|||
<artifactId>picketlink-impl</artifactId>
|
||||
<version>${picketlink.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.picketbox</groupId>
|
||||
<artifactId>picketbox-ldap</artifactId>
|
||||
<version>${picketbox.ldap.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.picketbox</groupId>
|
||||
<artifactId>picketbox-ldap</artifactId>
|
||||
<version>${picketbox.ldap.version}</version>
|
||||
<type>test-jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
|
@ -422,6 +412,28 @@
|
|||
<version>${winzipaes.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache DS -->
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-core-annotations</artifactId>
|
||||
<version>${apacheds.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-interceptor-kerberos</artifactId>
|
||||
<version>${apacheds.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-server-annotations</artifactId>
|
||||
<version>${apacheds.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.api</groupId>
|
||||
<artifactId>api-ldap-codec-standalone</artifactId>
|
||||
<version>${apacheds.codec.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Selenium -->
|
||||
<dependency>
|
||||
<groupId>org.seleniumhq.selenium</groupId>
|
||||
|
|
|
@ -27,11 +27,10 @@ public class LDAPConnectionTestManager {
|
|||
try {
|
||||
Hashtable<String, Object> env = new Hashtable<String, Object>();
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -113,10 +113,6 @@
|
|||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>javase</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
|
@ -212,15 +208,31 @@
|
|||
<groupId>org.seleniumhq.selenium</groupId>
|
||||
<artifactId>selenium-chrome-driver</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache DS -->
|
||||
<dependency>
|
||||
<groupId>org.picketbox</groupId>
|
||||
<artifactId>picketbox-ldap</artifactId>
|
||||
<type>test-jar</type>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-core-annotations</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.picketbox</groupId>
|
||||
<artifactId>picketbox-ldap</artifactId>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-interceptor-kerberos</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-server-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.api</groupId>
|
||||
<artifactId>api-ldap-codec-standalone</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.picketlink</groupId>
|
||||
<artifactId>picketlink-wildfly-common</artifactId>
|
||||
|
@ -270,6 +282,12 @@
|
|||
<workingDirectory>${project.basedir}</workingDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<inherited>true</inherited>
|
||||
<extensions>true</extensions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
@ -316,6 +334,34 @@
|
|||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>ldap</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>org.keycloak.testutils.ldap.LDAPEmbeddedServer</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>kerberos</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>org.keycloak.testutils.ldap.KerberosEmbeddedServer</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa</id>
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
package org.keycloak.testutils.ldap;
|
||||
|
||||
/**
|
||||
* Factory for ApacheDS based LDAP and Kerberos servers
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -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-<code>null</code>
|
||||
* @param partitionFactory must be not-<code>null</code>
|
||||
*/
|
||||
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<Throwable> 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;
|
||||
}
|
||||
}
|
|
@ -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<String, Boolean> resMap = ResourceMap.getResources(Pattern.compile("schema[/\\Q\\\\E]ou=schema.*"));
|
||||
for (String resourcePath : new TreeSet<String>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
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 <dpospisi@redhat.com>
|
||||
*/
|
||||
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 <dpospisi@redhat.com>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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: <principalName> <passPhrase> <outputKeytabFile>");
|
||||
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<KeytabEntry> entries = new ArrayList<KeytabEntry>();
|
||||
for (Map.Entry<EncryptionType, EncryptionKey> 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);
|
||||
}
|
||||
}
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
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<String, String> env = new Hashtable<String, String>();
|
||||
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<String,String> getLDAPConfig() {
|
||||
Map<String,String> ldapConfig = new HashMap<String,String>();
|
||||
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<NameClassPair> 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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
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<String>());
|
||||
return ldapServer;
|
||||
}
|
||||
|
||||
|
||||
private void importLdif() throws Exception {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
BIN
testsuite/integration/src/main/resources/kerberos/http.keytab
Normal file
BIN
testsuite/integration/src/main/resources/kerberos/http.keytab
Normal file
Binary file not shown.
|
@ -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
|
|
@ -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
|
||||
log4j.logger.org.jboss.resteasy=warn
|
||||
log4j.logger.org.apache.directory.api=warn
|
||||
log4j.logger.org.apache.directory.server.core=warn
|
|
@ -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<String,String> ldapConfig = ldapServer.getLDAPConfig();
|
||||
Map<String,String> ldapConfig = ldapRule.getLdapConfig();
|
||||
ldapConfig.put(LDAPFederationProvider.SYNC_REGISTRATIONS, "true");
|
||||
ldapConfig.put(LDAPFederationProvider.EDIT_MODE, UserFederationProvider.EditMode.WRITABLE.toString());
|
||||
|
||||
|
|
|
@ -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<String,String> ldapConfig = ldapServer.getLDAPConfig();
|
||||
Map<String,String> ldapConfig = ldapRule.getLdapConfig();
|
||||
ldapConfig.put(LDAPFederationProvider.SYNC_REGISTRATIONS, "false");
|
||||
ldapConfig.put(LDAPFederationProvider.EDIT_MODE, UserFederationProvider.EditMode.UNSYNCED.toString());
|
||||
|
||||
|
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
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<String, String> getLdapConfig() {
|
||||
return ldapConfiguration.getLDAPConfig();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue