title: Spring Boot Actuator - LDAP Health Endpoint Throwing NPE
body: <p>In our Spring Boot app we have are using <code>spring-security-ldap</code> to authenticate users that can access our app. We don't see any issues functionally with authentication, however when we hit the <code>/authenticator/health</code> URL, we get the following status for the ldap:</p>
  
  <pre><code>"ldap": {
      "status": "DOWN",
      "error": "java.lang.NullPointerException: null"
  }
  </code></pre>
  
  <p>Tracking down this null pointer exception, we get this trace when trying to access the <code>env.put(Context.SECURITY_PRINCIPAL, userDn);</code>:</p>
  
  <pre><code>java.lang.NullPointerException: null
      at java.util.Hashtable.put(Unknown Source) ~[na:1.8.0_111]
      at org.springframework.ldap.core.support.SimpleDirContextAuthenticationStrategy.setupEnvironment(SimpleDirContextAuthenticationStrategy.java:42) ~[spring-ldap-core-2.3.1.RELEASE.jar:2.3.1.RELEASE]
      at org.springframework.ldap.core.support.AbstractContextSource.setupAuthenticatedEnvironment(AbstractContextSource.java:194) ~[spring-ldap-core-2.3.1.RELEASE.jar:2.3.1.RELEASE]
      at org.springframework.ldap.core.support.AbstractContextSource.getAuthenticatedEnv(AbstractContextSource.java:582) ~[spring-ldap-core-2.3.1.RELEASE.jar:2.3.1.RELEASE]
      at org.springframework.ldap.core.support.AbstractContextSource.doGetContext(AbstractContextSource.java:134) ~[spring-ldap-core-2.3.1.RELEASE.jar:2.3.1.RELEASE]
      at org.springframework.ldap.core.support.AbstractContextSource.getReadOnlyContext(AbstractContextSource.java:158) ~[spring-ldap-core-2.3.1.RELEASE.jar:2.3.1.RELEASE]
      at org.springframework.ldap.core.LdapTemplate.executeReadOnly(LdapTemplate.java:802) ~[spring-ldap-core-2.3.1.RELEASE.jar:2.3.1.RELEASE]
      at org.springframework.boot.actuate.health.LdapHealthIndicator.doHealthCheck(LdapHealthIndicator.java:46) ~[spring-boot-actuator-1.5.4.RELEASE.jar:1.5.4.RELEASE]
      at org.springframework.boot.actuate.health.AbstractHealthIndicator.health(AbstractHealthIndicator.java:43) ~[spring-boot-actuator-1.5.4.RELEASE.jar:1.5.4.RELEASE]
      at org.springframework.boot.actuate.health.CompositeHealthIndicator.health(CompositeHealthIndicator.java:68) [spring-boot-actuator-1.5.4.RELEASE.jar:1.5.4.RELEASE]
      at org.springframework.boot.actuate.endpoint.HealthEndpoint.invoke(HealthEndpoint.java:81) [spring-boot-actuator-1.5.4.RELEASE.jar:1.5.4.RELEASE]
      at org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.getHealth(HealthMvcEndpoint.java:171) [spring-boot-actuator-1.5.4.RELEASE.jar:1.5.4.RELEASE]
      at org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(HealthMvcEndpoint.java:145) [spring-boot-actuator-1.5.4.RELEASE.jar:1.5.4.RELEASE]
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_111]
      at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_111]
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_111]
      at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_111]
      at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE]
      at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE]
      at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
      at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
      at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
      at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
      at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
      at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
      at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
      at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) [tomcat-embed-core-8.5.15.jar:8.5.15]
      at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) [tomcat-embed-core-8.5.15.jar:8.5.15]
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [tomcat-embed-core-8.5.15.jar:8.5.15]
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar:8.5.15]
      at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-embed-websocket-8.5.15.jar:8.5.15]
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.15.jar:8.5.15]
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar:8.5.15]
  ...
  </code></pre>
  
  <p>Finally, here is what our security configuration looks like:</p>
  
  <pre><code>@Configuration
  @EnableWebSecurity
  public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
  
      @Value("${security.ldap.url}")
      private String ldapUrl;
      @Value("${security.ldap.user-search-base}")
      private String ldapUserSearchBase;
      @Value("${security.ldap.group-search-base}")
      private String ldapGroupSearchBase;
      @Value("${security.ldap.group-role-attribute}")
      private String ldapGroupRoleAttribute;
      @Value("${security.ldap.authorized-role}")
      private String ldapAuthorizedRole;
  
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          // secure all core/data rest endpoints with basic auth
          http.authorizeRequests()
                  .antMatchers("/core/data/unauthenticated/**").permitAll()
                  .antMatchers("/core/data/**").hasRole(ldapAuthorizedRole)
                  .and().httpBasic()
                  .and().csrf().disable();
  
          // do not create sessions for security
          http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
      }
  
      @Autowired
      public void configure(AuthenticationManagerBuilder auth) throws Exception {
          // use ldap as the authentication provider
          auth.ldapAuthentication()
                  .userSearchBase(ldapUserSearchBase)
                  .userSearchFilter("(uid={0})")
                  .groupSearchBase(ldapGroupSearchBase)
                  .groupSearchFilter("uniqueMember={0}")
                  .groupRoleAttribute(ldapGroupRoleAttribute)
                  .contextSource()
                  .url(ldapUrl);
      }
  
  }
  </code></pre>
  
  <p>Now we do get a message in the console saying <code>2017-10-24 12:37:28.867  INFO 12788 --- [  restartedMain] o.s.l.c.support.AbstractContextSource    : Property 'userDn' not set - anonymous context will be used for read-write operations</code>, but this is our expectation and we're good with that. It seems the health endpoints isn't respecting this. I can't tell if this is a bug with our code or if it's an issue with the autoconfiguration for Spring Boot. </p>
  
  <p>I'm a bit unfamiliar with how exactly the Actuator endpoints work, so apologize if this is somewhat obvious. Thanks!</p>