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.
source to share
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
source to share
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.
source to share
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();
}
source to share