As of version 2.0.0.M7, when not setting any username property for LdapAutoConfiguration, this cause an NullPointerException to occur when attempting to connect to the LDAP server.

java.lang.NullPointerException: null
    at java.util.Hashtable.put(Hashtable.java:460) ~[na:1.8.0_152]
    at org.springframework.ldap.core.support.SimpleDirContextAuthenticationStrategy.setupEnvironment(SimpleDirContextAuthenticationStrategy.java:42) ~[spring-ldap-core-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.ldap.core.support.AbstractContextSource.setupAuthenticatedEnvironment(AbstractContextSource.java:194) ~[spring-ldap-core-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.ldap.core.support.AbstractContextSource.getAuthenticatedEnv(AbstractContextSource.java:582) ~[spring-ldap-core-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.ldap.core.support.AbstractContextSource.doGetContext(AbstractContextSource.java:134) ~[spring-ldap-core-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.ldap.core.support.AbstractContextSource.getReadOnlyContext(AbstractContextSource.java:158) ~[spring-ldap-core-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:357) ~[spring-ldap-core-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:309) ~[spring-ldap-core-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:642) ~[spring-ldap-core-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:578) ~[spring-ldap-core-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.ldap.core.LdapTemplate.find(LdapTemplate.java:1840) ~[spring-ldap-core-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.ldap.core.LdapTemplate.find(LdapTemplate.java:1861) ~[spring-ldap-core-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.ldap.core.LdapTemplate.findOne(LdapTemplate.java:1869) ~[spring-ldap-core-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.data.ldap.repository.query.AbstractLdapRepositoryQuery.execute(AbstractLdapRepositoryQuery.java:70) ~[spring-data-ldap-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:597) ~[spring-data-commons-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:580) ~[spring-data-commons-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) ~[spring-data-commons-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at com.sun.proxy.$Proxy78.findByLogin(Unknown Source) ~[na:na]

This problem occur because in org.springframework.ldap.core.support.AbstractContextSource the default values of userDn and password are set to an empty string which is then replaced by null.

Configuration example:

spring:
  ldap:
    urls:
      - 'ldap://mycompany.com:389'
    base: 'dc=mycompany,dc=com'

As a fix for this problem, I would suggest to set the anonymousReadOnly property to true when username is an empty String or null.

    @Bean
    @ConditionalOnMissingBean
    public ContextSource ldapContextSource() {
        LdapContextSource source = new LdapContextSource();
        if(StringUtils.isEmpty(this.properties.getUsername())) {
            source.setAnonymousReadOnly(true);
        }
        source.setUserDn(this.properties.getUsername());
        source.setPassword(this.properties.getPassword());
        source.setBase(this.properties.getBase());
        source.setUrls(this.properties.determineUrls(this.environment));
        source.setBaseEnvironmentProperties(
                Collections.unmodifiableMap(this.properties.getBaseEnvironment()));
        return source;
    }

Comment From: philwebb

@vdubus Is this a regression or are you also seeing this problem with Spring Boot 1.5?

It feels a little wrong to me that we should automatically set anonymousReadOnly. It feels more like this might be a bug in Spring LDAP, especially given the output it logs.

Comment From: philwebb

I've raised https://github.com/spring-projects/spring-ldap/issues/473 to see if Spring LDAP can fix the underlying problem.

Comment From: vdubus

@vdubus Is this a regression or are you also seeing this problem with Spring Boot 1.5?

I don't think that it's a regression.

I've raised spring-projects/spring-ldap#473 to see if Spring LDAP can fix the underlying problem.

In fact, there is two problems.

One is the NullPointerException which I do think should be fixed on spring-ldap side. In this case, opening an issue on their side seems to be the right thing to do. A work around for this exception is to set the username and password to an empty String in the configuration.

The other is the impossibility to define the property anonymousReadOnly from spring-autoconfigure configuration. There is also others configurations possible which aren't available in the current configuration system. Maybe there is already a ticket which ask for this kind of functionality ?

Comment From: philwebb

@vdubus I've raised #11722 to add anonymousReadOnly support.

Comment From: filiphr

Just in case someone else stumbles on this. The NPE is now fixed via https://github.com/spring-projects/spring-boot/pull/17861. Spring Boot will no longer set the userDn and password if they are null.

Comment From: chaqui

Sos grande, me has salvado