From cdc9d2fb83d11577e41f9aaec0d772641a0577ab Mon Sep 17 00:00:00 2001 From: Bastien Jansen Date: Wed, 28 Oct 2020 17:39:17 +0100 Subject: [PATCH 1/5] Add support for JUnit 5 extensions (#57) --- README.md | 22 +- pom.xml | 10 +- .../zapodot/junit/ldap/EmbeddedLdapRule.java | 57 +--- .../junit/ldap/EmbeddedLdapRuleBuilder.java | 256 +----------------- .../junit/ldap/EmbeddedLdapServer.java | 60 ++++ .../internal/AbstractEmbeddedLdapBuilder.java | 240 ++++++++++++++++ .../internal/EmbeddedLdapExtensionImpl.java | 54 ++++ .../ldap/internal/EmbeddedLdapRuleImpl.java | 221 +-------------- .../ldap/internal/EmbeddedLdapServerImpl.java | 148 ++++++++++ .../ldap/junit5/EmbeddedLdapExtension.java | 14 + .../junit5/EmbeddedLdapExtensionBuilder.java | 38 +++ .../EmbeddedLdapExtensionBuilderTest.java | 87 ++++++ .../EmbeddedLdapExtensionStaticTest.java | 28 ++ .../junit5/EmbeddedLdapExtensionTest.java | 94 +++++++ 14 files changed, 805 insertions(+), 524 deletions(-) create mode 100644 src/main/java/org/zapodot/junit/ldap/EmbeddedLdapServer.java create mode 100644 src/main/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilder.java create mode 100644 src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapExtensionImpl.java create mode 100644 src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerImpl.java create mode 100644 src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtension.java create mode 100644 src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilder.java create mode 100644 src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilderTest.java create mode 100644 src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionStaticTest.java create mode 100644 src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionTest.java diff --git a/README.md b/README.md index f183537..8318b98 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # embedded-ldap-junit [![Build Status](https://github.com/zapodot/embedded-ldap-junit/actions/workflows/maven.yml/badge.svg)](https://github.com/zapodot/embedded-ldap-junit/actions/workflows/maven.yml) [![codecov](https://codecov.io/gh/zapodot/embedded-ldap-junit/branch/master/graph/badge.svg?token=2jm8uT1bJg)](https://codecov.io/gh/zapodot/embedded-ldap-junit) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.zapodot/embedded-ldap-junit/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.zapodot/embedded-ldap-junit) [![Libraries.io for GitHub](https://img.shields.io/librariesio/github/zapodot/embedded-ldap-junit.svg)](https://libraries.io/github/zapodot/embedded-ldap-junit) [![GitHub](https://img.shields.io/github/license/zapodot/embedded-ldap-junit)](https://github.com/zapodot/embedded-ldap-junit/blob/master/LICENSE) [![Analytics](https://ga-beacon.appspot.com/UA-40926073-2/embedded-ldap-junit/README.md)](https://github.com/igrigorik/ga-beacon) -A [JUnit Rule](//github.com/junit-team/junit/wiki/Rules) for running an embedded LDAP server in your JUnit test based on the wonderful [UnboundID LDAP SDK](https://www.ldap.com/unboundid-ldap-sdk-for-java). Inspired by the [Embedded Database JUnit Rule](//github.com/zapodot/embedded-db-junit). +A [JUnit 4 Rule](//github.com/junit-team/junit/wiki/Rules) and [JUnit 5 Extension](https://junit.org/junit5/docs/current/user-guide/#extensions) for running an embedded LDAP server in your JUnit test based on the wonderful [UnboundID LDAP SDK](https://www.ldap.com/unboundid-ldap-sdk-for-java). Inspired by the [Embedded Database JUnit Rule](//github.com/zapodot/embedded-db-junit). ## Why? * you want to test your LDAP integration code without affecting your LDAP server @@ -29,7 +29,9 @@ See [releases](//github.com/zapodot/embedded-ldap-junit/releases) ``` -### Add to Junit test +### Add to JUnit test + +#### JUnit 4 ```java import com.unboundid.ldap.sdk.LDAPInterface; import javax.naming.Context; @@ -79,3 +81,19 @@ public void testContext() throws Exception { assertNotNull(user); } ``` + +#### JUnit 5 +For JUnit 5 tests, simply use `EmbeddedLdapExtensionBuilder` instead of `EmbeddedLdapRuleBuilder`: + +```java +@RegisterExtension +public EmbeddedLdapExtension embeddedLdapRule = EmbeddedLdapExtensionBuilder + .newInstance() + .usingDomainDsn("dc=example,dc=com") + .importingLdifs("example.ldif") + .build(); + +... +``` + +Both JUnit 4 and JUnit 5 builders share the same API, as do the rule and the extension. diff --git a/pom.xml b/pom.xml index 1278128..1211eee 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,7 @@ 4.13.2 + 5.7.0 6.0.6 1.7.36 31.1-jre @@ -51,6 +52,12 @@ junit ${junit.version} + + org.junit.jupiter + junit-jupiter-api + ${junit5.version} + true + com.google.guava guava @@ -270,4 +277,5 @@ - \ No newline at end of file + + diff --git a/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRule.java b/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRule.java index 0b742b4..4aa70d4 100755 --- a/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRule.java +++ b/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRule.java @@ -1,65 +1,10 @@ package org.zapodot.junit.ldap; -import com.unboundid.ldap.sdk.LDAPConnection; -import com.unboundid.ldap.sdk.LDAPException; -import com.unboundid.ldap.sdk.LDAPInterface; import org.junit.rules.TestRule; -import javax.naming.Context; -import javax.naming.NamingException; -import javax.naming.directory.DirContext; - /** * A JUnit rule that may be used as either a @Rule or a @ClassRule */ -public interface EmbeddedLdapRule extends TestRule { - - /** - * For tests depending on the UnboundID LDAP SDK. Returns a proxied version of an Unboundid interface that will be - * closed when the test(s) have been invoked - * - * @return a shared LDAPConnection - * @throws LDAPException if a connection can not be opened - */ - LDAPInterface ldapConnection() throws LDAPException; - - /** - * For tests depending on the UnboundID LDAP SDK that needs access to an ${link LDAPConnection} object - * rather than the interface. If your code does not close the connection for you it will be closed on teardown - * - * @return a LDAPConnection connected to the embedded LDAP server - * @throws LDAPException if an exception occurred while establishing the connection - */ - LDAPConnection unsharedLdapConnection() throws LDAPException; - - /** - * For tests depending on the standard Java JNDI API - * - * @return a shared Context connected to the in-memory LDAP server - * @throws NamingException if context can not be created - */ - Context context() throws NamingException; - - /** - * Like {@link #context()}, but returns a DirContext - * - * @return a DirContext connected to the in-memory LDAP server - * @throws NamingException if a LDAP failure happens during DirContext creation - */ - DirContext dirContext() throws NamingException; - - /** - * Gives access to the listening port for the currently running embedded LDAP server. - * This will make it easier to use other integration mechanisms - *

- * Note: the embedded LDAP server is by default configured to listen only on the loopback address - * (i.e localhost/127.0.0.1) unless another address has been provided to the builder when the rule was built - *

- * - * @return the port number that the embedded server is listening to - * @see org.zapodot.junit.ldap.EmbeddedLdapRuleBuilder#bindingToAddress(String) - */ - int embeddedServerPort(); - +public interface EmbeddedLdapRule extends EmbeddedLdapServer, TestRule { } diff --git a/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilder.java b/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilder.java index 83ba6f5..b00771e 100755 --- a/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilder.java +++ b/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilder.java @@ -1,65 +1,14 @@ package org.zapodot.junit.ldap; -import com.google.common.base.Function; -import com.google.common.collect.Lists; -import com.google.common.io.Resources; -import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig; -import com.unboundid.ldap.listener.InMemoryListenerConfig; -import com.unboundid.ldap.sdk.LDAPException; -import com.unboundid.ldap.sdk.schema.Schema; -import com.unboundid.ldif.LDIFException; -import org.zapodot.junit.ldap.internal.AuthenticationConfiguration; +import org.zapodot.junit.ldap.internal.AbstractEmbeddedLdapBuilder; import org.zapodot.junit.ldap.internal.EmbeddedLdapRuleImpl; -import javax.net.ssl.SSLSocketFactory; -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.net.URISyntaxException; -import java.net.UnknownHostException; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; import java.util.Objects; /** * A builder providing a fluent way of defining EmbeddedLdapRule instances */ -public class EmbeddedLdapRuleBuilder { - - public static final String DEFAULT_DOMAIN = "dc=example,dc=com"; - public static final String DEFAULT_BIND_DSN = "cn=Directory manager"; - public static final String DEFAULT_BIND_CREDENTIALS = "password"; - public static final String LDAP_SERVER_LISTENER_NAME = "test-listener"; - public static final int MIN_PORT_EXCLUSIVE = 0; - public static final int MAX_PORT_EXCLUSIVE = 65535; - private List domainDsn = new LinkedList<>(); - - private String bindDSN = DEFAULT_BIND_DSN; - - private String bindCredentials = DEFAULT_BIND_CREDENTIALS; - - private List ldifsToImport = new LinkedList<>(); - - private List schemaLdifs = new LinkedList<>(); - - private boolean addDefaultSchema = true; - - private Integer bindPort = 0; - - private InetAddress bindAddress = InetAddress.getLoopbackAddress(); - - private AuthenticationConfiguration authenticationConfiguration; - - private InMemoryListenerConfig listenerConfig = null; - - private boolean useTls = false; - private SSLSocketFactory socketFactory = null; - - private Integer maxSizeLimit = null; - - public EmbeddedLdapRuleBuilder() { - } +public class EmbeddedLdapRuleBuilder extends AbstractEmbeddedLdapBuilder { /** * Creates a new builder @@ -70,119 +19,8 @@ public static EmbeddedLdapRuleBuilder newInstance() { return new EmbeddedLdapRuleBuilder(); } - /** - * Sets a domainDsn to be used. May be multiple values. If not set, it will default to the value of the {@link #DEFAULT_DOMAIN DEFAULT_DOMAIN} field - * - * @param domainDsn a valid DSN string - * @return same EmbeddedLdapRuleBuilder instance with the domainDsn field set - */ - public EmbeddedLdapRuleBuilder usingDomainDsn(final String domainDsn) { - this.domainDsn.add(domainDsn); - return this; - } - - /** - * Sets the DSN to bind to when authenticating. If not set, it will default to the value of the {@link #DEFAULT_BIND_DSN DEFAULT_BIND_DSN} field - * - * @param bindDSN a valid DSN string - * @return same EmbeddedLdapRuleBuilder instance with the bindDSN field set - */ - public EmbeddedLdapRuleBuilder usingBindDSN(final String bindDSN) { - this.bindDSN = bindDSN; - return this; - } - - /** - * Sets the credentials to be used to authenticate. If not set, it will default to the value of the {@link #DEFAULT_BIND_CREDENTIALS DEFAULT_BIND_CREDENTIALS} field - * - * @param bindCredentials a password string - * @return same EmbeddedLdapRuleBuilder instance with the bindCredentials field set - */ - public EmbeddedLdapRuleBuilder usingBindCredentials(final String bindCredentials) { - this.bindCredentials = bindCredentials; - return this; - } - - /** - * Sets the port that the in-memory LDAP server will bind to. If not set, an available port will be picked automatically - * - * @param port a port number - * @return same EmbeddedLdapRuleBuilder instance with the port field set - * @throws IllegalArgumentException if the provided value for port is not between @{link MIN_PORT_EXCLUSIVE} - * and @{MAX_PORT_EXCLUSIVE} (exclusive) - */ - public EmbeddedLdapRuleBuilder bindingToPort(final int port) { - if ((port < MIN_PORT_EXCLUSIVE) || (port > MAX_PORT_EXCLUSIVE)) { - throw new IllegalArgumentException(String.format("Value \"%s\" is not a valid port number", port)); - } - this.bindPort = Integer.valueOf(port); - return this; - } - - /** - * Allows the listening address for the embedded LDAP server to be set. If not set it will bind to localhost/127.0.0.1. - * - * @param address a valid hostname or textual representation of an IP address - * @return same EmbeddedLdapRuleBuilder instance with the bindAddress field set - * @throws IllegalArgumentException if the value provided for \"address\" is invalid - */ - public EmbeddedLdapRuleBuilder bindingToAddress(final String address) { - Objects.requireNonNull(address); - try { - final InetAddress addressByName = InetAddress.getByName(address); - this.bindAddress = addressByName; - } catch (UnknownHostException e) { - throw new IllegalArgumentException(String.format("Unknown host address \"%s\"", address), e); - } - return this; - } - - public EmbeddedLdapRuleBuilder withMaxSizeLimit(final int maxSizeLimit) { - this.maxSizeLimit = Integer.valueOf(maxSizeLimit); - return this; - } - - /** - * Avoid adding UnboundID's default schema that contains the most common LDAP elements defined through various RFC's. - * - * @return same EmbeddedLdapRuleBuilder instance with the withoutDefaultSchema field set to FALSE - */ - public EmbeddedLdapRuleBuilder withoutDefaultSchema() { - this.addDefaultSchema = false; - return this; - } - - /** - * Define schemas to be used for the server. If not defined, UnboundID will set up a default schema. - * - * @param ldifSchemaFiles LDIF-files containing schema element definitions - * @return same EmbeddedLdapRuleBuilder with the given LDIF-files added to the internal schema file collection. - */ - public EmbeddedLdapRuleBuilder withSchema(final String... ldifSchemaFiles) { - this.schemaLdifs.addAll(Arrays.asList(ldifSchemaFiles)); - return this; - } - - /** - * Specify one or more LDIF resources to be imported on startup. - * - * @param ldifFiles LDIF-files to import - * @return same EmbeddedLdapRuleBuilder instance with the provided ldifFiles added to the list of LDIF files to import - */ - public EmbeddedLdapRuleBuilder importingLdifs(final String... ldifFiles) { - if (ldifFiles != null) { - ldifsToImport.addAll(Arrays.asList(ldifFiles)); - } - return this; - } - - public EmbeddedLdapRuleBuilder withListener(InMemoryListenerConfig listenerConfig) { - this.listenerConfig = listenerConfig; - return this; - } - - public EmbeddedLdapRuleBuilder useTls(boolean useTls) { - this.useTls = useTls; + @Override + protected EmbeddedLdapRuleBuilder getThis() { return this; } @@ -195,91 +33,7 @@ public EmbeddedLdapRule build() { Objects.requireNonNull(bindDSN, "\"bindDSN\" can not be null"); return EmbeddedLdapRuleImpl.createForConfiguration(createInMemoryServerConfiguration(), authenticationConfiguration, - ldifsToImport, useTls, socketFactory); - } - - private InMemoryDirectoryServerConfig createInMemoryServerConfiguration() { - try { - final InMemoryDirectoryServerConfig inMemoryDirectoryServerConfig = - new InMemoryDirectoryServerConfig(domainDsnArray()); - - if (bindCredentials != null) { - this.authenticationConfiguration = new AuthenticationConfiguration(bindDSN, bindCredentials); - inMemoryDirectoryServerConfig.addAdditionalBindCredentials(bindDSN, bindCredentials); - } - - if (listenerConfig == null) { - listenerConfig = InMemoryListenerConfig.createLDAPConfig( - LDAP_SERVER_LISTENER_NAME, - bindAddress, - bindPort, - null); - } - inMemoryDirectoryServerConfig.setListenerConfigs(listenerConfig); - inMemoryDirectoryServerConfig.setSchema(customSchema()); - if(maxSizeLimit != null) { - inMemoryDirectoryServerConfig.setMaxSizeLimit(maxSizeLimit); - } - return inMemoryDirectoryServerConfig; - } catch (LDAPException e) { - throw new IllegalStateException( - "Could not create configuration for the in-memory LDAP instance due to an exception", - e); - } + ldifsToImport); } - private String[] domainDsnArray() { - if (domainDsn.size() == 0) { - return new String[]{DEFAULT_DOMAIN}; - } else { - return domainDsn.toArray(new String[]{}); - } - } - - private Schema customSchema() { - final List schemaFiles = schemaFiles(); - - try { - final Schema initialSchema = (addDefaultSchema ? Schema.getDefaultStandardSchema() : null); - if (!schemaFiles.isEmpty()) { - final Schema customSchema = initialSchema == null - ? Schema.getSchema(schemaFiles) - : Schema.mergeSchemas(initialSchema, Schema.getSchema(schemaFiles)); - return customSchema; - } else { - return null; - } - - } catch (IOException | LDIFException | LDAPException e) { - throw new IllegalArgumentException( - "Could not create custom LDAP schema due, probably caused by an incorrectly formatted schema", - e); - } - } - - private List schemaFiles() { - return Lists.newArrayList(Lists.transform(this.schemaLdifs, new Function() { - @Override - public File apply(final String input) { - try { - final File file = new File(Resources.getResource(input).toURI()); - if (!file.isFile()) { - throw new IllegalArgumentException(String.format( - "The resource named \"%s\" can not be found or is not a file", - input)); - } - return file; - } catch (URISyntaxException e) { - throw new IllegalArgumentException(String.format( - "The resource named \"%s\" is not a valid file reference", - input), e); - } - } - })); - } - - public EmbeddedLdapRuleBuilder withSocketFactory(SSLSocketFactory socketFactory) { - this.socketFactory = socketFactory; - return this; - } } diff --git a/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapServer.java b/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapServer.java new file mode 100644 index 0000000..45191d9 --- /dev/null +++ b/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapServer.java @@ -0,0 +1,60 @@ +package org.zapodot.junit.ldap; + +import com.unboundid.ldap.sdk.LDAPConnection; +import com.unboundid.ldap.sdk.LDAPException; +import com.unboundid.ldap.sdk.LDAPInterface; + +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; + +public interface EmbeddedLdapServer { + + /** + * For tests depending on the UnboundID LDAP SDK. Returns a proxied version of an Unboundid interface that will be + * closed when the test(s) have been invoked + * + * @return a shared LDAPConnection + * @throws LDAPException if a connection can not be opened + */ + LDAPInterface ldapConnection() throws LDAPException; + + /** + * For tests depending on the UnboundID LDAP SDK that needs access to an ${link LDAPConnection} object + * rather than the interface. If your code does not close the connection for you it will be closed on teardown + * + * @return a LDAPConnection connected to the embedded LDAP server + * @throws LDAPException if an exception occurred while establishing the connection + */ + LDAPConnection unsharedLdapConnection() throws LDAPException; + + /** + * For tests depending on the standard Java JNDI API + * + * @return a shared Context connected to the in-memory LDAP server + * @throws NamingException if context can not be created + */ + Context context() throws NamingException; + + /** + * Like {@link #context()}, but returns a DirContext + * + * @return a DirContext connected to the in-memory LDAP server + * @throws NamingException if a LDAP failure happens during DirContext creation + */ + DirContext dirContext() throws NamingException; + + /** + * Gives access to the listening port for the currently running embedded LDAP server. + * This will make it easier to use other integration mechanisms + *

+ * Note: the embedded LDAP server is by default configured to listen only on the loopback address + * (i.e localhost/127.0.0.1) unless another address has been provided to the builder when the rule was built + *

+ * + * @return the port number that the embedded server is listening to + * @see org.zapodot.junit.ldap.EmbeddedLdapRuleBuilder#bindingToAddress(String) + */ + int embeddedServerPort(); + +} diff --git a/src/main/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilder.java b/src/main/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilder.java new file mode 100644 index 0000000..e5326ea --- /dev/null +++ b/src/main/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilder.java @@ -0,0 +1,240 @@ +package org.zapodot.junit.ldap.internal; + +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import com.google.common.io.Resources; +import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig; +import com.unboundid.ldap.listener.InMemoryListenerConfig; +import com.unboundid.ldap.sdk.LDAPException; +import com.unboundid.ldap.sdk.schema.Schema; +import com.unboundid.ldif.LDIFException; + +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +/** + * A builder providing a fluent way of defining {@link org.zapodot.junit.ldap.EmbeddedLdapRule} + * or {@link org.zapodot.junit.ldap.junit5.EmbeddedLdapExtension} instances. + */ +public abstract class AbstractEmbeddedLdapBuilder> { + + public static final String DEFAULT_DOMAIN = "dc=example,dc=com"; + public static final String DEFAULT_BIND_DSN = "cn=Directory manager"; + public static final String DEFAULT_BIND_CREDENTIALS = "password"; + public static final String LDAP_SERVER_LISTENER_NAME = "test-listener"; + public static final int MIN_PORT_EXCLUSIVE = 0; + public static final int MAX_PORT_EXCLUSIVE = 65535; + private List domainDsn = new LinkedList<>(); + + protected String bindDSN = DEFAULT_BIND_DSN; + + private String bindCredentials = DEFAULT_BIND_CREDENTIALS; + + protected List ldifsToImport = new LinkedList<>(); + + private List schemaLdifs = new LinkedList<>(); + + private boolean addDefaultSchema = true; + + private Integer bindPort = 0; + + private InetAddress bindAddress = InetAddress.getLoopbackAddress(); + + protected AuthenticationConfiguration authenticationConfiguration; + + private InMemoryListenerConfig listenerConfig = null; + + /** + * Sets a domainDsn to be used. May be multiple values. If not set, it will default to the value of the {@link #DEFAULT_DOMAIN DEFAULT_DOMAIN} field + * + * @param domainDsn a valid DSN string + * @return same builder instance with the domainDsn field set + */ + public Self usingDomainDsn(final String domainDsn) { + this.domainDsn.add(domainDsn); + return getThis(); + } + + /** + * Sets the DSN to bind to when authenticating. If not set, it will default to the value of the {@link #DEFAULT_BIND_DSN DEFAULT_BIND_DSN} field + * + * @param bindDSN a valid DSN string + * @return same builder instance with the bindDSN field set + */ + public Self usingBindDSN(final String bindDSN) { + this.bindDSN = bindDSN; + return getThis(); + } + + /** + * Sets the credentials to be used to authenticate. If not set, it will default to the value of the {@link #DEFAULT_BIND_CREDENTIALS DEFAULT_BIND_CREDENTIALS} field + * + * @param bindCredentials a password string + * @return same builder instance with the bindCredentials field set + */ + public Self usingBindCredentials(final String bindCredentials) { + this.bindCredentials = bindCredentials; + return getThis(); + } + + /** + * Sets the port that the in-memory LDAP server will bind to. If not set, an available port will be picked automatically + * + * @param port a port number + * @return same builder instance with the port field set + * @throws IllegalArgumentException if the provided value for port is not between @{link MIN_PORT_EXCLUSIVE} + * and @{MAX_PORT_EXCLUSIVE} (exclusive) + */ + public Self bindingToPort(final int port) { + if ((port < MIN_PORT_EXCLUSIVE) || (port > MAX_PORT_EXCLUSIVE)) { + throw new IllegalArgumentException(String.format("Value \"%s\" is not a valid port number", port)); + } + this.bindPort = Integer.valueOf(port); + return getThis(); + } + + /** + * Allows the listening address for the embedded LDAP server to be set. If not set it will bind to localhost/127.0.0.1. + * + * @param address a valid hostname or textual representation of an IP address + * @return same builder instance with the bindAddress field set + * @throws IllegalArgumentException if the value provided for \"address\" is invalid + */ + public Self bindingToAddress(final String address) { + Objects.requireNonNull(address); + try { + final InetAddress addressByName = InetAddress.getByName(address); + this.bindAddress = addressByName; + } catch (UnknownHostException e) { + throw new IllegalArgumentException(String.format("Unknown host address \"%s\"", address), e); + } + return getThis(); + } + + /** + * Avoid adding UnboundID's default schema that contains the most common LDAP elements defined through various RFC's. + * + * @return same builder instance with the withoutDefaultSchema field set to FALSE + */ + public Self withoutDefaultSchema() { + this.addDefaultSchema = false; + return getThis(); + } + + /** + * Define schemas to be used for the server. If not defined, UnboundID will set up a default schema. + * + * @param ldifSchemaFiles LDIF-files containing schema element definitions + * @return same builder with the given LDIF-files added to the internal schema file collection. + */ + public Self withSchema(final String... ldifSchemaFiles) { + this.schemaLdifs.addAll(Arrays.asList(ldifSchemaFiles)); + return getThis(); + } + + /** + * Specify one or more LDIF resources to be imported on startup. + * + * @param ldifFiles LDIF-files to import + * @return same builder instance with the provided ldifFiles added to the list of LDIF files to import + */ + public Self importingLdifs(final String... ldifFiles) { + if (ldifFiles != null) { + ldifsToImport.addAll(Arrays.asList(ldifFiles)); + } + return getThis(); + } + + public Self withListener(InMemoryListenerConfig listenerConfig) { + this.listenerConfig = listenerConfig; + return getThis(); + } + + protected abstract Self getThis(); + + protected InMemoryDirectoryServerConfig createInMemoryServerConfiguration() { + try { + final InMemoryDirectoryServerConfig inMemoryDirectoryServerConfig = + new InMemoryDirectoryServerConfig(domainDsnArray()); + + if (bindCredentials != null) { + this.authenticationConfiguration = new AuthenticationConfiguration(bindDSN, bindCredentials); + inMemoryDirectoryServerConfig.addAdditionalBindCredentials(bindDSN, bindCredentials); + } + + if (listenerConfig == null) { + listenerConfig = InMemoryListenerConfig.createLDAPConfig( + LDAP_SERVER_LISTENER_NAME, + bindAddress, + bindPort, + null); + } + inMemoryDirectoryServerConfig.setListenerConfigs(listenerConfig); + inMemoryDirectoryServerConfig.setSchema(customSchema()); + return inMemoryDirectoryServerConfig; + } catch (LDAPException e) { + throw new IllegalStateException( + "Could not create configuration for the in-memory LDAP instance due to an exception", + e); + } + } + + private String[] domainDsnArray() { + if (domainDsn.size() == 0) { + return new String[]{DEFAULT_DOMAIN}; + } else { + return domainDsn.toArray(new String[]{}); + } + } + + private Schema customSchema() { + final List schemaFiles = schemaFiles(); + + try { + final Schema initialSchema = (addDefaultSchema ? Schema.getDefaultStandardSchema() : null); + if (!schemaFiles.isEmpty()) { + final Schema customSchema = initialSchema == null + ? Schema.getSchema(schemaFiles) + : Schema.mergeSchemas(initialSchema, Schema.getSchema(schemaFiles)); + return customSchema; + } else { + return null; + } + + } catch (IOException | LDIFException | LDAPException e) { + throw new IllegalArgumentException( + "Could not create custom LDAP schema due, probably caused by an incorrectly formatted schema", + e); + } + } + + private List schemaFiles() { + return Lists.newArrayList(Lists.transform(this.schemaLdifs, new Function() { + @Override + public File apply(final String input) { + try { + final File file = new File(Resources.getResource(input).toURI()); + if (!file.isFile()) { + throw new IllegalArgumentException(String.format( + "The resource named \"%s\" can not be found or is not a file", + input)); + } + return file; + } catch (URISyntaxException e) { + throw new IllegalArgumentException(String.format( + "The resource named \"%s\" is not a valid file reference", + input), e); + } + } + })); + } + + +} diff --git a/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapExtensionImpl.java b/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapExtensionImpl.java new file mode 100644 index 0000000..1daf1ab --- /dev/null +++ b/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapExtensionImpl.java @@ -0,0 +1,54 @@ +package org.zapodot.junit.ldap.internal; + +import com.unboundid.ldap.listener.InMemoryDirectoryServer; +import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig; +import com.unboundid.ldap.sdk.LDAPException; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.zapodot.junit.ldap.junit5.EmbeddedLdapExtension; + +import java.util.List; + +public class EmbeddedLdapExtensionImpl extends EmbeddedLdapServerImpl implements EmbeddedLdapExtension { + + public static EmbeddedLdapExtension createForConfiguration(final InMemoryDirectoryServerConfig inMemoryDirectoryServerConfig, + final AuthenticationConfiguration authenticationConfiguration, + final List ldifs) { + try { + return new EmbeddedLdapExtensionImpl(createServer(inMemoryDirectoryServerConfig, ldifs), + authenticationConfiguration); + } catch (LDAPException e) { + throw new IllegalStateException("Can not initiate in-memory LDAP server due to an exception", e); + } + } + + private boolean isStartedBeforeAll = false; + + public EmbeddedLdapExtensionImpl(InMemoryDirectoryServer inMemoryDirectoryServer, AuthenticationConfiguration authenticationConfiguration1) { + super(inMemoryDirectoryServer, authenticationConfiguration1); + } + + @Override + public void beforeAll(ExtensionContext extensionContext) throws Exception { + isStartedBeforeAll = true; + startEmbeddedLdapServer(); + } + + @Override + public void afterAll(ExtensionContext extensionContext) { + takeDownEmbeddedLdapServer(); + } + + @Override + public void beforeEach(ExtensionContext extensionContext) throws Exception { + if (!isStartedBeforeAll) { + startEmbeddedLdapServer(); + } + } + + @Override + public void afterEach(ExtensionContext extensionContext) { + if (!isStartedBeforeAll) { + takeDownEmbeddedLdapServer(); + } + } +} diff --git a/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapRuleImpl.java b/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapRuleImpl.java index a394874..9f33d28 100755 --- a/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapRuleImpl.java +++ b/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapRuleImpl.java @@ -1,216 +1,31 @@ package org.zapodot.junit.ldap.internal; -import com.google.common.base.Charsets; -import com.google.common.io.Resources; import com.unboundid.ldap.listener.InMemoryDirectoryServer; import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig; -import com.unboundid.ldap.sdk.LDAPConnection; import com.unboundid.ldap.sdk.LDAPException; -import com.unboundid.ldap.sdk.LDAPInterface; import org.junit.runner.Description; import org.junit.runners.model.Statement; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.zapodot.junit.ldap.EmbeddedLdapRule; -import org.zapodot.junit.ldap.internal.jndi.ContextProxyFactory; -import org.zapodot.junit.ldap.internal.unboundid.LDAPInterfaceProxyFactory; -import javax.naming.Context; -import javax.naming.NamingException; -import javax.naming.directory.DirContext; -import javax.naming.directory.InitialDirContext; -import javax.naming.ldap.LdapContext; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Modifier; - -import javax.net.SocketFactory; -import javax.net.ssl.SSLSocketFactory; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.InetAddress; -import java.net.Socket; -import java.net.URLDecoder; -import java.net.UnknownHostException; -import java.util.Hashtable; import java.util.List; -import net.bytebuddy.ByteBuddy; -import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; -import net.bytebuddy.implementation.FixedValue; - -public class EmbeddedLdapRuleImpl implements EmbeddedLdapRule { - - private static final String JAVA_RT_CONTROL_FACTORY = "com.sun.jndi.ldap.DefaultResponseControlFactory"; - - private static final String JAVA_RT_CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory"; +public class EmbeddedLdapRuleImpl extends EmbeddedLdapServerImpl implements EmbeddedLdapRule { - private static Logger logger = LoggerFactory.getLogger(EmbeddedLdapRuleImpl.class); - private final InMemoryDirectoryServer inMemoryDirectoryServer; - private final AuthenticationConfiguration authenticationConfiguration; - private LDAPConnection ldapConnection; - private InitialDirContext initialDirContext; - private boolean isStarted = false; - private final boolean useTls; - private final SSLSocketFactory socketFactory; - - private EmbeddedLdapRuleImpl(final InMemoryDirectoryServer inMemoryDirectoryServer, - final AuthenticationConfiguration authenticationConfiguration1, - final boolean useTls, SSLSocketFactory socketFactory) { - this.inMemoryDirectoryServer = inMemoryDirectoryServer; - this.authenticationConfiguration = authenticationConfiguration1; - this.useTls = useTls; - this.socketFactory = socketFactory; - } - - public static EmbeddedLdapRule createForConfiguration( - final InMemoryDirectoryServerConfig inMemoryDirectoryServerConfig, - final AuthenticationConfiguration authenticationConfiguration, - final List ldifs, boolean useTls, SSLSocketFactory socketFactory) { + public static EmbeddedLdapRule createForConfiguration(final InMemoryDirectoryServerConfig inMemoryDirectoryServerConfig, + final AuthenticationConfiguration authenticationConfiguration, + final List ldifs) { try { return new EmbeddedLdapRuleImpl(createServer(inMemoryDirectoryServerConfig, ldifs), - authenticationConfiguration, useTls, socketFactory); + authenticationConfiguration); } catch (LDAPException e) { throw new IllegalStateException("Can not initiate in-memory LDAP server due to an exception", e); } } - private static InMemoryDirectoryServer createServer(final InMemoryDirectoryServerConfig inMemoryDirectoryServerConfig, - final List ldifs) throws LDAPException { - final InMemoryDirectoryServer ldapServer = - new InMemoryDirectoryServer(inMemoryDirectoryServerConfig); - if (ldifs != null && !ldifs.isEmpty()) { - for (final String ldif : ldifs) { - try { - ldapServer.importFromLDIF(false, URLDecoder.decode(Resources.getResource(ldif).getPath(), - Charsets.UTF_8.name())); - } catch (UnsupportedEncodingException e) { - throw new IllegalStateException("Can not URL decode path:" + Resources.getResource(ldif).getPath(), - e); - } - } - } - return ldapServer; + public EmbeddedLdapRuleImpl(InMemoryDirectoryServer inMemoryDirectoryServer, AuthenticationConfiguration authenticationConfiguration1) { + super(inMemoryDirectoryServer, authenticationConfiguration1); } - @Override - public LDAPInterface ldapConnection() throws LDAPException { - return LDAPInterfaceProxyFactory.createProxy(createOrGetLdapConnection()); - } - - @Override - public LDAPConnection unsharedLdapConnection() throws LDAPException { - return createOrGetLdapConnection(); - } - - private LDAPConnection createOrGetLdapConnection() throws LDAPException { - if (isStarted) { - if (ldapConnection == null || ! ldapConnection.isConnected()) { - ldapConnection = inMemoryDirectoryServer.getConnection(); - } - return ldapConnection; - } else { - throw new IllegalStateException( - "Can not get a LdapConnection before the embedded LDAP server has been started"); - } - } - - @Override - public Context context() throws NamingException { - return ContextProxyFactory.asDelegatingContext(createOrGetInitialDirContext()); - } - - @Override - public DirContext dirContext() throws NamingException { - return ContextProxyFactory.asDelegatingDirContext(createOrGetInitialDirContext()); - } - - @Override - public int embeddedServerPort() { - if(isStarted) { - return inMemoryDirectoryServer.getListenPort(); - } else { - throw new IllegalStateException("The embedded server must be started prior to accessing the listening port"); - } - } - - private InitialDirContext createOrGetInitialDirContext() throws NamingException { - if (isStarted) { - if (initialDirContext == null) { - initialDirContext = new InitialDirContext(createLdapEnvironment()); - } - return initialDirContext; - } else { - throw new IllegalStateException( - "Can not get an InitialDirContext before the embedded LDAP server has been started"); - } - } - - public static abstract class AbstractDelegatingSocketFactory extends SocketFactory { - public static AbstractDelegatingSocketFactory INSTANCE; - - public static AbstractDelegatingSocketFactory getDefault() { - return INSTANCE; - } - - protected abstract SocketFactory getDelegate(); - - @Override - public Socket createSocket() throws IOException, UnknownHostException { - return getDelegate().createSocket(); - } - - @Override - public Socket createSocket(String host, int port) throws IOException, UnknownHostException { - return getDelegate().createSocket(host, port); - } - - @Override - public Socket createSocket(String host, int port, InetAddress localHost, int localPort) - throws IOException, UnknownHostException { - return getDelegate().createSocket(host, port, localHost, localPort); - } - - @Override - public Socket createSocket(InetAddress host, int port) throws IOException { - return getDelegate().createSocket(host, port); - } - - @Override - public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) - throws IOException { - return getDelegate().createSocket(address, port, localAddress, localPort); - } - } - - private Hashtable createLdapEnvironment() { - final Hashtable environment = new Hashtable<>(); - if (socketFactory != null) { - final Class delegator = (new ByteBuddy()).subclass(AbstractDelegatingSocketFactory.class) - .defineMethod("getDelegate", SocketFactory.class, Modifier.PROTECTED) - .intercept(FixedValue.value(socketFactory)) - .make() - .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.INJECTION) - .getLoaded(); - try { - final Object instance = delegator.newInstance(); - delegator.getField("INSTANCE").set(instance, instance); - } catch (InstantiationException | IllegalAccessException | NoSuchFieldException e) { - throw new IllegalStateException(e); - } - environment.put("java.naming.ldap.factory.socket", delegator.getCanonicalName()); - } - environment.put(LdapContext.CONTROL_FACTORIES, JAVA_RT_CONTROL_FACTORY); - environment.put(Context.PROVIDER_URL, String.format("%s://%s:%s", - useTls ? "ldaps" : "ldap", - inMemoryDirectoryServer.getListenAddress().getHostName(), - embeddedServerPort())); - environment.put(Context.INITIAL_CONTEXT_FACTORY, JAVA_RT_CONTEXT_FACTORY); - if (authenticationConfiguration != null) { - environment.putAll(authenticationConfiguration.toAuthenticationEnvironment()); - } - return environment; - } @Override public Statement apply(final Statement base, final Description description) { @@ -231,26 +46,4 @@ public void evaluate() throws Throwable { }; } - private void startEmbeddedLdapServer() throws LDAPException { - inMemoryDirectoryServer.startListening(); - isStarted = true; - } - - private void takeDownEmbeddedLdapServer() { - try { - if (ldapConnection != null && ldapConnection.isConnected()) { - ldapConnection.close(); - } - if (initialDirContext != null) { - initialDirContext.close(); - } - } catch (NamingException e) { - logger.info("Could not close initial context, forcing server shutdown anyway", e); - } finally { - inMemoryDirectoryServer.shutDown(true); - } - - } - - } diff --git a/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerImpl.java b/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerImpl.java new file mode 100644 index 0000000..161ee12 --- /dev/null +++ b/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerImpl.java @@ -0,0 +1,148 @@ +package org.zapodot.junit.ldap.internal; + +import com.google.common.base.Charsets; +import com.google.common.io.Resources; +import com.unboundid.ldap.listener.InMemoryDirectoryServer; +import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig; +import com.unboundid.ldap.sdk.LDAPConnection; +import com.unboundid.ldap.sdk.LDAPException; +import com.unboundid.ldap.sdk.LDAPInterface; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.zapodot.junit.ldap.EmbeddedLdapServer; +import org.zapodot.junit.ldap.internal.jndi.ContextProxyFactory; +import org.zapodot.junit.ldap.internal.unboundid.LDAPInterfaceProxyFactory; + +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; +import javax.naming.ldap.LdapContext; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.Hashtable; +import java.util.List; + +abstract class EmbeddedLdapServerImpl implements EmbeddedLdapServer { + private static final String JAVA_RT_CONTROL_FACTORY = "com.sun.jndi.ldap.DefaultResponseControlFactory"; + + private static final String JAVA_RT_CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory"; + + private static Logger logger = LoggerFactory.getLogger(EmbeddedLdapExtensionImpl.class); + private final InMemoryDirectoryServer inMemoryDirectoryServer; + private final AuthenticationConfiguration authenticationConfiguration; + private LDAPConnection ldapConnection; + private InitialDirContext initialDirContext; + private boolean isStarted = false; + + public EmbeddedLdapServerImpl(final InMemoryDirectoryServer inMemoryDirectoryServer, + final AuthenticationConfiguration authenticationConfiguration1) { + this.inMemoryDirectoryServer = inMemoryDirectoryServer; + this.authenticationConfiguration = authenticationConfiguration1; + } + + protected static InMemoryDirectoryServer createServer(final InMemoryDirectoryServerConfig inMemoryDirectoryServerConfig, + final List ldifs) throws LDAPException { + final InMemoryDirectoryServer ldapServer = + new InMemoryDirectoryServer(inMemoryDirectoryServerConfig); + if (ldifs != null && !ldifs.isEmpty()) { + for (final String ldif : ldifs) { + try { + ldapServer.importFromLDIF(false, URLDecoder.decode(Resources.getResource(ldif).getPath(), + Charsets.UTF_8.name())); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException("Can not URL decode path:" + Resources.getResource(ldif).getPath(), + e); + } + } + } + return ldapServer; + } + + @Override + public LDAPInterface ldapConnection() throws LDAPException { + return LDAPInterfaceProxyFactory.createProxy(createOrGetLdapConnection()); + } + + @Override + public LDAPConnection unsharedLdapConnection() throws LDAPException { + return createOrGetLdapConnection(); + } + + private LDAPConnection createOrGetLdapConnection() throws LDAPException { + if (isStarted) { + if (ldapConnection == null || ! ldapConnection.isConnected()) { + ldapConnection = inMemoryDirectoryServer.getConnection(); + } + return ldapConnection; + } else { + throw new IllegalStateException( + "Can not get a LdapConnection before the embedded LDAP server has been started"); + } + } + + @Override + public Context context() throws NamingException { + return ContextProxyFactory.asDelegatingContext(createOrGetInitialDirContext()); + } + + @Override + public DirContext dirContext() throws NamingException { + return ContextProxyFactory.asDelegatingDirContext(createOrGetInitialDirContext()); + } + + @Override + public int embeddedServerPort() { + if(isStarted) { + return inMemoryDirectoryServer.getListenPort(); + } else { + throw new IllegalStateException("The embedded server must be started prior to accessing the listening port"); + } + } + + private InitialDirContext createOrGetInitialDirContext() throws NamingException { + if (isStarted) { + if (initialDirContext == null) { + initialDirContext = new InitialDirContext(createLdapEnvironment()); + } + return initialDirContext; + } else { + throw new IllegalStateException( + "Can not get an InitialDirContext before the embedded LDAP server has been started"); + } + } + + private Hashtable createLdapEnvironment() { + final Hashtable environment = new Hashtable<>(); + environment.put(LdapContext.CONTROL_FACTORIES, JAVA_RT_CONTROL_FACTORY); + environment.put(Context.PROVIDER_URL, String.format("ldap://%s:%s", + inMemoryDirectoryServer.getListenAddress().getHostName(), + embeddedServerPort())); + environment.put(Context.INITIAL_CONTEXT_FACTORY, JAVA_RT_CONTEXT_FACTORY); + if (authenticationConfiguration != null) { + environment.putAll(authenticationConfiguration.toAuthenticationEnvironment()); + } + return environment; + } + + protected void startEmbeddedLdapServer() throws LDAPException { + inMemoryDirectoryServer.startListening(); + isStarted = true; + } + + protected void takeDownEmbeddedLdapServer() { + try { + if (ldapConnection != null && ldapConnection.isConnected()) { + ldapConnection.close(); + } + if (initialDirContext != null) { + initialDirContext.close(); + } + } catch (NamingException e) { + logger.info("Could not close initial context, forcing server shutdown anyway", e); + } finally { + inMemoryDirectoryServer.shutDown(true); + } + + } +} diff --git a/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtension.java b/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtension.java new file mode 100644 index 0000000..10ccbf3 --- /dev/null +++ b/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtension.java @@ -0,0 +1,14 @@ +package org.zapodot.junit.ldap.junit5; + +import org.junit.jupiter.api.extension.*; +import org.zapodot.junit.ldap.EmbeddedLdapServer; + +/** + * A JUnit 5 extension that can be registered with @{@link RegisterExtension} + * (supports both {@code static} and instance fields). + */ +public interface EmbeddedLdapExtension extends EmbeddedLdapServer, Extension, + BeforeEachCallback, AfterEachCallback, + BeforeAllCallback, AfterAllCallback { + +} diff --git a/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilder.java b/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilder.java new file mode 100644 index 0000000..3bee8b7 --- /dev/null +++ b/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilder.java @@ -0,0 +1,38 @@ +package org.zapodot.junit.ldap.junit5; + +import org.zapodot.junit.ldap.internal.AbstractEmbeddedLdapBuilder; +import org.zapodot.junit.ldap.internal.EmbeddedLdapExtensionImpl; + +import java.util.Objects; + +/** + * A builder providing a fluent way of defining {@link EmbeddedLdapExtension} instances. + */ +public class EmbeddedLdapExtensionBuilder extends AbstractEmbeddedLdapBuilder { + + /** + * Creates a new builder + * + * @return a new EmbeddedLdapExtensionBuilder instance + */ + public static EmbeddedLdapExtensionBuilder newInstance() { + return new EmbeddedLdapExtensionBuilder(); + } + + /** + * Creates a new extension based on the information that was previously provided + * + * @return a new EmbeddedLdapExtension instance + */ + public EmbeddedLdapExtension build() { + Objects.requireNonNull(bindDSN, "\"bindDSN\" can not be null"); + return EmbeddedLdapExtensionImpl.createForConfiguration(createInMemoryServerConfiguration(), + authenticationConfiguration, + ldifsToImport); + } + + @Override + protected EmbeddedLdapExtensionBuilder getThis() { + return this; + } +} diff --git a/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilderTest.java b/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilderTest.java new file mode 100644 index 0000000..77d0d1e --- /dev/null +++ b/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilderTest.java @@ -0,0 +1,87 @@ +package org.zapodot.junit.ldap.junit5; + +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; + +public class EmbeddedLdapExtensionBuilderTest { + + @Test + public void bindingToLegalPort() { + assertNotNull(EmbeddedLdapExtensionBuilder.newInstance().bindingToPort(9999)); + } + + @Test(expected = IllegalStateException.class) + public void testPrematureLdapConnection() throws Exception { + EmbeddedLdapExtensionBuilder.newInstance().build().ldapConnection(); + + } + + @Test(expected = IllegalStateException.class) + public void testPrematureContext() throws Exception { + EmbeddedLdapExtensionBuilder.newInstance().build().context(); + + } + + @Test(expected = IllegalArgumentException.class) + public void testUnknownLDIF() { + EmbeddedLdapExtensionBuilder.newInstance().importingLdifs("nonExisting.ldif").build(); + + } + + @Test + public void testNullLDIF() { + assertNotNull(EmbeddedLdapExtensionBuilder.newInstance().importingLdifs(null).build()); + + } + + @Test(expected = IllegalStateException.class) + public void testIllegalDSN() { + EmbeddedLdapExtensionBuilder.newInstance().usingBindDSN("bindDsn").build(); + + } + + @Test(expected = IllegalArgumentException.class) + public void testIllegalPort() { + EmbeddedLdapExtensionBuilder.newInstance().bindingToPort(Integer.MIN_VALUE).build(); + + } + + @Test(expected = IllegalArgumentException.class) + public void testSchemaNotFound() { + EmbeddedLdapExtensionBuilder.newInstance().withSchema("non-existing-schema.ldif").build(); + + } + + @Test(expected = IllegalArgumentException.class) + public void testSchemaIsNotAFile() { + EmbeddedLdapExtensionBuilder.newInstance().withSchema("folder").build(); + + } + + @Test(expected = IllegalArgumentException.class) + public void testSchemaIsInvalid() { + EmbeddedLdapExtensionBuilder.newInstance().withSchema("invalid.ldif").build(); + + } + + @Test(expected = IllegalArgumentException.class) + public void testSchemaFileUnsupportedIsInvalid() { + EmbeddedLdapExtensionBuilder.newInstance().withSchema("\"#%¤&&%/¤##¤¤").build(); + + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidPort() { + EmbeddedLdapExtensionBuilder.newInstance().bindingToPort(Integer.MAX_VALUE); + + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidBindAddress() { + EmbeddedLdapExtensionBuilder.newInstance().bindingToAddress("åpsldfåpl"); + + } + + +} diff --git a/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionStaticTest.java b/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionStaticTest.java new file mode 100644 index 0000000..5fa054f --- /dev/null +++ b/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionStaticTest.java @@ -0,0 +1,28 @@ +package org.zapodot.junit.ldap.junit5; + +import com.unboundid.ldap.sdk.LDAPInterface; +import com.unboundid.ldap.sdk.SearchScope; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class EmbeddedLdapExtensionStaticTest { + public static final String DOMAIN_DSN = "dc=zapodot,dc=org"; + + @RegisterExtension + public static EmbeddedLdapExtension embeddedLdapExtension = EmbeddedLdapExtensionBuilder + .newInstance() + .usingDomainDsn(DOMAIN_DSN) + .usingBindDSN("cn=Directory manager") + .usingBindCredentials("testPass") + .importingLdifs("example.ldif") + .build(); + + @Test + void testCheck() throws Exception { + final LDAPInterface ldapConnection = embeddedLdapExtension.ldapConnection(); + assertEquals(4, ldapConnection.search(DOMAIN_DSN, SearchScope.SUB, "(objectClass=*)").getEntryCount()); + + } +} diff --git a/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionTest.java b/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionTest.java new file mode 100644 index 0000000..d2e40f7 --- /dev/null +++ b/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionTest.java @@ -0,0 +1,94 @@ +package org.zapodot.junit.ldap.junit5; + +import com.google.common.collect.Iterators; +import com.unboundid.ldap.sdk.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import javax.naming.Context; +import javax.naming.NamingEnumeration; +import javax.naming.directory.DirContext; +import javax.naming.directory.SearchControls; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; + +class EmbeddedLdapExtensionTest { + + public static final String DOMAIN_DSN = "dc=zapodot,dc=org"; + + @RegisterExtension + public EmbeddedLdapExtension embeddedLdapExtension = EmbeddedLdapExtensionBuilder + .newInstance() + .usingDomainDsn(DOMAIN_DSN) + .importingLdifs("example.ldif") + .build(); + + @Test + void testLdapConnection() throws Exception { + final LDAPInterface ldapConnection = embeddedLdapExtension.ldapConnection(); + final SearchResult searchResult = ldapConnection.search(DOMAIN_DSN, SearchScope.SUB, "(objectClass=person)"); + assertEquals(1, searchResult.getEntryCount()); + } + + @Test + void testRawLdapConnection() throws Exception { + final String commonName = "Test person"; + final String dn = String.format( + "cn=%s,ou=people,dc=zapodot,dc=org", + commonName); + LDAPConnection ldapConnection = embeddedLdapExtension.unsharedLdapConnection(); + try { + ldapConnection.add(new AddRequest(dn, Arrays.asList( + new Attribute("objectclass", "top", "person", "organizationalPerson", "inetOrgPerson"), + new Attribute("cn", commonName), new Attribute("sn", "Person"), new Attribute("uid", "test")))); + } finally { + // Forces the LDAP connection to be closed. This is not necessary as the rule will usually close it for you. + ldapConnection.close(); + } + ldapConnection = embeddedLdapExtension.unsharedLdapConnection(); + final SearchResultEntry entry = ldapConnection.searchForEntry(new SearchRequest(dn, + SearchScope.BASE, + "(objectClass=person)")); + assertNotNull(entry); + } + + @Test + void testDirContext() throws Exception { + final DirContext dirContext = embeddedLdapExtension.dirContext(); + final SearchControls searchControls = new SearchControls(); + searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); + final NamingEnumeration resultNamingEnumeration = + dirContext.search(DOMAIN_DSN, "(objectClass=person)", searchControls); + assertEquals(1, Iterators.size(Iterators.forEnumeration(resultNamingEnumeration))); + } + + @Test + void testContext() throws Exception { + final Context context = embeddedLdapExtension.context(); + final Object user = context.lookup("cn=Sondre Eikanger Kvalo,ou=people,dc=zapodot,dc=org"); + assertNotNull(user); + } + + @Test + void testContextClose() throws Exception { + final Context context = embeddedLdapExtension.context(); + context.close(); + assertNotNull(context.getNameInNamespace()); + + } + + @Test + void testEmbeddedServerPort() { + assertTrue(embeddedLdapExtension.embeddedServerPort() > 0); + + } + + @Test + void testNoPortAssignedYet() { + final EmbeddedLdapExtension embeddedLdapRule = new EmbeddedLdapExtensionBuilder().build(); + + assertThrows(IllegalStateException.class, embeddedLdapRule::embeddedServerPort); + + } +} From cde99b652f7c2012fcd668564d8d33e8516efa47 Mon Sep 17 00:00:00 2001 From: Bastien Jansen Date: Thu, 29 Oct 2020 10:32:02 +0100 Subject: [PATCH 2/5] Make Maven run JUnit 5 tests as well --- pom.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pom.xml b/pom.xml index 1211eee..d72f06c 100644 --- a/pom.xml +++ b/pom.xml @@ -91,6 +91,18 @@ ${bouncycastle.version} test + + org.junit.jupiter + junit-jupiter-engine + 5.7.0 + test + + + org.junit.vintage + junit-vintage-engine + ${junit5.version} + test + @@ -196,6 +208,10 @@ ${java.version} + + maven-surefire-plugin + 2.22.2 + From dceadfd17a9f90117d5d0dd01eed8870971b28a8 Mon Sep 17 00:00:00 2001 From: Bastien Jansen Date: Thu, 29 Oct 2020 11:30:34 +0100 Subject: [PATCH 3/5] Split the JUnit 4 rule and JUnit 5 extension into separate Maven modules --- embedded-ldap-core/pom.xml | 37 +++ .../junit/ldap/EmbeddedLdapServer.java | 2 +- .../internal/AbstractEmbeddedLdapBuilder.java | 4 +- .../internal/AuthenticationConfiguration.java | 0 .../ldap/internal/EmbeddedLdapServerImpl.java | 2 +- .../internal/jndi/ContextInterceptor.java | 0 .../ldap/internal/jndi/ContextProxy.java | 0 .../internal/jndi/ContextProxyFactory.java | 0 .../ldap/internal/jndi/DirContextProxy.java | 0 .../junit/ldap/internal/package-info.java | 0 .../unboundid/LDAPConnectionProxy.java | 0 .../unboundid/LDAPInterfaceProxyFactory.java | 0 .../org/zapodot/junit/ldap/package-info.java | 0 embedded-ldap-junit/pom.xml | 48 ++++ .../zapodot/junit/ldap/EmbeddedLdapRule.java | 0 .../junit/ldap/EmbeddedLdapRuleBuilder.java | 0 .../ldap/internal/EmbeddedLdapRuleImpl.java | 2 +- .../ldap/EmbeddedLdapRuleBuilderTest.java | 0 .../ldap/EmbeddedLdapRuleClassRuleTest.java | 0 ...dedLdapRuleCustomSchemaDuplicatedTest.java | 0 ...RuleCustomStandardAndCustomSchemaTest.java | 0 ...beddedLdapRuleCustomWithoutSchemaTest.java | 0 ...apRuleCustomWithoutStandardSchemaTest.java | 0 .../ldap/EmbeddedLdapRuleMultipleDSNs.java | 0 .../ldap/EmbeddedLdapRuleNoAuthTest.java | 0 .../ldap/EmbeddedLdapRuleStandardContext.java | 0 .../ldap/EmbeddedLdapRuleStarttlsTest.java | 0 .../junit/ldap/EmbeddedLdapRuleTest.java | 0 ...pRuleWithListeningAddressProvidedTest.java | 0 .../ldap/EmbeddedLdapRuleWithSpacesTest.java | 0 .../AuthenticationConfigurationTest.java | 0 .../jndi/ContextProxyFactoryTest.java | 0 .../LDAPInterfaceProxyFactoryTest.java | 0 .../src}/test/resources/custom-schema.ldif | 0 .../src}/test/resources/example.ldif | 0 .../resources/folder with space/example.ldif | 0 .../src}/test/resources/folder/.placeholder | 0 .../src}/test/resources/invalid.ldif | 0 .../src}/test/resources/standard-schema.ldif | 0 embedded-ldap-junit5/pom.xml | 35 +++ .../internal/EmbeddedLdapExtensionImpl.java | 0 .../ldap/junit5/EmbeddedLdapExtension.java | 0 .../junit5/EmbeddedLdapExtensionBuilder.java | 0 .../EmbeddedLdapExtensionBuilderTest.java | 99 ++++++++ .../EmbeddedLdapExtensionStaticTest.java | 0 .../junit5/EmbeddedLdapExtensionTest.java | 0 .../src/test/resources/example.ldif | 28 +++ pom.xml | 75 +----- .../junit/ldap/EmbeddedLdapRuleTlsTest.java | 216 ------------------ .../EmbeddedLdapExtensionBuilderTest.java | 87 ------- 50 files changed, 262 insertions(+), 373 deletions(-) create mode 100644 embedded-ldap-core/pom.xml rename {src => embedded-ldap-core/src}/main/java/org/zapodot/junit/ldap/EmbeddedLdapServer.java (95%) rename {src => embedded-ldap-core/src}/main/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilder.java (98%) rename {src => embedded-ldap-core/src}/main/java/org/zapodot/junit/ldap/internal/AuthenticationConfiguration.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-core/src}/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerImpl.java (99%) rename {src => embedded-ldap-core/src}/main/java/org/zapodot/junit/ldap/internal/jndi/ContextInterceptor.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-core/src}/main/java/org/zapodot/junit/ldap/internal/jndi/ContextProxy.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-core/src}/main/java/org/zapodot/junit/ldap/internal/jndi/ContextProxyFactory.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-core/src}/main/java/org/zapodot/junit/ldap/internal/jndi/DirContextProxy.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-core/src}/main/java/org/zapodot/junit/ldap/internal/package-info.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-core/src}/main/java/org/zapodot/junit/ldap/internal/unboundid/LDAPConnectionProxy.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-core/src}/main/java/org/zapodot/junit/ldap/internal/unboundid/LDAPInterfaceProxyFactory.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-core/src}/main/java/org/zapodot/junit/ldap/package-info.java (100%) mode change 100755 => 100644 create mode 100644 embedded-ldap-junit/pom.xml rename {src => embedded-ldap-junit/src}/main/java/org/zapodot/junit/ldap/EmbeddedLdapRule.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/main/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilder.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapRuleImpl.java (93%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilderTest.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleClassRuleTest.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomSchemaDuplicatedTest.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomStandardAndCustomSchemaTest.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomWithoutSchemaTest.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomWithoutStandardSchemaTest.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleMultipleDSNs.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleNoAuthTest.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleStandardContext.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleStarttlsTest.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleTest.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleWithListeningAddressProvidedTest.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleWithSpacesTest.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/internal/AuthenticationConfigurationTest.java (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/internal/jndi/ContextProxyFactoryTest.java (100%) rename {src => embedded-ldap-junit/src}/test/java/org/zapodot/junit/ldap/internal/unboundid/LDAPInterfaceProxyFactoryTest.java (100%) rename {src => embedded-ldap-junit/src}/test/resources/custom-schema.ldif (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/resources/example.ldif (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/resources/folder with space/example.ldif (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/resources/folder/.placeholder (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/resources/invalid.ldif (100%) mode change 100755 => 100644 rename {src => embedded-ldap-junit/src}/test/resources/standard-schema.ldif (100%) mode change 100755 => 100644 create mode 100644 embedded-ldap-junit5/pom.xml rename {src => embedded-ldap-junit5/src}/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapExtensionImpl.java (100%) rename {src => embedded-ldap-junit5/src}/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtension.java (100%) rename {src => embedded-ldap-junit5/src}/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilder.java (100%) create mode 100644 embedded-ldap-junit5/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilderTest.java rename {src => embedded-ldap-junit5/src}/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionStaticTest.java (100%) rename {src => embedded-ldap-junit5/src}/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionTest.java (100%) create mode 100644 embedded-ldap-junit5/src/test/resources/example.ldif delete mode 100755 src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleTlsTest.java delete mode 100644 src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilderTest.java diff --git a/embedded-ldap-core/pom.xml b/embedded-ldap-core/pom.xml new file mode 100644 index 0000000..60a0918 --- /dev/null +++ b/embedded-ldap-core/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + embedded-ldap-parent + org.zapodot + 0.9-SNAPSHOT + + + embedded-ldap-core + + + + com.unboundid + unboundid-ldapsdk + ${unboundid-ldapsdk.version} + + + com.google.guava + guava + ${guava.version} + + + net.bytebuddy + byte-buddy + ${byte-buddy.version} + + + org.slf4j + slf4j-api + ${slf4j.version} + + + diff --git a/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapServer.java b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapServer.java similarity index 95% rename from src/main/java/org/zapodot/junit/ldap/EmbeddedLdapServer.java rename to embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapServer.java index 45191d9..b73a258 100644 --- a/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapServer.java +++ b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapServer.java @@ -53,7 +53,7 @@ public interface EmbeddedLdapServer { *

* * @return the port number that the embedded server is listening to - * @see org.zapodot.junit.ldap.EmbeddedLdapRuleBuilder#bindingToAddress(String) + * @see org.zapodot.junit.ldap.internal.AbstractEmbeddedLdapBuilder#bindingToAddress(String) */ int embeddedServerPort(); diff --git a/src/main/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilder.java b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilder.java similarity index 98% rename from src/main/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilder.java rename to embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilder.java index e5326ea..5e03337 100644 --- a/src/main/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilder.java +++ b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilder.java @@ -20,8 +20,8 @@ import java.util.Objects; /** - * A builder providing a fluent way of defining {@link org.zapodot.junit.ldap.EmbeddedLdapRule} - * or {@link org.zapodot.junit.ldap.junit5.EmbeddedLdapExtension} instances. + * A builder providing a fluent way of defining EmbeddedLdapRule + * or EmbeddedLdapExtension instances. */ public abstract class AbstractEmbeddedLdapBuilder> { diff --git a/src/main/java/org/zapodot/junit/ldap/internal/AuthenticationConfiguration.java b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/AuthenticationConfiguration.java old mode 100755 new mode 100644 similarity index 100% rename from src/main/java/org/zapodot/junit/ldap/internal/AuthenticationConfiguration.java rename to embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/AuthenticationConfiguration.java diff --git a/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerImpl.java b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerImpl.java similarity index 99% rename from src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerImpl.java rename to embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerImpl.java index 161ee12..b848614 100644 --- a/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerImpl.java +++ b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerImpl.java @@ -28,7 +28,7 @@ abstract class EmbeddedLdapServerImpl implements EmbeddedLdapServer { private static final String JAVA_RT_CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory"; - private static Logger logger = LoggerFactory.getLogger(EmbeddedLdapExtensionImpl.class); + private static Logger logger = LoggerFactory.getLogger(EmbeddedLdapServerImpl.class); private final InMemoryDirectoryServer inMemoryDirectoryServer; private final AuthenticationConfiguration authenticationConfiguration; private LDAPConnection ldapConnection; diff --git a/src/main/java/org/zapodot/junit/ldap/internal/jndi/ContextInterceptor.java b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/jndi/ContextInterceptor.java old mode 100755 new mode 100644 similarity index 100% rename from src/main/java/org/zapodot/junit/ldap/internal/jndi/ContextInterceptor.java rename to embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/jndi/ContextInterceptor.java diff --git a/src/main/java/org/zapodot/junit/ldap/internal/jndi/ContextProxy.java b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/jndi/ContextProxy.java old mode 100755 new mode 100644 similarity index 100% rename from src/main/java/org/zapodot/junit/ldap/internal/jndi/ContextProxy.java rename to embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/jndi/ContextProxy.java diff --git a/src/main/java/org/zapodot/junit/ldap/internal/jndi/ContextProxyFactory.java b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/jndi/ContextProxyFactory.java old mode 100755 new mode 100644 similarity index 100% rename from src/main/java/org/zapodot/junit/ldap/internal/jndi/ContextProxyFactory.java rename to embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/jndi/ContextProxyFactory.java diff --git a/src/main/java/org/zapodot/junit/ldap/internal/jndi/DirContextProxy.java b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/jndi/DirContextProxy.java old mode 100755 new mode 100644 similarity index 100% rename from src/main/java/org/zapodot/junit/ldap/internal/jndi/DirContextProxy.java rename to embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/jndi/DirContextProxy.java diff --git a/src/main/java/org/zapodot/junit/ldap/internal/package-info.java b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/package-info.java old mode 100755 new mode 100644 similarity index 100% rename from src/main/java/org/zapodot/junit/ldap/internal/package-info.java rename to embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/package-info.java diff --git a/src/main/java/org/zapodot/junit/ldap/internal/unboundid/LDAPConnectionProxy.java b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/unboundid/LDAPConnectionProxy.java old mode 100755 new mode 100644 similarity index 100% rename from src/main/java/org/zapodot/junit/ldap/internal/unboundid/LDAPConnectionProxy.java rename to embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/unboundid/LDAPConnectionProxy.java diff --git a/src/main/java/org/zapodot/junit/ldap/internal/unboundid/LDAPInterfaceProxyFactory.java b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/unboundid/LDAPInterfaceProxyFactory.java old mode 100755 new mode 100644 similarity index 100% rename from src/main/java/org/zapodot/junit/ldap/internal/unboundid/LDAPInterfaceProxyFactory.java rename to embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/unboundid/LDAPInterfaceProxyFactory.java diff --git a/src/main/java/org/zapodot/junit/ldap/package-info.java b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/package-info.java old mode 100755 new mode 100644 similarity index 100% rename from src/main/java/org/zapodot/junit/ldap/package-info.java rename to embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/package-info.java diff --git a/embedded-ldap-junit/pom.xml b/embedded-ldap-junit/pom.xml new file mode 100644 index 0000000..16ac926 --- /dev/null +++ b/embedded-ldap-junit/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + + + embedded-ldap-parent + org.zapodot + 0.9-SNAPSHOT + + + embedded-ldap-junit + + + + org.zapodot + embedded-ldap-core + ${project.version} + + + + junit + junit + ${junit.version} + + + + + ch.qos.logback + logback-classic + ${logback.version} + test + + + org.bouncycastle + bcprov-jdk15on + ${bouncycastle.version} + test + + + org.bouncycastle + bcpkix-jdk15on + ${bouncycastle.version} + test + + + diff --git a/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRule.java b/embedded-ldap-junit/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRule.java old mode 100755 new mode 100644 similarity index 100% rename from src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRule.java rename to embedded-ldap-junit/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRule.java diff --git a/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilder.java b/embedded-ldap-junit/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilder.java old mode 100755 new mode 100644 similarity index 100% rename from src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilder.java rename to embedded-ldap-junit/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilder.java diff --git a/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapRuleImpl.java b/embedded-ldap-junit/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapRuleImpl.java old mode 100755 new mode 100644 similarity index 93% rename from src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapRuleImpl.java rename to embedded-ldap-junit/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapRuleImpl.java index 9f33d28..e55bd7f --- a/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapRuleImpl.java +++ b/embedded-ldap-junit/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapRuleImpl.java @@ -15,7 +15,7 @@ public static EmbeddedLdapRule createForConfiguration(final InMemoryDirectorySer final AuthenticationConfiguration authenticationConfiguration, final List ldifs) { try { - return new EmbeddedLdapRuleImpl(createServer(inMemoryDirectoryServerConfig, ldifs), + return new EmbeddedLdapRuleImpl(EmbeddedLdapServerImpl.createServer(inMemoryDirectoryServerConfig, ldifs), authenticationConfiguration); } catch (LDAPException e) { throw new IllegalStateException("Can not initiate in-memory LDAP server due to an exception", e); diff --git a/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilderTest.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilderTest.java old mode 100755 new mode 100644 similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilderTest.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilderTest.java diff --git a/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleClassRuleTest.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleClassRuleTest.java old mode 100755 new mode 100644 similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleClassRuleTest.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleClassRuleTest.java diff --git a/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomSchemaDuplicatedTest.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomSchemaDuplicatedTest.java old mode 100755 new mode 100644 similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomSchemaDuplicatedTest.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomSchemaDuplicatedTest.java diff --git a/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomStandardAndCustomSchemaTest.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomStandardAndCustomSchemaTest.java old mode 100755 new mode 100644 similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomStandardAndCustomSchemaTest.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomStandardAndCustomSchemaTest.java diff --git a/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomWithoutSchemaTest.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomWithoutSchemaTest.java old mode 100755 new mode 100644 similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomWithoutSchemaTest.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomWithoutSchemaTest.java diff --git a/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomWithoutStandardSchemaTest.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomWithoutStandardSchemaTest.java old mode 100755 new mode 100644 similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomWithoutStandardSchemaTest.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleCustomWithoutStandardSchemaTest.java diff --git a/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleMultipleDSNs.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleMultipleDSNs.java old mode 100755 new mode 100644 similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleMultipleDSNs.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleMultipleDSNs.java diff --git a/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleNoAuthTest.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleNoAuthTest.java old mode 100755 new mode 100644 similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleNoAuthTest.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleNoAuthTest.java diff --git a/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleStandardContext.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleStandardContext.java old mode 100755 new mode 100644 similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleStandardContext.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleStandardContext.java diff --git a/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleStarttlsTest.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleStarttlsTest.java old mode 100755 new mode 100644 similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleStarttlsTest.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleStarttlsTest.java diff --git a/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleTest.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleTest.java old mode 100755 new mode 100644 similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleTest.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleTest.java diff --git a/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleWithListeningAddressProvidedTest.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleWithListeningAddressProvidedTest.java old mode 100755 new mode 100644 similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleWithListeningAddressProvidedTest.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleWithListeningAddressProvidedTest.java diff --git a/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleWithSpacesTest.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleWithSpacesTest.java old mode 100755 new mode 100644 similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleWithSpacesTest.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleWithSpacesTest.java diff --git a/src/test/java/org/zapodot/junit/ldap/internal/AuthenticationConfigurationTest.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/internal/AuthenticationConfigurationTest.java old mode 100755 new mode 100644 similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/internal/AuthenticationConfigurationTest.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/internal/AuthenticationConfigurationTest.java diff --git a/src/test/java/org/zapodot/junit/ldap/internal/jndi/ContextProxyFactoryTest.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/internal/jndi/ContextProxyFactoryTest.java similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/internal/jndi/ContextProxyFactoryTest.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/internal/jndi/ContextProxyFactoryTest.java diff --git a/src/test/java/org/zapodot/junit/ldap/internal/unboundid/LDAPInterfaceProxyFactoryTest.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/internal/unboundid/LDAPInterfaceProxyFactoryTest.java similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/internal/unboundid/LDAPInterfaceProxyFactoryTest.java rename to embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/internal/unboundid/LDAPInterfaceProxyFactoryTest.java diff --git a/src/test/resources/custom-schema.ldif b/embedded-ldap-junit/src/test/resources/custom-schema.ldif old mode 100755 new mode 100644 similarity index 100% rename from src/test/resources/custom-schema.ldif rename to embedded-ldap-junit/src/test/resources/custom-schema.ldif diff --git a/src/test/resources/example.ldif b/embedded-ldap-junit/src/test/resources/example.ldif old mode 100755 new mode 100644 similarity index 100% rename from src/test/resources/example.ldif rename to embedded-ldap-junit/src/test/resources/example.ldif diff --git a/src/test/resources/folder with space/example.ldif b/embedded-ldap-junit/src/test/resources/folder with space/example.ldif old mode 100755 new mode 100644 similarity index 100% rename from src/test/resources/folder with space/example.ldif rename to embedded-ldap-junit/src/test/resources/folder with space/example.ldif diff --git a/src/test/resources/folder/.placeholder b/embedded-ldap-junit/src/test/resources/folder/.placeholder old mode 100755 new mode 100644 similarity index 100% rename from src/test/resources/folder/.placeholder rename to embedded-ldap-junit/src/test/resources/folder/.placeholder diff --git a/src/test/resources/invalid.ldif b/embedded-ldap-junit/src/test/resources/invalid.ldif old mode 100755 new mode 100644 similarity index 100% rename from src/test/resources/invalid.ldif rename to embedded-ldap-junit/src/test/resources/invalid.ldif diff --git a/src/test/resources/standard-schema.ldif b/embedded-ldap-junit/src/test/resources/standard-schema.ldif old mode 100755 new mode 100644 similarity index 100% rename from src/test/resources/standard-schema.ldif rename to embedded-ldap-junit/src/test/resources/standard-schema.ldif diff --git a/embedded-ldap-junit5/pom.xml b/embedded-ldap-junit5/pom.xml new file mode 100644 index 0000000..b366ad8 --- /dev/null +++ b/embedded-ldap-junit5/pom.xml @@ -0,0 +1,35 @@ + + + + embedded-ldap-parent + org.zapodot + 0.9-SNAPSHOT + + 4.0.0 + + embedded-ldap-junit5 + + + + org.zapodot + embedded-ldap-core + ${project.version} + + + + org.junit.jupiter + junit-jupiter-api + ${junit5.version} + + + + + org.junit.jupiter + junit-jupiter-engine + ${junit5.version} + test + + + diff --git a/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapExtensionImpl.java b/embedded-ldap-junit5/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapExtensionImpl.java similarity index 100% rename from src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapExtensionImpl.java rename to embedded-ldap-junit5/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapExtensionImpl.java diff --git a/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtension.java b/embedded-ldap-junit5/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtension.java similarity index 100% rename from src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtension.java rename to embedded-ldap-junit5/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtension.java diff --git a/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilder.java b/embedded-ldap-junit5/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilder.java similarity index 100% rename from src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilder.java rename to embedded-ldap-junit5/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilder.java diff --git a/embedded-ldap-junit5/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilderTest.java b/embedded-ldap-junit5/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilderTest.java new file mode 100644 index 0000000..bb8c546 --- /dev/null +++ b/embedded-ldap-junit5/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilderTest.java @@ -0,0 +1,99 @@ +package org.zapodot.junit.ldap.junit5; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class EmbeddedLdapExtensionBuilderTest { + + @Test + void bindingToLegalPort() { + assertNotNull(EmbeddedLdapExtensionBuilder.newInstance().bindingToPort(9999)); + } + + @Test + void testPrematureLdapConnection() { + assertThrows(IllegalStateException.class, () -> + EmbeddedLdapExtensionBuilder.newInstance().build().ldapConnection() + ); + } + + @Test + void testPrematureContext() { + assertThrows(IllegalStateException.class, () -> + EmbeddedLdapExtensionBuilder.newInstance().build().context() + ); + } + + @Test + void testUnknownLDIF() { + assertThrows(IllegalArgumentException.class, () -> + EmbeddedLdapExtensionBuilder.newInstance().importingLdifs("nonExisting.ldif").build() + ); + } + + @Test + void testNullLDIF() { + assertNotNull(EmbeddedLdapExtensionBuilder.newInstance().importingLdifs(null).build()); + + } + + @Test + void testIllegalDSN() { + assertThrows(IllegalStateException.class, () -> + EmbeddedLdapExtensionBuilder.newInstance().usingBindDSN("bindDsn").build() + ); + } + + @Test + void testIllegalPort() { + assertThrows(IllegalArgumentException.class, () -> + EmbeddedLdapExtensionBuilder.newInstance().bindingToPort(Integer.MIN_VALUE).build() + ); + } + + @Test + void testSchemaNotFound() { + assertThrows(IllegalArgumentException.class, () -> + EmbeddedLdapExtensionBuilder.newInstance().withSchema("non-existing-schema.ldif").build() + ); + } + + @Test + void testSchemaIsNotAFile() { + assertThrows(IllegalArgumentException.class, () -> + EmbeddedLdapExtensionBuilder.newInstance().withSchema("folder").build() + ); + } + + @Test + void testSchemaIsInvalid() { + assertThrows(IllegalArgumentException.class, () -> + EmbeddedLdapExtensionBuilder.newInstance().withSchema("invalid.ldif").build() + ); + } + + @Test + void testSchemaFileUnsupportedIsInvalid() { + assertThrows(IllegalArgumentException.class, () -> + EmbeddedLdapExtensionBuilder.newInstance().withSchema("\"#%¤&&%/¤##¤¤").build() + ); + } + + @Test + void testInvalidPort() { + assertThrows(IllegalArgumentException.class, () -> + EmbeddedLdapExtensionBuilder.newInstance().bindingToPort(Integer.MAX_VALUE) + ); + } + + @Test + void testInvalidBindAddress() { + assertThrows(IllegalArgumentException.class, () -> + EmbeddedLdapExtensionBuilder.newInstance().bindingToAddress("åpsldfåpl") + ); + } + + +} diff --git a/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionStaticTest.java b/embedded-ldap-junit5/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionStaticTest.java similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionStaticTest.java rename to embedded-ldap-junit5/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionStaticTest.java diff --git a/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionTest.java b/embedded-ldap-junit5/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionTest.java similarity index 100% rename from src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionTest.java rename to embedded-ldap-junit5/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionTest.java diff --git a/embedded-ldap-junit5/src/test/resources/example.ldif b/embedded-ldap-junit5/src/test/resources/example.ldif new file mode 100644 index 0000000..5eb286a --- /dev/null +++ b/embedded-ldap-junit5/src/test/resources/example.ldif @@ -0,0 +1,28 @@ +version: 1 + +dn: dc=zapodot,dc=org +objectClass: domain +objectClass: top +dc: zapodot + +dn: ou=groups,dc=zapodot,dc=org +objectclass: top +objectclass: organizationalUnit +ou: groups + +dn: ou=people,dc=zapodot,dc=org +objectclass: top +objectclass: organizationalUnit +ou: people + +dn: cn=Sondre Eikanger Kvalo,ou=people,dc=zapodot,dc=org +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: zapodot +userPassword: password +cn: Sondre Eikanger Kvalo +cn:: U29uZHJlIEVpa2FuZ2VyIEt2YWzDuA== +sn: Person +description: Developer \ No newline at end of file diff --git a/pom.xml b/pom.xml index d72f06c..cda93fa 100644 --- a/pom.xml +++ b/pom.xml @@ -5,10 +5,17 @@ 4.0.0 org.zapodot - embedded-ldap-junit + embedded-ldap-parent + pom 0.9.1-SNAPSHOT + + + embedded-ldap-core + embedded-ldap-junit + embedded-ldap-junit5 + ${project.artifactId} - Library that provides a JUnit rule for setting up an in-memory LDAP server by using the glorious Unboundid LDAP SDK + Library that provides a JUnit rule and extension for setting up an in-memory LDAP server by using the glorious Unboundid LDAP SDK https://github.com/zapodot/embedded-ldap-junit 2015 @@ -41,69 +48,7 @@ 8 0.8.8 - - - com.unboundid - unboundid-ldapsdk - ${unboundid-ldapsdk.version} - - - junit - junit - ${junit.version} - - - org.junit.jupiter - junit-jupiter-api - ${junit5.version} - true - - - com.google.guava - guava - ${guava.version} - - - net.bytebuddy - byte-buddy - ${byte-buddy.version} - - - org.slf4j - slf4j-api - ${slf4j.version} - - - ch.qos.logback - logback-classic - ${logback.version} - test - - - org.bouncycastle - bcprov-jdk15on - ${bouncycastle.version} - test - - - org.bouncycastle - bcpkix-jdk15on - ${bouncycastle.version} - test - - - org.junit.jupiter - junit-jupiter-engine - 5.7.0 - test - - - org.junit.vintage - junit-vintage-engine - ${junit5.version} - test - - + diff --git a/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleTlsTest.java b/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleTlsTest.java deleted file mode 100755 index 43c703d..0000000 --- a/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleTlsTest.java +++ /dev/null @@ -1,216 +0,0 @@ -package org.zapodot.junit.ldap; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.util.Arrays; -import java.io.IOException; -import java.math.BigInteger; -import java.net.InetAddress; -import java.security.KeyManagementException; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.Provider; -import java.security.Security; -import java.security.UnrecoverableKeyException; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; - -import javax.naming.Context; -import javax.naming.NamingEnumeration; -import javax.naming.directory.DirContext; -import javax.naming.directory.SearchControls; - -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x509.BasicConstraints; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; -import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.operator.ContentSigner; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; -import org.junit.Rule; -import org.junit.Test; - -import com.google.common.collect.Iterators; -import com.unboundid.ldap.listener.InMemoryListenerConfig; -import com.unboundid.ldap.sdk.AddRequest; -import com.unboundid.ldap.sdk.Attribute; -import com.unboundid.ldap.sdk.LDAPConnection; -import com.unboundid.ldap.sdk.LDAPInterface; -import com.unboundid.ldap.sdk.SearchRequest; -import com.unboundid.ldap.sdk.SearchResult; -import com.unboundid.ldap.sdk.SearchResultEntry; -import com.unboundid.ldap.sdk.SearchScope; - -public class EmbeddedLdapRuleTlsTest { - - public static final String DOMAIN_DSN = "dc=zapodot,dc=org"; - - final SSLContext sslContext; - { - try { - sslContext = buildSslContext(); - } catch (Exception e) { - throw new IllegalStateException("Failed to create LDAPS config", e); - } - } - - @Rule - public EmbeddedLdapRule embeddedLdapRule = EmbeddedLdapRuleBuilder - .newInstance() - .usingDomainDsn(DOMAIN_DSN) - .importingLdifs("example.ldif") - .withListener(getListenerConfig()) - .useTls(true) - .withSocketFactory(sslContext.getSocketFactory()) - .build(); - - private InMemoryListenerConfig getListenerConfig() { - try { - return InMemoryListenerConfig.createLDAPSConfig( - "tls", InetAddress.getLoopbackAddress(), 0, sslContext.getServerSocketFactory(), - sslContext.getSocketFactory() - ); - } catch (Exception e) { - throw new IllegalStateException("Failed to create LDAPS config", e); - } - } - - @Test - public void testLdapConnection() throws Exception { - final LDAPInterface ldapConnection = embeddedLdapRule.ldapConnection(); - final SearchResult searchResult = ldapConnection.search(DOMAIN_DSN, SearchScope.SUB, "(objectClass=person)"); - assertEquals(1, searchResult.getEntryCount()); - } - - @Test - public void testRawLdapConnection() throws Exception { - final String commonName = "Test person"; - final String dn = String.format( - "cn=%s,ou=people,dc=zapodot,dc=org", - commonName); - LDAPConnection ldapConnection = embeddedLdapRule.unsharedLdapConnection(); - try { - ldapConnection.add(new AddRequest(dn, Arrays.asList( - new Attribute("objectclass", "top", "person", "organizationalPerson", "inetOrgPerson"), - new Attribute("cn", commonName), new Attribute("sn", "Person"), new Attribute("uid", "test")))); - } finally { - // Forces the LDAP connection to be closed. This is not necessary as the rule will usually close it for you. - ldapConnection.close(); - } - ldapConnection = embeddedLdapRule.unsharedLdapConnection(); - final SearchResultEntry entry = ldapConnection.searchForEntry(new SearchRequest(dn, - SearchScope.BASE, - "(objectClass=person)")); - assertNotNull(entry); - } - - @Test - public void testDirContext() throws Exception { - final DirContext dirContext = embeddedLdapRule.dirContext(); - final SearchControls searchControls = new SearchControls(); - searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); - final NamingEnumeration resultNamingEnumeration = - dirContext.search(DOMAIN_DSN, "(objectClass=person)", searchControls); - assertEquals(1, Iterators.size(Iterators.forEnumeration(resultNamingEnumeration))); - } - - @Test - public void testContext() throws Exception { - final Context context = embeddedLdapRule.context(); - final Object user = context.lookup("cn=Sondre Eikanger Kvalo,ou=people,dc=zapodot,dc=org"); - assertNotNull(user); - } - - @Test - public void testContextClose() throws Exception { - final Context context = embeddedLdapRule.context(); - context.close(); - assertNotNull(context.getNameInNamespace()); - - } - - @Test - public void testEmbeddedServerPort() throws Exception { - assertTrue(embeddedLdapRule.embeddedServerPort() > 0); - - } - - @Test(expected = IllegalStateException.class) - public void testNoPortAssignedYet() throws Exception { - final EmbeddedLdapRule embeddedLdapRule = new EmbeddedLdapRuleBuilder().build(); - embeddedLdapRule.embeddedServerPort(); - - } - - public static SSLContext buildSslContext() - throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, - UnrecoverableKeyException, KeyManagementException, OperatorCreationException { - KeyStore keystore = KeyStore.getInstance("jks"); - keystore.load(null, new char[] {}); - KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA"); - gen.initialize(2014); - final KeyPair keyPair = gen.generateKeyPair(); - - Provider bcProvider = new BouncyCastleProvider(); - Security.addProvider(bcProvider); - - long now = System.currentTimeMillis(); - Date startDate = new Date(now); - - org.bouncycastle.asn1.x500.X500Name dn = new org.bouncycastle.asn1.x500.X500Name("cn=localhost"); - BigInteger sn = new BigInteger(Long.toString(now)); - - Calendar calendar = Calendar.getInstance(); - calendar.setTime(startDate); - calendar.add(Calendar.HOUR, 1); - Date endDate = calendar.getTime(); - - String signatureAlgorithm = "SHA256WithRSA"; - - final ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).build(keyPair.getPrivate()); - - final X509CertificateHolder holder = - new JcaX509v3CertificateBuilder(dn, sn, startDate, endDate, dn, keyPair.getPublic()) - .addExtension(new ASN1ObjectIdentifier("2.5.29.19"), true, new BasicConstraints(true)) - .build(contentSigner); - final X509Certificate cert = new JcaX509CertificateConverter() - .setProvider(bcProvider) - .getCertificate(holder); - keystore.setCertificateEntry("test", cert); - keystore.setKeyEntry("key", keyPair.getPrivate(), new char[] {}, new Certificate[] { cert }); - - final KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - kmfactory.init(keystore, new char[] {}); - final KeyManager[] kms = kmfactory.getKeyManagers(); - - KeyStore truststore = KeyStore.getInstance("jks"); - truststore.load(null, new char[] {}); - truststore.setCertificateEntry("test", cert); - - final TrustManagerFactory tmfactory = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm() - ); - tmfactory.init(truststore); - final TrustManager[] tms = tmfactory.getTrustManagers(); - final SSLContext sslcontext = SSLContext.getInstance("TLS"); - sslcontext.init(kms, tms, null); - return sslcontext; - } -} diff --git a/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilderTest.java b/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilderTest.java deleted file mode 100644 index 77d0d1e..0000000 --- a/src/test/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilderTest.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.zapodot.junit.ldap.junit5; - -import org.junit.Test; - -import static org.junit.Assert.assertNotNull; - -public class EmbeddedLdapExtensionBuilderTest { - - @Test - public void bindingToLegalPort() { - assertNotNull(EmbeddedLdapExtensionBuilder.newInstance().bindingToPort(9999)); - } - - @Test(expected = IllegalStateException.class) - public void testPrematureLdapConnection() throws Exception { - EmbeddedLdapExtensionBuilder.newInstance().build().ldapConnection(); - - } - - @Test(expected = IllegalStateException.class) - public void testPrematureContext() throws Exception { - EmbeddedLdapExtensionBuilder.newInstance().build().context(); - - } - - @Test(expected = IllegalArgumentException.class) - public void testUnknownLDIF() { - EmbeddedLdapExtensionBuilder.newInstance().importingLdifs("nonExisting.ldif").build(); - - } - - @Test - public void testNullLDIF() { - assertNotNull(EmbeddedLdapExtensionBuilder.newInstance().importingLdifs(null).build()); - - } - - @Test(expected = IllegalStateException.class) - public void testIllegalDSN() { - EmbeddedLdapExtensionBuilder.newInstance().usingBindDSN("bindDsn").build(); - - } - - @Test(expected = IllegalArgumentException.class) - public void testIllegalPort() { - EmbeddedLdapExtensionBuilder.newInstance().bindingToPort(Integer.MIN_VALUE).build(); - - } - - @Test(expected = IllegalArgumentException.class) - public void testSchemaNotFound() { - EmbeddedLdapExtensionBuilder.newInstance().withSchema("non-existing-schema.ldif").build(); - - } - - @Test(expected = IllegalArgumentException.class) - public void testSchemaIsNotAFile() { - EmbeddedLdapExtensionBuilder.newInstance().withSchema("folder").build(); - - } - - @Test(expected = IllegalArgumentException.class) - public void testSchemaIsInvalid() { - EmbeddedLdapExtensionBuilder.newInstance().withSchema("invalid.ldif").build(); - - } - - @Test(expected = IllegalArgumentException.class) - public void testSchemaFileUnsupportedIsInvalid() { - EmbeddedLdapExtensionBuilder.newInstance().withSchema("\"#%¤&&%/¤##¤¤").build(); - - } - - @Test(expected = IllegalArgumentException.class) - public void testInvalidPort() { - EmbeddedLdapExtensionBuilder.newInstance().bindingToPort(Integer.MAX_VALUE); - - } - - @Test(expected = IllegalArgumentException.class) - public void testInvalidBindAddress() { - EmbeddedLdapExtensionBuilder.newInstance().bindingToAddress("åpsldfåpl"); - - } - - -} From bd1152625a7f0368cf8d134e9c8565cc7f95aaf0 Mon Sep 17 00:00:00 2001 From: Bastien Jansen Date: Mon, 2 Nov 2020 13:14:34 +0100 Subject: [PATCH 4/5] Moved most of the unit tests from embedded-ldap-junit to embedded-ldap-core --- embedded-ldap-core/pom.xml | 20 + .../AbstractEmbeddedLdapBuilderTest.java | 88 + .../AuthenticationConfigurationTest.java | 0 ...dLdapServerCustomSchemaDuplicatedTest.java | 35 + ...rverCustomStandardAndCustomSchemaTest.java | 37 + ...ddedLdapServerCustomWithoutSchemaTest.java | 35 + ...ServerCustomWithoutStandardSchemaTest.java | 36 + .../EmbeddedLdapServerMultipleDSNs.java | 40 + .../EmbeddedLdapServerNoAuthTest.java | 35 + .../EmbeddedLdapServerStandardContext.java | 33 + .../EmbeddedLdapServerStarttlsTest.java | 151 ++ .../ldap/internal/EmbeddedLdapServerTest.java | 104 ++ ...erverWithListeningAddressProvidedTest.java | 46 + .../EmbeddedLdapServerWithSpacesTest.java | 34 + .../internal/FakeEmbeddedLdapBuilder.java | 32 + .../jndi/ContextProxyFactoryTest.java | 0 .../LDAPInterfaceProxyFactoryTest.java | 0 .../src/test/resources/custom-schema.ldif | 7 + .../src/test/resources/example.ldif | 28 + .../resources/folder with space/example.ldif | 28 + .../src/test/resources/folder/.placeholder | 0 .../src/test/resources/invalid.ldif | 2 + .../src/test/resources/standard-schema.ldif | 1546 +++++++++++++++++ 23 files changed, 2337 insertions(+) create mode 100644 embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilderTest.java rename {embedded-ldap-junit => embedded-ldap-core}/src/test/java/org/zapodot/junit/ldap/internal/AuthenticationConfigurationTest.java (100%) create mode 100644 embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomSchemaDuplicatedTest.java create mode 100644 embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomStandardAndCustomSchemaTest.java create mode 100644 embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomWithoutSchemaTest.java create mode 100644 embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomWithoutStandardSchemaTest.java create mode 100644 embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerMultipleDSNs.java create mode 100644 embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerNoAuthTest.java create mode 100644 embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerStandardContext.java create mode 100644 embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerStarttlsTest.java create mode 100644 embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerTest.java create mode 100644 embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerWithListeningAddressProvidedTest.java create mode 100644 embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerWithSpacesTest.java create mode 100644 embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/FakeEmbeddedLdapBuilder.java rename {embedded-ldap-junit => embedded-ldap-core}/src/test/java/org/zapodot/junit/ldap/internal/jndi/ContextProxyFactoryTest.java (100%) rename {embedded-ldap-junit => embedded-ldap-core}/src/test/java/org/zapodot/junit/ldap/internal/unboundid/LDAPInterfaceProxyFactoryTest.java (100%) create mode 100644 embedded-ldap-core/src/test/resources/custom-schema.ldif create mode 100644 embedded-ldap-core/src/test/resources/example.ldif create mode 100644 embedded-ldap-core/src/test/resources/folder with space/example.ldif create mode 100644 embedded-ldap-core/src/test/resources/folder/.placeholder create mode 100644 embedded-ldap-core/src/test/resources/invalid.ldif create mode 100644 embedded-ldap-core/src/test/resources/standard-schema.ldif diff --git a/embedded-ldap-core/pom.xml b/embedded-ldap-core/pom.xml index 60a0918..dde3d64 100644 --- a/embedded-ldap-core/pom.xml +++ b/embedded-ldap-core/pom.xml @@ -33,5 +33,25 @@ slf4j-api ${slf4j.version} + + + + junit + junit + ${junit.version} + test + + + org.bouncycastle + bcprov-jdk15on + ${bouncycastle.version} + test + + + org.bouncycastle + bcpkix-jdk15on + ${bouncycastle.version} + test + diff --git a/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilderTest.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilderTest.java new file mode 100644 index 0000000..9754cb4 --- /dev/null +++ b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilderTest.java @@ -0,0 +1,88 @@ +package org.zapodot.junit.ldap.internal; + +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; + +public class AbstractEmbeddedLdapBuilderTest { + + @Test + public void bindingToLegalPort() { + assertNotNull(FakeEmbeddedLdapBuilder.newInstance().bindingToPort(9999)); + } + + @Test(expected = IllegalStateException.class) + public void testPrematureLdapConnection() throws Exception { + FakeEmbeddedLdapBuilder.newInstance().build().ldapConnection(); + + } + + @Test(expected = IllegalStateException.class) + public void testPrematureContext() throws Exception { + FakeEmbeddedLdapBuilder.newInstance().build().context(); + + } + + @Test(expected = IllegalArgumentException.class) + public void testUnknownLDIF() { + FakeEmbeddedLdapBuilder.newInstance().importingLdifs("nonExisting.ldif").build(); + + } + + @Test + public void testNullLDIF() { + assertNotNull(FakeEmbeddedLdapBuilder.newInstance().importingLdifs(null).build()); + + } + + @Test(expected = IllegalStateException.class) + public void testIllegalDSN() { + FakeEmbeddedLdapBuilder.newInstance().usingBindDSN("bindDsn").build(); + + } + + @Test(expected = IllegalArgumentException.class) + public void testIllegalPort() { + FakeEmbeddedLdapBuilder.newInstance().bindingToPort(Integer.MIN_VALUE).build(); + + } + + @Test(expected = IllegalArgumentException.class) + public void testSchemaNotFound() { + FakeEmbeddedLdapBuilder.newInstance().withSchema("non-existing-schema.ldif").build(); + + } + + @Test(expected = IllegalArgumentException.class) + public void testSchemaIsNotAFile() { + FakeEmbeddedLdapBuilder.newInstance().withSchema("folder").build(); + + } + + @Test(expected = IllegalArgumentException.class) + public void testSchemaIsInvalid() { + FakeEmbeddedLdapBuilder.newInstance().withSchema("invalid.ldif").build(); + + } + + @Test(expected = IllegalArgumentException.class) + public void testSchemaFileUnsupportedIsInvalid() { + FakeEmbeddedLdapBuilder.newInstance().withSchema("\"#%¤&&%/¤##¤¤").build(); + + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidPort() { + FakeEmbeddedLdapBuilder.newInstance().bindingToPort(Integer.MAX_VALUE); + + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidBindAddress() { + FakeEmbeddedLdapBuilder.newInstance().bindingToAddress("åpsldfåpl"); + + } + + +} + diff --git a/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/internal/AuthenticationConfigurationTest.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/AuthenticationConfigurationTest.java similarity index 100% rename from embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/internal/AuthenticationConfigurationTest.java rename to embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/AuthenticationConfigurationTest.java diff --git a/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomSchemaDuplicatedTest.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomSchemaDuplicatedTest.java new file mode 100644 index 0000000..2afa57d --- /dev/null +++ b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomSchemaDuplicatedTest.java @@ -0,0 +1,35 @@ +package org.zapodot.junit.ldap.internal; + +import com.unboundid.ldap.sdk.LDAPException; +import com.unboundid.ldap.sdk.schema.AttributeTypeDefinition; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.zapodot.junit.ldap.EmbeddedLdapServer; + +import static org.junit.Assert.assertNotNull; + +public class EmbeddedLdapServerCustomSchemaDuplicatedTest { + + private final EmbeddedLdapServer embeddedLdapRule = FakeEmbeddedLdapBuilder.newInstance() + .withSchema("standard-schema.ldif") + .build(); + + @Before + public void setup() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).startEmbeddedLdapServer(); + } + + @After + public void teardown() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).takeDownEmbeddedLdapServer(); + } + + @Test + public void testFindCustomAttribute() throws Exception { + final AttributeTypeDefinition changelogAttribute = + embeddedLdapRule.ldapConnection().getSchema().getAttributeType("changelog"); + assertNotNull(changelogAttribute); + + } +} diff --git a/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomStandardAndCustomSchemaTest.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomStandardAndCustomSchemaTest.java new file mode 100644 index 0000000..eba39eb --- /dev/null +++ b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomStandardAndCustomSchemaTest.java @@ -0,0 +1,37 @@ +package org.zapodot.junit.ldap.internal; + +import com.unboundid.ldap.sdk.LDAPException; +import com.unboundid.ldap.sdk.schema.AttributeTypeDefinition; +import com.unboundid.ldap.sdk.schema.Schema; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.zapodot.junit.ldap.EmbeddedLdapServer; + +import static org.junit.Assert.assertNotNull; + +public class EmbeddedLdapServerCustomStandardAndCustomSchemaTest { + + private final EmbeddedLdapServer embeddedLdapRule = FakeEmbeddedLdapBuilder.newInstance() + .withSchema("custom-schema.ldif") + .build(); + + @Before + public void setup() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).startEmbeddedLdapServer(); + } + + @After + public void teardown() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).takeDownEmbeddedLdapServer(); + } + + @Test + public void testFindCustomAttribute() throws Exception { + final Schema currentSchema = embeddedLdapRule.ldapConnection().getSchema(); + final AttributeTypeDefinition changelogAttribute = + currentSchema.getAttributeType("attribute"); + assertNotNull(changelogAttribute); + assertNotNull(currentSchema.getObjectClass("type")); + } +} diff --git a/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomWithoutSchemaTest.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomWithoutSchemaTest.java new file mode 100644 index 0000000..3daaceb --- /dev/null +++ b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomWithoutSchemaTest.java @@ -0,0 +1,35 @@ +package org.zapodot.junit.ldap.internal; + +import com.unboundid.ldap.sdk.LDAPException; +import com.unboundid.ldap.sdk.schema.Schema; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.zapodot.junit.ldap.EmbeddedLdapServer; + +import static org.junit.Assert.assertTrue; + +public class EmbeddedLdapServerCustomWithoutSchemaTest { + + private final EmbeddedLdapServer embeddedLdapRule = FakeEmbeddedLdapBuilder.newInstance() + .withoutDefaultSchema() + .build(); + + @Before + public void setup() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).startEmbeddedLdapServer(); + } + + @After + public void teardown() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).takeDownEmbeddedLdapServer(); + } + + @Test + public void testEmptySchema() throws Exception { + final Schema schema = + embeddedLdapRule.ldapConnection().getSchema(); + assertTrue(schema.getAttributeTypes().isEmpty()); + + } +} diff --git a/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomWithoutStandardSchemaTest.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomWithoutStandardSchemaTest.java new file mode 100644 index 0000000..84e8639 --- /dev/null +++ b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerCustomWithoutStandardSchemaTest.java @@ -0,0 +1,36 @@ +package org.zapodot.junit.ldap.internal; + +import com.unboundid.ldap.sdk.LDAPException; +import com.unboundid.ldap.sdk.schema.AttributeTypeDefinition; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.zapodot.junit.ldap.EmbeddedLdapServer; + +import static org.junit.Assert.assertNotNull; + +public class EmbeddedLdapServerCustomWithoutStandardSchemaTest { + + private final EmbeddedLdapServer embeddedLdapRule = FakeEmbeddedLdapBuilder.newInstance() + .withoutDefaultSchema() + .withSchema("standard-schema.ldif") + .build(); + + @Before + public void setup() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).startEmbeddedLdapServer(); + } + + @After + public void teardown() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).takeDownEmbeddedLdapServer(); + } + + @Test + public void testFindCustomAttribute() throws Exception { + final AttributeTypeDefinition changelogAttribute = + embeddedLdapRule.ldapConnection().getSchema().getAttributeType("changelog"); + assertNotNull(changelogAttribute); + + } +} diff --git a/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerMultipleDSNs.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerMultipleDSNs.java new file mode 100644 index 0000000..7ec4dab --- /dev/null +++ b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerMultipleDSNs.java @@ -0,0 +1,40 @@ +package org.zapodot.junit.ldap.internal; + +import com.unboundid.ldap.sdk.LDAPException; +import com.unboundid.ldap.sdk.LDAPInterface; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.zapodot.junit.ldap.EmbeddedLdapServer; + +import static org.junit.Assert.assertArrayEquals; + +public class EmbeddedLdapServerMultipleDSNs { + + public static final String DSN_ROOT_ONE = "dc=zapodot,dc=com"; + public static final String DSN_ROOT_TWO = "dc=zapodot,dc=org"; + + private final EmbeddedLdapServer embeddedLdapRule = FakeEmbeddedLdapBuilder.newInstance() + .usingDomainDsn(DSN_ROOT_ONE) + .usingDomainDsn(DSN_ROOT_TWO) + .importingLdifs("example.ldif") + .build(); + + @Before + public void setup() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).startEmbeddedLdapServer(); + } + + @After + public void teardown() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).takeDownEmbeddedLdapServer(); + } + + @Test + public void testCheckNamingContexts() throws Exception { + final LDAPInterface ldapConnection = embeddedLdapRule.ldapConnection(); + final String[] namingContextDNs = ldapConnection.getRootDSE().getNamingContextDNs(); + assertArrayEquals(new String[]{DSN_ROOT_ONE, DSN_ROOT_TWO}, namingContextDNs); + + } +} diff --git a/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerNoAuthTest.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerNoAuthTest.java new file mode 100644 index 0000000..39e5fe3 --- /dev/null +++ b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerNoAuthTest.java @@ -0,0 +1,35 @@ +package org.zapodot.junit.ldap.internal; + +import com.unboundid.ldap.sdk.LDAPException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.zapodot.junit.ldap.EmbeddedLdapServer; + +import static org.junit.Assert.assertNotNull; + +public class EmbeddedLdapServerNoAuthTest { + + private final EmbeddedLdapServer embeddedLdapRule = FakeEmbeddedLdapBuilder + .newInstance() + .usingBindCredentials(null) + .usingDomainDsn("dc=zapodot,dc=org") + .importingLdifs("example.ldif") + .build(); + + @Before + public void setup() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).startEmbeddedLdapServer(); + } + + @After + public void teardown() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).takeDownEmbeddedLdapServer(); + } + + @Test + public void testConnect() throws Exception { + assertNotNull(embeddedLdapRule.dirContext().search("cn=Sondre Eikanger Kvalo,ou=people,dc=zapodot,dc=org", null)); + + } +} diff --git a/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerStandardContext.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerStandardContext.java new file mode 100644 index 0000000..1848975 --- /dev/null +++ b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerStandardContext.java @@ -0,0 +1,33 @@ +package org.zapodot.junit.ldap.internal; + +import com.unboundid.ldap.sdk.LDAPException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.zapodot.junit.ldap.EmbeddedLdapServer; + +import static org.junit.Assert.assertArrayEquals; + +public class EmbeddedLdapServerStandardContext { + + private final EmbeddedLdapServer embeddedLdapRule = FakeEmbeddedLdapBuilder.newInstance() + .build(); + + @Before + public void setup() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).startEmbeddedLdapServer(); + } + + @After + public void teardown() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).takeDownEmbeddedLdapServer(); + } + + @Test + public void testUsingDefaultDomain() throws Exception { + assertArrayEquals(new String[]{FakeEmbeddedLdapBuilder.DEFAULT_DOMAIN}, + embeddedLdapRule.ldapConnection().getRootDSE().getNamingContextDNs()); + + + } +} diff --git a/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerStarttlsTest.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerStarttlsTest.java new file mode 100644 index 0000000..a19a991 --- /dev/null +++ b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerStarttlsTest.java @@ -0,0 +1,151 @@ +package org.zapodot.junit.ldap.internal; + +import com.unboundid.ldap.listener.InMemoryListenerConfig; +import com.unboundid.ldap.sdk.*; +import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.zapodot.junit.ldap.EmbeddedLdapServer; + +import javax.net.ssl.*; +import java.io.IOException; +import java.math.BigInteger; +import java.net.InetAddress; +import java.security.*; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; + +import static org.junit.Assert.assertNotNull; + +public class EmbeddedLdapServerStarttlsTest { + + public static final String DOMAIN_DSN = "dc=zapodot,dc=org"; + + final SSLContext sslContext; + { + try { + sslContext = buildSslContext(); + } catch (Exception e) { + throw new IllegalStateException("Failed to create LDAPS config", e); + } + } + + private final EmbeddedLdapServer embeddedLdapRule = FakeEmbeddedLdapBuilder + .newInstance() + .usingDomainDsn(DOMAIN_DSN) + .importingLdifs("example.ldif") + .withListener(getListenerConfig()) + .build(); + + @Before + public void setup() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).startEmbeddedLdapServer(); + } + + @After + public void teardown() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).takeDownEmbeddedLdapServer(); + } + + private InMemoryListenerConfig getListenerConfig() { + try { + return InMemoryListenerConfig.createLDAPConfig( + "tls", InetAddress.getLoopbackAddress(), 0, sslContext.getSocketFactory() + ); + } catch (Exception e) { + throw new IllegalStateException("Failed to create LDAPS config", e); + } + } + + @Test + public void testRawLdapConnection() throws Exception { + final String commonName = "Test person"; + final String dn = String.format( + "cn=%s,ou=people,dc=zapodot,dc=org", + commonName); + LDAPConnection ldapConnection = embeddedLdapRule.unsharedLdapConnection(); + ldapConnection.processExtendedOperation(new StartTLSExtendedRequest(sslContext)); + try { + ldapConnection.add(new AddRequest(dn, Arrays.asList( + new Attribute("objectclass", "top", "person", "organizationalPerson", "inetOrgPerson"), + new Attribute("cn", commonName), new Attribute("sn", "Person"), new Attribute("uid", "test")))); + } finally { + // Forces the LDAP connection to be closed. This is not necessary as the rule will usually close it for you. + ldapConnection.close(); + } + ldapConnection = embeddedLdapRule.unsharedLdapConnection(); + final SearchResultEntry entry = ldapConnection.searchForEntry(new SearchRequest(dn, + SearchScope.BASE, + "(objectClass=person)")); + assertNotNull(entry); + } + + public static SSLContext buildSslContext() + throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, + UnrecoverableKeyException, KeyManagementException, OperatorCreationException { + KeyStore keystore = KeyStore.getInstance("jks"); + keystore.load(null, new char[] {}); + KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA"); + gen.initialize(2014); + final KeyPair keyPair = gen.generateKeyPair(); + + Provider bcProvider = new BouncyCastleProvider(); + Security.addProvider(bcProvider); + + long now = System.currentTimeMillis(); + Date startDate = new Date(now); + + org.bouncycastle.asn1.x500.X500Name dn = new org.bouncycastle.asn1.x500.X500Name("cn=localhost"); + BigInteger sn = new BigInteger(Long.toString(now)); + + Calendar calendar = Calendar.getInstance(); + calendar.setTime(startDate); + calendar.add(Calendar.HOUR, 1); + Date endDate = calendar.getTime(); + + String signatureAlgorithm = "SHA256WithRSA"; + + final ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).build(keyPair.getPrivate()); + + final X509CertificateHolder holder = + new JcaX509v3CertificateBuilder(dn, sn, startDate, endDate, dn, keyPair.getPublic()) + .addExtension(new ASN1ObjectIdentifier("2.5.29.19"), true, new BasicConstraints(true)) + .build(contentSigner); + final X509Certificate cert = new JcaX509CertificateConverter() + .setProvider(bcProvider) + .getCertificate(holder); + keystore.setCertificateEntry("test", cert); + keystore.setKeyEntry("key", keyPair.getPrivate(), new char[] {}, new Certificate[] { cert }); + + final KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmfactory.init(keystore, new char[] {}); + final KeyManager[] kms = kmfactory.getKeyManagers(); + + KeyStore truststore = KeyStore.getInstance("jks"); + truststore.load(null, new char[] {}); + truststore.setCertificateEntry("test", cert); + + final TrustManagerFactory tmfactory = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm() + ); + tmfactory.init(truststore); + final TrustManager[] tms = tmfactory.getTrustManagers(); + final SSLContext sslcontext = SSLContext.getInstance("TLS"); + sslcontext.init(kms, tms, null); + return sslcontext; + } +} diff --git a/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerTest.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerTest.java new file mode 100644 index 0000000..7267fcf --- /dev/null +++ b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerTest.java @@ -0,0 +1,104 @@ +package org.zapodot.junit.ldap.internal; + +import com.google.common.collect.Iterators; +import com.unboundid.ldap.sdk.*; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.zapodot.junit.ldap.EmbeddedLdapServer; + +import javax.naming.Context; +import javax.naming.NamingEnumeration; +import javax.naming.directory.DirContext; +import javax.naming.directory.SearchControls; +import java.util.Arrays; + +import static org.junit.Assert.*; + +public class EmbeddedLdapServerTest { + + public static final String DOMAIN_DSN = "dc=zapodot,dc=org"; + + private final EmbeddedLdapServer embeddedLdapRule = FakeEmbeddedLdapBuilder + .newInstance() + .usingDomainDsn(DOMAIN_DSN) + .importingLdifs("example.ldif") + .build(); + + @Before + public void setup() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).startEmbeddedLdapServer(); + } + + @After + public void teardown() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).takeDownEmbeddedLdapServer(); + } + + @Test + public void testLdapConnection() throws Exception { + final LDAPInterface ldapConnection = embeddedLdapRule.ldapConnection(); + final SearchResult searchResult = ldapConnection.search(DOMAIN_DSN, SearchScope.SUB, "(objectClass=person)"); + assertEquals(1, searchResult.getEntryCount()); + } + + @Test + public void testRawLdapConnection() throws Exception { + final String commonName = "Test person"; + final String dn = String.format( + "cn=%s,ou=people,dc=zapodot,dc=org", + commonName); + LDAPConnection ldapConnection = embeddedLdapRule.unsharedLdapConnection(); + try { + ldapConnection.add(new AddRequest(dn, Arrays.asList( + new Attribute("objectclass", "top", "person", "organizationalPerson", "inetOrgPerson"), + new Attribute("cn", commonName), new Attribute("sn", "Person"), new Attribute("uid", "test")))); + } finally { + // Forces the LDAP connection to be closed. This is not necessary as the rule will usually close it for you. + ldapConnection.close(); + } + ldapConnection = embeddedLdapRule.unsharedLdapConnection(); + final SearchResultEntry entry = ldapConnection.searchForEntry(new SearchRequest(dn, + SearchScope.BASE, + "(objectClass=person)")); + assertNotNull(entry); + } + + @Test + public void testDirContext() throws Exception { + final DirContext dirContext = embeddedLdapRule.dirContext(); + final SearchControls searchControls = new SearchControls(); + searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); + final NamingEnumeration resultNamingEnumeration = + dirContext.search(DOMAIN_DSN, "(objectClass=person)", searchControls); + assertEquals(1, Iterators.size(Iterators.forEnumeration(resultNamingEnumeration))); + } + + @Test + public void testContext() throws Exception { + final Context context = embeddedLdapRule.context(); + final Object user = context.lookup("cn=Sondre Eikanger Kvalo,ou=people,dc=zapodot,dc=org"); + assertNotNull(user); + } + + @Test + public void testContextClose() throws Exception { + final Context context = embeddedLdapRule.context(); + context.close(); + assertNotNull(context.getNameInNamespace()); + + } + + @Test + public void testEmbeddedServerPort() throws Exception { + assertTrue(embeddedLdapRule.embeddedServerPort() > 0); + + } + + @Test(expected = IllegalStateException.class) + public void testNoPortAssignedYet() throws Exception { + final EmbeddedLdapServer embeddedLdapRule = new FakeEmbeddedLdapBuilder().build(); + embeddedLdapRule.embeddedServerPort(); + + } +} diff --git a/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerWithListeningAddressProvidedTest.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerWithListeningAddressProvidedTest.java new file mode 100644 index 0000000..f653ca5 --- /dev/null +++ b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerWithListeningAddressProvidedTest.java @@ -0,0 +1,46 @@ +package org.zapodot.junit.ldap.internal; + +import com.unboundid.ldap.sdk.LDAPException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.zapodot.junit.ldap.EmbeddedLdapServer; + +import java.net.InetAddress; + +import static org.junit.Assert.assertEquals; + +public class EmbeddedLdapServerWithListeningAddressProvidedTest { + + public static InetAddress inetAddress; + + private final EmbeddedLdapServer embeddedLdapRule = FakeEmbeddedLdapBuilder + .newInstance() + .usingDomainDsn("dc=zapodot,dc=org") + .importingLdifs("example.ldif") + .bindingToAddress(inetAddress.getHostAddress()) + .build(); + + @Before + public void setup() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).startEmbeddedLdapServer(); + } + + @After + public void teardown() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).takeDownEmbeddedLdapServer(); + } + + @BeforeClass + public static void setupAddress() throws Exception { + inetAddress = InetAddress.getLocalHost(); + } + + @Test + public void testLookupAddress() throws Exception { + assertEquals(inetAddress.getHostAddress(), + embeddedLdapRule.unsharedLdapConnection().getConnectedAddress()); + + } +} diff --git a/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerWithSpacesTest.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerWithSpacesTest.java new file mode 100644 index 0000000..7b5ec78 --- /dev/null +++ b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/EmbeddedLdapServerWithSpacesTest.java @@ -0,0 +1,34 @@ +package org.zapodot.junit.ldap.internal; + +import com.unboundid.ldap.sdk.LDAPException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.zapodot.junit.ldap.EmbeddedLdapServer; + +import static org.junit.Assert.assertNotNull; + +public class EmbeddedLdapServerWithSpacesTest { + + private final EmbeddedLdapServer embeddedLdapRule = FakeEmbeddedLdapBuilder + .newInstance() + .usingDomainDsn("dc=zapodot,dc=org") + .importingLdifs("folder with space/example.ldif") + .build(); + + @Before + public void setup() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).startEmbeddedLdapServer(); + } + + @After + public void teardown() throws LDAPException { + ((EmbeddedLdapServerImpl) embeddedLdapRule).takeDownEmbeddedLdapServer(); + } + + @Test + public void testIsUp() throws Exception { + assertNotNull(embeddedLdapRule.ldapConnection().getRootDSE()); + + } +} diff --git a/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/FakeEmbeddedLdapBuilder.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/FakeEmbeddedLdapBuilder.java new file mode 100644 index 0000000..04ceae4 --- /dev/null +++ b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/FakeEmbeddedLdapBuilder.java @@ -0,0 +1,32 @@ +package org.zapodot.junit.ldap.internal; + +import com.unboundid.ldap.listener.InMemoryDirectoryServer; +import com.unboundid.ldap.sdk.LDAPException; +import org.zapodot.junit.ldap.EmbeddedLdapServer; + +import static org.zapodot.junit.ldap.internal.EmbeddedLdapServerImpl.createServer; + +class FakeEmbeddedLdapBuilder extends AbstractEmbeddedLdapBuilder { + + static FakeEmbeddedLdapBuilder newInstance() { + return new FakeEmbeddedLdapBuilder(); + } + + @Override + protected FakeEmbeddedLdapBuilder getThis() { + return this; + } + + EmbeddedLdapServer build() { + try { + InMemoryDirectoryServer server = createServer(createInMemoryServerConfiguration(), ldifsToImport); + return new EmbeddedLdapServerImpl( + server, + authenticationConfiguration) { + + }; + } catch (LDAPException e) { + throw new IllegalStateException("Can not initiate in-memory LDAP server due to an exception", e); + } + } +} diff --git a/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/internal/jndi/ContextProxyFactoryTest.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/jndi/ContextProxyFactoryTest.java similarity index 100% rename from embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/internal/jndi/ContextProxyFactoryTest.java rename to embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/jndi/ContextProxyFactoryTest.java diff --git a/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/internal/unboundid/LDAPInterfaceProxyFactoryTest.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/unboundid/LDAPInterfaceProxyFactoryTest.java similarity index 100% rename from embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/internal/unboundid/LDAPInterfaceProxyFactoryTest.java rename to embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/unboundid/LDAPInterfaceProxyFactoryTest.java diff --git a/embedded-ldap-core/src/test/resources/custom-schema.ldif b/embedded-ldap-core/src/test/resources/custom-schema.ldif new file mode 100644 index 0000000..552eeca --- /dev/null +++ b/embedded-ldap-core/src/test/resources/custom-schema.ldif @@ -0,0 +1,7 @@ +dn: cn=custom-schema +objectClass: top +objectClass: ldapSubEntry +objectClass: subschema +cn: custom-schema +attributeTypes: ( 1.3.6.1.4.1.41609.1.75 NAME 'attribute' DESC 'A simple attribute' SUP name SINGLE-VALUE ) +objectClasses: ( 1.3.6.1.4.1.41609.2.13 NAME 'type' DESC 'A simple objectClass' SUP top STRUCTURAL MUST ( cn $ attribute ) MAY ( description ) ) diff --git a/embedded-ldap-core/src/test/resources/example.ldif b/embedded-ldap-core/src/test/resources/example.ldif new file mode 100644 index 0000000..5eb286a --- /dev/null +++ b/embedded-ldap-core/src/test/resources/example.ldif @@ -0,0 +1,28 @@ +version: 1 + +dn: dc=zapodot,dc=org +objectClass: domain +objectClass: top +dc: zapodot + +dn: ou=groups,dc=zapodot,dc=org +objectclass: top +objectclass: organizationalUnit +ou: groups + +dn: ou=people,dc=zapodot,dc=org +objectclass: top +objectclass: organizationalUnit +ou: people + +dn: cn=Sondre Eikanger Kvalo,ou=people,dc=zapodot,dc=org +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: zapodot +userPassword: password +cn: Sondre Eikanger Kvalo +cn:: U29uZHJlIEVpa2FuZ2VyIEt2YWzDuA== +sn: Person +description: Developer \ No newline at end of file diff --git a/embedded-ldap-core/src/test/resources/folder with space/example.ldif b/embedded-ldap-core/src/test/resources/folder with space/example.ldif new file mode 100644 index 0000000..5eb286a --- /dev/null +++ b/embedded-ldap-core/src/test/resources/folder with space/example.ldif @@ -0,0 +1,28 @@ +version: 1 + +dn: dc=zapodot,dc=org +objectClass: domain +objectClass: top +dc: zapodot + +dn: ou=groups,dc=zapodot,dc=org +objectclass: top +objectclass: organizationalUnit +ou: groups + +dn: ou=people,dc=zapodot,dc=org +objectclass: top +objectclass: organizationalUnit +ou: people + +dn: cn=Sondre Eikanger Kvalo,ou=people,dc=zapodot,dc=org +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: zapodot +userPassword: password +cn: Sondre Eikanger Kvalo +cn:: U29uZHJlIEVpa2FuZ2VyIEt2YWzDuA== +sn: Person +description: Developer \ No newline at end of file diff --git a/embedded-ldap-core/src/test/resources/folder/.placeholder b/embedded-ldap-core/src/test/resources/folder/.placeholder new file mode 100644 index 0000000..e69de29 diff --git a/embedded-ldap-core/src/test/resources/invalid.ldif b/embedded-ldap-core/src/test/resources/invalid.ldif new file mode 100644 index 0000000..bbd8c77 --- /dev/null +++ b/embedded-ldap-core/src/test/resources/invalid.ldif @@ -0,0 +1,2 @@ +zndskjnckjdsn +daf diff --git a/embedded-ldap-core/src/test/resources/standard-schema.ldif b/embedded-ldap-core/src/test/resources/standard-schema.ldif new file mode 100644 index 0000000..063a7d8 --- /dev/null +++ b/embedded-ldap-core/src/test/resources/standard-schema.ldif @@ -0,0 +1,1546 @@ +# Retrieved from the UnboundID LDAP SDK repository http://sourceforge.net/p/ldap-sdk/code/HEAD/tree/trunk/resource/standard-schema.ldif +# This file contains a set of standard schema definitions from various RFCs and +# Internet Drafts. It is not intended to be a complete comprehensive schema +# for all purposes, but it may be used by the LDAP SDK for cases in which +# schema information may be required and no other definitions are available. +# +# Definitions in this class come from the following sources: +# * RFC 2798: +# Definition of the inetOrgPerson LDAP Object Class +# * RFC 3045: +# Storing Vendor Information in the LDAP Root DSE +# * RFC 3112: +# LDAP Authentication Password Schema +# * RFC 3296: +# Named Subordinate References in LDAP Directories +# * RFC 4512: +# LDAP Directory Information Models +# * RFC 4519: +# LDAP Schema for User Applications +# * RFC 4523: +# LDAP Schema Definitions for X.509 Certificates +# * RFC 4524: +# COSINE LDAP/X.500 Schema +# * RFC 4530: +# LDAP entryUUID Operational Attribute +# * RFC 5020: +# The LDAP entryDN Operational Attribute +# * draft-good-ldap-changelog: +# Definition of an Object Class to Hold LDAP Change Records +# * draft-howard-namedobject: +# A Structural Object Class for Arbitrary Auxiliary Object Classes +# * draft-ietf-boreham-numsubordinates: +# numSubordinates LDAP Operational Attribute +# * draft-ietf-ldup-subentry: +# LDAP Subentry Schema +dn: cn=schema +objectClass: top +objectClass: ldapSubEntry +objectClass: subschema +cn: schema +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.3 + DESC 'Attribute Type Description' + X-ORIGIN 'RFC 4517' ) +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.6 + DESC 'Bit String' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.7 + DESC 'Boolean' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.11 + DESC 'Country String' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.14 + DESC 'Delivery Method' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.15 + DESC 'Directory String' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.16 + DESC 'DIT Content Rule Description' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.17 + DESC 'DIT Structure Rule Description' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.12 + DESC 'DN' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.21 + DESC 'Enhanced Guide' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.22 + DESC 'Facsimile Telephone Number' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.23 + DESC 'Fax' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.24 + DESC 'Generalized Time' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.25 + DESC 'Guide' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.26 + DESC 'IA5 String' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.27 + DESC 'INTEGER' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.28 + DESC 'JPEG' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.54 + DESC 'LDAP Syntax Description' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.30 + DESC 'Matching Rule Description' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.31 + DESC 'Matching Rule Use Description' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.34 + DESC 'Name And Optional UID' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.35 + DESC 'Name Form Description' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.36 + DESC 'Numeric String' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.37 + DESC 'Object Class Description' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.40 + DESC 'Octet String' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.38 + DESC 'OID' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.39 + DESC 'Other Mailbox' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.41 + DESC 'Postal Address' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.44 + DESC 'Printable String' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.58 + DESC 'Substring Assertion' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.50 + DESC 'Telephone Number' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.51 + DESC 'Teletex Terminal Identifier' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.52 + DESC 'Telex Number' + X-ORIGIN 'RFC 4517') +ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.53 + DESC 'UTC Time' + X-ORIGIN 'RFC 4517') +matchingRules: ( 2.5.13.16 + NAME 'bitStringMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.13 + NAME 'booleanMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 1.3.6.1.4.1.1466.109.114.1 + NAME 'caseExactIA5Match' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.5 + NAME 'caseExactMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.6 + NAME 'caseExactOrderingMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.7 + NAME 'caseExactSubstringsMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 1.3.6.1.4.1.1466.109.114.2 + NAME 'caseIgnoreIA5Match' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 1.3.6.1.4.1.1466.109.114.3 + NAME 'caseIgnoreIA5SubstringsMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.11 + NAME 'caseIgnoreListMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.12 + NAME 'caseIgnoreListSubstringsMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.2 + NAME 'caseIgnoreMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.3 + NAME 'caseIgnoreOrderingMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.4 + NAME 'caseIgnoreSubstringsMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.31 + NAME 'directoryStringFirstComponentMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.1 + NAME 'distinguishedNameMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.27 + NAME 'generalizedTimeMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.28 + NAME 'generalizedTimeOrderingMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.29 + NAME 'integerFirstComponentMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.14 + NAME 'integerMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.15 + NAME 'integerOrderingMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.33 + NAME 'keywordMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.8 + NAME 'numericStringMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.9 + NAME 'numericStringOrderingMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.10 + NAME 'numericStringSubstringsMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.30 + NAME 'objectIdentifierFirstComponentMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.0 + NAME 'objectIdentifierMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.17 + NAME 'octetStringMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.18 + NAME 'octetStringOrderingMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.20 + NAME 'telephoneNumberMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.21 + NAME 'telephoneNumberSubstringsMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.23 + NAME 'uniqueMemberMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 + X-ORIGIN 'RFC 4517' ) +matchingRules: ( 2.5.13.32 + NAME 'wordMatch' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4517' ) +attributeTypes: ( 2.5.4.0 + NAME 'objectClass' + EQUALITY objectIdentifierMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.4.1 + NAME 'aliasedObjectName' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.18.3 + NAME 'creatorsName' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE directoryOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.18.1 + NAME 'createTimestamp' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE directoryOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.18.4 + NAME 'modifiersName' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE directoryOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.18.2 + NAME 'modifyTimestamp' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE directoryOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.21.9 + NAME 'structuralObjectClass' + EQUALITY objectIdentifierMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE directoryOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.21.10 + NAME 'governingStructureRule' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE directoryOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.18.10 + NAME 'subschemaSubentry' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE directoryOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.21.6 + NAME 'objectClasses' + EQUALITY objectIdentifierFirstComponentMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.37 + USAGE directoryOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.21.5 + NAME 'attributeTypes' + EQUALITY objectIdentifierFirstComponentMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.3 + USAGE directoryOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.21.4 + NAME 'matchingRules' + EQUALITY objectIdentifierFirstComponentMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.30 + USAGE directoryOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.21.8 + NAME 'matchingRuleUse' + EQUALITY objectIdentifierFirstComponentMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.31 + USAGE directoryOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 1.3.6.1.4.1.1466.101.120.16 + NAME 'ldapSyntaxes' + EQUALITY objectIdentifierFirstComponentMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.54 + USAGE directoryOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.21.2 + NAME 'dITContentRules' + EQUALITY objectIdentifierFirstComponentMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.16 + USAGE directoryOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.21.1 + NAME 'dITStructureRules' + EQUALITY integerFirstComponentMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.17 + USAGE directoryOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.21.7 + NAME 'nameForms' + EQUALITY objectIdentifierFirstComponentMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.35 + USAGE directoryOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 1.3.6.1.4.1.1466.101.120.6 + NAME 'altServer' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + USAGE dSAOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 1.3.6.1.4.1.1466.101.120.5 + NAME 'namingContexts' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + USAGE dSAOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 1.3.6.1.4.1.1466.101.120.13 + NAME 'supportedControl' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 + USAGE dSAOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 1.3.6.1.4.1.1466.101.120.7 + NAME 'supportedExtension' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 + USAGE dSAOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 1.3.6.1.4.1.4203.1.3.5 + NAME 'supportedFeatures' + EQUALITY objectIdentifierMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 + USAGE dSAOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 1.3.6.1.4.1.1466.101.120.15 + NAME 'supportedLDAPVersion' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + USAGE dSAOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 1.3.6.1.4.1.1466.101.120.14 + NAME 'supportedSASLMechanisms' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + USAGE dSAOperation + X-ORIGIN 'RFC 4512' ) +attributeTypes: ( 2.5.4.41 + NAME 'name' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.15 + NAME 'businessCategory' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.6 + NAME 'c' + SUP name + SYNTAX 1.3.6.1.4.1.1466.115.121.1.11 + SINGLE-VALUE + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.3 + NAME 'cn' + SUP name + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 0.9.2342.19200300.100.1.25 + NAME 'dc' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + SINGLE-VALUE + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.13 + NAME 'description' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.27 + NAME 'destinationIndicator' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.49 + NAME 'distinguishedName' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.46 + NAME 'dnQualifier' + EQUALITY caseIgnoreMatch + ORDERING caseIgnoreOrderingMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.47 + NAME 'enhancedSearchGuide' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.21 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.23 + NAME 'facsimileTelephoneNumber' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.22 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.44 + NAME 'generationQualifier' + SUP name + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.42 + NAME 'givenName' + SUP name + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.51 + NAME 'houseIdentifier' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.43 + NAME 'initials' + SUP name + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.25 + NAME 'internationalISDNNumber' + EQUALITY numericStringMatch + SUBSTR numericStringSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.7 + NAME 'l' + SUP name + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.31 + NAME 'member' + SUP distinguishedName + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.10 + NAME 'o' + SUP name + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.11 + NAME 'ou' + SUP name + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.32 + NAME 'owner' + SUP distinguishedName + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.19 + NAME 'physicalDeliveryOfficeName' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.16 + NAME 'postalAddress' + EQUALITY caseIgnoreListMatch + SUBSTR caseIgnoreListSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.17 + NAME 'postalCode' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.18 + NAME 'postOfficeBox' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.28 + NAME 'preferredDeliveryMethod' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.14 + SINGLE-VALUE + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.26 + NAME 'registeredAddress' + SUP postalAddress + SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.33 + NAME 'roleOccupant' + SUP distinguishedName + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.14 + NAME 'searchGuide' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.25 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.34 + NAME 'seeAlso' + SUP distinguishedName + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.5 + NAME 'serialNumber' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.4 + NAME 'sn' + SUP name + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.8 + NAME 'st' + SUP name + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.9 + NAME 'street' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.20 + NAME 'telephoneNumber' + EQUALITY telephoneNumberMatch + SUBSTR telephoneNumberSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.22 + NAME 'teletexTerminalIdentifier' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.51 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.21 + NAME 'telexNumber' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.52 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.12 + NAME 'title' + SUP name + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 0.9.2342.19200300.100.1.1 + NAME 'uid' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.50 + NAME 'uniqueMember' + EQUALITY uniqueMemberMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.35 + NAME 'userPassword' + EQUALITY octetStringMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.24 + NAME 'x121Address' + EQUALITY numericStringMatch + SUBSTR numericStringSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.5.4.45 + NAME 'x500UniqueIdentifier' + EQUALITY bitStringMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 + X-ORIGIN 'RFC 4519' ) +attributeTypes: ( 2.16.840.1.113730.3.1.1 + NAME 'carLicense' + DESC 'vehicle license or registration plate' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 2798' ) +attributeTypes: ( 2.16.840.1.113730.3.1.2 + NAME 'departmentNumber' + DESC 'identifies a department within an organization' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 2798' ) +attributeTypes: ( 2.16.840.1.113730.3.1.241 + NAME 'displayName' + DESC 'preferred name of a person to be used when displaying entries' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + SINGLE-VALUE + X-ORIGIN 'RFC 2798' ) +attributeTypes: ( 2.16.840.1.113730.3.1.3 + NAME 'employeeNumber' + DESC 'numerically identifies an employee within an organization' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + SINGLE-VALUE + X-ORIGIN 'RFC 2798' ) +attributeTypes: ( 2.16.840.1.113730.3.1.4 + NAME 'employeeType' + DESC 'type of employment for a person' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 2798' ) +attributeTypes: ( 0.9.2342.19200300.100.1.60 + NAME 'jpegPhoto' + DESC 'a JPEG image' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.28 + X-ORIGIN 'RFC 2798' ) +attributeTypes: ( 2.16.840.1.113730.3.1.39 + NAME 'preferredLanguage' + DESC 'preferred written or spoken language for a person' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + SINGLE-VALUE + X-ORIGIN 'RFC 2798' ) +attributeTypes: ( 2.16.840.1.113730.3.1.40 + NAME 'userSMIMECertificate' + DESC 'PKCS#7 SignedData used to support S/MIME' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 + X-ORIGIN 'RFC 2798' ) +attributeTypes: ( 2.16.840.1.113730.3.1.216 + NAME 'userPKCS12' + DESC 'PKCS #12 PFX PDU for exchange of personal identity information' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 + X-ORIGIN 'RFC 2798' ) +attributeTypes: ( 2.5.4.36 + NAME 'userCertificate' + DESC 'X.509 user certificate' + EQUALITY certificateExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 + X-ORIGIN 'RFC 4523' ) +attributeTypes: ( 2.5.4.37 + NAME 'cACertificate' + DESC 'X.509 CA certificate' + EQUALITY certificateExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 + X-ORIGIN 'RFC 4523' ) +attributeTypes: ( 2.5.4.40 + NAME 'crossCertificatePair' + DESC 'X.509 cross certificate pair' + EQUALITY certificatePairExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.10 + X-ORIGIN 'RFC 4523' ) +attributeTypes: ( 2.5.4.39 + NAME 'certificateRevocationList' + DESC 'X.509 certificate revocation list' + EQUALITY certificateListExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 + X-ORIGIN 'RFC 4523' ) +attributeTypes: ( 2.5.4.38 + NAME 'authorityRevocationList' + DESC 'X.509 authority revocation list' + EQUALITY certificateListExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 + X-ORIGIN 'RFC 4523' ) +attributeTypes: ( 2.5.4.53 + NAME 'deltaRevocationList' + DESC 'X.509 delta revocation list' + EQUALITY certificateListExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 + X-ORIGIN 'RFC 4523' ) +attributeTypes: ( 2.5.4.52 + NAME 'supportedAlgorithms' + DESC 'X.509 supported algorithms' + EQUALITY algorithmIdentifierMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.49 + X-ORIGIN 'RFC 4523' ) +attributeTypes: ( 0.9.2342.19200300.100.1.37 + NAME 'associatedDomain' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.38 + NAME 'associatedName' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.48 + NAME 'buildingName' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.43 + NAME 'co' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.14 + NAME 'documentAuthor' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.11 + NAME 'documentIdentifier' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.15 + NAME 'documentLocation' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.56 + NAME 'documentPublisher' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.12 + NAME 'documentTitle' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.13 + NAME 'documentVersion' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.5 + NAME 'drink' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.20 + NAME 'homePhone' + EQUALITY telephoneNumberMatch + SUBSTR telephoneNumberSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.39 + NAME 'homePostalAddress' + EQUALITY caseIgnoreListMatch + SUBSTR caseIgnoreListSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.9 + NAME 'host' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.4 + NAME 'info' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{2048} + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.3 + NAME 'mail' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.10 + NAME 'manager' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.41 + NAME 'mobile' + EQUALITY telephoneNumberMatch + SUBSTR telephoneNumberSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.45 + NAME 'organizationalStatus' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.42 + NAME 'pager' + EQUALITY telephoneNumberMatch + SUBSTR telephoneNumberSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.40 + NAME 'personalTitle' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.6 + NAME 'roomNumber' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.21 + NAME 'secretary' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.44 + NAME 'uniqueIdentifier' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.8 + NAME 'userClass' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} + X-ORIGIN 'RFC 4524' ) +attributeTypes: ( 0.9.2342.19200300.100.1.55 + NAME 'audio' + EQUALITY octetStringMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{250000} + X-ORIGIN 'RFC 2798' ) +attributeTypes: ( 0.9.2342.19200300.100.1.7 + NAME 'photo' + X-ORIGIN 'RFC 2798' ) +attributeTypes: ( 1.3.6.1.4.1.250.1.57 + NAME 'labeledURI' + EQUALITY caseExactMatch + SUBSTR caseExactSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-ORIGIN 'RFC 2798' ) +attributeTypes: ( 1.3.6.1.1.20 + NAME 'entryDN' + DESC 'DN of the entry' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE directoryOperation + X-ORIGIN 'RFC 5020' ) +attributeTypes: ( 2.16.840.1.113730.3.1.34 + NAME 'ref' + DESC 'named reference - a labeledURI' + EQUALITY caseExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + USAGE distributedOperation + X-ORIGIN 'RFC 3296' ) +attributeTypes: ( 1.3.6.1.1.4 + NAME 'vendorName' + EQUALITY 1.3.6.1.4.1.1466.109.114.1 + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE dSAOperation + X-ORIGIN 'RFC 3045' ) +attributeTypes: ( 1.3.6.1.1.5 + NAME 'vendorVersion' + EQUALITY 1.3.6.1.4.1.1466.109.114.1 + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE dSAOperation + X-ORIGIN 'RFC 3045' ) +attributeTypes: ( 1.3.6.1.1.16.4 + NAME 'entryUUID' + DESC 'UUID of the entry' + EQUALITY uuidMatch + ORDERING uuidOrderingMatch + SYNTAX 1.3.6.1.1.16.1 + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE directoryOperation + X-ORIGIN 'RFC 4530' ) +attributeTypes: ( 1.3.6.1.4.1.453.16.2.103 + NAME 'numSubordinates' + DESC 'count of immediate subordinates' + EQUALITY integerMatch + ORDERING integerOrderingMatch + SYNTAX 1.3.6.1.4.1.453.16.2.103 + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE directoryOperation + X-ORIGIN 'draft-ietf-boreham-numsubordinates' ) +attributeTypes: ( 1.3.6.1.4.1.7628.5.4.1 + NAME 'inheritable' + SYNTAX BOOLEAN + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE dSAOperation + X-ORIGIN 'draft-ietf-ldup-subentry' ) +attributeTypes: ( 1.3.6.1.4.1.7628.5.4.2 + NAME 'blockInheritance' + SYNTAX BOOLEAN + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE dSAOperation + X-ORIGIN 'draft-ietf-ldup-subentry' ) +attributeTypes: ( 2.16.840.1.113730.3.1.5 + NAME 'changeNumber' + DESC 'a number which uniquely identifies a change made to a directory entry' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + EQUALITY integerMatch + ORDERING integerOrderingMatch + SINGLE-VALUE + X-ORIGIN 'draft-good-ldap-changelog' ) +attributeTypes: ( 2.16.840.1.113730.3.1.6 + NAME 'targetDN' + DESC 'the DN of the entry which was modified' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + X-ORIGIN 'draft-good-ldap-changelog' ) +attributeTypes: ( 2.16.840.1.113730.3.1.7 + NAME 'changeType' + DESC 'the type of change made to an entry' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + SINGLE-VALUE + X-ORIGIN 'draft-good-ldap-changelog' ) +attributeTypes: ( 2.16.840.1.113730.3.1.8 + NAME 'changes' + DESC 'a set of changes to apply to an entry' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 + X-ORIGIN 'draft-good-ldap-changelog' ) +attributeTypes: ( 2.16.840.1.113730.3.1.9 + NAME 'newRDN' + DESC 'the new RDN of an entry which is the target of a modrdn operation' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + X-ORIGIN 'draft-good-ldap-changelog' ) +attributeTypes: ( 2.16.840.1.113730.3.1.10 + NAME 'deleteOldRDN' + DESC 'a flag which indicates if the old RDN should be retained as an + attribute of the entry' + EQUALITY booleanMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 + SINGLE-VALUE + X-ORIGIN 'draft-good-ldap-changelog' ) +attributeTypes: ( 2.16.840.1.113730.3.1.11 + NAME 'newSuperior' + DESC 'the new parent of an entry which is the target of a moddn operation' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + X-ORIGIN 'draft-good-ldap-changelog' ) +attributeTypes: ( 2.16.840.1.113730.3.1.35 + NAME 'changelog' + DESC 'the distinguished name of the entry which contains the set of entries + comprising the server changelog' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + X-ORIGIN 'draft-good-ldap-changelog' ) +attributeTypes: ( 1.3.6.1.4.1.4203.1.3.3 + NAME 'supportedAuthPasswordSchemes' + DESC 'supported password storage schemes' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} + USAGE dSAOperation + X-ORIGIN 'RFC 3112' ) +attributeTypes: ( 1.3.6.1.4.1.4203.1.3.4 + NAME 'authPassword' + DESC 'password authentication information' + EQUALITY 1.3.6.1.4.1.4203.1.2.2 + SYNTAX 1.3.6.1.4.1.4203.1.1.2 + X-ORIGIN 'RFC 3112' ) +attributeTypes: ( 2.16.840.1.113730.3.1.55 + NAME 'aci' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + USAGE directoryOperation + X-ORIGIN 'De facto standard' ) +objectClasses: ( 2.5.6.0 + NAME 'top' + ABSTRACT + MUST objectClass + X-ORIGIN 'RFC 4512' ) +objectClasses: ( 2.5.6.1 + NAME 'alias' + SUP top + STRUCTURAL + MUST aliasedObjectName + X-ORIGIN 'RFC 4512' ) +objectClasses: ( 1.3.6.1.4.1.1466.101.120.111 + NAME 'extensibleObject' + SUP top + AUXILIARY + X-ORIGIN 'RFC 4512' ) +objectClasses: ( 2.5.20.1 + NAME 'subschema' + AUXILIARY + MAY ( dITStructureRules $ + nameForms $ + ditContentRules $ + objectClasses $ + attributeTypes $ + matchingRules $ + matchingRuleUse ) + X-ORIGIN 'RFC 4512' ) +objectClasses: ( 2.5.6.11 + NAME 'applicationProcess' + SUP top + STRUCTURAL + MUST cn + MAY ( seeAlso $ + ou $ + l $ + description ) + X-ORIGIN 'RFC 4519' ) +objectClasses: ( 2.5.6.2 + NAME 'country' + SUP top + STRUCTURAL + MUST c + MAY ( searchGuide $ + description ) + X-ORIGIN 'RFC 4519' ) +objectClasses: ( 1.3.6.1.4.1.1466.344 + NAME 'dcObject' + SUP top + AUXILIARY + MUST dc + X-ORIGIN 'RFC 4519' ) +objectClasses: ( 2.5.6.14 + NAME 'device' + SUP top + STRUCTURAL + MUST cn + MAY ( serialNumber $ + seeAlso $ + owner $ + ou $ + o $ + l $ + description ) + X-ORIGIN 'RFC 4519' ) +objectClasses: ( 2.5.6.9 + NAME 'groupOfNames' + SUP top + STRUCTURAL + MUST cn + MAY ( member $ + businessCategory $ + seeAlso $ + owner $ + ou $ + o $ + description ) + X-ORIGIN 'RFC 4519' ) +objectClasses: ( 2.5.6.17 + NAME 'groupOfUniqueNames' + SUP top + STRUCTURAL + MUST cn + MAY ( uniqueMember $ + businessCategory $ + seeAlso $ + owner $ + ou $ + o $ + description ) + X-ORIGIN 'RFC 4519' ) +objectClasses: ( 2.5.6.3 + NAME 'locality' + SUP top + STRUCTURAL + MAY ( street $ + seeAlso $ + searchGuide $ + st $ + l $ + description ) + X-ORIGIN 'RFC 4519' ) +objectClasses: ( 2.5.6.4 + NAME 'organization' + SUP top + STRUCTURAL + MUST o + MAY ( userPassword $ + searchGuide $ + seeAlso $ + businessCategory $ + x121Address $ + registeredAddress $ + destinationIndicator $ + preferredDeliveryMethod $ + telexNumber $ + teletexTerminalIdentifier $ + telephoneNumber $ + internationalISDNNumber $ + facsimileTelephoneNumber $ + street $ + postOfficeBox $ + postalCode $ + postalAddress $ + physicalDeliveryOfficeName $ + st $ + l $ + description ) + X-ORIGIN 'RFC 4519' ) +objectClasses: ( 2.5.6.6 + NAME 'person' + SUP top + STRUCTURAL + MUST ( sn $ + cn ) + MAY ( userPassword $ + telephoneNumber $ + seeAlso $ + description ) + X-ORIGIN 'RFC 4519' ) +objectClasses: ( 2.5.6.7 + NAME 'organizationalPerson' + SUP person + STRUCTURAL + MAY ( title $ + x121Address $ + registeredAddress $ + destinationIndicator $ + preferredDeliveryMethod $ + telexNumber $ + teletexTerminalIdentifier $ + telephoneNumber $ + internationalISDNNumber $ + facsimileTelephoneNumber $ + street $ + postOfficeBox $ + postalCode $ + postalAddress $ + physicalDeliveryOfficeName $ + ou $ + st $ + l ) + X-ORIGIN 'RFC 4519' ) +objectClasses: ( 2.5.6.8 + NAME 'organizationalRole' + SUP top + STRUCTURAL + MUST cn + MAY ( x121Address $ + registeredAddress $ + destinationIndicator $ + preferredDeliveryMethod $ + telexNumber $ + teletexTerminalIdentifier $ + telephoneNumber $ + internationalISDNNumber $ + facsimileTelephoneNumber $ + seeAlso $ + roleOccupant $ + preferredDeliveryMethod $ + street $ + postOfficeBox $ + postalCode $ + postalAddress $ + physicalDeliveryOfficeName $ + ou $ + st $ + l $ + description ) + X-ORIGIN 'RFC 4519' ) +objectClasses: ( 2.5.6.5 + NAME 'organizationalUnit' + SUP top + STRUCTURAL + MUST ou + MAY ( businessCategory $ + description $ + destinationIndicator $ + facsimileTelephoneNumber $ + internationalISDNNumber $ + l $ + physicalDeliveryOfficeName $ + postalAddress $ + postalCode $ + postOfficeBox $ + preferredDeliveryMethod $ + registeredAddress $ + searchGuide $ + seeAlso $ + st $ + street $ + telephoneNumber $ + teletexTerminalIdentifier $ + telexNumber $ + userPassword $ + x121Address ) + X-ORIGIN 'RFC 4519' ) +objectClasses: ( 2.5.6.10 + NAME 'residentialPerson' + SUP person + STRUCTURAL + MUST l + MAY ( businessCategory $ + x121Address $ + registeredAddress $ + destinationIndicator $ + preferredDeliveryMethod $ + telexNumber $ + teletexTerminalIdentifier $ + telephoneNumber $ + internationalISDNNumber $ + facsimileTelephoneNumber $ + preferredDeliveryMethod $ + street $ + postOfficeBox $ + postalCode $ + postalAddress $ + physicalDeliveryOfficeName $ + st $ + l ) + X-ORIGIN 'RFC 4519' ) +objectClasses: ( 1.3.6.1.1.3.1 + NAME 'uidObject' + SUP top + AUXILIARY + MUST uid + X-ORIGIN 'RFC 4519' ) +objectClasses: ( 2.16.840.1.113730.3.2.2 + NAME 'inetOrgPerson' + SUP organizationalPerson + STRUCTURAL + MAY ( audio $ + businessCategory $ + carLicense $ + departmentNumber $ + displayName $ + employeeNumber $ + employeeType $ + givenName $ + homePhone $ + homePostalAddress $ + initials $ + jpegPhoto $ + labeledURI $ + mail $ + manager $ + mobile $ + o $ + pager $ + photo $ + roomNumber $ + secretary $ + uid $ + userCertificate $ + x500uniqueIdentifier $ + preferredLanguage $ + userSMIMECertificate $ + userPKCS12 ) + X-ORIGIN 'RFC 2798' ) +objectClasses: ( 2.5.6.21 + NAME 'pkiUser' + DESC 'X.509 PKI User' + SUP top AUXILIARY + MAY userCertificate + X-ORIGIN 'RFC 4523' ) +objectClasses: ( 2.5.6.22 + NAME 'pkiCA' + DESC 'X.509 PKI Certificate Authority' + SUP top + AUXILIARY + MAY ( cACertificate $ + certificateRevocationList $ + authorityRevocationList $ + crossCertificatePair ) + X-ORIGIN 'RFC 4523' ) +objectClasses: ( 2.5.6.19 + NAME 'cRLDistributionPoint' + DESC 'X.509 CRL distribution point' + SUP top + STRUCTURAL + MUST cn + MAY ( certificateRevocationList $ + authorityRevocationList $ + deltaRevocationList ) + X-ORIGIN 'RFC 4523' ) +objectClasses: ( 2.5.6.23 + NAME 'deltaCRL' + DESC 'X.509 delta CRL' + SUP top + AUXILIARY + MAY deltaRevocationList + X-ORIGIN 'RFC 4523' ) +objectClasses: ( 2.5.6.15 + NAME 'strongAuthenticationUser' + DESC 'X.521 strong authentication user' + SUP top + AUXILIARY + MUST userCertificate + X-ORIGIN 'RFC 4523' ) +objectClasses: ( 2.5.6.18 + NAME 'userSecurityInformation' + DESC 'X.521 user security information' + SUP top + AUXILIARY + MAY ( supportedAlgorithms ) + X-ORIGIN 'RFC 4523' ) +objectClasses: ( 2.5.6.16 + NAME 'certificationAuthority' + DESC 'X.509 certificate authority' + SUP top + AUXILIARY + MUST ( authorityRevocationList $ + certificateRevocationList $ + cACertificate ) + MAY crossCertificatePair + X-ORIGIN 'RFC 4523' ) +objectClasses: ( 2.5.6.16.2 + NAME 'certificationAuthority-V2' + DESC 'X.509 certificate authority, version 2' + SUP certificationAuthority + AUXILIARY + MAY deltaRevocationList + X-ORIGIN 'RFC 4523' ) +objectClasses: ( 0.9.2342.19200300.100.4.5 + NAME 'account' + SUP top STRUCTURAL + MUST uid + MAY ( description $ + seeAlso $ + l $ + o $ + ou $ + host ) + X-ORIGIN 'RFC 4524' ) +objectClasses: ( 0.9.2342.19200300.100.4.6 + NAME 'document' + SUP top STRUCTURAL + MUST documentIdentifier + MAY ( cn $ + description $ + seeAlso $ + l $ + o $ + ou $ + documentTitle $ + documentVersion $ + documentAuthor $ + documentLocation $ + documentPublisher ) + X-ORIGIN 'RFC 4524' ) +objectClasses: ( 0.9.2342.19200300.100.4.9 + NAME 'documentSeries' + SUP top STRUCTURAL + MUST cn + MAY ( description $ + l $ + o $ + ou $ + seeAlso $ + telephonenumber ) + X-ORIGIN 'RFC 4524' ) +objectClasses: ( 0.9.2342.19200300.100.4.13 + NAME 'domain' + SUP top + STRUCTURAL + MUST dc + MAY ( userPassword $ + searchGuide $ + seeAlso $ + businessCategory $ + x121Address $ + registeredAddress $ + destinationIndicator $ + preferredDeliveryMethod $ + telexNumber $ + teletexTerminalIdentifier $ + telephoneNumber $ + internationaliSDNNumber $ + facsimileTelephoneNumber $ + street $ + postOfficeBox $ + postalCode $ + postalAddress $ + physicalDeliveryOfficeName $ + st $ + l $ + description $ + o $ + associatedName ) + X-ORIGIN 'RFC 4524' ) +objectClasses: ( 0.9.2342.19200300.100.4.17 + NAME 'domainRelatedObject' + SUP top + AUXILIARY + MUST associatedDomain + X-ORIGIN 'RFC 4524' ) +objectClasses: ( 0.9.2342.19200300.100.4.18 + NAME 'friendlyCountry' + SUP country + STRUCTURAL + MUST co + X-ORIGIN 'RFC 4524' ) +objectClasses: ( 0.9.2342.19200300.100.4.14 + NAME 'rFC822localPart' + SUP domain + STRUCTURAL + MAY ( cn $ + description $ + destinationIndicator $ + facsimileTelephoneNumber $ + internationaliSDNNumber $ + physicalDeliveryOfficeName $ + postalAddress $ + postalCode $ + postOfficeBox $ + preferredDeliveryMethod $ + registeredAddress $ + seeAlso $ + sn $ + street $ + telephoneNumber $ + teletexTerminalIdentifier $ + telexNumber $ + x121Address ) + X-ORIGIN 'RFC 4524' ) +objectClasses: ( 0.9.2342.19200300.100.4.7 + NAME 'room' + SUP top + STRUCTURAL + MUST cn + MAY ( roomNumber $ + description $ + seeAlso $ + telephoneNumber ) + X-ORIGIN 'RFC 4524' ) +objectClasses: ( 0.9.2342.19200300.100.4.19 + NAME 'simpleSecurityObject' + SUP top + AUXILIARY + MUST userPassword + X-ORIGIN 'RFC 4524' ) +objectClasses: ( 2.16.840.1.113730.3.2.6 + NAME 'referral' + DESC 'named subordinate reference object' + STRUCTURAL + MUST ref + X-ORIGIN 'RFC 3296' ) +objectClasses: ( 1.3.6.1.4.1.5322.13.1.1 + NAME 'namedObject' + SUP top + STRUCTURAL MAY cn + X-ORIGIN 'draft-howard-namedobject' ) +objectClasses: ( 2.16.840.1.113719.2.142.6.1.1 + NAME 'ldapSubEntry' + DESC 'LDAP Subentry class, version 1' + SUP top + STRUCTURAL + MAY ( cn ) + X-ORIGIN 'draft-ietf-ldup-subentry' ) +objectClasses: ( 1.3.6.1.4.1.7628.5.6.1.1 + NAME 'inheritableLDAPSubEntry' + DESC 'Inheritable LDAP Subentry class, version 1' + SUP ldapSubEntry + STRUCTURAL + MUST ( inheritable ) + MAY ( blockInheritance ) + X-ORIGIN 'draft-ietf-ldup-subentry' ) +objectClasses: ( 2.16.840.1.113730.3.2.1 + NAME 'changeLogEntry' + SUP top + STRUCTURAL + MUST ( changeNumber $ + targetDN $ + changeType ) + MAY ( changes $ + newRDN $ + deleteOldRDN $ + newSuperior ) + X-ORIGIN 'draft-good-ldap-changelog' ) +objectClasses: ( 1.3.6.1.4.1.4203.1.4.7 + NAME 'authPasswordObject' + DESC 'authentication password mix in class' + AUXILIARY + MAY authPassword + X-ORIGIN 'RFC 3112' ) + From d87f91008bf1d1ecc1afd9c2c0ac101f6eff03ca Mon Sep 17 00:00:00 2001 From: Bastien Jansen Date: Mon, 26 Dec 2022 09:49:51 +0100 Subject: [PATCH 5/5] Rebase from master --- .../internal/AbstractEmbeddedLdapBuilder.java | 25 +- .../ldap/internal/EmbeddedLdapServerImpl.java | 72 +++++- .../internal/FakeEmbeddedLdapBuilder.java | 4 +- .../junit/ldap/EmbeddedLdapRuleBuilder.java | 10 +- .../ldap/internal/EmbeddedLdapRuleImpl.java | 10 +- .../junit/ldap/EmbeddedLdapRuleTlsTest.java | 215 ++++++++++++++++++ .../internal/EmbeddedLdapExtensionImpl.java | 10 +- .../junit5/EmbeddedLdapExtensionBuilder.java | 10 +- 8 files changed, 336 insertions(+), 20 deletions(-) create mode 100644 embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleTlsTest.java diff --git a/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilder.java b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilder.java index 5e03337..240cdd4 100644 --- a/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilder.java +++ b/embedded-ldap-core/src/main/java/org/zapodot/junit/ldap/internal/AbstractEmbeddedLdapBuilder.java @@ -9,6 +9,7 @@ import com.unboundid.ldap.sdk.schema.Schema; import com.unboundid.ldif.LDIFException; +import javax.net.ssl.SSLSocketFactory; import java.io.File; import java.io.IOException; import java.net.InetAddress; @@ -51,6 +52,12 @@ public abstract class AbstractEmbeddedLdapBuilder createLdapEnvironment() { final Hashtable environment = new Hashtable<>(); + if (socketFactory != null) { + final Class delegator = (new ByteBuddy()).subclass(AbstractDelegatingSocketFactory.class) + .defineMethod("getDelegate", SocketFactory.class, Modifier.PROTECTED) + .intercept(FixedValue.value(socketFactory)) + .make() + .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.INJECTION) + .getLoaded(); + try { + final Object instance = delegator.newInstance(); + delegator.getField("INSTANCE").set(instance, instance); + } catch (InstantiationException | IllegalAccessException | NoSuchFieldException e) { + throw new IllegalStateException(e); + } + environment.put("java.naming.ldap.factory.socket", delegator.getCanonicalName()); + } environment.put(LdapContext.CONTROL_FACTORIES, JAVA_RT_CONTROL_FACTORY); - environment.put(Context.PROVIDER_URL, String.format("ldap://%s:%s", + environment.put(Context.PROVIDER_URL, String.format("%s://%s:%s", + useTls ? "ldaps" : "ldap", inMemoryDirectoryServer.getListenAddress().getHostName(), embeddedServerPort())); environment.put(Context.INITIAL_CONTEXT_FACTORY, JAVA_RT_CONTEXT_FACTORY); diff --git a/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/FakeEmbeddedLdapBuilder.java b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/FakeEmbeddedLdapBuilder.java index 04ceae4..e23ba63 100644 --- a/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/FakeEmbeddedLdapBuilder.java +++ b/embedded-ldap-core/src/test/java/org/zapodot/junit/ldap/internal/FakeEmbeddedLdapBuilder.java @@ -20,9 +20,7 @@ protected FakeEmbeddedLdapBuilder getThis() { EmbeddedLdapServer build() { try { InMemoryDirectoryServer server = createServer(createInMemoryServerConfiguration(), ldifsToImport); - return new EmbeddedLdapServerImpl( - server, - authenticationConfiguration) { + return new EmbeddedLdapServerImpl(server, authenticationConfiguration, false, null) { }; } catch (LDAPException e) { diff --git a/embedded-ldap-junit/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilder.java b/embedded-ldap-junit/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilder.java index b00771e..b43e4d8 100644 --- a/embedded-ldap-junit/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilder.java +++ b/embedded-ldap-junit/src/main/java/org/zapodot/junit/ldap/EmbeddedLdapRuleBuilder.java @@ -31,9 +31,13 @@ protected EmbeddedLdapRuleBuilder getThis() { */ public EmbeddedLdapRule build() { Objects.requireNonNull(bindDSN, "\"bindDSN\" can not be null"); - return EmbeddedLdapRuleImpl.createForConfiguration(createInMemoryServerConfiguration(), - authenticationConfiguration, - ldifsToImport); + return EmbeddedLdapRuleImpl.createForConfiguration( + createInMemoryServerConfiguration(), + authenticationConfiguration, + ldifsToImport, + useTls, + socketFactory + ); } } diff --git a/embedded-ldap-junit/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapRuleImpl.java b/embedded-ldap-junit/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapRuleImpl.java index e55bd7f..aeac793 100644 --- a/embedded-ldap-junit/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapRuleImpl.java +++ b/embedded-ldap-junit/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapRuleImpl.java @@ -7,23 +7,25 @@ import org.junit.runners.model.Statement; import org.zapodot.junit.ldap.EmbeddedLdapRule; +import javax.net.ssl.SSLSocketFactory; import java.util.List; public class EmbeddedLdapRuleImpl extends EmbeddedLdapServerImpl implements EmbeddedLdapRule { public static EmbeddedLdapRule createForConfiguration(final InMemoryDirectoryServerConfig inMemoryDirectoryServerConfig, final AuthenticationConfiguration authenticationConfiguration, - final List ldifs) { + final List ldifs, boolean useTls, SSLSocketFactory socketFactory) { try { return new EmbeddedLdapRuleImpl(EmbeddedLdapServerImpl.createServer(inMemoryDirectoryServerConfig, ldifs), - authenticationConfiguration); + authenticationConfiguration, useTls, socketFactory); } catch (LDAPException e) { throw new IllegalStateException("Can not initiate in-memory LDAP server due to an exception", e); } } - public EmbeddedLdapRuleImpl(InMemoryDirectoryServer inMemoryDirectoryServer, AuthenticationConfiguration authenticationConfiguration1) { - super(inMemoryDirectoryServer, authenticationConfiguration1); + public EmbeddedLdapRuleImpl(InMemoryDirectoryServer inMemoryDirectoryServer, AuthenticationConfiguration authenticationConfiguration1, + boolean useTls, SSLSocketFactory socketFactory) { + super(inMemoryDirectoryServer, authenticationConfiguration1, useTls, socketFactory); } diff --git a/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleTlsTest.java b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleTlsTest.java new file mode 100644 index 0000000..bedf39f --- /dev/null +++ b/embedded-ldap-junit/src/test/java/org/zapodot/junit/ldap/EmbeddedLdapRuleTlsTest.java @@ -0,0 +1,215 @@ +package org.zapodot.junit.ldap; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.io.IOException; +import java.math.BigInteger; +import java.net.InetAddress; +import java.security.KeyManagementException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Calendar; +import java.util.Date; + +import javax.naming.Context; +import javax.naming.NamingEnumeration; +import javax.naming.directory.DirContext; +import javax.naming.directory.SearchControls; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.junit.Rule; +import org.junit.Test; + +import com.google.common.collect.Iterators; +import com.unboundid.ldap.listener.InMemoryListenerConfig; +import com.unboundid.ldap.sdk.AddRequest; +import com.unboundid.ldap.sdk.Attribute; +import com.unboundid.ldap.sdk.LDAPConnection; +import com.unboundid.ldap.sdk.LDAPInterface; +import com.unboundid.ldap.sdk.SearchRequest; +import com.unboundid.ldap.sdk.SearchResult; +import com.unboundid.ldap.sdk.SearchResultEntry; +import com.unboundid.ldap.sdk.SearchScope; + +public class EmbeddedLdapRuleTlsTest { + + public static final String DOMAIN_DSN = "dc=zapodot,dc=org"; + + final SSLContext sslContext; + { + try { + sslContext = buildSslContext(); + } catch (Exception e) { + throw new IllegalStateException("Failed to create LDAPS config", e); + } + } + + @Rule + public EmbeddedLdapRule embeddedLdapRule = EmbeddedLdapRuleBuilder + .newInstance() + .usingDomainDsn(DOMAIN_DSN) + .importingLdifs("example.ldif") + .withListener(getListenerConfig()) + .useTls(true) + .withSocketFactory(sslContext.getSocketFactory()) + .build(); + + private InMemoryListenerConfig getListenerConfig() { + try { + return InMemoryListenerConfig.createLDAPSConfig( + "tls", InetAddress.getLoopbackAddress(), 0, sslContext.getServerSocketFactory(), + sslContext.getSocketFactory() + ); + } catch (Exception e) { + throw new IllegalStateException("Failed to create LDAPS config", e); + } + } + + @Test + public void testLdapConnection() throws Exception { + final LDAPInterface ldapConnection = embeddedLdapRule.ldapConnection(); + final SearchResult searchResult = ldapConnection.search(DOMAIN_DSN, SearchScope.SUB, "(objectClass=person)"); + assertEquals(1, searchResult.getEntryCount()); + } + + @Test + public void testRawLdapConnection() throws Exception { + final String commonName = "Test person"; + final String dn = String.format( + "cn=%s,ou=people,dc=zapodot,dc=org", + commonName); + LDAPConnection ldapConnection = embeddedLdapRule.unsharedLdapConnection(); + try { + ldapConnection.add(new AddRequest(dn, Arrays.asList( + new Attribute("objectclass", "top", "person", "organizationalPerson", "inetOrgPerson"), + new Attribute("cn", commonName), new Attribute("sn", "Person"), new Attribute("uid", "test")))); + } finally { + // Forces the LDAP connection to be closed. This is not necessary as the rule will usually close it for you. + ldapConnection.close(); + } + ldapConnection = embeddedLdapRule.unsharedLdapConnection(); + final SearchResultEntry entry = ldapConnection.searchForEntry(new SearchRequest(dn, + SearchScope.BASE, + "(objectClass=person)")); + assertNotNull(entry); + } + + @Test + public void testDirContext() throws Exception { + final DirContext dirContext = embeddedLdapRule.dirContext(); + final SearchControls searchControls = new SearchControls(); + searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); + final NamingEnumeration resultNamingEnumeration = + dirContext.search(DOMAIN_DSN, "(objectClass=person)", searchControls); + assertEquals(1, Iterators.size(Iterators.forEnumeration(resultNamingEnumeration))); + } + + @Test + public void testContext() throws Exception { + final Context context = embeddedLdapRule.context(); + final Object user = context.lookup("cn=Sondre Eikanger Kvalo,ou=people,dc=zapodot,dc=org"); + assertNotNull(user); + } + + @Test + public void testContextClose() throws Exception { + final Context context = embeddedLdapRule.context(); + context.close(); + assertNotNull(context.getNameInNamespace()); + + } + + @Test + public void testEmbeddedServerPort() throws Exception { + assertTrue(embeddedLdapRule.embeddedServerPort() > 0); + + } + + @Test(expected = IllegalStateException.class) + public void testNoPortAssignedYet() throws Exception { + final EmbeddedLdapRule embeddedLdapRule = new EmbeddedLdapRuleBuilder().build(); + embeddedLdapRule.embeddedServerPort(); + + } + + public static SSLContext buildSslContext() + throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, + UnrecoverableKeyException, KeyManagementException, OperatorCreationException { + KeyStore keystore = KeyStore.getInstance("jks"); + keystore.load(null, new char[] {}); + KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA"); + gen.initialize(2014); + final KeyPair keyPair = gen.generateKeyPair(); + + Provider bcProvider = new BouncyCastleProvider(); + Security.addProvider(bcProvider); + + long now = System.currentTimeMillis(); + Date startDate = new Date(now); + + org.bouncycastle.asn1.x500.X500Name dn = new org.bouncycastle.asn1.x500.X500Name("cn=localhost"); + BigInteger sn = new BigInteger(Long.toString(now)); + + Calendar calendar = Calendar.getInstance(); + calendar.setTime(startDate); + calendar.add(Calendar.HOUR, 1); + Date endDate = calendar.getTime(); + + String signatureAlgorithm = "SHA256WithRSA"; + + final ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).build(keyPair.getPrivate()); + + final X509CertificateHolder holder = + new JcaX509v3CertificateBuilder(dn, sn, startDate, endDate, dn, keyPair.getPublic()) + .addExtension(new ASN1ObjectIdentifier("2.5.29.19"), true, new BasicConstraints(true)) + .build(contentSigner); + final X509Certificate cert = new JcaX509CertificateConverter() + .setProvider(bcProvider) + .getCertificate(holder); + keystore.setCertificateEntry("test", cert); + keystore.setKeyEntry("key", keyPair.getPrivate(), new char[] {}, new Certificate[] { cert }); + + final KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmfactory.init(keystore, new char[] {}); + final KeyManager[] kms = kmfactory.getKeyManagers(); + + KeyStore truststore = KeyStore.getInstance("jks"); + truststore.load(null, new char[] {}); + truststore.setCertificateEntry("test", cert); + + final TrustManagerFactory tmfactory = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm() + ); + tmfactory.init(truststore); + final TrustManager[] tms = tmfactory.getTrustManagers(); + final SSLContext sslcontext = SSLContext.getInstance("TLS"); + sslcontext.init(kms, tms, null); + return sslcontext; + } +} diff --git a/embedded-ldap-junit5/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapExtensionImpl.java b/embedded-ldap-junit5/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapExtensionImpl.java index 1daf1ab..66dd274 100644 --- a/embedded-ldap-junit5/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapExtensionImpl.java +++ b/embedded-ldap-junit5/src/main/java/org/zapodot/junit/ldap/internal/EmbeddedLdapExtensionImpl.java @@ -6,16 +6,17 @@ import org.junit.jupiter.api.extension.ExtensionContext; import org.zapodot.junit.ldap.junit5.EmbeddedLdapExtension; +import javax.net.ssl.SSLSocketFactory; import java.util.List; public class EmbeddedLdapExtensionImpl extends EmbeddedLdapServerImpl implements EmbeddedLdapExtension { public static EmbeddedLdapExtension createForConfiguration(final InMemoryDirectoryServerConfig inMemoryDirectoryServerConfig, final AuthenticationConfiguration authenticationConfiguration, - final List ldifs) { + final List ldifs, boolean useTls, SSLSocketFactory socketFactory) { try { return new EmbeddedLdapExtensionImpl(createServer(inMemoryDirectoryServerConfig, ldifs), - authenticationConfiguration); + authenticationConfiguration, useTls, socketFactory); } catch (LDAPException e) { throw new IllegalStateException("Can not initiate in-memory LDAP server due to an exception", e); } @@ -23,8 +24,9 @@ public static EmbeddedLdapExtension createForConfiguration(final InMemoryDirecto private boolean isStartedBeforeAll = false; - public EmbeddedLdapExtensionImpl(InMemoryDirectoryServer inMemoryDirectoryServer, AuthenticationConfiguration authenticationConfiguration1) { - super(inMemoryDirectoryServer, authenticationConfiguration1); + public EmbeddedLdapExtensionImpl(InMemoryDirectoryServer inMemoryDirectoryServer, AuthenticationConfiguration authenticationConfiguration1, + boolean useTls, SSLSocketFactory socketFactory) { + super(inMemoryDirectoryServer, authenticationConfiguration1, useTls, socketFactory); } @Override diff --git a/embedded-ldap-junit5/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilder.java b/embedded-ldap-junit5/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilder.java index 3bee8b7..dc37aaa 100644 --- a/embedded-ldap-junit5/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilder.java +++ b/embedded-ldap-junit5/src/main/java/org/zapodot/junit/ldap/junit5/EmbeddedLdapExtensionBuilder.java @@ -26,9 +26,13 @@ public static EmbeddedLdapExtensionBuilder newInstance() { */ public EmbeddedLdapExtension build() { Objects.requireNonNull(bindDSN, "\"bindDSN\" can not be null"); - return EmbeddedLdapExtensionImpl.createForConfiguration(createInMemoryServerConfiguration(), - authenticationConfiguration, - ldifsToImport); + return EmbeddedLdapExtensionImpl.createForConfiguration( + createInMemoryServerConfiguration(), + authenticationConfiguration, + ldifsToImport, + useTls, + socketFactory + ); } @Override