Spring Boot Actuator - LDAP健康端点抛出NPE

28

我们的Spring Boot应用程序中,使用 spring-security-ldap 进行用户身份验证,以便访问我们的应用程序。 身份验证在功能上没有任何问题,但是当我们访问 /authenticator/health URL 时,我们会得到有关ldap的以下状态:

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

追踪这个空指针异常,我们在尝试访问 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]
...

最后,这是我们的安全配置:

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

}

现在我们在控制台中得到了一条消息,内容为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,但这是我们的期望结果,我们接受这种情况。看起来健康检查端点没有尊重这一点。我不能确定这是我们代码的错误还是Spring Boot的自动配置问题。对于Actuator端点的工作原理,我有点不太熟悉,如果这显而易见,请见谅。谢谢!
2个回答

51

这是一个spring-ldap bug,已经有修复方案了,但似乎还没有合并到主要的spring-ldap分支中。

但是我发现在application.properties中添加这个属性可以解决问题:

management.health.ldap.enabled=false

1
我正在使用 spring-ldap-core2.3.2-release 版本,并将 management.health.ldap.enabled=false 添加到 application.yml 中,问题得到了解决 :)。 - belgoros
它并没有解决问题,只是在访问健康端点时删除了LDAP检查。 - pixel
1
这并没有解决问题,只是在访问/actuator/health端点时删除了LDAP检查,导致根本没有检查LDAP。 - pixel

7
另一种解决方案是将凭据输入到LDAP Spring属性中,以便LDAPAutoConfiguration自动识别:
spring.ldap.username=myuser@mydomain.com
spring.ldap.password=secret
spring.ldap.urls=ldap://mydomain.com:389

这样,您仍然可以使用健康检查。

1
这应该被标记为答案。这解决了问题,/health执行器端点将报告Ldap的状态。上述接受的答案是不正确的,因为它没有解决与Ldap的连接问题,而只是删除了/health端点中对Ldap的检查。 - pixel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接