javaspringspring-dataspring-ldapunboundid-ldap-sdk

Setting up Spring Data LDAP Embedded for tests with base DN


I have a weird behaviour of Spring Data Ldap and was wondering how I can fight it.

From the looks of it, it seems that the base information is either lost or handled differently when I use a "proper" LDAP server and the embedded version. The embedded version should be used for some of my integration tests. But what works perfectly fine when I configure my LDAP server like so:

spring:
  ldap:
    urls: ldap://localhost:389
    base: dc=e-mehlbox,dc=eu
    username: cn=admin,dc=e-mehlbox,dc=eu
    password: root

in my application.yml. But once I set up the embedded server, my searches fail:

spring:
  ldap:
    urls: ldap://localhost:9321
    base: dc=e-mehlbox,dc=eu
    username: uid=admin
    password: secret
    embedded:
      base-dn: dc=e-mehlbox,dc=eu
      credential:
        username: uid=admin
        password: secret
      ldif: classpath:test-schema.ldif
      port: 9321
      validation:
        enabled: false

Enabling debugging, it shows the missing base DN. Here are the corresponding lines for the working configuration agains a "real" LDAP server:

2018-01-10 18:06:55.296 DEBUG 23275 --- [           main] o.s.ldap.core.LdapTemplate               : Searching - base=ou=internal,ou=Users, finalFilter=(&(&(objectclass=inetOrgPerson)(objectclass=organizationalPerson)(objectclass=person)(objectclass=qmailUser))(uid=big.bird)), scope=javax.naming.directory.SearchControls@6a013bdd
2018-01-10 18:06:55.311 DEBUG 23275 --- [           main] o.s.l.c.support.AbstractContextSource    : Got Ldap context on server 'ldap://localhost:389/dc=e-mehlbox,dc=eu'

The interesting bit is the Ldap context, having the base in it.

And this the output when I switch to the embedded LDAP:

2018-01-10 18:08:42.836 DEBUG 23569 --- [           main] o.s.ldap.core.LdapTemplate               : Searching - base=ou=internal,ou=Users, finalFilter=(&(&(objectclass=inetOrgPerson)(objectclass=organizationalPerson)(objectclass=person)(objectclass=qmailUser))(uid=big.bird)), scope=javax.naming.directory.SearchControls@55202ba6
2018-01-10 18:08:42.871 DEBUG 23569 --- [           main] o.s.l.c.support.AbstractContextSource    : Got Ldap context on server 'ldap://localhost:9321'

I am a bit lost, as I can not find any other configuration options to set the base DN.

Some details of my project:

Right now, I am using the following Spring Data LDAP related dependencies (my project is Gradle driven):

compile (
    "org.springframework.boot:spring-boot-starter-data-ldap:1.5.9.RELEASE",
    "org.springframework.data:spring-data-ldap:1.0.9.RELEASE"
)

testCompile (
    "org.springframework.ldap:spring-ldap-test:2.3.2.RELEASE",
    "com.unboundid:unboundid-ldapsdk:4.0.3"
)

And here is one of my entity classes:

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode(doNotUseGetters = true)
@ToString(doNotUseGetters = true)
@Entry(
        objectClasses = {"inetOrgPerson", "organizationalPerson", "person", "qmailUser"},
        base = "ou=internal,ou=Users")
public class User implements Serializable {

    @Id
    private Name dn;

    @Attribute(name = "entryUuid", readonly = true)
    private String entryUuid;

    @Attribute(name = "uid")
    private String username;

    @Attribute(name = "userPassword")
    private byte[] password;

    @Attribute(name = "mail")
    private String internalMailAddress;

    @Attribute(name = "mailAlternateAddress")
    private List<String> mailAddresses;

    @Attribute(name = "displayName")
    private String displayName;

    @Attribute(name = "accountStatus")
    private String status;

    @Attribute(name = "givenName")
    private String firstName;

    @Attribute(name = "sn")
    private String lastName;

    @Attribute(name = "mailMessageStore")
    private String mailboxHome;

}

Any ideas? Is this a bug or just me not seeing the obvious?


Solution

  • Thanks to @vdubus and this question, I got it working.

    It seems like the embedded LDAP server version does not set the configured base DN (see the other SO question). But adding the following class to my project fixes this:

    import com.unboundid.ldap.listener.InMemoryDirectoryServer;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.autoconfigure.ldap.LdapProperties;
    import org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapProperties;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.DependsOn;
    import org.springframework.core.env.Environment;
    import org.springframework.ldap.core.ContextSource;
    import org.springframework.ldap.core.support.LdapContextSource;
    
    @Configuration
    @EnableConfigurationProperties({LdapProperties.class, EmbeddedLdapProperties.class})
    @ConditionalOnClass(InMemoryDirectoryServer.class)
    public class EmbeddedLdapConf {
    
        private final Environment environment;
        private final LdapProperties properties;
    
    
        public EmbeddedLdapConf(Environment environment, LdapProperties properties) {
            this.environment = environment;
            this.properties = properties;
        }
    
        @Bean
        @DependsOn("directoryServer")
        public ContextSource ldapContextSource() {
            final LdapContextSource source = new LdapContextSource();
            source.setUrls(this.properties.determineUrls(this.environment));
            source.setBase(this.properties.getBase());
            return source;
        }
    }