Handle 403-error in Spring - spring

I want to handle 403 error to show normal message:
#ExceptionHandler(AccessDeniedException.class)
#ResponseBody
public String accessDeniedException () {
return "my message";
}
But AccessDeniedException not handle 403 error.
Same not working follow:
#ResponseStatus(value = HttpStatus.FORBIDDEN)
#ExceptionHandler(SecurityException.class)
#ResponseBody

As I know, If an exception is not being thrown by the code called through your controller, you can't handle it by using #ExceptionHandler (or #ControllerAdvice). For example, exceptions thrown directly from Spring Security, like the CSRF exception, can't be caught this way.

This most likely is coming via Spring Security. If that's the case you need to setup and register an access-denied-handler.
Here is a detailed tutorial of how to do that.

Related

Error handling on quarkus mutiny rest client

On my quarkus rest project i have a restclient that uses mutiny:
#Path("/")
#RegisterRestClient(configKey = "my-api")
#RegisterClientHeaders
#RegisterProvider(MyExceptionMapper.class)
public interface MyClient {
#POST
#Path("path")
Uni<MyBean> get(String body);
}
I wanna handle propery non 2XX httpError so i have made my ExceptionMaper
public class MyExceptionMapper implements ResponseExceptionMapper<MyException> {
#Override
public MyException toThrowable(Response response) {
//TODO
return new MyException();
}
}
a bad call on the client shows that MyExceptionMapper handle the response but the exception raises and does not became a failure on my Uni Client response object
Uni<MyBean> bean = myClient.get("") // i do not have a failure in case of 4XX http
.onFailure().invoke(fail -> System.out.println("how can i get here?"));
Am i using mutiny on a rest client in the wrong way?
Thanks
UPDATE
ok i forgot to add the dependency quarkus-rest-client-mutiny, adding this i notice 2 things,
i still pass through Myexceptionmapper
i also produce a Uni.failure, but the exception into the failure is not the custom exception i created into MyExceptionmapper but a RestEasyWebApplicationException
Failure : org.jboss.resteasy.client.exception.ResteasyWebApplicationException: Unknown error, status code 400
at org.jboss.resteasy.client.exception.WebApplicationExceptionWrapper.wrap(WebApplicationExceptionWrapper.java:107)
at org.jboss.resteasy.microprofile.client.DefaultResponseExceptionMapper.toThrowable(DefaultResponseExceptionMapper.java:21)
Does the ExceptionMapper becomes useless in this context?
I think this is a bug in quarkus-rest-client-mutiny. I created an Github issue based on your findings.
It will work as you expect if you switch to quarkus-rest-client-reactive

Can I get Spring Validation errors in prehandle

I currently have something similar to this in all of my endpoints in my spring app.
if(bindingResult.hasErrors()){
return new ResponseEntity<>(BAD_REQUEST);
}
I would like to move this to a http interceptor so that I only need it in one place. However, I cannot figure out how to get all of the errors from the binding result in preHandle.
How would I get validation errors in preHandle, or some other time before it starts the actual route?
One way to achieve what I think you're looking for is to not include BindingResult as a method parameter. Given no BindingResult is included as a method argument Spring will throw a BindException exception. You can define an ExceptionHandler, generally I've placed these within a #ControllerAdvice, to handle the exception as needed. Below is some sample code
Controller
#PostMapping
public SomeReturnObject someMethod(#Valid SomeCommand command) {
// logic - no longer contains checks for binding result errors
}
As part of ControllerAdvice
#ControllerAdvice
#Order(Ordered.HIGHEST_PRECEDENCE)
public class ApplicationControllerAdvice {
....
#ExceptionHandler(BindException.class)
#ResponseBody
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
protected SomeResponse handleBindException(BindException ex) {
// handle exception
}
}

How to handle HttpMediaTypeNotAcceptableException by writing error content to the response body using exception handler annotation?

When a client request for a resource producing application/json content with Accept Header of application/xml. The request fails with HttpMediaTypeNotAcceptableException exception and is wrapped into error message body in the response entity object by using exception handler annotation as mentioned in below code. However, we receive HttpMediaTypeNotAcceptableException again when return values are written to the response with HttpMessageConverter. It is because it checks the producible content type for the response with the acceptable request type, but this is exactly something we are trying to communicate to the client using error message. How do I workaround this issue ? Btw, all the other exceptions are parsing fine to error message. Please advise.
#ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body,
HttpHeaders headers, HttpStatus status, WebRequest request) {
// Setting the response content type to json
headers.setContentType(MediaType.APPLICATION_JSON);
return ResponseEntity.status(status).headers(headers).body(body);
}
}
A few options come to my mind. One is that your controller method produces all content types and then you throw an exception in your method if the content type is not the one you are expecting, then the exception handler can take this exception and transform it. This is the only one that works with exception handlers, as exception handlers only deal with exceptions produced in the controller method.
The other options are:
Use an interceptor (but I'm not sure if this will work, as Spring might try to resolve first the controller method rather than invoking the interceptors).
Extend RequestMappingHandlerMapping to call the exception handler if it doesn't find a suitable method. You'll probably need to override the method handleNoMatch. In there you'll need to get a reference to the list of HandlerExceptionResolver
The first one is the simplest to understand, and the latest one might be the most 'extensible', but it also requires some understanding of the internals of Spring.
Resolved by setting different content negotiation strategy FixedContentNegotiationStrategy for ExceptionHandlerExceptionResolver and HeaderContentNegotiationStrategy for RequestResponseBodyMethodProcessor.
I have been using a serialized enum-based response (enum annotated with jackson #JsonFormat(shape = Shape.OBJECT) to standardize the error messages in my exception handler class and faced the same issue when it caught with a HttpMediaTypeNotAcceptableException.
The workaround is to set the media type you expect to return directly to the builder method available in the ResponseEntity.
The below code works fine for me.
#ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public final ResponseEntity<ResponseMessagesEnum> handleHttpMediaTypeNotAcceptableException(
HttpMediaTypeNotAcceptableException e, HttpServletRequest request) {
logger.error("No acceptable representation found for [{}] | supported {}", request.getHeader("Accept"), e.getSupportedMediaTypes());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).contentType(MediaType.APPLICATION_JSON)
.body(ResponseMessagesEnum.EX_001);
}

Building a façade with spring which calls another server and returns its response

For an application I need to create a security façade in Spring 4.x.
This thiny layer must accepts any request from our mobile application and execute a security check for the provided token (with openId and Oauth).
Upon a successful validation, the request needs to be forwarded to the backend application, which does not need to be aware of the security token mechanism.
Thus, the flow will be something like this:
security_facade_url/path/of/the/request
With a header that indicates the backend to invoke upon successful validation of the token
Upon successful validation the security façade sends a request to the backend URL
backend_application_url/path/of/the/request
The façade must not have a controller which maps to any possible path of the request, but must call the request on the correct backend server, based on a value in the header of the request. Then return this response to the user.
What I have so far is an implementation of the HandlerInterceptor. This interceptor works, however, I am not really happy with the way I need to avoid the afterCompletion by throwing an exception in the postHandle method.
If I do not throw an error, the default error page is appended to the correct response in the afterCompletion step.
This is my code so far:
public class RequestProcessingInterceptor implements HandlerInterceptor {
private final Logger log = LoggerFactory.getLogger(RequestProcessingInterceptor.class);
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
log.info("Doing some security stuff now ...");
log.warn("... security ok ... since I am not really checking stuff");
return true;
}
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
log.info("Forwarding request and sending that info back ...");
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WebResource service = client.resource(UriBuilder.fromUri("http://localhost:8080").build());
response.setContentType("application/json");
response.getWriter().write(service.path(modelAndView.getModel().get("path").toString()).accept("application/json").get(String.class));
response.setStatus(200);
throw new Exception("Need to avoid the execution of the afterCompletion. Only way to do so is by throwing an exception...");
}
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
Is there a more proper way to intervene with the Spring livecycle or obtain the behaviour as described above?
Found a better solution. For what I need, I do not need to manipulate the results in an interceptor.
A much cleaner way is to define a Controller which maps with the request methods.
#RequestMapping(method = {RequestMethod.GET, RequestMethod.PUT, RequestMethod.POST})
public void handleRequest(HttpServletRequest request, HttpServletResponse response) { // code omitted }
You should not try to avoid the call to afterCompletion. Just implement an empty method and let SpringFramework call it.
Provided your controller returns null indicating that no view has to be called, it should work with a smoother Spring integration.
But I cannot understand why you use Spring MVC here. As you only interact with low level HttpServletRequest and HttpServletResponse, you could as well use :
a dedicated servlet in charge to relay the request and response to the backend and write the returned value in the response
a filter that would do the security stuff before passing request to filter chain

Exception handler for REST controller in spring

I want to handle exceptions so the URL information is automatically shown to the client. Is there an easy way to do this?
<bean id="outboundExceptionAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">
<!-- what property to set here? -->
</bean>
You have two choices:
Spring Reference 15.9.1 HandlerExceptionResolver
Spring HandlerExceptionResolvers ease the pain of unexpected
exceptions that occur while your request is handled by a controller
that matched the request. HandlerExceptionResolvers somewhat resemble
the exception mappings you can define in the web application
descriptor web.xml. However, they provide a more flexible way to
handle exceptions. They provide information about which handler was
executing when the exception was thrown. Furthermore, a programmatic
way of handling exceptions gives you more options for responding
appropriately before the request is forwarded to another URL (the same
end result as when you use the servlet specific exception mappings).
The HandlerExceptionResolver has one method, containing everything you need:
HandlerExceptionResolver.resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex)
Or if you need different handlers for different controllers: Spring Reference Chapter 15.9.2 #ExceptionHandler
#ExceptionHandler(IOException.class)
public String handleIOException(IOException ex, HttpServletRequest request) {
return "every thing you asked for: " + request;
}
Short question short answer
I'm doing the following trick:
#ExceptionHandler(Exception.class)
public ModelAndView handleMyException(Exception exception) {
ModelAndView mv = new ModelAndView("redirect:errorMessage?error="+exception.getMessage());
return mv;
}
#RequestMapping(value="/errorMessage", method=RequestMethod.GET)
#Responsebody
public String handleMyExceptionOnRedirect(#RequestParamter("error") String error) {
return error;
}
Works flawless.

Resources