KEYCLOAK-1531 Added embedded LDAP for examples. Added module keycloak-util-embedded-ldap with common code for testsuite and examples
This commit is contained in:
parent
351a17f68d
commit
c6c73e5e59
34 changed files with 1262 additions and 428 deletions
|
@ -89,13 +89,6 @@ public class BasicDBObjectMapper<S> implements Mapper<BasicDBObject, S> {
|
||||||
Type[] genericTypeArguments = parameterized.getActualTypeArguments();
|
Type[] genericTypeArguments = parameterized.getActualTypeArguments();
|
||||||
|
|
||||||
List<Type> genericTypes = Arrays.asList(genericTypeArguments);
|
List<Type> genericTypes = Arrays.asList(genericTypeArguments);
|
||||||
/*for (Type genericType : genericTypeArguments) {
|
|
||||||
if (genericType instanceof Class) {
|
|
||||||
genericTypes.add((Class<?>) genericType);
|
|
||||||
} else {
|
|
||||||
System.out.println("foo");
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
Class<?> expectedReturnType = (Class<?>)parameterized.getRawType();
|
Class<?> expectedReturnType = (Class<?>)parameterized.getRawType();
|
||||||
context = new MapperContext<Object, Object>(valueFromDB, expectedReturnType, genericTypes);
|
context = new MapperContext<Object, Object>(valueFromDB, expectedReturnType, genericTypes);
|
||||||
|
|
|
@ -19,7 +19,7 @@ cp http.keytab /tmp/http.keytab
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternative is to configure different location for `keyTab` property in `kerberosrealm.json` configuration file (On Windows this will be needed).
|
Alternative is to configure different location for `keyTab` property in `kerberosrealm.json` configuration file (On Windows this will be needed).
|
||||||
Note that in production, keytab file should be in secured location accessible just to the user under which is Keycloak server running.
|
WARNING: In production, keytab file should be in secured location accessible just to the user under which is Keycloak server running.
|
||||||
|
|
||||||
|
|
||||||
**3)** Run Keycloak server and import `kerberosrealm.json` into it through admin console. This will import realm with sample application
|
**3)** Run Keycloak server and import `kerberosrealm.json` into it through admin console. This will import realm with sample application
|
||||||
|
@ -37,12 +37,13 @@ Also if you are on Linux, make sure that record like:
|
||||||
```
|
```
|
||||||
is in your `/etc/hosts` before other records for the 127.0.0.1 host to avoid issues related to incompatible reverse lookup (Ensure the similar for other OS as well)
|
is in your `/etc/hosts` before other records for the 127.0.0.1 host to avoid issues related to incompatible reverse lookup (Ensure the similar for other OS as well)
|
||||||
|
|
||||||
|
**4)** Install kerberos client. This is platform dependent. If you are on Fedora, Ubuntu or RHEL, you can install package `freeipa-client`, which contains Kerberos client and bunch of other stuff.
|
||||||
|
|
||||||
**4)** Configure Kerberos client (On linux it's in file `/etc/krb5.conf` ). You need to configure `KEYCLOAK.ORG` realm and enable `forwardable` flag, which is needed
|
**5)** Configure Kerberos client (On linux it's in file `/etc/krb5.conf` ). You need to configure `KEYCLOAK.ORG` realm for host `localhost` and enable `forwardable` flag, which is needed
|
||||||
for credential delegation example, as application needs to forward Kerberos ticket and authenticate with it against LDAP server.
|
for credential delegation example, as application needs to forward Kerberos ticket and authenticate with it against LDAP server.
|
||||||
See [this file](https://github.com/keycloak/keycloak/blob/master/testsuite/integration/src/test/resources/kerberos/test-krb5.conf) for inspiration.
|
See [this file](https://github.com/keycloak/keycloak/blob/master/testsuite/integration/src/test/resources/kerberos/test-krb5.conf) for inspiration.
|
||||||
|
|
||||||
**5)** Run ApacheDS based Kerberos server embedded in Keycloak. Easiest is to checkout keycloak sources, build and then run KerberosEmbeddedServer
|
**6)** Run ApacheDS based Kerberos server embedded in Keycloak. Easiest is to checkout keycloak sources, build and then run KerberosEmbeddedServer
|
||||||
as shown here:
|
as shown here:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -55,12 +56,12 @@ mvn exec:java -Pkerberos
|
||||||
More details about embedded Kerberos server in [testsuite README](https://github.com/keycloak/keycloak/blob/master/misc/Testsuite.md#kerberos-server).
|
More details about embedded Kerberos server in [testsuite README](https://github.com/keycloak/keycloak/blob/master/misc/Testsuite.md#kerberos-server).
|
||||||
|
|
||||||
|
|
||||||
**6)** Configure browser (Firefox, Chrome or other) and enable SPNEGO authentication and credential delegation for `localhost` .
|
**7)** Configure browser (Firefox, Chrome or other) and enable SPNEGO authentication and credential delegation for `localhost` .
|
||||||
In Firefox it can be done by adding `localhost` to both `network.negotiate-auth.trusted-uris` and `network.negotiate-auth.delegation-uris` .
|
In Firefox it can be done by adding `localhost` to both `network.negotiate-auth.trusted-uris` and `network.negotiate-auth.delegation-uris` .
|
||||||
More info in [testsuite README](https://github.com/keycloak/keycloak/blob/master/misc/Testsuite.md#kerberos-server).
|
More info in [testsuite README](https://github.com/keycloak/keycloak/blob/master/misc/Testsuite.md#kerberos-server).
|
||||||
|
|
||||||
|
|
||||||
**7)** Test the example. Obtain kerberos ticket by running command from CMD (on linux):
|
**8)** Test the example. Obtain kerberos ticket by running command from CMD (on linux):
|
||||||
```
|
```
|
||||||
kinit hnelson@KEYCLOAK.ORG
|
kinit hnelson@KEYCLOAK.ORG
|
||||||
```
|
```
|
||||||
|
|
0
examples/kerberos/users.ldif
Normal file
0
examples/kerberos/users.ldif
Normal file
21
examples/ldap/embedded-ldap/assembly.xml
Normal file
21
examples/ldap/embedded-ldap/assembly.xml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<assembly>
|
||||||
|
<id>embedded-ldap</id>
|
||||||
|
|
||||||
|
<formats>
|
||||||
|
<format>dir</format>
|
||||||
|
</formats>
|
||||||
|
|
||||||
|
<includeBaseDirectory>false</includeBaseDirectory>
|
||||||
|
|
||||||
|
<dependencySets>
|
||||||
|
<dependencySet>
|
||||||
|
<unpack>false</unpack>
|
||||||
|
<useTransitiveDependencies>true</useTransitiveDependencies>
|
||||||
|
<useTransitiveFiltering>true</useTransitiveFiltering>
|
||||||
|
<includes>
|
||||||
|
<include>org.keycloak:keycloak-util-embedded-ldap</include>
|
||||||
|
<include>org.slf4j:slf4j-log4j12</include>
|
||||||
|
</includes>
|
||||||
|
</dependencySet>
|
||||||
|
</dependencySets>
|
||||||
|
</assembly>
|
82
examples/ldap/embedded-ldap/pom.xml
Normal file
82
examples/ldap/embedded-ldap/pom.xml
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>keycloak-examples-ldap-parent</artifactId>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<version>1.4.0.Final-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>org.keycloak.example.demo</groupId>
|
||||||
|
<artifactId>keycloak-examples-embedded-ldap</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<name>LDAP Demo Application</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-util-embedded-ldap</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>embedded-ldap</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>assemble</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<descriptors>
|
||||||
|
<descriptor>assembly.xml</descriptor>
|
||||||
|
</descriptors>
|
||||||
|
<outputDirectory>
|
||||||
|
target
|
||||||
|
</outputDirectory>
|
||||||
|
<workDirectory>
|
||||||
|
target/assembly/work
|
||||||
|
</workDirectory>
|
||||||
|
<appendAssemblyId>false</appendAssemblyId>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>org.keycloak.example.ldap.embedded.EmbeddedLDAPLauncher</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>${maven.compiler.source}</source>
|
||||||
|
<target>${maven.compiler.target}</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,127 @@
|
||||||
|
package org.keycloak.example.ldap.embedded;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is supposed to be executed from JAR file (java -jar target/embedded-ldap.jar ). For executing from IDE or Maven use directly
|
||||||
|
* the proper class (LDAPEmbeddedServer, KerberosEmbeddedServer or KerberosKeytabCreator)
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class EmbeddedLDAPLauncher {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
String arg = args.length == 0 ? null : args[0];
|
||||||
|
if (arg == null) {
|
||||||
|
System.err.println("Missing argument: either 'kerberos', 'ldap' or 'keytabCreator' must be passed as argument");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
String clazz = null;
|
||||||
|
File home = getHome();
|
||||||
|
Properties defaultProperties = new Properties();
|
||||||
|
if (arg.equalsIgnoreCase("ldap")) {
|
||||||
|
|
||||||
|
clazz = "org.keycloak.util.ldap.LDAPEmbeddedServer";
|
||||||
|
File ldapLdif = file(home, "..", "ldap-app", "users.ldif");
|
||||||
|
defaultProperties.put("ldap.ldif", ldapLdif.getAbsolutePath());
|
||||||
|
} else if (arg.equalsIgnoreCase("kerberos")) {
|
||||||
|
|
||||||
|
clazz = "org.keycloak.util.ldap.KerberosEmbeddedServer";
|
||||||
|
File kerberosLdif = file(home, "..", "..", "kerberos", "users.ldif");
|
||||||
|
defaultProperties.put("ldap.ldif", kerberosLdif.getAbsolutePath());
|
||||||
|
} else if (arg.equalsIgnoreCase("keytabCreator")) {
|
||||||
|
|
||||||
|
clazz = "org.keycloak.util.ldap.KerberosKeytabCreator";
|
||||||
|
} else {
|
||||||
|
|
||||||
|
System.err.println("Invalid argument: '" + arg + "' . Either 'kerberos', 'ldap' or 'keytabCreator' must be passed as argument");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove first argument
|
||||||
|
String[] newArgs = new String[args.length - 1];
|
||||||
|
for (int i=0 ; i<(args.length - 1) ; i++) {
|
||||||
|
newArgs[i] = args[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Executing " + clazz);
|
||||||
|
runClass(clazz, newArgs, defaultProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void runClass(String className, String[] args, Properties defaultProperties) throws Exception {
|
||||||
|
File home = getHome();
|
||||||
|
File lib = file(home, "target", "embedded-ldap");
|
||||||
|
|
||||||
|
if (!lib.exists()) {
|
||||||
|
System.err.println("Could not find lib directory: " + lib.toString());
|
||||||
|
System.exit(1);
|
||||||
|
} else {
|
||||||
|
System.out.println("Found directory to load jars: " + lib.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<URL> jars = new ArrayList<URL>();
|
||||||
|
for (File file : lib.listFiles()) {
|
||||||
|
jars.add(file.toURI().toURL());
|
||||||
|
}
|
||||||
|
URL[] urls = jars.toArray(new URL[jars.size()]);
|
||||||
|
URLClassLoader loader = new URLClassLoader(urls, EmbeddedLDAPLauncher.class.getClassLoader());
|
||||||
|
|
||||||
|
Class mainClass = loader.loadClass(className);
|
||||||
|
Method executeMethod = null;
|
||||||
|
for (Method m : mainClass.getMethods()) if (m.getName().equals("execute")) { executeMethod = m; break; }
|
||||||
|
Object obj = args;
|
||||||
|
executeMethod.invoke(null, obj, defaultProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static File getHome() {
|
||||||
|
String launcherPath = EmbeddedLDAPLauncher.class.getName().replace('.', '/') + ".class";
|
||||||
|
URL jarfile = EmbeddedLDAPLauncher.class.getClassLoader().getResource(launcherPath);
|
||||||
|
if (jarfile != null) {
|
||||||
|
Matcher m = Pattern.compile("jar:(file:.*)!/" + launcherPath).matcher(jarfile.toString());
|
||||||
|
if (m.matches()) {
|
||||||
|
try {
|
||||||
|
File jarPath = new File(new URI(m.group(1)));
|
||||||
|
File libPath = jarPath.getParentFile().getParentFile();
|
||||||
|
System.out.println("Home directory: " + libPath.toString());
|
||||||
|
if (!libPath.exists()) {
|
||||||
|
System.exit(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
return libPath;
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.err.println("jar file null: " + launcherPath);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File file(File home, String... pathItems) {
|
||||||
|
File current = home;
|
||||||
|
|
||||||
|
for (String item : pathItems) {
|
||||||
|
if (item.equals("..")) {
|
||||||
|
current = current.getParentFile();
|
||||||
|
} else {
|
||||||
|
current = new File(current, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
}
|
68
examples/ldap/ldap-app/pom.xml
Normal file
68
examples/ldap/ldap-app/pom.xml
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>keycloak-examples-ldap-parent</artifactId>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<version>1.4.0.Final-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>org.keycloak.example.demo</groupId>
|
||||||
|
<artifactId>keycloak-examples-ldap-app</artifactId>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
<name>LDAP Demo Application</name>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>jboss</id>
|
||||||
|
<name>jboss repo</name>
|
||||||
|
<url>http://repository.jboss.org/nexus/content/groups/public/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
|
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-core</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-adapter-core</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>ldap-portal</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.jboss.as.plugins</groupId>
|
||||||
|
<artifactId>jboss-as-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>false</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.wildfly.plugins</groupId>
|
||||||
|
<artifactId>wildfly-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>false</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
0
examples/ldap/ldap-app/users.ldif
Normal file
0
examples/ldap/ldap-app/users.ldif
Normal file
20
examples/ldap/pom.xml
Normal file
20
examples/ldap/pom.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>keycloak-examples-parent</artifactId>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<version>1.4.0.Final-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<name>Keycloak LDAP Examples - Parent</name>
|
||||||
|
<description/>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>keycloak-examples-ldap-parent</artifactId>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>embedded-ldap</module>
|
||||||
|
<module>ldap-app</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
</project>
|
|
@ -44,5 +44,6 @@
|
||||||
<module>kerberos</module>
|
<module>kerberos</module>
|
||||||
<module>themes</module>
|
<module>themes</module>
|
||||||
<module>saml</module>
|
<module>saml</module>
|
||||||
|
<module>ldap</module>
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</project>
|
||||||
|
|
11
pom.xml
11
pom.xml
|
@ -155,6 +155,7 @@
|
||||||
<module>testsuite</module>
|
<module>testsuite</module>
|
||||||
<module>timer</module>
|
<module>timer</module>
|
||||||
<module>export-import</module>
|
<module>export-import</module>
|
||||||
|
<module>util</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
|
@ -431,25 +432,21 @@
|
||||||
<groupId>org.apache.directory.server</groupId>
|
<groupId>org.apache.directory.server</groupId>
|
||||||
<artifactId>apacheds-core-annotations</artifactId>
|
<artifactId>apacheds-core-annotations</artifactId>
|
||||||
<version>${apacheds.version}</version>
|
<version>${apacheds.version}</version>
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.directory.server</groupId>
|
<groupId>org.apache.directory.server</groupId>
|
||||||
<artifactId>apacheds-interceptor-kerberos</artifactId>
|
<artifactId>apacheds-interceptor-kerberos</artifactId>
|
||||||
<version>${apacheds.version}</version>
|
<version>${apacheds.version}</version>
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.directory.server</groupId>
|
<groupId>org.apache.directory.server</groupId>
|
||||||
<artifactId>apacheds-server-annotations</artifactId>
|
<artifactId>apacheds-server-annotations</artifactId>
|
||||||
<version>${apacheds.version}</version>
|
<version>${apacheds.version}</version>
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.directory.api</groupId>
|
<groupId>org.apache.directory.api</groupId>
|
||||||
<artifactId>api-ldap-codec-standalone</artifactId>
|
<artifactId>api-ldap-codec-standalone</artifactId>
|
||||||
<version>${apacheds.codec.version}</version>
|
<version>${apacheds.codec.version}</version>
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Selenium -->
|
<!-- Selenium -->
|
||||||
|
@ -1120,6 +1117,11 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<type>zip</type>
|
<type>zip</type>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-util-embedded-ldap</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-docs-dist</artifactId>
|
<artifactId>keycloak-docs-dist</artifactId>
|
||||||
|
@ -1184,6 +1186,7 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<classifier>classes</classifier>
|
<classifier>classes</classifier>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>federation-properties-example</artifactId>
|
<artifactId>federation-properties-example</artifactId>
|
||||||
|
|
|
@ -190,40 +190,8 @@
|
||||||
|
|
||||||
<!-- Apache DS -->
|
<!-- Apache DS -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.directory.server</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>apacheds-core-annotations</artifactId>
|
<artifactId>keycloak-util-embedded-ldap</artifactId>
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.apache.directory.jdbm</groupId>
|
|
||||||
<artifactId>apacheds-jdbm1</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.directory.server</groupId>
|
|
||||||
<artifactId>apacheds-interceptor-kerberos</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.directory.server</groupId>
|
|
||||||
<artifactId>apacheds-server-annotations</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.apache.directory.jdbm</groupId>
|
|
||||||
<artifactId>apacheds-jdbm1</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.directory.api</groupId>
|
|
||||||
<artifactId>api-ldap-codec-standalone</artifactId>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -344,7 +312,7 @@
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>exec-maven-plugin</artifactId>
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<mainClass>org.keycloak.testsuite.ldap.LDAPEmbeddedServer</mainClass>
|
<mainClass>org.keycloak.util.ldap.LDAPEmbeddedServer</mainClass>
|
||||||
<classpathScope>test</classpathScope>
|
<classpathScope>test</classpathScope>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
@ -359,7 +327,7 @@
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>exec-maven-plugin</artifactId>
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<mainClass>org.keycloak.testsuite.ldap.KerberosEmbeddedServer</mainClass>
|
<mainClass>org.keycloak.util.ldap.KerberosEmbeddedServer</mainClass>
|
||||||
<classpathScope>test</classpathScope>
|
<classpathScope>test</classpathScope>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
|
@ -68,10 +68,10 @@ public class FederationProvidersIntegrationTest {
|
||||||
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
|
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
|
||||||
FederationTestUtils.removeAllLDAPUsers(ldapFedProvider, appRealm);
|
FederationTestUtils.removeAllLDAPUsers(ldapFedProvider, appRealm);
|
||||||
|
|
||||||
LDAPObject john = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "johnkeycloak", "John", "Doe", "john@email.org", "1234");
|
LDAPObject john = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "johnkeycloak", "John", "Doe", "john@email.org", null, "1234");
|
||||||
ldapFedProvider.getLdapIdentityStore().updatePassword(john, "Password1");
|
ldapFedProvider.getLdapIdentityStore().updatePassword(john, "Password1");
|
||||||
|
|
||||||
LDAPObject existing = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "existing", "Existing", "Foo", "existing@email.org", "5678");
|
LDAPObject existing = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "existing", "Existing", "Foo", "existing@email.org", null, "5678");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ public class FederationProvidersIntegrationTest {
|
||||||
RealmModel appRealm = new RealmManager(session).getRealmByName("test");
|
RealmModel appRealm = new RealmManager(session).getRealmByName("test");
|
||||||
|
|
||||||
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
|
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
|
||||||
LDAPObject johnZip = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "johnzip", "John", "Zip", "johnzip@email.org", "12398");
|
LDAPObject johnZip = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "johnzip", "John", "Zip", "johnzip@email.org", null, "12398");
|
||||||
|
|
||||||
// Remove default zipcode mapper and add the mapper for "POstalCode" to test case sensitivity
|
// Remove default zipcode mapper and add the mapper for "POstalCode" to test case sensitivity
|
||||||
UserFederationMapperModel currentZipMapper = appRealm.getUserFederationMapperByName(ldapModel.getId(), "zipCodeMapper");
|
UserFederationMapperModel currentZipMapper = appRealm.getUserFederationMapperByName(ldapModel.getId(), "zipCodeMapper");
|
||||||
|
@ -295,7 +295,7 @@ public class FederationProvidersIntegrationTest {
|
||||||
RealmModel appRealm = new RealmManager(session).getRealmByName("test");
|
RealmModel appRealm = new RealmManager(session).getRealmByName("test");
|
||||||
|
|
||||||
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
|
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
|
||||||
LDAPObject johnDirect = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "johndirect", "John", "Direct", "johndirect@email.org", "12399");
|
LDAPObject johnDirect = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "johndirect", "John", "Direct", "johndirect@email.org", null, "12399");
|
||||||
|
|
||||||
// Fetch user from LDAP and check that postalCode is filled
|
// Fetch user from LDAP and check that postalCode is filled
|
||||||
UserModel user = session.users().getUserByUsername("johndirect", appRealm);
|
UserModel user = session.users().getUserByUsername("johndirect", appRealm);
|
||||||
|
@ -370,7 +370,7 @@ public class FederationProvidersIntegrationTest {
|
||||||
|
|
||||||
// Add the user with some fullName into LDAP directly. Ensure that fullName is saved into "cn" attribute in LDAP (currently mapped to model firstName)
|
// Add the user with some fullName into LDAP directly. Ensure that fullName is saved into "cn" attribute in LDAP (currently mapped to model firstName)
|
||||||
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
|
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
|
||||||
FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "fullname", "James Dee", "Dee", "fullname@email.org", "4578");
|
FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "fullname", "James Dee", "Dee", "fullname@email.org", null, "4578");
|
||||||
|
|
||||||
// add fullname mapper to the provider and remove "firstNameMapper". For this test, we will simply map full name to the LDAP attribute, which was before firstName ( "givenName" on active directory, "cn" on other LDAP servers)
|
// add fullname mapper to the provider and remove "firstNameMapper". For this test, we will simply map full name to the LDAP attribute, which was before firstName ( "givenName" on active directory, "cn" on other LDAP servers)
|
||||||
firstNameMapper = appRealm.getUserFederationMapperByName(ldapModel.getId(), "first name");
|
firstNameMapper = appRealm.getUserFederationMapperByName(ldapModel.getId(), "first name");
|
||||||
|
@ -485,10 +485,10 @@ public class FederationProvidersIntegrationTest {
|
||||||
RealmModel appRealm = session.realms().getRealmByName("test");
|
RealmModel appRealm = session.realms().getRealmByName("test");
|
||||||
LDAPFederationProvider ldapProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
|
LDAPFederationProvider ldapProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
|
||||||
|
|
||||||
FederationTestUtils.addLDAPUser(ldapProvider, appRealm, "username1", "John1", "Doel1", "user1@email.org", "121");
|
FederationTestUtils.addLDAPUser(ldapProvider, appRealm, "username1", "John1", "Doel1", "user1@email.org", null, "121");
|
||||||
FederationTestUtils.addLDAPUser(ldapProvider, appRealm, "username2", "John2", "Doel2", "user2@email.org", "122");
|
FederationTestUtils.addLDAPUser(ldapProvider, appRealm, "username2", "John2", "Doel2", "user2@email.org", null, "122");
|
||||||
FederationTestUtils.addLDAPUser(ldapProvider, appRealm, "username3", "John3", "Doel3", "user3@email.org", "123");
|
FederationTestUtils.addLDAPUser(ldapProvider, appRealm, "username3", "John3", "Doel3", "user3@email.org", null, "123");
|
||||||
FederationTestUtils.addLDAPUser(ldapProvider, appRealm, "username4", "John4", "Doel4", "user4@email.org", "124");
|
FederationTestUtils.addLDAPUser(ldapProvider, appRealm, "username4", "John4", "Doel4", "user4@email.org", null, "124");
|
||||||
|
|
||||||
// Users are not at local store at this moment
|
// Users are not at local store at this moment
|
||||||
Assert.assertNull(session.userStorage().getUserByUsername("username1", appRealm));
|
Assert.assertNull(session.userStorage().getUserByUsername("username1", appRealm));
|
||||||
|
|
|
@ -47,7 +47,7 @@ class FederationTestUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LDAPObject addLDAPUser(LDAPFederationProvider ldapProvider, RealmModel realm, final String username,
|
public static LDAPObject addLDAPUser(LDAPFederationProvider ldapProvider, RealmModel realm, final String username,
|
||||||
final String firstName, final String lastName, final String email, final String postalCode) {
|
final String firstName, final String lastName, final String email, final String street, final String... postalCode) {
|
||||||
UserModel helperUser = new UserModelDelegate(null) {
|
UserModel helperUser = new UserModelDelegate(null) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -74,6 +74,8 @@ class FederationTestUtils {
|
||||||
public List<String> getAttribute(String name) {
|
public List<String> getAttribute(String name) {
|
||||||
if ("postal_code".equals(name)) {
|
if ("postal_code".equals(name)) {
|
||||||
return Arrays.asList(postalCode);
|
return Arrays.asList(postalCode);
|
||||||
|
} else if ("street".equals(name)) {
|
||||||
|
return Arrays.asList(street);
|
||||||
} else {
|
} else {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package org.keycloak.testsuite.federation;
|
package org.keycloak.testsuite.federation;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -17,6 +20,7 @@ import org.junit.runners.MethodSorters;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.federation.ldap.LDAPFederationProvider;
|
import org.keycloak.federation.ldap.LDAPFederationProvider;
|
||||||
import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
|
import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
|
||||||
|
import org.keycloak.federation.ldap.idm.model.LDAPObject;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.LDAPConstants;
|
import org.keycloak.models.LDAPConstants;
|
||||||
|
@ -60,6 +64,19 @@ public class LDAPMultipleAttributesTest {
|
||||||
FederationTestUtils.addZipCodeLDAPMapper(appRealm, ldapModel);
|
FederationTestUtils.addZipCodeLDAPMapper(appRealm, ldapModel);
|
||||||
FederationTestUtils.addUserAttributeMapper(appRealm, ldapModel, "streetMapper", "street", LDAPConstants.STREET);
|
FederationTestUtils.addUserAttributeMapper(appRealm, ldapModel, "streetMapper", "street", LDAPConstants.STREET);
|
||||||
|
|
||||||
|
// Remove current users and add default users
|
||||||
|
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
|
||||||
|
FederationTestUtils.removeAllLDAPUsers(ldapFedProvider, appRealm);
|
||||||
|
|
||||||
|
LDAPObject james = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "jbrown", "James", "Brown", "jbrown@keycloak.org", "", "88441");
|
||||||
|
ldapFedProvider.getLdapIdentityStore().updatePassword(james, "password");
|
||||||
|
|
||||||
|
// User for testing duplicating surname and postalCode
|
||||||
|
LDAPObject bruce = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "bwilson", "Bruce", "Wilson", "bwilson@keycloak.org", "Elm 5", "88441", "77332");
|
||||||
|
bruce.setAttribute("sn", new LinkedHashSet<>(Arrays.asList("Wilson", "Schneider")));
|
||||||
|
ldapFedProvider.getLdapIdentityStore().update(bruce);
|
||||||
|
ldapFedProvider.getLdapIdentityStore().updatePassword(bruce, "password");
|
||||||
|
|
||||||
// Create ldap-portal client
|
// Create ldap-portal client
|
||||||
ClientModel ldapClient = appRealm.addClient("ldap-portal");
|
ClientModel ldapClient = appRealm.addClient("ldap-portal");
|
||||||
ldapClient.addRedirectUri("/ldap-portal");
|
ldapClient.addRedirectUri("/ldap-portal");
|
||||||
|
|
|
@ -76,13 +76,13 @@ public class LDAPRoleMappingsTest {
|
||||||
FederationTestUtils.removeAllLDAPRoles(manager.getSession(), appRealm, ldapModel, "financeRolesMapper");
|
FederationTestUtils.removeAllLDAPRoles(manager.getSession(), appRealm, ldapModel, "financeRolesMapper");
|
||||||
|
|
||||||
// Add some users for testing
|
// Add some users for testing
|
||||||
LDAPObject john = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "johnkeycloak", "John", "Doe", "john@email.org", "1234");
|
LDAPObject john = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "johnkeycloak", "John", "Doe", "john@email.org", null, "1234");
|
||||||
ldapFedProvider.getLdapIdentityStore().updatePassword(john, "Password1");
|
ldapFedProvider.getLdapIdentityStore().updatePassword(john, "Password1");
|
||||||
|
|
||||||
LDAPObject mary = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "marykeycloak", "Mary", "Kelly", "mary@email.org", "5678");
|
LDAPObject mary = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "marykeycloak", "Mary", "Kelly", "mary@email.org", null, "5678");
|
||||||
ldapFedProvider.getLdapIdentityStore().updatePassword(mary, "Password1");
|
ldapFedProvider.getLdapIdentityStore().updatePassword(mary, "Password1");
|
||||||
|
|
||||||
LDAPObject rob = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "robkeycloak", "Rob", "Brown", "rob@email.org", "8910");
|
LDAPObject rob = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "robkeycloak", "Rob", "Brown", "rob@email.org", null, "8910");
|
||||||
ldapFedProvider.getLdapIdentityStore().updatePassword(rob, "Password1");
|
ldapFedProvider.getLdapIdentityStore().updatePassword(rob, "Password1");
|
||||||
|
|
||||||
// Add some roles for testing
|
// Add some roles for testing
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package org.keycloak.testsuite.ldap;
|
package org.keycloak.testsuite.federation;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
|
@ -61,7 +61,7 @@ public class SyncProvidersTest {
|
||||||
FederationTestUtils.removeAllLDAPUsers(ldapFedProvider, appRealm);
|
FederationTestUtils.removeAllLDAPUsers(ldapFedProvider, appRealm);
|
||||||
|
|
||||||
for (int i=1 ; i<=5 ; i++) {
|
for (int i=1 ; i<=5 ; i++) {
|
||||||
LDAPObject ldapUser = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "user" + i, "User" + i + "FN", "User" + i + "LN", "user" + i + "@email.org", "12" + i);
|
LDAPObject ldapUser = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "user" + i, "User" + i + "FN", "User" + i + "LN", "user" + i + "@email.org", null, "12" + i);
|
||||||
ldapFedProvider.getLdapIdentityStore().updatePassword(ldapUser, "Password1");
|
ldapFedProvider.getLdapIdentityStore().updatePassword(ldapUser, "Password1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ public class SyncProvidersTest {
|
||||||
|
|
||||||
// Add user to LDAP and update 'user5' in LDAP
|
// Add user to LDAP and update 'user5' in LDAP
|
||||||
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
|
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
|
||||||
FederationTestUtils.addLDAPUser(ldapFedProvider, testRealm, "user6", "User6FN", "User6LN", "user6@email.org", "126");
|
FederationTestUtils.addLDAPUser(ldapFedProvider, testRealm, "user6", "User6FN", "User6LN", "user6@email.org", null, "126");
|
||||||
LDAPObject ldapUser5 = ldapFedProvider.loadLDAPUserByUsername(testRealm, "user5");
|
LDAPObject ldapUser5 = ldapFedProvider.loadLDAPUserByUsername(testRealm, "user5");
|
||||||
// NOTE: Changing LDAP attributes directly here
|
// NOTE: Changing LDAP attributes directly here
|
||||||
ldapUser5.setSingleAttribute(LDAPConstants.EMAIL, "user5Updated@email.org");
|
ldapUser5.setSingleAttribute(LDAPConstants.EMAIL, "user5Updated@email.org");
|
||||||
|
|
|
@ -1,110 +0,0 @@
|
||||||
package org.keycloak.testsuite.ldap;
|
|
||||||
|
|
||||||
import org.ietf.jgss.GSSException;
|
|
||||||
import org.ietf.jgss.GSSManager;
|
|
||||||
import org.ietf.jgss.GSSName;
|
|
||||||
import org.keycloak.util.KerberosSerializationUtils;
|
|
||||||
import sun.security.jgss.GSSNameImpl;
|
|
||||||
import sun.security.jgss.krb5.Krb5NameElement;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 static final String DEFAULT_KDC_ENCRYPTION_TYPES = "aes128-cts-hmac-sha1-96, des-cbc-md5, des3-cbc-sha1-kd";
|
|
||||||
|
|
||||||
private String baseDN;
|
|
||||||
private String bindHost;
|
|
||||||
private int bindPort;
|
|
||||||
private String ldapSaslPrincipal;
|
|
||||||
private String ldifFile;
|
|
||||||
private String kerberosRealm;
|
|
||||||
private int kdcPort;
|
|
||||||
private String kdcEncryptionTypes;
|
|
||||||
|
|
||||||
|
|
||||||
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.ldapSaslPrincipal = System.getProperty("ldap.saslPrincipal");
|
|
||||||
|
|
||||||
this.kerberosRealm = System.getProperty("kerberos.realm");
|
|
||||||
String kdcPort = System.getProperty("kerberos.port");
|
|
||||||
this.kdcEncryptionTypes = System.getProperty("kerberos.encTypes");
|
|
||||||
|
|
||||||
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);
|
|
||||||
if (kdcEncryptionTypes == null || kdcEncryptionTypes.isEmpty()) {
|
|
||||||
kdcEncryptionTypes = DEFAULT_KDC_ENCRYPTION_TYPES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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, ldapSaslPrincipal);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public KerberosEmbeddedServer createKerberosServer() {
|
|
||||||
|
|
||||||
// Override LDIF file with default for embedded Kerberos
|
|
||||||
if (ldifFile.equals(DEFAULT_LDIF_FILE)) {
|
|
||||||
ldifFile = DEFAULT_KERBEROS_LDIF_FILE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init ldap sasl principal just when creating kerberos server
|
|
||||||
if (ldapSaslPrincipal == null || ldapSaslPrincipal.isEmpty()) {
|
|
||||||
try {
|
|
||||||
// Same algorithm like sun.security.krb5.PrincipalName constructor
|
|
||||||
GSSName gssName = GSSManager.getInstance().createName("ldap@" + bindHost, GSSName.NT_HOSTBASED_SERVICE);
|
|
||||||
GSSNameImpl gssName1 = (GSSNameImpl) gssName;
|
|
||||||
Krb5NameElement krb5NameElement = (Krb5NameElement) gssName1.getElement(KerberosSerializationUtils.KRB5_OID);
|
|
||||||
this.ldapSaslPrincipal = krb5NameElement.getKrb5PrincipalName().toString();
|
|
||||||
} catch (GSSException uhe) {
|
|
||||||
throw new RuntimeException(uhe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new KerberosEmbeddedServer(baseDN, bindHost, bindPort, ldifFile, ldapSaslPrincipal, kerberosRealm, kdcPort, kdcEncryptionTypes);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,196 +0,0 @@
|
||||||
package org.keycloak.testsuite.ldap;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URL;
|
|
||||||
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 final String ldapSaslPrincipal;
|
|
||||||
|
|
||||||
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, String ldapSaslPrincipal) {
|
|
||||||
this.baseDN = baseDN;
|
|
||||||
this.bindHost = bindHost;
|
|
||||||
this.bindPort = bindPort;
|
|
||||||
this.ldifFile = ldifFile;
|
|
||||||
this.ldapSaslPrincipal = ldapSaslPrincipal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void init() throws Exception {
|
|
||||||
log.info("Creating LDAP Directory Service. Config: baseDN=" + baseDN + ", bindHost=" + bindHost + ", bindPort=" + bindPort +
|
|
||||||
", ldapSaslPrincipal=" + ldapSaslPrincipal);
|
|
||||||
|
|
||||||
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");
|
|
||||||
ldapServer.setSearchBaseDn(this.baseDN);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
return ldapServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void importLdif() throws Exception {
|
|
||||||
Map<String, String> map = new HashMap<String, String>();
|
|
||||||
map.put("hostname", this.bindHost);
|
|
||||||
if (this.ldapSaslPrincipal != null) {
|
|
||||||
map.put("ldapSaslPrincipal", this.ldapSaslPrincipal);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For now, assume that LDIF file is on classpath
|
|
||||||
InputStream is;
|
|
||||||
if (ldifFile.startsWith("file:")) {
|
|
||||||
is = new URL(ldifFile).openStream();
|
|
||||||
} else {
|
|
||||||
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("Content of 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("Stopping LDAP server.");
|
|
||||||
ldapServer.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void shutdownDirectoryService() throws Exception {
|
|
||||||
log.info("Stopping Directory service.");
|
|
||||||
directoryService.shutdown();
|
|
||||||
|
|
||||||
log.info("Removing Directory service workfiles.");
|
|
||||||
FileUtils.deleteDirectory(directoryService.getInstanceLayout().getInstanceDirectory());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -2,11 +2,12 @@ package org.keycloak.testsuite.rule;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.testsuite.ldap.EmbeddedServersFactory;
|
import org.keycloak.testsuite.federation.LDAPTestConfiguration;
|
||||||
import org.keycloak.testsuite.ldap.LDAPTestConfiguration;
|
import org.keycloak.util.ldap.KerberosEmbeddedServer;
|
||||||
import org.keycloak.testsuite.ldap.LDAPEmbeddedServer;
|
import org.keycloak.util.ldap.LDAPEmbeddedServer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
@ -33,7 +34,11 @@ public class KerberosRule extends LDAPRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LDAPEmbeddedServer createServer(EmbeddedServersFactory factory) {
|
protected LDAPEmbeddedServer createServer() {
|
||||||
return factory.createKerberosServer();
|
Properties defaultProperties = new Properties();
|
||||||
|
defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_DSF, LDAPEmbeddedServer.DSF_INMEMORY);
|
||||||
|
defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_LDIF_FILE, "classpath:kerberos/users-kerberos.ldif");
|
||||||
|
|
||||||
|
return new KerberosEmbeddedServer(defaultProperties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package org.keycloak.testsuite.rule;
|
package org.keycloak.testsuite.rule;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.junit.rules.ExternalResource;
|
import org.junit.rules.ExternalResource;
|
||||||
import org.keycloak.testsuite.ldap.EmbeddedServersFactory;
|
import org.keycloak.testsuite.federation.LDAPTestConfiguration;
|
||||||
import org.keycloak.testsuite.ldap.LDAPTestConfiguration;
|
import org.keycloak.util.ldap.LDAPEmbeddedServer;
|
||||||
import org.keycloak.testsuite.ldap.LDAPEmbeddedServer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
@ -23,8 +23,7 @@ public class LDAPRule extends ExternalResource {
|
||||||
ldapTestConfiguration = LDAPTestConfiguration.readConfiguration(connectionPropsLocation);
|
ldapTestConfiguration = LDAPTestConfiguration.readConfiguration(connectionPropsLocation);
|
||||||
|
|
||||||
if (ldapTestConfiguration.isStartEmbeddedLdapLerver()) {
|
if (ldapTestConfiguration.isStartEmbeddedLdapLerver()) {
|
||||||
EmbeddedServersFactory factory = EmbeddedServersFactory.readConfiguration();
|
ldapEmbeddedServer = createServer();
|
||||||
ldapEmbeddedServer = createServer(factory);
|
|
||||||
ldapEmbeddedServer.init();
|
ldapEmbeddedServer.init();
|
||||||
ldapEmbeddedServer.start();
|
ldapEmbeddedServer.start();
|
||||||
}
|
}
|
||||||
|
@ -47,8 +46,12 @@ public class LDAPRule extends ExternalResource {
|
||||||
return LDAP_CONNECTION_PROPERTIES_LOCATION;
|
return LDAP_CONNECTION_PROPERTIES_LOCATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected LDAPEmbeddedServer createServer(EmbeddedServersFactory factory) {
|
protected LDAPEmbeddedServer createServer() {
|
||||||
return factory.createLdapServer();
|
Properties defaultProperties = new Properties();
|
||||||
|
defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_DSF, LDAPEmbeddedServer.DSF_INMEMORY);
|
||||||
|
defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_LDIF_FILE, "classpath:ldap/users.ldif");
|
||||||
|
|
||||||
|
return new LDAPEmbeddedServer(defaultProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> getConfig() {
|
public Map<String, String> getConfig() {
|
||||||
|
|
|
@ -18,30 +18,3 @@ dn: ou=FinanceRoles,dc=keycloak,dc=org
|
||||||
objectclass: top
|
objectclass: top
|
||||||
objectclass: organizationalUnit
|
objectclass: organizationalUnit
|
||||||
ou: FinanceRoles
|
ou: FinanceRoles
|
||||||
|
|
||||||
dn: uid=jbrown,ou=People,dc=keycloak,dc=org
|
|
||||||
objectclass: top
|
|
||||||
objectclass: person
|
|
||||||
objectclass: organizationalPerson
|
|
||||||
objectclass: inetOrgPerson
|
|
||||||
uid: jbrown
|
|
||||||
cn: James
|
|
||||||
sn: Brown
|
|
||||||
mail: jbrown@keycloak.org
|
|
||||||
postalCode: 88441
|
|
||||||
userPassword: password
|
|
||||||
|
|
||||||
dn: uid=bwilson,ou=People,dc=keycloak,dc=org
|
|
||||||
objectclass: top
|
|
||||||
objectclass: person
|
|
||||||
objectclass: organizationalPerson
|
|
||||||
objectclass: inetOrgPerson
|
|
||||||
uid: bwilson
|
|
||||||
cn: Bruce
|
|
||||||
sn: Wilson
|
|
||||||
sn: Schneider
|
|
||||||
mail: bwilson@keycloak.org
|
|
||||||
postalCode: 88441
|
|
||||||
postalCode: 77332
|
|
||||||
street: Elm 5
|
|
||||||
userPassword: password
|
|
||||||
|
|
91
util/embedded-ldap/pom.xml
Normal file
91
util/embedded-ldap/pom.xml
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>keycloak-parent</artifactId>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<version>1.4.0.Final-SNAPSHOT</version>
|
||||||
|
<relativePath>../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>keycloak-util-embedded-ldap</artifactId>
|
||||||
|
<name>Keycloak Util Embedded LDAP</name>
|
||||||
|
<description/>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.logging</groupId>
|
||||||
|
<artifactId>jboss-logging</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>log4j</groupId>
|
||||||
|
<artifactId>log4j</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.directory.server</groupId>
|
||||||
|
<artifactId>apacheds-core-annotations</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.directory.jdbm</groupId>
|
||||||
|
<artifactId>apacheds-jdbm1</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.directory.server</groupId>
|
||||||
|
<artifactId>apacheds-interceptor-kerberos</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.directory.server</groupId>
|
||||||
|
<artifactId>apacheds-server-annotations</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.directory.jdbm</groupId>
|
||||||
|
<artifactId>apacheds-jdbm1</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.directory.api</groupId>
|
||||||
|
<artifactId>api-ldap-codec-standalone</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>${maven.compiler.source}</source>
|
||||||
|
<target>${maven.compiler.target}</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,267 @@
|
||||||
|
package org.keycloak.util.ldap;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.directory.api.ldap.model.constants.SchemaConstants;
|
||||||
|
import org.apache.directory.api.ldap.model.exception.LdapEntryAlreadyExistsException;
|
||||||
|
import org.apache.directory.api.ldap.model.exception.LdapException;
|
||||||
|
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.schemaextractor.SchemaLdifExtractor;
|
||||||
|
import org.apache.directory.api.ldap.schemaextractor.impl.DefaultSchemaLdifExtractor;
|
||||||
|
import org.apache.directory.api.ldap.schemaloader.LdifSchemaLoader;
|
||||||
|
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.interceptor.context.AddOperationContext;
|
||||||
|
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.DefaultDirectoryServiceFactory;
|
||||||
|
import org.apache.directory.server.core.factory.DirectoryServiceFactory;
|
||||||
|
import org.apache.directory.server.core.factory.JdbmPartitionFactory;
|
||||||
|
import org.apache.directory.server.core.factory.LdifPartitionFactory;
|
||||||
|
import org.apache.directory.server.core.factory.PartitionFactory;
|
||||||
|
import org.apache.directory.server.core.partition.ldif.LdifPartition;
|
||||||
|
import org.apache.directory.server.i18n.I18n;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slightly modified version of {@link DefaultDirectoryServiceFactory} which allows persistence among restarts and uses LDIF partitions by default
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
class FileDirectoryServiceFactory implements DirectoryServiceFactory {
|
||||||
|
|
||||||
|
/** A logger for this class */
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(FileDirectoryServiceFactory.class);
|
||||||
|
|
||||||
|
/** The directory service. */
|
||||||
|
private DirectoryService directoryService;
|
||||||
|
|
||||||
|
/** The partition factory. */
|
||||||
|
private PartitionFactory partitionFactory;
|
||||||
|
|
||||||
|
|
||||||
|
public FileDirectoryServiceFactory()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// creating the instance here so that
|
||||||
|
// we we can set some properties like accesscontrol, anon access
|
||||||
|
// before starting up the service
|
||||||
|
directoryService = new DefaultDirectoryService();
|
||||||
|
|
||||||
|
// no need to register a shutdown hook during tests because this
|
||||||
|
// starts a lot of threads and slows down test execution
|
||||||
|
directoryService.setShutdownHookEnabled( false );
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
throw new RuntimeException( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String typeName = System.getProperty( "apacheds.partition.factory" );
|
||||||
|
|
||||||
|
if ( typeName != null )
|
||||||
|
{
|
||||||
|
Class<? extends PartitionFactory> type = ( Class<? extends PartitionFactory> ) Class.forName( typeName );
|
||||||
|
partitionFactory = type.newInstance();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// partitionFactory = new JdbmPartitionFactory();
|
||||||
|
partitionFactory = new LdifPartitionFactory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
LOG.error( "Error instantiating custom partiton factory", e );
|
||||||
|
throw new RuntimeException( e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public FileDirectoryServiceFactory( DirectoryService directoryService, PartitionFactory partitionFactory )
|
||||||
|
{
|
||||||
|
this.directoryService = directoryService;
|
||||||
|
this.partitionFactory = partitionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public void init( String name ) throws Exception
|
||||||
|
{
|
||||||
|
if ( ( directoryService != null ) && directoryService.isStarted() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
build(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the working directory
|
||||||
|
*/
|
||||||
|
private void buildInstanceDirectory( String name ) throws IOException
|
||||||
|
{
|
||||||
|
String instanceDirectory = System.getProperty( "workingDirectory" );
|
||||||
|
|
||||||
|
if ( instanceDirectory == null )
|
||||||
|
{
|
||||||
|
instanceDirectory = System.getProperty( "java.io.tmpdir" ) + "/server-work-" + name;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceLayout instanceLayout = new InstanceLayout( instanceDirectory );
|
||||||
|
|
||||||
|
/*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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inits the schema and schema partition.
|
||||||
|
*/
|
||||||
|
private void initSchema() throws Exception
|
||||||
|
{
|
||||||
|
File workingDirectory = directoryService.getInstanceLayout().getPartitionsDirectory();
|
||||||
|
|
||||||
|
// Extract the schema on disk (a brand new one) and load the registries
|
||||||
|
File schemaRepository = new File( workingDirectory, "schema" );
|
||||||
|
SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor( workingDirectory );
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
extractor.extractOrCopy();
|
||||||
|
}
|
||||||
|
catch ( IOException ioe )
|
||||||
|
{
|
||||||
|
// The schema has already been extracted, bypass
|
||||||
|
}
|
||||||
|
|
||||||
|
SchemaLoader loader = new LdifSchemaLoader( schemaRepository );
|
||||||
|
SchemaManager schemaManager = new DefaultSchemaManager( loader );
|
||||||
|
|
||||||
|
// We have to load the schema now, otherwise we won't be able
|
||||||
|
// to initialize the Partitions, as we won't be able to parse
|
||||||
|
// and normalize their suffix Dn
|
||||||
|
schemaManager.loadAllEnabled();
|
||||||
|
|
||||||
|
// Tell all the normalizer comparators that they should not normalize anything
|
||||||
|
ComparatorRegistry comparatorRegistry = schemaManager.getComparatorRegistry();
|
||||||
|
|
||||||
|
for ( LdapComparator<?> comparator : comparatorRegistry )
|
||||||
|
{
|
||||||
|
if ( comparator instanceof NormalizingComparator)
|
||||||
|
{
|
||||||
|
( ( NormalizingComparator ) comparator ).setOnServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
directoryService.setSchemaManager( schemaManager );
|
||||||
|
|
||||||
|
// Init the LdifPartition
|
||||||
|
LdifPartition ldifPartition = new LdifPartition( schemaManager, directoryService.getDnFactory() );
|
||||||
|
ldifPartition.setPartitionPath( new File( workingDirectory, "schema" ).toURI() );
|
||||||
|
SchemaPartition schemaPartition = new SchemaPartition( schemaManager );
|
||||||
|
schemaPartition.setWrappedPartition( ldifPartition );
|
||||||
|
directoryService.setSchemaPartition( schemaPartition );
|
||||||
|
|
||||||
|
List<Throwable> errors = schemaManager.getErrors();
|
||||||
|
|
||||||
|
if ( errors.size() != 0 )
|
||||||
|
{
|
||||||
|
throw new Exception( I18n.err(I18n.ERR_317, Exceptions.printErrors(errors)) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inits the system partition.
|
||||||
|
*
|
||||||
|
* @throws Exception the exception
|
||||||
|
*/
|
||||||
|
private void initSystemPartition() throws Exception
|
||||||
|
{
|
||||||
|
// change the working directory to something that is unique
|
||||||
|
// on the system and somewhere either under target directory
|
||||||
|
// or somewhere in a temp area of the machine.
|
||||||
|
|
||||||
|
// Inject the 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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the directory server instance.
|
||||||
|
*
|
||||||
|
* @param name the instance name
|
||||||
|
*/
|
||||||
|
private void build( String name ) throws Exception
|
||||||
|
{
|
||||||
|
directoryService.setInstanceId( name );
|
||||||
|
buildInstanceDirectory( name );
|
||||||
|
|
||||||
|
CacheService cacheService = new CacheService();
|
||||||
|
cacheService.initialize( directoryService.getInstanceLayout() );
|
||||||
|
|
||||||
|
directoryService.setCacheService( cacheService );
|
||||||
|
|
||||||
|
// Init the service now
|
||||||
|
initSchema();
|
||||||
|
initSystemPartition();
|
||||||
|
|
||||||
|
directoryService.startup();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public DirectoryService getDirectoryService() throws Exception
|
||||||
|
{
|
||||||
|
return directoryService;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public PartitionFactory getPartitionFactory() throws Exception
|
||||||
|
{
|
||||||
|
return partitionFactory;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package org.keycloak.testsuite.ldap;
|
package org.keycloak.util.ldap;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -76,7 +76,7 @@ class InMemoryDirectoryServiceFactory implements DirectoryServiceFactory {
|
||||||
directoryService.setInstanceId(name);
|
directoryService.setInstanceId(name);
|
||||||
|
|
||||||
// instance layout
|
// instance layout
|
||||||
InstanceLayout instanceLayout = new InstanceLayout(System.getProperty("java.io.tmpdir") + "/server-work-" + name);
|
InstanceLayout instanceLayout = new InstanceLayout(System.getProperty("java.io.tmpdir") + "/server-work-inmemory-" + name);
|
||||||
if (instanceLayout.getInstanceDirectory().exists()) {
|
if (instanceLayout.getInstanceDirectory().exists()) {
|
||||||
try {
|
try {
|
||||||
FileUtils.deleteDirectory(instanceLayout.getInstanceDirectory());
|
FileUtils.deleteDirectory(instanceLayout.getInstanceDirectory());
|
|
@ -1,4 +1,4 @@
|
||||||
package org.keycloak.testsuite.ldap;
|
package org.keycloak.util.ldap;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -61,7 +61,7 @@ class InMemorySchemaPartition extends AbstractLdifPartition {
|
||||||
|
|
||||||
// add mandatory attributes
|
// add mandatory attributes
|
||||||
if (entry.get(SchemaConstants.ENTRY_CSN_AT) == null) {
|
if (entry.get(SchemaConstants.ENTRY_CSN_AT) == null) {
|
||||||
entry.add(SchemaConstants.ENTRY_CSN_AT, defaultCSNFactory.newInstance().toString());
|
entry.add(SchemaConstants.ENTRY_CSN_AT, AbstractLdifPartition.defaultCSNFactory.newInstance().toString());
|
||||||
}
|
}
|
||||||
if (entry.get(SchemaConstants.ENTRY_UUID_AT) == null) {
|
if (entry.get(SchemaConstants.ENTRY_UUID_AT) == null) {
|
||||||
entry.add(SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString());
|
entry.add(SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString());
|
|
@ -1,9 +1,10 @@
|
||||||
package org.keycloak.testsuite.ldap;
|
package org.keycloak.util.ldap;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||||
|
@ -25,7 +26,13 @@ import org.apache.directory.server.protocol.shared.transport.UdpTransport;
|
||||||
import org.apache.directory.shared.kerberos.KerberosTime;
|
import org.apache.directory.shared.kerberos.KerberosTime;
|
||||||
import org.apache.directory.shared.kerberos.KerberosUtils;
|
import org.apache.directory.shared.kerberos.KerberosUtils;
|
||||||
import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
|
import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
|
||||||
|
import org.ietf.jgss.GSSException;
|
||||||
|
import org.ietf.jgss.GSSManager;
|
||||||
|
import org.ietf.jgss.GSSName;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.util.KerberosSerializationUtils;
|
||||||
|
import sun.security.jgss.GSSNameImpl;
|
||||||
|
import sun.security.jgss.krb5.Krb5NameElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
@ -34,6 +41,16 @@ public class KerberosEmbeddedServer extends LDAPEmbeddedServer {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(KerberosEmbeddedServer.class);
|
private static final Logger log = Logger.getLogger(KerberosEmbeddedServer.class);
|
||||||
|
|
||||||
|
public static final String PROPERTY_KERBEROS_REALM = "kerberos.realm";
|
||||||
|
public static final String PROPERTY_KDC_PORT = "kerberos.port";
|
||||||
|
public static final String PROPERTY_KDC_ENCTYPES = "kerberos.encTypes";
|
||||||
|
|
||||||
|
private static final String DEFAULT_KERBEROS_LDIF_FILE = "classpath:kerberos/default-users.ldif";
|
||||||
|
|
||||||
|
private static final String DEFAULT_KERBEROS_REALM = "KEYCLOAK.ORG";
|
||||||
|
private static final String DEFAULT_KDC_PORT = "6088";
|
||||||
|
private static final String DEFAULT_KDC_ENCRYPTION_TYPES = "aes128-cts-hmac-sha1-96, des-cbc-md5, des3-cbc-sha1-kd";
|
||||||
|
|
||||||
private final String kerberosRealm;
|
private final String kerberosRealm;
|
||||||
private final int kdcPort;
|
private final int kdcPort;
|
||||||
private final String kdcEncryptionTypes;
|
private final String kdcEncryptionTypes;
|
||||||
|
@ -42,18 +59,53 @@ public class KerberosEmbeddedServer extends LDAPEmbeddedServer {
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
EmbeddedServersFactory factory = EmbeddedServersFactory.readConfiguration();
|
Properties defaultProperties = new Properties();
|
||||||
KerberosEmbeddedServer kerberosEmbeddedServer = factory.createKerberosServer();
|
defaultProperties.put(PROPERTY_DSF, DSF_FILE);
|
||||||
|
|
||||||
|
execute(args, defaultProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void execute(String[] args, Properties defaultProperties) throws Exception {
|
||||||
|
final KerberosEmbeddedServer kerberosEmbeddedServer = new KerberosEmbeddedServer(defaultProperties);
|
||||||
kerberosEmbeddedServer.init();
|
kerberosEmbeddedServer.init();
|
||||||
kerberosEmbeddedServer.start();
|
kerberosEmbeddedServer.start();
|
||||||
|
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
kerberosEmbeddedServer.stop();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected KerberosEmbeddedServer(String baseDN, String bindHost, int bindPort, String ldifFile, String ldapSaslPrincipal, String kerberosRealm, int kdcPort, String kdcEncryptionTypes) {
|
public KerberosEmbeddedServer(Properties defaultProperties) {
|
||||||
super(baseDN, bindHost, bindPort, ldifFile, ldapSaslPrincipal);
|
super(defaultProperties);
|
||||||
this.kdcEncryptionTypes = kdcEncryptionTypes;
|
|
||||||
this.kerberosRealm = kerberosRealm;
|
this.ldifFile = readProperty(PROPERTY_LDIF_FILE, DEFAULT_KERBEROS_LDIF_FILE);
|
||||||
this.kdcPort = kdcPort;
|
|
||||||
|
this.kerberosRealm = readProperty(PROPERTY_KERBEROS_REALM, DEFAULT_KERBEROS_REALM);
|
||||||
|
String kdcPort = readProperty(PROPERTY_KDC_PORT, DEFAULT_KDC_PORT);
|
||||||
|
this.kdcPort = Integer.parseInt(kdcPort);
|
||||||
|
this.kdcEncryptionTypes = readProperty(PROPERTY_KDC_ENCTYPES, DEFAULT_KDC_ENCRYPTION_TYPES);
|
||||||
|
|
||||||
|
if (ldapSaslPrincipal == null || ldapSaslPrincipal.isEmpty()) {
|
||||||
|
try {
|
||||||
|
// Same algorithm like sun.security.krb5.PrincipalName constructor
|
||||||
|
GSSName gssName = GSSManager.getInstance().createName("ldap@" + bindHost, GSSName.NT_HOSTBASED_SERVICE);
|
||||||
|
GSSNameImpl gssName1 = (GSSNameImpl) gssName;
|
||||||
|
Krb5NameElement krb5NameElement = (Krb5NameElement) gssName1.getElement(KerberosSerializationUtils.KRB5_OID);
|
||||||
|
this.ldapSaslPrincipal = krb5NameElement.getKrb5PrincipalName().toString();
|
||||||
|
} catch (GSSException uhe) {
|
||||||
|
throw new RuntimeException(uhe);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package org.keycloak.testsuite.ldap;
|
package org.keycloak.util.ldap;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.apache.directory.server.kerberos.shared.crypto.encryption.KerberosKeyFactory;
|
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.Keytab;
|
||||||
|
@ -34,7 +35,7 @@ public class KerberosKeytabCreator {
|
||||||
System.out.println("-------------------------");
|
System.out.println("-------------------------");
|
||||||
System.out.println("Arguments missing or invalid. Required arguments are: <principalName> <passPhrase> <outputKeytabFile>");
|
System.out.println("Arguments missing or invalid. Required arguments are: <principalName> <passPhrase> <outputKeytabFile>");
|
||||||
System.out.println("Example of usage:");
|
System.out.println("Example of usage:");
|
||||||
System.out.println("mvn exec:java -Dexec.mainClass=\"org.keycloak.testsuite.ldap.KerberosKeytabCreator\" -Dexec.args=\"HTTP/localhost@KEYCLOAK.ORG httppwd src/main/resources/kerberos/http.keytab\"");
|
System.out.println("java -jar embedded-ldap/target/embedded-ldap.jar keytabCreator HTTP/localhost@KEYCLOAK.ORG httppassword /tmp/http.keytab");
|
||||||
} else {
|
} else {
|
||||||
final File keytabFile = new File(args[2]);
|
final File keytabFile = new File(args[2]);
|
||||||
createKeytab(args[0], args[1], keytabFile);
|
createKeytab(args[0], args[1], keytabFile);
|
||||||
|
@ -42,6 +43,11 @@ public class KerberosKeytabCreator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Just for the reflection purposes
|
||||||
|
public static void execute(String[] args, Properties defaultProperties) throws Exception {
|
||||||
|
main(args);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a keytab file for given principal.
|
* Creates a keytab file for given principal.
|
||||||
*
|
*
|
|
@ -0,0 +1,272 @@
|
||||||
|
package org.keycloak.util.ldap;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
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.DirectoryServiceFactory;
|
||||||
|
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.FindFile;
|
||||||
|
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);
|
||||||
|
|
||||||
|
public static final String PROPERTY_BASE_DN = "ldap.baseDN";
|
||||||
|
public static final String PROPERTY_BIND_HOST = "ldap.host";
|
||||||
|
public static final String PROPERTY_BIND_PORT = "ldap.port";
|
||||||
|
public static final String PROPERTY_LDIF_FILE = "ldap.ldif";
|
||||||
|
public static final String PROPERTY_SASL_PRINCIPAL = "ldap.saslPrincipal";
|
||||||
|
public static final String PROPERTY_DSF = "ldap.dsf";
|
||||||
|
|
||||||
|
private static final String DEFAULT_BASE_DN = "dc=keycloak,dc=org";
|
||||||
|
private static final String DEFAULT_BIND_HOST = "localhost";
|
||||||
|
private static final String DEFAULT_BIND_PORT = "10389";
|
||||||
|
private static final String DEFAULT_LDIF_FILE = "classpath:ldap/default-users.ldif";
|
||||||
|
|
||||||
|
public static final String DSF_INMEMORY = "mem";
|
||||||
|
public static final String DSF_FILE = "file";
|
||||||
|
public static final String DEFAULT_DSF = DSF_FILE;
|
||||||
|
|
||||||
|
protected Properties defaultProperties;
|
||||||
|
|
||||||
|
protected String baseDN;
|
||||||
|
protected String bindHost;
|
||||||
|
protected int bindPort;
|
||||||
|
protected String ldifFile;
|
||||||
|
protected String ldapSaslPrincipal;
|
||||||
|
protected String directoryServiceFactory;
|
||||||
|
|
||||||
|
protected DirectoryService directoryService;
|
||||||
|
protected LdapServer ldapServer;
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
Properties defaultProperties = new Properties();
|
||||||
|
defaultProperties.put(PROPERTY_DSF, DSF_FILE);
|
||||||
|
|
||||||
|
execute(args, defaultProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void execute(String[] args, Properties defaultProperties) throws Exception {
|
||||||
|
final LDAPEmbeddedServer ldapEmbeddedServer = new LDAPEmbeddedServer(defaultProperties);
|
||||||
|
ldapEmbeddedServer.init();
|
||||||
|
ldapEmbeddedServer.start();
|
||||||
|
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
ldapEmbeddedServer.stop();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public LDAPEmbeddedServer(Properties defaultProperties) {
|
||||||
|
this.defaultProperties = defaultProperties;
|
||||||
|
|
||||||
|
this.baseDN = readProperty(PROPERTY_BASE_DN, DEFAULT_BASE_DN);
|
||||||
|
this.bindHost = readProperty(PROPERTY_BIND_HOST, DEFAULT_BIND_HOST);
|
||||||
|
String bindPort = readProperty(PROPERTY_BIND_PORT, DEFAULT_BIND_PORT);
|
||||||
|
this.bindPort = Integer.parseInt(bindPort);
|
||||||
|
this.ldifFile = readProperty(PROPERTY_LDIF_FILE, DEFAULT_LDIF_FILE);
|
||||||
|
this.ldapSaslPrincipal = readProperty(PROPERTY_SASL_PRINCIPAL, null);
|
||||||
|
this.directoryServiceFactory = readProperty(PROPERTY_DSF, DEFAULT_DSF);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String readProperty(String propertyName, String defaultValue) {
|
||||||
|
String value = System.getProperty(propertyName);
|
||||||
|
|
||||||
|
if (value == null || value.isEmpty()) {
|
||||||
|
value = (String) this.defaultProperties.get(propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == null || value.isEmpty()) {
|
||||||
|
value = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void init() throws Exception {
|
||||||
|
log.info("Creating LDAP Directory Service. Config: baseDN=" + baseDN + ", bindHost=" + bindHost + ", bindPort=" + bindPort +
|
||||||
|
", ldapSaslPrincipal=" + ldapSaslPrincipal + ", directoryServiceFactory=" + directoryServiceFactory + ", ldif=" + ldifFile);
|
||||||
|
|
||||||
|
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];
|
||||||
|
dcName = dcName.substring(dcName.indexOf("=") + 1);
|
||||||
|
|
||||||
|
DirectoryServiceFactory dsf;
|
||||||
|
if (this.directoryServiceFactory.equals(DSF_INMEMORY)) {
|
||||||
|
dsf = new InMemoryDirectoryServiceFactory();
|
||||||
|
} else if (this.directoryServiceFactory.equals(DSF_FILE)) {
|
||||||
|
dsf = new FileDirectoryServiceFactory();
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Unknown value of directoryServiceFactory: " + this.directoryServiceFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
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";
|
||||||
|
importLdifContent(service, entryLdif);
|
||||||
|
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected LdapServer createLdapServer() {
|
||||||
|
LdapServer ldapServer = new LdapServer();
|
||||||
|
|
||||||
|
ldapServer.setServiceName("DefaultLdapServer");
|
||||||
|
ldapServer.setSearchBaseDn(this.baseDN);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
return ldapServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void importLdif() throws Exception {
|
||||||
|
Map<String, String> map = new HashMap<String, String>();
|
||||||
|
map.put("hostname", this.bindHost);
|
||||||
|
if (this.ldapSaslPrincipal != null) {
|
||||||
|
map.put("ldapSaslPrincipal", this.ldapSaslPrincipal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find LDIF file on filesystem or classpath ( if it's like classpath:ldap/users.ldif )
|
||||||
|
InputStream is = FindFile.findFile(ldifFile);
|
||||||
|
if (is == null) {
|
||||||
|
throw new IllegalStateException("LDIF file not found on classpath or on file system. Location was: " + ldifFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String ldifContent = StrSubstitutor.replace(StreamUtil.readString(is), map);
|
||||||
|
log.info("Content of LDIF: " + ldifContent);
|
||||||
|
final SchemaManager schemaManager = directoryService.getSchemaManager();
|
||||||
|
|
||||||
|
importLdifContent(directoryService, ldifContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void importLdifContent(DirectoryService directoryService, String ldifContent) throws Exception {
|
||||||
|
LdifReader ldifReader = new LdifReader(IOUtils.toInputStream(ldifContent));
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (LdifEntry ldifEntry : ldifReader) {
|
||||||
|
try {
|
||||||
|
directoryService.getAdminSession().add(new DefaultEntry(directoryService.getSchemaManager(), ldifEntry.getEntry()));
|
||||||
|
} catch (LdapEntryAlreadyExistsException ignore) {
|
||||||
|
log.info("Entry " + ldifEntry.getDn() + " already exists. Ignoring");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
ldifReader.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void stop() throws Exception {
|
||||||
|
stopLdapServer();
|
||||||
|
shutdownDirectoryService();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void stopLdapServer() {
|
||||||
|
log.info("Stopping LDAP server.");
|
||||||
|
ldapServer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void shutdownDirectoryService() throws Exception {
|
||||||
|
log.info("Stopping Directory service.");
|
||||||
|
directoryService.shutdown();
|
||||||
|
|
||||||
|
// Delete workfiles just for 'inmemory' implementation used in tests. Normally we want LDAP data to persist
|
||||||
|
File instanceDir = directoryService.getInstanceLayout().getInstanceDirectory();
|
||||||
|
if (this.directoryServiceFactory.equals(DSF_INMEMORY)) {
|
||||||
|
log.infof("Removing Directory service workfiles: %s", instanceDir.getAbsolutePath());
|
||||||
|
FileUtils.deleteDirectory(instanceDir);
|
||||||
|
} else {
|
||||||
|
log.info("Working LDAP directory not deleted. Delete it manually if you want to start with fresh LDAP data. Directory location: " + instanceDir.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
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: ${ldapSaslPrincipal}
|
||||||
|
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
|
||||||
|
sn: Nelson
|
||||||
|
mail: hnelson@keycloak.org
|
||||||
|
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
|
||||||
|
sn: Duke
|
||||||
|
mail: jduke@keycloak.org
|
||||||
|
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
|
|
@ -0,0 +1,47 @@
|
||||||
|
dn: dc=keycloak,dc=org
|
||||||
|
objectclass: dcObject
|
||||||
|
objectclass: organization
|
||||||
|
o: Keycloak
|
||||||
|
dc: Keycloak
|
||||||
|
|
||||||
|
dn: ou=People,dc=keycloak,dc=org
|
||||||
|
objectclass: top
|
||||||
|
objectclass: organizationalUnit
|
||||||
|
ou: People
|
||||||
|
|
||||||
|
dn: ou=RealmRoles,dc=keycloak,dc=org
|
||||||
|
objectclass: top
|
||||||
|
objectclass: organizationalUnit
|
||||||
|
ou: RealmRoles
|
||||||
|
|
||||||
|
dn: ou=FinanceRoles,dc=keycloak,dc=org
|
||||||
|
objectclass: top
|
||||||
|
objectclass: organizationalUnit
|
||||||
|
ou: FinanceRoles
|
||||||
|
|
||||||
|
dn: uid=jbrown,ou=People,dc=keycloak,dc=org
|
||||||
|
objectclass: top
|
||||||
|
objectclass: person
|
||||||
|
objectclass: organizationalPerson
|
||||||
|
objectclass: inetOrgPerson
|
||||||
|
uid: jbrown
|
||||||
|
cn: James
|
||||||
|
sn: Brown
|
||||||
|
mail: jbrown@keycloak.org
|
||||||
|
postalCode: 88441
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
dn: uid=bwilson,ou=People,dc=keycloak,dc=org
|
||||||
|
objectclass: top
|
||||||
|
objectclass: person
|
||||||
|
objectclass: organizationalPerson
|
||||||
|
objectclass: inetOrgPerson
|
||||||
|
uid: bwilson
|
||||||
|
cn: Bruce
|
||||||
|
sn: Wilson
|
||||||
|
sn: Schneider
|
||||||
|
mail: bwilson@keycloak.org
|
||||||
|
postalCode: 88441
|
||||||
|
postalCode: 77332
|
||||||
|
street: Elm 5
|
||||||
|
userPassword: password
|
9
util/embedded-ldap/src/main/resources/log4j.properties
Normal file
9
util/embedded-ldap/src/main/resources/log4j.properties
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
log4j.rootLogger=info, stdout
|
||||||
|
|
||||||
|
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||||
|
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||||
|
log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] %m%n
|
||||||
|
|
||||||
|
log4j.logger.org.keycloak=info
|
||||||
|
log4j.logger.org.apache.directory.api=warn
|
||||||
|
log4j.logger.org.apache.directory.server.core=warn
|
22
util/pom.xml
Normal file
22
util/pom.xml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>keycloak-parent</artifactId>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<version>1.4.0.Final-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<name>Keycloak Util Parent</name>
|
||||||
|
<description/>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-util-parent</artifactId>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>embedded-ldap</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
</project>
|
Loading…
Reference in a new issue