web-dev-qa-db-ja.com

Spring Bootアクチュエータ-NPEをスローするLDAPヘルスエンドポイント

Spring Bootアプリでは、_spring-security-ldap_を使用して、アプリにアクセスできるユーザーを認証しています。認証に関する機能的な問題はありませんが、_/authenticator/health_ URLにアクセスすると、LDAPの次のステータスが表示されます。

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

この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エンドポイントが正確にどのように機能するのか、私は少し不慣れです。ありがとう!

17
justbaum30

これは spring-ldapバグ 修正がコミットされていますが、メインのspring-ldapブランチにまだマージされていないようです。

ただし、このプロパティをapplication.propertiesに追加すると問題が解決することがわかりました。

management.health.ldap.enabled=false
26
badjr

別の解決策は、LDAPSpringプロパティに資格情報を入力して、LDAPAutoConfigurationによって取得されるようにすることです。

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

この方法でも、ヘルスチェックを使用できます。

1
Sonata