Run Embedded LDAP in a Spring Boot Application
Use opendj-embedded for an LDAP server owned by your application’s lifecycle, for example in integration tests. Each EmbeddedOpenDJ instance creates a temporary installation and deletes it on close(). Use a standalone server when directory data must survive application restarts. Run one embedded server at a time in a JVM, with its LDAP, administration and JMX ports available.
Add the Dependency
In an existing Spring Boot Maven application, add:
<dependency>
<groupId>org.openidentityplatform.opendj</groupId>
<artifactId>opendj-embedded</artifactId>
<version>5.2.0</version>
</dependency>
Use a JDK supported by your Spring Boot version and at least Java 11 for OpenDJ.
Configure the Bean and Import Data
Put this configuration in your application’s component-scan package. It imports src/main/resources/test-directory.ldif after startup and calls the server’s close() method when the Spring context closes or initialization fails:
import java.io.IOException;
import java.io.InputStream;
import org.openidentityplatform.opendj.embedded.Config;
import org.openidentityplatform.opendj.embedded.EmbeddedOpenDJ;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class LdapConfiguration {
@Bean(destroyMethod = "close")
public EmbeddedOpenDJ embeddedOpenDJ(
@Value("${opendj.password:TestPassword123!}") String password) throws Exception {
Config config = new Config();
config.setBaseDN("dc=example,dc=com");
config.setAdminPassword(password);
config.setPort(1389);
config.setAdminPort(4444);
config.setJmxPort(1689);
EmbeddedOpenDJ server = new EmbeddedOpenDJ(config);
try {
server.run();
try (InputStream data = getClass().getResourceAsStream("/test-directory.ldif")) {
if (data == null) {
throw new IOException("Missing test-directory.ldif");
}
server.importData(data);
}
return server;
} catch (Exception e) {
server.close();
throw e;
}
}
}
Use this LDIF file. importData adds entries; it does not replace existing entries. Check the logs for rejected additions and verify the imported entry:
dn: dc=example,dc=com
objectClass: domain
dc: example
dn: ou=people,dc=example,dc=com
objectClass: organizationalUnit
ou: people
dn: uid=jdoe,ou=people,dc=example,dc=com
objectClass: inetOrgPerson
cn: John Doe
sn: Doe
uid: jdoe
Verify Through LDAP
With the Spring application running, use ldapsearch from an OpenDJ distribution:
bin/ldapsearch --hostname localhost --port 1389 \
--bindDN 'cn=Directory Manager' --bindPassword 'TestPassword123!' \
--baseDN 'uid=jdoe,ou=people,dc=example,dc=com' --searchScope base \
'(objectClass=*)' uid cn
Expect uid: jdoe and cn: John Doe. Use the same assertion in your application’s integration tests, for example with Spring LDAP’s LdapTemplate. Closing the context calls close() to stop the server and clean up its temporary files. If the server cannot be stopped, the instance stays open and retains its directory and shutdown hook so that a later close() call or JVM exit can retry the stop.