title: Can't catch LDAP CommunicationException with Spring handlers
body: <p>Currently I'm using <code>ActiveDirectoryLdapAuthenticationProvider</code> and one custom provider on security authentication process. Assuming that <code>CustomAuthenticationProvider</code> throws exception, security flow goes to <code>ldapAuthenticationProvider</code>.
  I have a problem that when there is no connection to AD server I get <code>CommunicationException</code>, which can't be handled:</p>
  
  <p>a) by <code>@ControllerAdvice</code> and <code>@ExceptionHandler</code></p>
  
  <p>b) by <code>AuthenticationFailureHandler</code></p>
  
  <p>c) by <code>AuthenticationEntryPoint</code></p>
  
  <p>I got exception in console and callback for default spring "error". I'm assuming it is done somewhere in the background, but I can't do anything about it and find the cause. I want to catch <code>CommunicationException</code> and throw my <code>CustomException</code> (or any other) to resolve message on javascript client. How can I do that?</p>
  
  <p><a href="https://i.stack.imgur.com/f1Kf3.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/f1Kf3.png" alt="callbackUrl"></a></p>
  
  <p>SecurityConfig:</p>
  
  <pre><code>@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());
  }
  </code></pre>
  
  <p>UnauthorizedHandler:</p>
  
  <pre><code>@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);
      }
  }
  </code></pre>
  
  <p>CustomFailureHandler:</p>
  
  <pre><code>@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();
      }
  }
  </code></pre>
  
  <p>Exception:</p>
  
  <pre><code>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.&lt;init&gt;(Connection.java:237)
      at java.naming/com.sun.jndi.ldap.LdapClient.&lt;init&gt;(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.&lt;init&gt;(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.&lt;init&gt;(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.&lt;init&gt;(Socket.java:436)
      at java.base/java.net.Socket.&lt;init&gt;(Socket.java:213)
      at java.naming/com.sun.jndi.ldap.Connection.createSocket(Connection.java:330)
      at java.naming/com.sun.jndi.ldap.Connection.&lt;init&gt;(Connection.java:216)
      ... 62 common frames omitted
  </code></pre>