Validate a HTTP-Header field in a Spring RestController - spring

I'm looking for a way to validate whether the custom header 'X-Client-Id' is set to a value defined in a Repository within an HTTP request sent to a REST-controller in SpringBoot.
I see tutorials (like this) which includes the header in the method like this: #RequestHeader(value="User-Agent"). I assume I would have to write that line to every method and inject a common validator-bean to verify the value.
Another stackoverflow answer seems to suggest using an HandlerInterceptor. I'm not sure though if that's applicable to header values and REST endpoints.
So what is the recommended way to validate all methods of a class/REST-controller whether a specific header is set or not?

Basically the easiest (and most logical) way is to catch the Request before it gets to your Controller. That can be achieved either with a HandlerInterceptor as the other answer states or with a simple Filter like OncePerRequestFilter.
Extend that class, override the doFilterInternal() method as doFilter() is final, extract the proper header value, check it against whatever you need and depending on the value, either throw an Exception or continue with the chain.

Related

How to get the original handler URI (with wildcards, etc.) in a HandlerInterceptor in Spring?

I am collecting custom metrics for my controller endpoints via HandlerInterceptor. In postHandle I have everything I need and I would like to save the metrics for my endpoints along with the original route defined in the controller, so not the actual route filled with the data.
E.g. I have #GetMapping("/cats/{name}") and make GET request on /cats/tom I still want the defined route "cats/{name}"
I found that I can do this with the Object handler which is the parameter of postHandle -> I can cast it to HandlerMethod get the annotations of the method and find it from memberValues. This seems a bit overkill I also have to filter for Get-, Post-, Put-, Delete-, Patch-, RequestMapping annotations. Is there any easier or more straightforward way to do this? If so how? If not what else do I have to take into consideration with this solution?
It turns out Spring adds this data to the HttpServletRequest attributes. So it can be retrieved using:
String routePattern = (String) request.getAttribute("org.springframework.web.servlet.HandlerMapping.bestMatchingPattern");

Good idea using ControllerAdvice to perform REST authentication of a request?

In my current Spring Boot application i seem to hit a wall when trying to implement a REST request filter. My goal with the request filter was to read the header and body part and validate the incoming data and check if it meets the HMAC construction we are using.
So the request filter seemed not to work an alternative solutions is to use #ControllerAdvice.
Then the request validation can be implemented very easy. But i am not sure if it normally seen as an incorrect usage of the #ControllerAdvice annotation.
#ControllerAdvice
public class GenericWebControllerAdvice {
#ModelAttribute
public void authenticationFilter(#RequestHeader(value = "Authorization") String authHeader, #RequestBody String payload) {
// process authentication based on header info and body content
// calculate the hash and check if meets the security settings
// if the hash fails throw an exception that returns a http status code
}
}
Any comments on the solution or alternatives that are better?
No you should do the validation in the controller (ie method with #RequestMapping).
Spring supports JSR 303/349 bean validation. Thus if your request body is a POJO and you have the correct annotation Spring will automatically do the validation for you. There is a tutorial of that here:
http://www.leveluplunch.com/java/tutorials/017-validate-spring-rest-webservice-request/
As for request parameter validation (ie not bean validation) I have had to make my own transfer objects and exception handling. How you do global exception handling is covered in the Spring Reference guide but generally you extend and/or register a org.springframework.web.servlet.handler.SimpleMappingExceptionResolver. Ironically #ControllerAdvice can be used for exception handling but I find it better to extend and register an Exception Resolver. More info can be found here:
https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-exceptionhandlers
Edit based on OP comments and edits:
If your doing authentication or some other request based validation/authorization its probably best to use an Interceptor. Reference doc. #ControllerAdvice will probably not work as the request handling is too far a long. That is you want something before databinding happens.

what controller responds to /auth/{providerId}?

I need to override the requestmapping of /auth/{providerId} so that I can introduce two another behaviour from a different part of the website and therefore need to find that controller...
One way to do it with Spring would be to extend HandlerInterceptorAdapter to create a new interceptor which will be invoked before the Controller is invoked.
In its preHandle(HttpServletRequest, HttpServletResponse, Object handler) method, the handler is the controller which will serve the request, and therefore you can log the controller's name in your log files. Remember to set the log level accordingly for this class.
You need to add this interceptor to <mvc:interceptors> in your spring-mvc-config.xml.
Then when you access your URL you can see the name of the controller being logged in your log files.
This answer was given to my question here, which is essentially the same as your question as Hybris uses Spring.
An easier way to do it, would be to search for the string "/auth/" in your *.java files. But you might have to be lucky.

ContainerRequest .getEntity is empty in filter method of ContainerResponseFilter

I am creating my own logging filter implementing ContainerRequestFilter and ContainerResponseFilter. I want to print the request entity only if the response failed eg. Response status code as 404, 500.
But I get empty string when I do request.getEntity() or request.getEntityInputStream()
in the filter method of ContainerResponseFilter();
It looks like jersey removes the content after reading it at resource level.
It needs to read the entity from the input stream, which is not resettable (the infrastructure involved doesn't keep a copy of it). So, as the input stream is read previously, it is supposed to be have nothing when you call request.getEntityInputStream() in the class that implements ContainerResponseFilter. LoggingFilter does the work for you. But as you mentioned, if you want to customize it, then you need write an implementation similar to that one, with added code to customize logging of course.

How can I bind fieldName_1, fieldName_2 to a list in spring mvc

I'm trying to convert a struts 1 application to Spring MVC 3.0. We have an form with quite a few parameters, most of which where automatically binded in struts. However there where a number of fields in the format fieldName_# where # is a number that we manually bound by looping through the request.
I'm looking for a tidier way to do this in Spring mvc, but don't know where to start.
Ideally we should have them as fieldName[#] and it would be easier, but we cannot change this and have to keep the fieldName_# format. Also the number of these fields that are sent in the request are unknown.
One way to achieve this is by wrapping the servletRequest and implementing the getParameter (and associated methods) such a way that parameters with name fieldName_# are returned as fieldName[#]. A servletFilter would be one option to wrap the request.

Resources