Server side custom headers with embedded jetty and jersey - java

We have a legacy application that uses embedded Jetty and provides functionality through clients making HTTP calls. Most of the information/parameters needed by the server is sent by the client through HTTP headers. We are now prototyping the use of REST API calls using Jersey where the same parameters are provided as JSON inputs. One of the requirements is to maintain backward compatibility and not disturb the existing functionality.
While we were able to use Jersey and pass in parameters, we are looking for help with the following:
We want to avoid changing the current jetty handlers in the application, so we would like to convert the json input from the REST API input into headers and pass them on to the handlers, so that the current functionality can kick in from that point.
I have tried the other (very helpful) posts on using the wrapper/filter mechanisms to add custom headers, even one using the ContainterRequestFilter. Following are my references:
Adding an HTTP header to the request in a servlet filter
How to add servlet filter with embedded jetty
How to add a header to http request using a filter in jax-rs
However for security reasons, the legacy application has this line of code (recommended in Jetty docs) which uses the base request instead of the wrapped request:
Request base_request = request instanceof Request ? (Request)request : HttpConnection.getCurrentConnection().getHttpChannel().getRequest();
Response base_response = response instanceof Response ? (Response)response : HttpConnection.getCurrentConnection().getHttpChannel().getResponse();
This effectively does not use the HttpServletRequestWrapper object that I send in. Since this line of code looks for the org.eclipse.jetty.server.Request object, I tried creating a wrapper around this object, like so, but this did not work because this instance seems to have most of the content as null, plus it would not provide the rest of the methods that the Request object would provide.
class MyRequestWrapper extends Request
{
public MyRequestWrapper(HttpServletRequest request)
{
super( ((Request)request).getHttpChannel(), ((Request)request).getHttpInput());
}
#Override
public String getHeader(String name)
{
if(name.equalsIgnoreCase("X-My-Test"))
{
return "MyName";
}
return super.getHeader(name);
}
}
What is the best way to send the JSON inputs in as headers from the REST handling method to the existing Jetty handlers, without creating security concerns? I guess I could tweak that check for the base request a bit, but I am not sure of the best way to do it.

Wrapped requests are only valid for the same ServletContext and Filter chain that the wrapped request was created in and only applies to the rest of the executing Filter chain from the point in time it was created.
A wrapped request will never apply to a standard Jetty Handler, as that's not participating in a ServletContext or Filter chain.
It is also impossible to wrap the core Jetty Request object due to the needs of the context-less environment it executes within. You cannot change this behavior.
If you are wrapping requests and whatnot just to provide a custom request header, then stop doing ALL of the wrapping and nonsense you are dealing with right now.
Note: The minute you stop wrapping HttpServletRequest, HttpServletResponse, or the Servlet streams is the minute you will have the ability to use features introduced for Servlet 3.0 and newer, such as AsyncContext and Async I/O. The technique of wrapping these components is discouraged in modern usage because it limits your options for better performing webapps.
You have 2 choices, both modify the Request headers in-place.
Modify the Request headers before dispatch.
Modify the Request headers during dispatch via a low level Jetty Handler.
If you choose to modify the headers before dispatch, there are 2 places you can do this.
As a HttpConfiguration.Customizer
During one of the pre-dispatch HttpChannel.Listener events
If you choose to modify the headers during dispatch, then create a Jetty Handler that modifies the Request headers, and put it somewhere early in your server handler hierarchy.
The code that modifies the Request headers will all do the same thing, here's the Handler version as an example.
package jetty.demo;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.HandlerWrapper;
public class ModifyRequestHeadersHandler extends AbstractHandler
{
#Override
public void handle(String target, Request baseRequest,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
// As fully fleshed out field
final HttpField X_MY_TEST = new HttpField("X-My-Test", "MyName");
baseRequest.getHttpFields().put(X_MY_TEST);
// As predefined header and custom value
baseRequest.getHttpFields().put(HttpHeader.X_POWERED_BY,
"ModifiedRequestHeadersHandler");
// As string header and string value
baseRequest.getHttpFields().put("X-Foo-Test", "MyFooName");
}
}

Related

Spring: How to add XSS protection to #RequestBody in a RESTful service?

I am trying to add custom XSS protection by creating a RequestWrapper extending HttpServletRequestWrapper in an XSS filter. The below code provides XSS protection to:
1. Request Params
2. Payload.
public class XssRequestWrapper extends HttpServletRequestWrapper {
XssRequestWrapper(HttpServletRequest request) {
super(request);
}
#Override
public String getQueryString() {
/*
Custom XSS logic
*/
}
#Override
public String getParameterMap() {
/*
Custom XSS logic
*/
}
#Override
public String getParameterValues() {
/*
Custom XSS logic
*/
}
}
But when I configure my REST Api with #RequestBody Annotation in my controller, the overridden getParameterValues is not invoked. Instead, getInputStream is invoked, which results in the addition of the following:
#Override
public ServletInputStream getInputStream() throws IOException {
/*
Custom XSS logic
*/
}
Is there any better/ideal way to provide XSS protection to data passed via #RequestBody annotation?
Edit:
Solution: https://www.baeldung.com/spring-reading-httpservletrequest-multiple-times
Since I was using ContentCachingRequestWrapper in one of my previous filters, I was unable to use the same and hence went forward with the above solution.
By Caching the request, I was able to read it multiple times and perform XSS check over the cached content.
I am a bit confused of what you are trying to achieve with the code.
First thing first - there are three types of Cross-site Scripting (XSS) vulnerabilities:
DOM based - runs in the browser often due a flaw in JavaScript. No server calls are needed for the vulnerability to be exploited.
Reflected XSS - the payload gets reflected in the HTML body by the web server.
Persistent XSS - the payload lands in the DB and is embedded in the HTML body by the web server.
So there are no ways you can address the DOM based XSS with a request wrapper because there is no need for a request to be made.
You might try to address the points 2 and 3, but handling with the request values is a uncommon thing to be done. XSS vulnerabilities are context sensitive, and if you try to encode or escape without knowing the context in which the value is to be used later - you might and will fail.
Please look over the XSS prevention cheat sheet from OWASP to learn how to prevent XSS flaws in the code.

How to support batch web api request processing using Spring/Servlets

We have our Web API written in using RESTEasy. We would like to provide support for Batch requests processing the way Google Batch request processing works.
Following is the approach which are using currently,
We have a filter which accepts incoming multipart request. This filter then creates multiple mock requests and response objects and then calls chain.doFilter using these mock requests.
public class BatchRequestProcessingFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
MockHttpServletRequest[] mockRequests = BatchRequestProcessorUtils.parseRequest(request);
MockHttpServletResponse[] mockResponses = new MockHttpServletResponse[mockRequests.length];
for(int i=0 ; i <= mockRequests.length ; i++ ) {
chain.doFilter(mockRequests[i], mockResponses[i], chain);
}
BatchRequestProcessingUtils.populateResponseFromMockResponses(res, mockResponses);
}
}
MockHttpServletResponse class returns a dummy OutputStream which wraps ByteArrayOutputStream.
BatchRequestProcessorUtils parses the multipart request and returns the mock request which wraps actual request but returns the header specified in split body of the actual request body.
I could not find any existing library which supports batch request processing. So my question is that, is this the correct approach to support batch request or is there any standard way which should be used?
Note that we are using Tomcat 8.
Sachin Gorade. I have not heard about such libraries, but I think your approach is reasonable. If I had to solve that problem, I would think like this:
In our HTTP servlets we can process requests only separately, and it is the reason why we should wrap all requests, that we want to send, into another single request at client side.
As on our server side we have only one request, then we should unwrap all requests we have put into it. And, because we dont know how to process each request in our batch mechanizm - we shold send it through all filters/servlets. Also it is a reason to put our batch filter at the first position in the order.
Eventually, when all requests has been processed, we should send a response back to the client. And again, to do that we should wrap all responses into a single one.
At the client side we should unwrap responses and send each of that to some objects, that can process it.
In my oponion there should be two mechanizms:
Batch sender for client side, that is responsible for collecting and wrapping requests, unwrapping responses and sending them to theirs processors(methods that process regular responses).
Batch processor for server side, that is responsible for unwrapping requests, and collecting and wrapping responses.
Of course, that two parts may be coupled (i.g. to have shared "Wrapper" module), because objects we must be wrapped and unwrapped in the same way.
Also, if I worked on it, I would try to develop the client side mechanizm like a decorator upon a class that I use to send regular requests. In that case, I would be able to substitute regular/batch mode anytime I need to do it.
Hope my opinion is helpful for you.

Changing HTTP method in RequestDispatcher

How do I change HTTP method in javax,servlet.RequestDispatcher?
I have some old service APIs that support GET and POST, The new version supports DELETE method for removing a record which used to happen through POST earlier.
We are decommissioning old version APIs by setting RequestDispatcher.forward() for old end points (stop gap arrangement until clients change). everything was cool except this POST to DELETE mapping.
Any solution there for this problem without adding POST end point for delete operation in new API?>
Although I agree using the next layer after your servlets would be a better choice, this is interesting. It use to be common to wrap an incoming request to add request based functionality (IE: auth state, etc). The HttpServletRequestWrapper was used to accomplish this. You could do the following if you just need to change the method:
class PostDeleteAdapter extends HttpServletRequestWrapper {
public String getMethod(){ return "POST"; }
}
You may also change other aspects of the incoming request if you need to further adapt the request. This may play well with your servlet containers RequestDispatcher, however it's dependent upon the container entirely.
I think you can't do it using servlet API. You can do what you want creating a new request, processing it's response and sending it back through the original response (in the servlet).
Some http clientes might help you. See Apache HTTP client:
http://hc.apache.org/httpclient-3.x/methods/delete.html)

How can i preserve the request headers in error response prepared through JAX-RS ( Apache-CXF implementation) ExceptionMapper

I am implementing JAX-RS using apache CXF. I have created an ExceptionMapper to handle bad requests like this:
public class ClientErrorExceptionMapper implements ExceptionMapper<ClientErrorException> {
#Override
public Response toResponse(final ClientErrorException exception) {
return Response.status(Response.Status.BAD_REQUEST).entity("Invalid request: Invalid URI.").build();
}
}
I am not sure how this works internally but i suppose that framework would throw an exception in case user is making an invalid request and this handler will prepare an error message to be send back. My problem is that i wish to preserve some custom headers that user sends in the request, so that i send that back with the response. But using this exception mapper, i cant see any option to get the original request headers. I can set any new header in the response, but i wish to preserve the request headers - like i do in a normal request.
So is there any way in JAX-RS where i can preserve or efficiently refer to the custom headers in current request ?
What we have resorted to is using a thread local variable to save the RequestContext when the request arrives and then in the ExceptionMapper we can obtain request specific information.
Ugly but it works. I think we have a generic filter in the filter list that catches all requests before dispatch.

Is there any way to simulate HTTP Error responses 5xx and 4xx

I am developing a RESTful service which has two severs talking to each other, which may be named as external and internal.
Internal registers requests to external for further processing. Only external is accessible to users.
For testing reliability my link between internal and external server, I want to simulate HTTP error as returned by external to internal. Is there any easy way to do so or I'll have to hardcode the response being sent by external to internal for testing mainly 5xx and 4xx errors.
Server I am using is JBoss if at all this info is needed.
On searching Google, I found this data for iPlanet
1. edit the obj.conf or your virtual server specific obj.conf
2. Add the following line under
Error code="200" fn="set-variable" error="503"
this would return 503 even for successful serving (which would cause 200 to be returned by the default).
I am looking for something similar for JBoss
I am not aware of a JBoss configuration that will allow you to do this outside of the application. But its easy enough to setup a Resource within your application that would simulate this behavior and remove dependency on vendor specific application server:
#GET #POST #PUT #DELETE
#Path("/echostatus/{statusCode}")
#Produces(MediaType.TEXT_PLAIN, MediaType.TEXT_HTML)
public Response echoStatus(#PathParam("statusCode") final Integer statusCode) {
return Response.status(statusCode.intValue()).build();
}
In my opinion, to test this integration, it would be much easier to develop simple stub web app that will return 5xx code for any URI. To make it more flexible, you can add some handles to be able to tweak behavior of this test app in run time (e.g. based on URI, on various parameters of the request, ...).
I am not aware of any component in JBoss that will do the thing with rewriting status code, but it is simple to do it on your own. Just write your own Tomcat Valve and put it in server.xml
import java.io.IOException;
import javax.servlet.ServletException;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;
public class RequestThroughputLimitValve extends ValveBase implements Lifecycle {
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE: THIS IS NOT COMPLETE IMPLEMENTATION
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
private int statusCode;
#Override
public void invoke(Request request, Response response) throws IOException, ServletException {
// Pass the request further, if necessary
getNext().invoke(request, response);
// Tweak the response
response.setContentType("text/plain");
response.sendError(this.statusCode, "Forced error.");
}
// This will make the status code configurable in valve
public void setStatusCode(int statusCode) {
this.statusCode = statusCode
}
public int getStatusCode() {
return this.statusCode;
}
}
It is very easy to produce error 500. Just throw exception into web service method. JBoss will generate response code 500.
Other way it to use HTTP Resptonse API. Just set status as you want. If you want you can write this code in HTTP filter that can be installed for testing purposes only. This way you can simulate any HTTP status (both 400 or 500 series)

Categories