Spring security add ApplicationEventListener to ExpiredJwtException - java

I had implemented AuthenticationFailureListener for fail login by using ApplicationListener<AuthenticationFailureBadCredentialsEvent> and all my Bad Credentials event are handeled in the same class, very convenient, I have tried to add a Listener to ExpiredJwtException or SignatureException but I could not figure which event is triggered, I have tried -
#Component
public class ApplicationEventListener implements ApplicationListener<ApplicationEvent>{
#Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println(event.toString()); //not printed when ExpiredJwtException thrown
}
}
to catch all ApplicationEvent but when one of this exception happens the method onApplicationEvent does not fired.
I can catch this Exceptions but I want to handle them globally like BadCredentialsException is handled by AuthenticationFailureBadCredentialsEvent.
Tried AuthenticationFailureExpiredEvent -
#Component
public class ApplicationEventListener implements ApplicationListener<AuthenticationFailureExpiredEvent>{
#Override
public void onApplicationEvent(AuthenticationFailureExpiredEvent event) {
System.out.println("Expired!!"); //same result
}
}
but still not working.

I think the easiest way to publish an ApplicationEvent when catching exceptions is by using the ApplicationEventPublisher. There is no need to implement ApplicationEvent using this method as it wraps any object into a PayloadApplicationEvent that you can use in your ApplicationEventListener and act on it. This works from Spring 4.2 and here is the official link: https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2

I'm not sure about this, I would have to check the source, but: it could be that an application event is not emitted for ExpiredJwtException or SignatureException.
Possible solutions are:
Publish the event yourself: as you mentioned you are able to catch these exceptions, so a simple solution would be to catch them and then emit the desired event. You just need to autowire the ApplicationEventPublisher and then call publishEvent(event).
Use a Filter to catch and handle the exceptions in a single place.
Example of solution 2:
public class AuthFailureFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (ExpiredJwtException | SignatureException exception) {
handle(exception);
}
}
}

Related

Intercept exceptions thrown by repository method with different error codes

Is there a way to intercept DataAccessException that is thrown by data-layer (#Repository) with knowing which method is causing this exception?
Writing custom SQLExceptionTranslator does not fit my need as I cannot determine which method caused the exception.
I have a repository like this:
public interface UserRepository extends JpaRepository<UserEntity, Integer> {
#ErrorCode("E1000")
User findById(int id);
#ErrorCode("E1001")
User findByUsername(String username);
}
ErrorCode is a custom annotation holds an error code that I need to send to client whenever DataAccessException occurs.
If there is a way to intercept the call to findById with catching DataAccessException, then it is easy to extract error code from annotation and re-throw a custom exception that can be catched by exception handler.
If Spring AOP is allowed, you could build your own aspect, for example:
#Aspect
public class ErrorCodeAspect {
#Around("#annotation(errorCode)")
public Object aroundErrorCode(ProceedingJoinPoint joinPoint, ErrorCode errorCode) throws Throwable {
try {
return joinPoint.proceed();
} catch (DataAccessException dae) {
throw new YourCustomException(errorCode.value(), dae);
}
}
}
Note that annotations on interface methods are not inherited by implementing class methods (even with #Inherited which applies to parent classes only), so you will probably need to annotate your concrete service classes instead for the aspect to plug in (unless Spring does some additional black magic with the repository proxies I wouldn't be aware of).
You can define the custom ExceptionHandler.
#RestControllerAdvice
public class RestExceptionResolver {
#ExceptionHandler(DataAccessException.class)
public ResponseEntity<String> handleNoSuchElementException(DataAccessException ex) {
return ResponseEntity.status(yourErrorCode);
}
}

#Async will not call by #ControllerAdvice for global exception

I have a service class with #Async method and If it's calling method throwing any exception then the #ControllerAdvice will not call for global exception handling. But for other classes and services it will call advice and sending email properly.
#Service
public class FileScanServiceImpl implements FileScanService {
#Override
#Async
public void scanFileScheduler() throws MQException {
try{
messageProducer.putFileNameToMQ(fileName);
} catch (Exception e) {
ExceptionUtility.handleException(e, currentFile);
}
}
The ExceptionUtility is used for checking instance on exception and doing some functionality there and throwing custom exception.
public static void handleException(Exception e throws MQException {
String errMsg = "";
if (e instanceof MQException) {
// some functionality
throw new MQException(subject, errMsg);
}
}
And this is my #ControlleAdvice
#ControllerAdvice
public class GlobalExceptionHandler {
#ExceptionHandler(MQException.class)
#ResponseBody
public void handleMQException(HttpServletRequest request, MQException ex) {
// send email
}
}
It there any solution for #Async which will call #ControllerAdvice for global exception, also the existing functionality will not break.
#ExceptionHandler was created to catch only "synchronous exceptions". If it had the ability to catch exceptions from asynchronous threads, then when several threads start and if any of them fail, the request to the server would be interrupted completely and the system could remain in an inconsistent state (due to many other active threads generated by this request)
For handling asynchronous exceptions Spring has the AsyncUncaughtExceptionHandler interface:
public class YourAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
#Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
// Your exception handling logic
}
}
More information can be found here in the Exceptions section: https://www.baeldung.com/spring-async

Spring Boot intercept all exception handlers

I am trying to perform some common logic that applies to all my #ExceptionHandlers in code. I know I can write a HandlerInterceptor to intercept happy paths. But I would like to hook into the exception handling lifecycle so that I can execute some common logic such as logging, before the error response is rendered.
Is there anyway to do this in Spring Boot / Spring MVC? I would like to avoid having to write a servlet filter for this purpose if possible.
I have a solution. It's about using HandlerInterceptor.afterCompletion method. However, there is a line in the documentation of this method that states that:
Note: Will only be called if this interceptor's preHandle method has successfully completed and returned true!
So the trick is to also implement the preHandle and make it return true.
Now my interceptor looks like this:
#Component
public class MyInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// perform common logic here
}
}
One thing to be aware of though is that if you have a chain of interceptors and an interceptor before this one throws an exception, this interceptor won't get a chance to execute. So if we reorder the interceptor chain so that MyInterceptor is right at the top, it will intercept all requests.
There is a way with #RestControllerAdvice and #ExceptionHandler, an example:
#RestControllerAdvice
public class GlobalControllerExceptionHandler {
#ExceptionHandler(value = {DeniedPermissionException.class})
#ResponseStatus(HttpStatus.FORBIDDEN)
public String deniedPermissionException(DeniedPermissionException ex) {
return "Denied permission";
}
#ExceptionHandler(value = {ConstraintViolationException.class})
#ResponseStatus(HttpStatus.BAD_REQUEST)
public String constraintViolationException(ConstraintViolationException ex) {
return "Bad request";
}
#ExceptionHandler(value = {Exception.class})
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String internalServerError(Exception ex) {
return "Internal error";
}
}
*DeniedPermissionException is a custom exception.
This is not really a Spring Boot concern. This is really a Spring MVC concern. One good approach is to implement the HandlerExceptionResolver or extend from something like ExceptionHandlerExceptionResolver. The implementation needs to be given a higher precedence than the default exception resolvers (which all run with the lowest precedence). And if you want to retain the existing behavior of the default resolvers but only trap the exception for something cross-cutting like logging or tracking, then just return null for the ModelAndView and Spring will ensure other default resolvers are invoked as before.

Spring filter throws custom exception

I have a controller advice that handle all validation exception thrown by my application as below.
#RestControllerAdvice
public class RestApiExceptionController {
#ExceptionHandler(ValidationErrorException.class)
public ResponseEntity<?> appNotFoundException(ValidationErrorException exception) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse(exception.getErrorCode(), exception.getMessage()));
}
}
In my way, I would like to create a filter that will make validation to every request and throw custom exception when necessary. But the thing is that I cannot throw custom exception as show below.
public class ValidationFilter implements Filter {
...
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
throw new ValidationErrorException(); // This is impossible
}
...
}
How can I throw the ValidationErrorException in this case or there are other better ways to handle such task.
The validations are generally done on the request objects which are in general available in Controller layer after they are transformed from request format to server processing format. e.g. JSON to Java object.
So the validation should be performed or triggered on Controller layer once the request is reached by completing your entire filter chaining.
Any validation exception thrown then later on can be handled in your following handler,
#RestControllerAdvice
public class RestApiExceptionController {
#ExceptionHandler(ValidationErrorException.class)
public ResponseEntity<?> appNotFoundException(ValidationErrorException exception) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse(exception.getErrorCode(), exception.getMessage()));
}
}
The very much one of the purpose of filters is,
To intercept requests from a client before they access a resource at
back end.
So filters in real don't have the actual resource yet to be validated. They are available once the control reaches to correct component and in your case it is Controller.
So better approach is not to do any resource based validations at filter components.

is it possible to handle exception from a single place

I have dao, service and action classes in my spring mvc application.
I am throwing Exception in Dao and Service classes. Now in Action, normally I have to write try catch block and in case exception occurs in dao and service, it will be thrown from there and it will go in catch block in action.
I have a error jsp which will be displayed.
Problem is I need to write same catch block in all action methods.
Is it possible to throw it again in action methods too and handle it from a single point rather than writing same code everywhere.
Please suggest.
You can also have a look at Spring Integration. It provides the use of gateways, filters and channels. Each can have a Request, Response and Error channel assigned. Or there is even a default error handler. In case all data flows through a specific channel, having a custom error handler is as simple as follows:
#MessageEndpoint
public class MyErrorHandler {
#ServiceActivator(inputChannel = "errorChannel")
public String handle(String messsage) {
// do whatever you like
}
}
The Integration framework offers lots of usefull stuff for general handling.
I think you are looking for cross-cutting exception handling and good news, you are working with Spring MVC yes you can use this feature.
All you need to do, is throw your CustomExcptions or whatever other Exceptions that are from your services to your action methods.
Let's say here is your service:
#Service
public class MyService {
public void someMethod throws RuntimeException {
...
}
}
In your controller method:
#Controller
public class MyController {
#Autowired
MyService service;
#RequestMapping("/someuri"){
try {
service.someMethod();
} catch {
throw new RuntimeException();
}
}
#ExceptionHandler(RuntimeException.class)
public ModelAndView handleException(RuntimeException ex) {
ModelAndView model = new ModelAndView("errorpage");
return model;
}
}
The handleException method annotated with ExceptionHandler is your advice method for exception handling and it will be called anytime a RuntimeException is throw inside your controller and you can keep up like this for all other exceptions.

Categories