Skip to content

Added config interceptor for in-memory server #1000

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CONTRIBUTING.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ The wiki pages https://github.com/spring-projects/spring-framework/wiki/Code-Sty

To format the code as well as check the style, run `./gradlew format check`.

Lastly, run `./gradlew checkstyleMain checkstyleTest` before submitting a pull request, for additional style checks.

[[submit-a-pull-request]]
=== Submit a Pull Request

Expand Down
18 changes: 10 additions & 8 deletions modules/ROOT/pages/testing.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -182,17 +182,19 @@ testCompile "com.unboundid:unboundid-ldapsdk:3.1.1"
The following bean definition creates an embedded LDAP server:

====
[source,xml]
[source,java]
----
<bean id="embeddedLdapServer" class="org.springframework.ldap.test.unboundid.EmbeddedLdapServerFactoryBean">
<property name="partitionName" value="example"/>
<property name="partitionSuffix" value="dc=261consulting,dc=com" />
<property name="port" value="9321" />
</bean>
@Bean
EmbeddedLdapServer embeddedLdapServer() {
return EmbeddedLdapServer.withPartitionSuffix("dc=jayway,dc=se")
.partitionName("jayway")
.port(18881)
.configurationCustomizer((config) -> config.setCodeLogDetails(tempLogFile, true))
.build();
}
----
====

`spring-ldap-test` provides a way to populate the LDAP server by using `org.springframework.ldap.test.unboundid.LdifPopulator`. To use it, create a bean similar to the following:
Alternatively, you can use the `org.springframework.ldap.test.unboundid.LdifPopulator` to create and populate the LDAP server. To use it, create a bean similar to the following:

====
[source,xml]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@

package org.springframework.ldap.test.unboundid;

import java.util.List;
import java.util.function.Consumer;

import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;

import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
Expand All @@ -24,6 +31,7 @@
import com.unboundid.ldap.sdk.LDAPException;

import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

/**
* Helper class for embedded Unboundid ldap server.
Expand All @@ -45,27 +53,30 @@ public EmbeddedLdapServer(InMemoryDirectoryServer directoryServer) {
this.directoryServer = directoryServer;
}

/**
* Creates a new {@link Builder} with a given partition suffix.
*
* @since 3.3
*/
public static Builder withPartitionSuffix(String partitionSuffix) {
return new Builder(partitionSuffix);
}

/**
* Creates and starts new embedded LDAP server.
* @deprecated Use the builder pattern exposed via
* {@link #withPartitionSuffix(String)} instead.
*/
@Deprecated(since = "3.3")
public static EmbeddedLdapServer newEmbeddedServer(String defaultPartitionName, String defaultPartitionSuffix,
int port) throws Exception {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry that I didn't catch this earlier. We can't remove checked exceptions from signatures as this can break some forms of compatibility. Please see https://wiki.eclipse.org/Evolving_Java-based_APIs_2 and look specifically for "Delete checked exceptions thrown".

InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(defaultPartitionSuffix);
config.addAdditionalBindCredentials("uid=admin,ou=system", "secret");

config.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("LDAP", port));

config.setEnforceSingleStructuralObjectClass(false);
config.setEnforceAttributeSyntaxCompliance(true);
EmbeddedLdapServer server = EmbeddedLdapServer.withPartitionSuffix(defaultPartitionSuffix)
.partitionName(defaultPartitionName)
.port(port)
.build();

Entry entry = new Entry(new DN(defaultPartitionSuffix));
entry.addAttribute("objectClass", "top", "domain", "extensibleObject");
entry.addAttribute("dc", defaultPartitionName);

InMemoryDirectoryServer directoryServer = new InMemoryDirectoryServer(config);
directoryServer.add(entry);
directoryServer.startListening();
return new EmbeddedLdapServer(directoryServer);
server.start();
return server;
}

/**
Expand Down Expand Up @@ -102,4 +113,119 @@ public void shutdown() {
this.directoryServer.shutDown(true);
}

/**
* Helper class for embedded Unboundid ldap server.
*
* @author Emanuel Trandafir
* @since 3.3
*/
public static final class Builder {

private final String partitionSuffix;

private String partitionName;

private int port = 0;

private Consumer<InMemoryDirectoryServerConfig> configurationCustomizer = (__) -> {
};

private Builder(String partitionSuffix) {
this.partitionSuffix = partitionSuffix;
this.partitionName = leftMostElement(partitionSuffix);
}

/**
* Sets the port for the embedded LDAP server.
* @param port the port for the embedded LDAP server. Defaults to 0 in which case
* the server should automatically choose an available port.
* @return this {@link Builder} instance.
*/
public Builder port(int port) {
this.port = port;
return this;
}

/**
* Sets a customizer for the {@link InMemoryDirectoryServerConfig}.
* @param configurationCustomizer a {@link Consumer} function that will be applied
* to the {@link InMemoryDirectoryServerConfig} before creating the
* {@link InMemoryDirectoryServer}. The default values, it a Consumer function
* that does nothing: (config) -> {}
* @return this {@link Builder} instance.
*/
public Builder configurationCustomizer(Consumer<InMemoryDirectoryServerConfig> configurationCustomizer) {
this.configurationCustomizer = configurationCustomizer;
return this;
}

/**
* Sets the partition name for the embedded LDAP server.
* @param partitionName the partition name for the embedded LDAP server. Defaults
* to the left most element of the partition suffix.
* @return this {@link Builder} instance.
*/
public Builder partitionName(String partitionName) {
this.partitionName = partitionName;
return this;
}

/**
* Builds and returns a {@link EmbeddedLdapServer}.
* <p>
* In order to start the server, you should call
* {@link EmbeddedLdapServer#start()}.
* @return a new {@link EmbeddedLdapServer}.
*/
public EmbeddedLdapServer build() {
try {
InMemoryDirectoryServerConfig config = inMemoryDirectoryServerConfig(this.partitionSuffix, this.port);
this.configurationCustomizer.accept(config);

Entry entry = ldapEntry(this.partitionName, this.partitionSuffix);
InMemoryDirectoryServer directoryServer = inMemoryDirectoryServer(config, entry);
return new EmbeddedLdapServer(directoryServer);
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}

static String leftMostElement(String partitionSuffix) {
try {
List<Rdn> rdns = new LdapName(partitionSuffix).getRdns();
return CollectionUtils.lastElement(rdns).getValue().toString();
}
catch (InvalidNameException ex) {
throw new RuntimeException(ex);
}
}

private static InMemoryDirectoryServerConfig inMemoryDirectoryServerConfig(String partitionSuffix, int port)
throws LDAPException {
InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(partitionSuffix);
config.addAdditionalBindCredentials("uid=admin,ou=system", "secret");
config.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("LDAP", port));
config.setEnforceSingleStructuralObjectClass(false);
config.setEnforceAttributeSyntaxCompliance(true);
return config;
}

private static Entry ldapEntry(String defaultPartitionName, String defaultPartitionSuffix)
throws LDAPException {
Entry entry = new Entry(new DN(defaultPartitionSuffix));
entry.addAttribute("objectClass", "top", "domain", "extensibleObject");
entry.addAttribute("dc", defaultPartitionName);
return entry;
}

private static InMemoryDirectoryServer inMemoryDirectoryServer(InMemoryDirectoryServerConfig config,
Entry entry) throws LDAPException {
InMemoryDirectoryServer directoryServer = new InMemoryDirectoryServer(config);
directoryServer.add(entry);
return directoryServer;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,13 @@ public void setPort(int port) {

@Override
protected EmbeddedLdapServer createInstance() throws Exception {
return EmbeddedLdapServer.newEmbeddedServer(this.partitionName, this.partitionSuffix, this.port);
EmbeddedLdapServer server = EmbeddedLdapServer.withPartitionSuffix(this.partitionSuffix)
.partitionName(this.partitionName)
.port(this.port)
.build();

server.start();
return server;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,12 @@ public static void startEmbeddedServer(int port, String defaultPartitionSuffix,
}

try {
embeddedServer = EmbeddedLdapServer.newEmbeddedServer(defaultPartitionName, defaultPartitionSuffix, port);
embeddedServer = EmbeddedLdapServer.withPartitionSuffix(defaultPartitionSuffix)
.partitionName(defaultPartitionName)
.port(port)
.build();

embeddedServer.start();
}
catch (Exception ex) {
throw new UncategorizedLdapException("Failed to start embedded server", ex);
Expand Down
Loading
Loading