当前,我在安全认证过程中使用ActiveDirectoryLdapAuthenticationProvider
和一个自定义提供程序。假设CustomAuthenticationProvider
引发异常,则安全流进入ldapAuthenticationProvider
。
我有一个问题,当没有连接到AD服务器时,我得到CommunicationException
,无法处理:
a)由@ControllerAdvice
和@ExceptionHandler
b)由AuthenticationFailureHandler
c)AuthenticationEntryPoint
我在控制台和默认弹簧“错误”的回调中遇到异常。我假设它是在后台某处完成的,但是我对此无能为力,无法找到原因。我想捕获CommunicationException
并扔掉CustomException
(或任何其他)以解决javascript客户端上的消息。我该怎么办?
SecurityConfig:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.and().authorizeRequests()
.antMatchers("...").permitAll()
.anyRequest().authenticated()
.and().formLogin().loginPage("/login")
.failureHandler(new CustomFailureHandler())
.successHandler(new CustomSuccessHandler()).permitAll()
.and().logout().permitAll()
.and().exceptionHandling().authenticationEntryPoint(unauthorizedHandler);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth
.authenticationProvider(new CustomAuthenticationProvider())
.authenticationProvider(ldapAuthenticationProvider());
}
UnauthorizedHandler:
@Component
public class UnauthorizedHandler implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
String[] url = request.getRequestURL().toString().split(request.getContextPath());
String redirect = request.getContextPath();
if (url.length == 2) redirect = request.getContextPath() + "/?callbackUrl=" + url[1].substring(1);
response.sendRedirect(redirectUrl);
}
}
CustomFailureHandler:
@Component
public class CustomFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException exception) throws IOException {
String message = "...";
if (exception instanceof BadCredentialsException) {
message = "...";
} else if (exception instanceof CommunicationException) {
message = "...";
}
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setStatus(500);
httpServletResponse.getWriter().print(message);
httpServletResponse.getWriter().flush();
httpServletResponse.getWriter().close();
}
}
例外:
org.springframework.ldap.CommunicationException: 10.1.3.13:389; nested exception is javax.naming.CommunicationException: 10.1.3.13:389 [Root exception is java.net.ConnectException: Connection timed out: connect]
at org.springframework.ldap.support.LdapUtils.convertLdapException(LdapUtils.java:108)
at org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.bindAsUser(ActiveDirectoryLdapAuthenticationProvider.java:215)
at org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.doAuthentication(ActiveDirectoryLdapAuthenticationProvider.java:146)
at org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider.authenticate(AbstractLdapAuthenticationProvider.java:85)
at org........authenticate(ActiveDirectoryLdapAuthenticationProvider.java:29)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:175)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:200)
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:124)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:835)
Caused by: javax.naming.CommunicationException: 10.1.3.13:389
at java.naming/com.sun.jndi.ldap.Connection.<init>(Connection.java:237)
at java.naming/com.sun.jndi.ldap.LdapClient.<init>(LdapClient.java:137)
at java.naming/com.sun.jndi.ldap.LdapClient.getInstance(LdapClient.java:1610)
at java.naming/com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2752)
at java.naming/com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:320)
at java.naming/com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxFromUrl(LdapCtxFactory.java:225)
at java.naming/com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:189)
at java.naming/com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:243)
at java.naming/com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:154)
at java.naming/com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:84)
at java.naming/javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:730)
at java.naming/javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305)
at java.naming/javax.naming.InitialContext.init(InitialContext.java:236)
at java.naming/javax.naming.ldap.InitialLdapContext.<init>(InitialLdapContext.java:154)
at org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider$ContextFactory.createContext(ActiveDirectoryLdapAuthenticationProvider.java:426)
at org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.bindAsUser(ActiveDirectoryLdapAuthenticationProvider.java:206)
... 47 common frames omitted
Caused by: java.net.ConnectException: Connection timed out: connect
at java.base/java.net.PlainSocketImpl.connect0(Native Method)
at java.base/java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:101)
at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:403)
at java.base/java.net.Socket.connect(Socket.java:591)
at java.base/java.net.Socket.connect(Socket.java:540)
at java.base/java.net.Socket.<init>(Socket.java:436)
at java.base/java.net.Socket.<init>(Socket.java:213)
at java.naming/com.sun.jndi.ldap.Connection.createSocket(Connection.java:330)
at java.naming/com.sun.jndi.ldap.Connection.<init>(Connection.java:216)
... 62 common frames omitted
答案 0 :(得分:1)
CommunicationException
不是AuthenticationException
的实例,所以该行
if (exception instanceof CommunicationException) {
永远不会过去。
捕获此异常的简单方法是将LDAP身份验证提供程序包装在您自己的包装中:
public class MyLdapAuthenticationProvider implements AuthenticationProvider {
private final ActiveDirectoryLdapAuthenticationProvider delegate;
public MyLdapAuthenticationProvider(
ActiveDirectoryLdapAuthenticationProvider delegate) {
this.delegate = delegate;
}
public Authentication authenticate(Authentication authentication) {
try {
return this.delegate.authenticate(authentication);
} catch (CommunicationException e) {
throw new InternalAuthenticationServiceException(e);
}
}
}
然后:
@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth
.authenticationProvider(new CustomAuthenticationProvider())
.authenticationProvider(
new MyLdapAuthenticationProvider(ldapAuthenticationProvider()));
}
现在说,Spring Security中有一个开放票证,以便CommunicationException
is correctly wrapped in an InternalAuthenticationServiceException
。您可能会考虑提供一个修补程序,以便不需要委托的身份验证提供程序。