简体   繁体   中英

How to handle run time exceptions thrown by Spring Security AuthenticationProviders?

How to handle runtime exceptions thrown by Spring Security Authentication Providers ? I'm using Spring Boot 1.4.2 but I feel like this applies also to classic Spring applications.

Let's say I have an ActiveDirectoryLdapAuthenticationProvider configured to authenticate users against my corporate AD. It all works nice with Spring Security when the authentication fails due to bad credentials (an AuthenticationException is thrown which is properly handled by the Spring Security mechanism = the app goes back to the login screen and the authentication error can be shown).

However it so happens that sometimes, the AD is down temporarily and a org.springframework.ldap.CommunicationException is thrown instead. This exception is a runtime exception and therefore isn't trapped by Spring's security mechanism because it doesn't extend AuthenticationException .

What happens in this case, is that the app is redirected to the default error page (which is /error). What I want to do, is to still show the login screen with a custom message.

I've found that I can do that, if I create something like

public class ActiveDirectoryLdapExtendedAuthenticationProvider implements AuthenticationProvider {

private final ActiveDirectoryLdapAuthenticationProvider adAuthenticationProvider;

public ActiveDirectoryLdapExtendedAuthenticationProvider(ActiveDirectoryLdapAuthenticationProvider adAuthenticationProvider) {
    this.adAuthenticationProvider = adAuthenticationProvider;
}

@Override
public Authentication authenticate(Authentication a) throws AuthenticationException {

    Authentication auth = null;

    try {            
        auth = adAuthenticationProvider.authenticate(a);
    }
    catch(CommunicationException communicationException) {
        throw new AuthenticationServiceException("Could not reach User Directory. Please try again in a few minutes");
    }

    return auth;
}

This works but I feel that there must be a better way.

I've tried creating a ControllerAdvice annotated class but it doesn't get called by the POST to login by Spring Security. I would imagine that it's because POST is handled by Spring Security filters, which being Servlet filters, sit above the main Spring MVC dispatcher servlet.

I've also tried to create a SimpleMappingExceptionResolver to handle a CommunicationException and redirect to the login page, but that doesn't work either as my SimpleMappingExceptionResolver doesn't get called either.

The other workaround that I've come up with is to tackle the exception at the error page itself, something like (using Thymeleaf)

<div class="container error" th:switch="${exception}">
        <span  th:case="'org.springframework.ldap.CommunicationException'">Error communicating with User Directory. Please try again in a few minutes</span>
        <span  th:case="*">An unexpected error has occurred</span>
</div>

I still feel like there should be a better way. How can I configure the DispatcherServlet to ensure that a CommunicationException is to be redirected to the /login controller, and not the error page ? Or more generically... how can I configure that any exception at the login stage, is shown on the login screen ?

Experienced same problem and solved it creating custom Spring AuthenticationFailureHandler . It caught error by throwing BadCredentialsException in custom AuthenticationProvider class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM