Throwing Exception in AuthenticationProvider

I am using a custom 'AuthenticationProvider'. If not authenticated, I throw an exception inside the "authenticate" function as shown below.

public class DelegatingLdapAuthenticationProvider implements AuthenticationProvider {

    private ActiveDirectoryLdapAuthenticationProvider primaryProvider;
    private List<ActiveDirectoryLdapAuthenticationProvider> secondaryProviders = new ArrayList<>();

    public DelegatingLdapAuthenticationProvider() {

    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        Authentication result = null;
        AuthenticationException exception = null;
        try {
            result = primaryProvider.authenticate(authentication);
        } catch (AuthenticationException e) {
            exception = e;
            for (ActiveDirectoryLdapAuthenticationProvider secondaryProvider : secondaryProviders) {
                try {
                    result = secondaryProvider.authenticate(authentication);
                    if (result.isAuthenticated()) {
                            break;
                    }
                } catch (AuthenticationException e1) {
                            exception = e;
                }
            }
        }
        if (result == null || !result.isAuthenticated()) {
            throw exception;
    }

    return result;
}

      

I have a global exception handler as shown below.

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler({NoPermissionException.class})
    @ResponseBody
    @ResponseStatus(value = HttpStatus.FORBIDDEN)
    public Map<String, String> noPermission(NoPermissionException e) {
        return createErrorResponse(e, "Don't have permissions");
    }

    @ExceptionHandler({Exception.class})
    @ResponseBody
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public Map<String, String> exceptionInProcessing(Exception e) {
        return createErrorResponse(e, "Unable to process. Unknown error occurred: " + e.getMessage());
    }

    private Map<String, String> createErrorResponse(Exception e, String errorMessage) {
        Map<String, String> errorResponse = new HashMap<>();
        errorResponse.put("message", errorMessage);
        errorResponse.put("reason", e.toString());
        return errorResponse;
    }
}

      

When an exception is thrown inside the "authenticate" function, the global exception handler is not called. With all other exceptions, it is called. I want to catch the exception inside a global exception handler and return an error message. How can i do this? Any help is appreciated. Thanks in advance.

+1


source to share


3 answers


GlobalExceptionHandler

is intended for the controller exception handler, but AuthenticationProvider

still in the filter, if you want to handle AuthenticationException

it you need to handle it to implement AuthenticationEntryPoint

and override the method commence

.

public void commence(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException authException) throws IOException, ServletException

      



AuthenticationException

and AccessDeniedException

have already been processed ExceptionTranslationFilter

. You just need to enter AuthenticationEntryPoint

and AccessDeniedHandler

(which process AccessDeniedException

)

Or you can catch this exception in a filter and then handle it in filer like AuthenticationFailureHandler

inAbstractAuthenticationProcessingFilter

+1


source


The authentication provider is called before the controller's exception handler has a chance to catch the exception.

You can override AuthenticationFailureHandler to handle exceptions at the security filter chain level, see examples



The behavior described in the documentation :

The filter calls the configured AuthenticationManager to process each authentication request. Assignment after successful authentication or failure of authentication is controlled by the authentication policy interfaces, SuccessHandler and AuthenticationFailureHandler, respectively. A filter has properties that allow you to set them so that you can completely customize the behavior.

0


source


As @chaoluo already said you need to implement AuthenticationEntryPoint

and override the method commence

. If you want to return an error JSON object, you can do the following:

@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
            throws IOException, ServletException {

    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    //create errorObj
    PrintWriter writer = response.getWriter();
    mapper.writeValue(writer, errorObj);
    writer.flush();
}

      

0


source







All Articles