Spring Boot Actuator - LDAP Health Endpoint Throwing NPE
Asked Answered
S

2

31

In our Spring Boot app we have are using spring-security-ldap to authenticate users that can access our app. We don't see any issues functionally with authentication, however when we hit the /authenticator/health URL, we get the following status for the ldap:

"ldap": {
    "status": "DOWN",
    "error": "java.lang.NullPointerException: null"
}

Tracking down this null pointer exception, we get this trace when trying to access the env.put(Context.SECURITY_PRINCIPAL, userDn);:

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]
...

Finally, here is what our security configuration looks like:

@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);
    }

}

Now we do get a message in the console saying 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, 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.

I'm a bit unfamiliar with how exactly the Actuator endpoints work, so apologize if this is somewhat obvious. Thanks!

Spelaean answered 24/10, 2017 at 17:46 Comment(0)
K
54

This is a spring-ldap bug that has a fix committed, but it doesn't appear to be merged into the main spring-ldap branch yet.

However, I have found that adding this property in application.properties fixes the issue:

management.health.ldap.enabled=false
Koran answered 13/7, 2018 at 17:19 Comment(3)
I'm using 2.3.2-release version of spring-ldap-core and adding management.health.ldap.enabled=false to application.yml did fixed the problem :).Pantaloon
It does not fix the issue, it just removes LDAP check when hitting health endpointFrigorific
This does not fix the issue. It just removes LDAP check when hitting /actuator/health endpoint resulting in Ldap not being checked at all.Frigorific
Q
8

Another solution is to enter credentials into the LDAP Spring properties so they are picked up by the LDAPAutoConfiguration:

[email protected]
spring.ldap.password=secret
spring.ldap.urls=ldap://mydomain.com:389

This way, you can still use the health check.

Quadrireme answered 28/8, 2019 at 11:35 Comment(1)
This should be marked as an answer. This resolves the issue and /health actuator endpoint will report status of Ldap. The above accepted answer is incorrect as it does not solve connectivity issue with Ldap but just removes check for Ldap in the /health endpointFrigorific

© 2022 - 2025 — McMap. All rights reserved.