Spring Framework HttpRequestHandler failure - java

We have an application which communicates via REST requests made by clients.
The REST requests contain "region name" and a "ID" as parameters
So, a request would look something like this (for a DELETE)
http://host:port/regionnameID
These REST requests between regions in a federation are properly URL encoded
I find that these request fail if the region name has a slash ("/") in it.
Then, the request would look like so
http://host:port/region/nameID
This is due to incorrect interpretation of the Rest URL by HttpRequesthandler when there is a '/' in the region name.
Now, we have no control over clients sending REST request with "/" in the Region name.
Is there any method / configuration / workaround that can be done to prevent the HttpRequestHandler from returning 404

you should rewrite your urls with urlrwrite and use query parameters internal.
<rule>
<name>Inbound:</name>
<from>^(.*)ID$</from>
<to last="true">delete?regionName=$1</to>
</rule>
Add your urlrewrite Filter in front of all other filters in web.xml

This is a bit of a dirty problem. What I would try to do here is to use the Spring #RequestMapping annotation. There is some documentation on it here:
http://static.springsource.org/spring/docs/2.5.x/reference/mvc.html
You can specific ant wildcards in the value you pass #RequestMapping. If you have a limited number of regions, then you can map them all to a single method as follows:
#RequestMapping(value={"/region1**","/region2**","/region3**")
In your controller method, you will have to add additional logical for parsing out the nameID.
If you have a large number of regions, I would then create a separate Spring Web app (servlet) just to handle these requests. That app would have a cached lookup table of regions.

Configure your own handlerMapping bean (perhaps based on AbstractUrlHandlerMapping)

Related

Is it possible to programmatically resolve producible content-type given a request in spring-webflux?

My application uses spring-webflux, it still uses classic #Controllers with #RequestMapping-annotated handler methods.
Some methods produce application/json, while others produce text/event-stream.
When a request hits a controller, there is no problem: each mapping has produces with the corresponding media type defined.
The application also uses spring-security (the reactive flavor). If an unauthenticated request arrives, we must build a error response using correct format: JSON for application/json endpoints and a Server-Sent-Event for text/event-stream endpoints.
The problem is that security checks are made before the request handler is resolved, so Spring has no clue about the correct response media type at this point.
If a client sends Accept header, this solves the problem: we just parse it and decide what content type to use, with something like the following:
request.getHeaders().getAccept().contains(MediaType.TEXT_EVENT_STREAM)
(the algorithm is oversimplified, but you get the idea).
But some clients do not send Accept header at all. Strictly speaking, we have all the information we need: we have request, and, somewhere in spring-webflux beans information about all the mappings is stored.
So the question is: how (only having ServerWebExchange instance and access to Spring context) do you make use of this mapping information to find out what media types are supported by a handler corresponding to the current request?
P.S. What I tried/thought of so far:
Manually maintain list of all streaming endpoints... yuck!
Use a bean post-processor to collect information about all mappings and then try to emulate spring-webflux behavior... cumbersome and probably fragile.

AppDynamics to group REST endpoints containing UUIDs as a single business transaction

I have a web application running on JBoss/Wildfly and using RESTEasy. I'm monitoring it with AppDynamics. I've configured my business transaction detection to use a Java Servlet.
This just about works, but some of my REST paths contain UUIDs, for example:
/data/scenario/d345d238-e0d2-4e01-a96e-4bf11290ce1d/job
Each time this end-point is invoked with a different UUID, AppD treats it as a different business transaction. Is there a way to make AppD recognise UUIDs within a path, and group these into a single business transaction? Something like:
/data/scenario/{id}/job
I should be able to do it by applying a regex to the request's path info:
request.getPathInfo().replaceAll(
"[0-9a-f]{8}\\-[0-9a-f]{4}\\-[0-9a-f]{4}\\-[0-9a-f]{4}\\-[0-9a-f]{12}",
"{id}")
or even just
request.getPathInfo().replaceAll("[0-9a-f\\-]{36}", "{id}")
but I can't figure out how to escape it properly.
${getPathInfo().replaceAll([0-9a-f\\-]{36}, id)}
doesn't work, and neither does
${getPathInfo().replaceAll(\[0\-9a\-f\\\\-\]\{36\}, id)}
Configuration->Instrumentation->Transaction Detection->Add
On the "Split Transactions Using Request Data" section you must choose "Specific URI Segments"
Segment Numbers: 1,2,4
In your case transaction name will be "/data/scenario/job"
Sample Configuration:

Spring MVC - allowing requests from localhost only to specific controller

I have a specific controller (among many other controllers).
I would like to allow requests to this controller that are being invoked from localhost only.
Whats the best way to do this?
here is the controller:
#Controller
public class LocalProvider {
#RequestMapping(value = "/someURL", method = RequestMethod.POST)
#ResponseBody
public responseDTO doSomethingForLocalRequest(#RequestBody ReqDTO reqDTO ) {
//do something
}
EDIT :
Succesffuly achieved that by adding the following to spring security.xml:
<intercept-url pattern="/someURL/*" access="hasIpAddress('127.0.0.1')" />
I would create a custom annotation #LocalhostOnly and a MVC interceptor that would check if handler method is annotated with #LocalhostOnly and in that case check if remote ip address fetched from the HttpServletRequest.getRemoteAddr() is indeed localhost.
If you're using spring security then, as NimChimpsky suggested, it might be better plug in remote ip check into that. You could define a custom permission evaluator that checks remote ip address.
You could also use servlet filter and do the localhost check there for a specific URL (e.g. /someURL**).
Lastly, be aware that if you'll be running the application behind a reverse proxy at some point, all the requests will look like they arrived from localhost (that is, if reverse proxy is installed at the same host). In that case you'll need to pick up the ip address from X-Forwarded-For header.
EDIT
Spring security actually has ip checking expression hasIpAddress('127.0.0.1') so NimChimpsky's answer is probably the best way to go.
spring-security provides #PreAuthorize annotation that can be used on type or method so an alternative to <intercept-url>
can be #PreAuthorize("hasIpAddress('127.0.0.1')")
To restrict access to your whole webserveryou could use
<Connector port="8080" address="127.0.0.1" maxHttpHeaderSize="8192"
In server xml of tomcat (or similar in a different app server).
For one app use add allow="localhost" to the context :
<Context>
<Valve className="org.apache.catalina.valves.RemoteHostValve" allow="localhost"/>
</Context>
But for specific controller methods, you'll be best using spring security.
Solution is to use the following expression:
#PreAuthorize("#request.getRemoteAddr().equals(#request.getLocalAddr())")
As first comment suggested, Failed to evaluate expression error will show using #request if #P("request") HttpServletRequest parameter is missing.
Full solution:
#PreAuthorize("#request.getRemoteAddr().equals(#request.getLocalAddr())")
#PostMapping("/doSomething")
public void myMethod(#P("request") HttpServletRequest request) {
...
}

How to manage requests without get parameters

I am currently using front controller pattern in a Java servlet and and redirecting requests to an appropriate handler via a "action" GET parameter. So, every link or process in the application will route to the front controller with an appropriate ?action=x query string and then the front controller uses the output from request.getParameter("action") to load and execute the appropriate handler.
How can I do this without having query strings in all of my URLs on the web application?
Here is the general approach used by most of the HTTP services framework.
You can use two things to decide about the handlers mapping:
The reference URL of entity i.e. URL part appended to the base URL of your application
The Http method, if you want to have different handlers for different HTTP operations
For example, you have this URL
http://mydomain.com/myapplication/myentity
Here the base URL part is: http://mydomain.com/myapplication/
Entity reference URL part is: myentity
Also the operation can be mapped to the HTTP method : GET(get), POST(create), DELETE(remove), PUT(update)
So you should have mapping of refURL myentity to some handler like MyEntityHandler class alongwith the operartion(optional). Pass the input request and response object for necessary information to the handler class.

Using original URL request for proxied HttpServlet Request

I have an Apache proxy which redirects requests to /foo/bar to a web app running on /foo. The problem is that I have a Servlet filter in my filter chain which requires the request to still be in the /foo/bar format. It is an authentication filter I can't change and this is resulting in incorrect redirects after login to /foo instead of /foo/bar.
Following other similar threads, I've attempted using RequestDispatcher.forward with a modified request and HttpServletResponse.sendRedirect to modify the URL. The first approach seems to skip the rest of my filter chain, and the second goes to the proxy which then modifies the URL back to /foo.
Is there any way around this. Ideally what I'd like is for just the authentication filter to get a /foo/bar request and the rest of the chain to get a /foo request.
Looks like HttpServletRequestWrapper was what I was looking for. Just needed to extend this and provide getRequestURI and getRequestURL overrides (rather like described here). Then needed to add filter mappings before and after my auth filter to convert the request URL/URI as needed.

Categories