Doing CORS manually - java

I'm trying to debug my web app,
I have a POST request. (using ajax, with xhrFields: { withCredentials: true } ). dataType is 'application/json', my server is tomcat and i set my "Access-Control-Allow-Origin" header manually to "http://localhost:8080".
other headers:
response.addHeader("Access-Control-Allow-Credentials", "true");
response.addHeader("Access-Control-Allow-Headers", "x-request-verification-token");
Cant get this to work. this is the error i get:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/MysServlet. (Reason: CORS header 'Access-Control-Allow-Origin' does not match 'http://localhost:8080').
thanks ahead!

If you want a configuration that apply to all your requests add in your web.xml the following filter:
<filter>
<filter-name>originfilter</filter-name>
<filter-class>it.damore.web.ApiOriginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>originfilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
This is the ApiOriginFilter class:
public class ApiOriginFilter implements javax.servlet.Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
res.addHeader("Access-Control-Allow-Headers", "Content-Type");
chain.doFilter(request, response);
}
public void destroy() {
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}

Related

Handle CORS in java server side

We have some protected resources which we need to CORS enable. These resources can be fetched/created by get and post.
To handle CORS we have put the handling for preflighted options request in server side. We have a special header to be sent from clients which enables it to be a preflighted request as per https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
On receiving the options request with an origin header we allow the origin using "Access-Control-Allow-Origin" and make Access-Control-Allow-Credentials", "true".
My question is there anything else i need to do or can be there cases where browser does not send the preflighted options request ?
Best Regards,
Saurav
Source: https://howtodoinjava.com/servlets/java-cors-filter-example/
public class CORSFilter implements Filter {
public CORSFilter() {
}
public void destroy() {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
System.out.println("CORSFilter HTTP Request: " + request.getMethod());
// Authorize (allow) all domains to consume the content
((HttpServletResponse) servletResponse).addHeader("Access-Control-Allow-Origin", "*");
((HttpServletResponse) servletResponse).addHeader("Access-Control-Allow-Methods","GET, OPTIONS, HEAD, PUT, POST");
HttpServletResponse resp = (HttpServletResponse) servletResponse;
// For HTTP OPTIONS verb/method reply with ACCEPTED status code -- per CORS handshake
if (request.getMethod().equals("OPTIONS")) {
resp.setStatus(HttpServletResponse.SC_ACCEPTED);
return;
}
// pass the request along the filter chain
chain.doFilter(request, servletResponse);
}
public void init(FilterConfig fConfig) throws ServletException {
}
}

Client side Ajax call on CORS server doesn't include credentials

I'm using Shiro in my web app for security over the REST API. It works fine when the client side is running on the same server, but I can't get it to work with CORS requests. After some research, the app looks like that:
web.xml
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.company.project.cors.CORSFilter</filter-class>
<!--<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>-->
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/v2/*</url-pattern>
</filter-mapping>
I tried with the tomcat's CorsFilter implementations, but as I couldn't get it to work, I implemented my own custom filter:
public class CORSFilter implements Filter {
public CORSFilter() {}
public void destroy() {}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
System.out.println("CORSFilter HTTP Request: " + request.getMethod());
HttpServletResponse resp = (HttpServletResponse) servletResponse;
String origin = request.getHeader("Origin");
resp.setHeader("Access-Control-Allow-Origin", origin);
resp.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
resp.setHeader("Vary", "Origin");
resp.setHeader("Access-Control-Allow-Credentials", "true");
resp.setHeader("Access-Control-Max-Age", "6000");
resp.setHeader("Access-Control-Expose-Headers","Access-Control-Allow-Origin, Access-Control-Allow-Headers, Access-Control-Allow-Credentials, Access-Control-Allow-Methods");
if (request.getMethod().equals("OPTIONS")) {
resp.setStatus(HttpServletResponse.SC_ACCEPTED);
resp.setHeader("Access-Control-Allow-Methods", "PUT, GET, OPTIONS, POST, DELETE");
return;
}
// pass the request along the filter chain
chain.doFilter(request, servletResponse);
}
public void init(FilterConfig fConfig) throws ServletException {}
}
I modified a service to check what the server was receiving in CORS requests:
#POST
#Compress
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response getElementsSearch(SearchRequestObject sro, #Context HttpServletRequest hsr) {
Subject currentUser = SecurityUtils.getSubject();
System.out.println("Current User: " + currentUser);
System.out.println("Session: " + currentUser.getSession(false));
System.out.println("Current User: " + currentUser.getPrincipal());
System.out.println("Origin: " + hsr.getHeader("Origin"));
System.out.println("Headers: ");
Enumeration<String> e1 = hsr.getHeaderNames();
while(e1.hasMoreElements()) {
String param = e1.nextElement();
System.out.print(param + "; ");
}
System.out.println("Cookie: " + hsr.getHeader("cookie"));
if(!currentUser.isAuthenticated())
return Response.status(Response.Status.UNAUTHORIZED).build();
.
.
.
}
The ajax call using jQuery looks like this:
$.ajax({
url: ServerUrl+'search',
type: 'POST',
data: JSON.stringify(objSearch),
headers: {'Content-Type':'application/json'},
xhrFields: {
withCredentials: true
},
success: function (result) {
//Format result
}, //success
error: ajaxErrorCallback
});
This call returns unauthorized because the cookie with the JSESSIONID isn't include in the request's headers in spite of having set the xhrFields.withCredentials to true, so the server treat it like a new not-authenticated session. I don't know whether the problem is in the server or client side. Does anyone knows if I missed something?
The login request must include the withCredentials=true flag too. If not, it seems like the JSESSIONID cookie is dismissed by the browser. Now it's working fine.

How do I activate a CORS Filter for Cross Domain POST Requests in Maven?

I made a React Application deployed to a separate Google App Engine, which sends a POST Request to fetch some data from a Webapp, and I'm trying to parse the data within my React Application. I was able to fetch the correct data from PostMan, but the same request kept giving me a "No 'Access-Control-Allow-Origin' Header is present on the requested resource" Error.
I'm currently receiving the PostRequest from the Bigger Webapp like this:
#POST
#Path("/initializer")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String getOrCreateSeller(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
this.shopifyStoreName = body.get("id").toString();
long hashedName = hashStoreName();
SellerId sellerId = new SellerId(hashedName);
try {
Seller seller = sellerService.findSellerById(sellerId);
getStore(seller);
String json = getResponseJson();
return Response.ok(json, MediaType.APPLICATION_JSON).build();
} catch (NotFoundException e) {
Seller seller = new Seller(sellerId.toDatastoreId(),
this.shopifyStoreName, 3L);
datastoreRepository.transact(() -> {
sellerValidator.validate(seller);
sellerRepository.save(seller);
});
createStore(seller);
String json = getResponseJson();
Response.ResponseBuilder r = Response.ok(json, MediaType.APPLICATION_JSON);
return r.build();
}
}
It turns out that in the bigger webapp I'm fetching data from contains a "CORSFilter" Class that looks like this:
public class CORSFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,
ServletException {
HttpServletResponse httpResp = (HttpServletResponse) resp;
HttpServletRequest httpReq = (HttpServletRequest) req;
httpResp.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS");
httpResp.setHeader("Access-Control-Allow-Origin", "*");
if (httpReq.getMethod().equalsIgnoreCase("OPTIONS")) {
httpResp.setHeader("Access-Control-Allow-Headers",
httpReq.getHeader("Access-Control-Request-Headers"));
}
chain.doFilter(req, resp);
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
#Override
public void destroy() {
}
}
Hence, I feel like I should use this class to enable CORs, but I am not sure how. Please help!
As your server-side code seems to be using JAX-RS, a way to add CORS Headers to a JAX-RS application (following the same rules of that CORSFilter of yours) is just to add this class to your app:
#Provider
#Priority(Priorities.HEADER_DECORATOR)
public class AccessControlResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
final MultivaluedMap<String,Object> headers = responseContext.getHeaders();
headers.add("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS");
headers.add("Access-Control-Allow-Origin", "*");
if (requestContext.getMethod().equalsIgnoreCase("OPTIONS")) {
headers.add("Access-Control-Allow-Headers", requestContext.getHeaderString("Access-Control-Request-Headers"));
}
}
}
Alternatively, if you have that CORSFilter class available to your project, you could add it as a servlet filter to your web.xml:
<filter>
<filter-name>CORSFilter</filter-name>
<filter-class>com.mycompany.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CORSFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Pick one of the two solutions, not both.
You can use #CrossOrigin annotation in controller class. Can get more information here - crossorigin

Tomcat HTTPS only except 1 endpoint

I already configured my Connector in the server.xml with the redirection from 8080 to 8443, and set the security-constraint in web.xml with the appropriate sub-tags. It redirects properly, but I would like to ignore the HTTP access and use only HTTPS. So I do not need redirection or smthing like that. An external service requires HTTP access for an endpoint, I would like to enable only that endpoint over HTTP.
I tried to remove the Connector with 8080 port, but with this approach there is no chance to get the request over http.
If you disable http conection you will not have an access to your application over http.
So you can implement a filter that checks if the protocol of current request is HTTP and endpoint URL is allowed otherwise block the request.
In your web.xml you can declare following filter:
<filter>
<filter-name>blockHttpFilter</filter-name>
<filter-class>com.example.BlockHttpFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>urlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Implementation may be following:
public class BlockHttpFilter implements Filter {
private ServletContext context;
public void init(FilterConfig fConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
if(req.isSecure() && checkHttpEnpointPath(req)){
chain.doFilter(request, response);
} else {
HttpServletResponse res = (HttpServletResponse)response;
res.sendError(403);
}
}
public void destroy() {
//we can close resources here
}
}

How to update the response Content-Type after Servlet processing is done using ServeletFilter

I tried to change the ServletResponse Content-Type using ServletFilter. But, the servelet (in my content, AxisServlet) updates that Content-Type when chain.doFilter() calls. But other Response Headers are correctly updated.
I tried setting response headers after doFilter is called. At that time no response header was updated.
Does anyone know a way to update the Content-Type of the ServletResponse after Servelt is completed?
Code :
public class HeaderFilter implements Filter {
private HashMap<String,String> rsCustomHeaders = new HashMap<String,String>();
public void init(FilterConfig config) throws ServletException {
Enumeration<String> initParameterNames = config.getInitParameterNames();
while (initParameterNames.hasMoreElements()) {
String initParameterName = initParameterNames.nextElement();
rsCustomHeaders.put(initParameterName, config.getInitParameter(initParameterName));
}
System.out.println("init().rsCustomHeaders : " + rsCustomHeaders);
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
for (Map.Entry<String, String> rsCustomHeaderEntry : rsCustomHeaders.entrySet()) {
httpServletResponse.addHeader(rsCustomHeaderEntry.getKey(), rsCustomHeaderEntry.getValue());
}
System.out.println("doFilter().encoding :Set Response Headers Done");
chain.doFilter(httpServletRequest, httpServletResponse);
System.out.println("doFilter().HeaderFilter is Done!!!");
}
public void destroy() {
System.out.println("destroy(). : Destroy is called!");
}
}
web.xml
<filter>
<filter-name>HeaderFilter</filter-name>
<filter-class>filters.HeaderFilter</filter-class>
<init-param>
<param-name>content-type</param-name>
<param-value>application/xml; charset=utf-8</param-value>
</init-param>
<init-param>
<param-name>Content_type</param-name>
<param-value>text/xml; charset=utf-8</param-value>
</init-param>
<init-param>
<param-name>rq_content-type</param-name>
<param-value>text/xml; charset=utf-8</param-value>
</init-param>
<init-param>
<param-name>Header-X</param-name>
<param-value>Value-X</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>HeaderFilter</filter-name>
<url-pattern>/services/GradeThreeMath</url-pattern>
</filter-mapping>
Set content type on the original response.
Use HttpServletResponseWrapper with overridden setContentType to wrap response that is passed to child.doFilter. Overridden setContentType should just ignore any attempts to change content type.
The code snippet:
// Setting content type
httpServletResponse.setContentType("you-content-type");
chain.doFilter(httpServletRequest, new HttpServletResponseWrapper(httpServletResponse) {
#Override
public void setContentType(final String type) {
// Ignore any further attempts to change content type
}
});

Categories

Resources