How to get HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE value in case of 403, 401 errors? - spring

There is useful http request attribute that is being set in
org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java:195
org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#extractMatchDetails(org.springframework.web.servlet.mvc.condition.PatternsRequestCondition,
java.lang.String, javax.servlet.http.HttpServletRequest)
request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
We can use it in some filters to track metrics etc.
We use Spring Security (5.7.4) and defined SecurityFilterChain
The problem is that when user makes some unauthorised operation, this attribute does not set, because security filter applied before execution of this code.
Can we somehow extract bestPattern instead of using getRequestURI() from HttpServletRequest?
Unfortunately even common metrics has just root (instead of best pattern) value in uri label
http_server_requests_seconds_count{exception="None",method="GET",outcome="CLIENT_ERROR",status="403",uri="root",}
1.0

Related

Spring Boot doesn't recognize multipart form-data element when filename is missing

I have this code:
#PostMapping("foobar")
public ResponseEntity<SaveLogsResult> foobar(#RequestPart("file") MultipartFile log, #RequestPart("env") MultipartFile json){
return ResponseEntity.ok(fooService.saveFooBar(log, json, UUID.randomUUID().toString()));
}
Two applications send formally correct data to this endpoint, one fails miserably and receives an http status 400.
I set logging.level.org.springframework.web=DEBUG and can see (among other lines) this:
Required request part 'env' is not present
Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'env' is not present]
Completed 400 BAD_REQUEST
To further diagnose this I compared a working (left) and a non-working (right) request. The only different is the mising filename:
As far as I understand the RFC for Content-Disposition leaving out the filename is perfectly valid:
Is followed by a string containing the original name of the file
transmitted. The filename is always optional and must not be used
blindly by the application: path information should be stripped, and
conversion to the server file system rules should be done. This
parameter provides mostly indicative information. When used in
combination with Content-Disposition: attachment, it is used as the
default filename for an eventual "Save As" dialog presented to the
user.
Is this an error inside Spring ? I use Spring Boot 2.6.2
Unfortunately I can't change the non-working component for a quick test because it is a bought component that doesn't receive bugfixes very often.
I think that my problem is different from that described here because the failure only happens in a specific scenario.
It looks like you have to provide the filename. see this issue
This [The situation in which filename is not present] can lead to inconsistencies, e.g. you would get it with
MultipartFile but not with collection or array of MultipartFile, and
one can make the opposite argument that it should be rejected.
Why does it matter to have it injected as MultipartFile if it doesn't
even have a filename? You could also inject it as InputStream or any
other type supported by a registered HttpMessageConverter.

Spring Boot 2.2.5. How to retrieve a PathVariable parameter inside a Spring Filter

The problem I want to solve.
I need to apply a specific logic to all restful endpoints where the url belongs to a specific sub path: let's say "/api/employee/{id}". This means all the links which start with this path should apply a logic based on the employee ID, which I am trying to apply directly in Spring Boot filter in order to avoid to spread the logic everywhere.
The problem I face.
I am able to get the query parameters from the ServletRequest, but the PathVariables are not available in the Filter.
Any idea how this could be parsed?
Would be much appreciated :)
The PathVariables are simply the URI. You cann call getRequestURI()
From the docs:
java.lang.String getRequestURI()
Returns the part of this request's URL from the protocol name up to the query string in the first line of the HTTP request. The web container does not decode this String. For example:
First line of HTTP request Returned Value
POST /some/path.html HTTP/1.1 /some/path.html
GET http://foo.bar/a.html HTTP/1.0 /a.html
HEAD /xyz?a=b HTTP/1.1 /xyz
https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html#getRequestURI--

Is it possible to return an error for an extra query parameter shows up in light-4j request

I have a question about the light-rest-4j URL validation, for example, if I have a POST request path /party, if I type the path as /party11, I will get error: No handler defined for path /party11, but if I put /party?qqqq, It will pass through, and system treat it as /party should we add validation for this? Our QA team creates this as a defect, in case user input it by mistake, they expect to have error message return.
The light-rest-4j framework validates the request/response based on the OpenAPI specification during the runtime; however, it only validates based on the spec — nothing more and nothing less. In most cases, the spec will define the type of headers, query parameters, path parameters, and cookies, as well as if they are required. We make sure these are validated as defined. For anything that is not defined in the spec, we are doing nothing. For example, an extra query parameter or an extra header in the request will be ignored as they are not defined in the spec. We cannot do any negative validation as we don't know if any client will add additional headers or query parameters for tracing, auditing, etc. A request that comes from one client might be different than another one comes from the same client through a gateway or proxy.

How to validate request against XSD and return an error object?

My task is to implement a webservice that:
consumes an XML file on a POST endpoint
in happy flow, it returns a DTO as JSON + HTTP 2xx
the incoming XML file is validated against a XSD; if the validation fails, a JSON with a list of all validation errors is returned (including the line, column, error) with HTTP Bad request
the application exposes two endpoints, only one of them should be validated
I have started the implementation with Spring Boot + web, using regular #PostMapping which has "consumes" and "produces" set to application/xml and application/json, respectively. The usual flow works perfectly fine. Now, I stumbled upon the issue of validating the incoming payload. What I figured out:
1) I have to validate the payload before it is converted (marshalled) to an object.
2) Once validated, I have to either:
allow further processing
stop any further processing, write the error object to the response and set the status code to 400 Bad request
My approaches were:
1) using a RequestBodyAdvice, more specifically the beforeBodyRead method implementation. I had the following issue here: I don't know how to write anything to the output in case the validation fails.
2) using a Filter (I've extended OncePerRequestFilter) - fortunately, I can read the request (request.getInputStream()) and write to the response (response.getOutputStream()).
However, how can I do the selective filtering (as mentioned, I only want to validate one single endpoint)?
Are there any other alternatives for placing the incoming request XSD validation? Is spring-web the appropriate choice here? Would you recommend some other library / framework?
To validate xml against xsd schema, my preference is XML Beans. It is very easy to use. Other options are JABX, Castor. Take a look at Java to XML conversions?.
You will need to jar using xsd schmema and will need to put it in the classpath of your application so that it's classes are available for you for validation. Please take a look at this blog.
You can use validation API as mentioned here.
I would prefer to write validation code in the aspect so that it can be reused with other APIs.
If validation fails, throw valid exception from the aspect itself.
If validation is passed, process your input string that you receive.
Please let us know if you need any more information.

Validate request headers with Spring validation framework

Is it possible to use the Spring validation framework with Spring MVC to validate the presence and value of an HTTP request header?
To check the presence of a request header, you don't need the validation framework. Request header parameters are mandatory by default, and if a mandatory header is missing in a request, Spring MVC automatically responds with 400 Bad Request.
So the following code automatically checks the presence of the header "Header-Name"...
#PostMapping("/action")
public ResponseEntity<String> doAction(#RequestHeader("Header-Name") String headerValue) {
// ...
}
... and if the header shall be optional, the annotation would need to be replaced by:
#RequestHeader(name = "Header-Name", required = false)
To check the value of a request header, the Spring validation framework can be used. To do this, you need to
Add #Validated to the controller class. This is a workaround needed until this feature is implemented.
Add the JSR-303 annotation to the request header parameter, e.g.
#RequestHeader("Header-Name") #Pattern(regexp = "[A-Za-z]*") String headerValue
Note however that this will result in a 500 in case of an invalid header value. Check this question for how to also get the correct status code (i.e. 400) for this case.
I don't see how this would be possible, since the validation framework only operates on your domain objects, not on the HTTP request itself. Specifically, the Validator interface doesn't specify any methods that take the HttpServletRequest object, which is what you'd need to have access to in order to grab the headers and test them.
Using the validation framework feels like the wrong solution to whatever problem you're trying to solve, especially since it's hard to know how there'd be a unique HTTP request header for a given form submission. Are you looking to test for an HTTP header that should always be present in requests to your app? Then you might want to consider implementing a HandlerInterceptor, which will intercept and process all requests to pages that you've mapped in any HanderMappings. Are you looking to test for an HTTP header that should always be present in any page view of your app? Then you'd want to implement a Filter, which operates outside of the context of Spring MVC.

Resources