Весенний загрузочный привод - LDAP Health Endpoint Throwing NPE
В нашем приложении Spring Boot мы используем spring-security-ldap
для аутентификации пользователей, которые могут получить доступ к нашему приложению. Мы не видим никаких проблем с аутентификацией, однако, когда мы попадаем в URL-адрес /authenticator/health
, мы получаем следующий статус для ldap:
"ldap": {
"status": "DOWN",
"error": "java.lang.NullPointerException: null"
}
Отслеживая это исключение нулевого указателя, мы получаем этот env.put(Context.SECURITY_PRINCIPAL, userDn);
при попытке доступа к 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] oslcsupport.AbstractContextSource: Property 'userDn' not set - anonymous context will be used for read-write operations
, но это наше ожидание, и мы хорошо справляемся с этим. Кажется, что конечные точки здоровья не соблюдают это. Я не могу сказать, является ли это ошибкой с нашим кодом или проблема с автоконфигурацией для Spring Boot.
Я немного незнакома с тем, как работают конечные точки Actuator, поэтому извините, если это несколько очевидно. Спасибо!
Ответы
Ответ 1
Это ошибка spring-ldap, в которой зафиксировано исправление, но она пока не включена в основную ветку spring-ldap
.
Однако я обнаружил, что добавление этого свойства в application.properties
устраняет проблему:
management.health.ldap.enabled=false
Ответ 2
Другое решение заключается в том, чтобы ввести учетные данные в свойствах LDAP Spring, чтобы они были выбраны LDAPAutoConfiguration:
[email protected]
spring.ldap.password=secret
spring.ldap.urls=ldap://mydomain.com:389
Таким образом, вы все еще можете использовать проверку здоровья.