1

I have a java server handling RESTful services on port 8080 using Glassfish/Jersey libraries (I do not have a web.xml file as I am hosting the services in the console app). I am running a webpack-dev-server with ReactJS on port 8081. In my ReactJS control I make a GET request from my RESTful service. When I make that call I get the following error:

Fetch API cannot load http://localhost:8080/realtime/initialize. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8081' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

This is the javascript code:

fetch('http://localhost:8080/realtime/initialize', {
        method: "GET",
        headers: {
            mode: 'cors',
        } 
    })
    .then(function(response) {
        console.log("financial services initialization ok");
        this.setState({loginState: 1});
    }).catch(function(err) {
        console.log("financial services initialization error: " + err);
        alert("initialized failed");
    });

here is my java class:

package Application.Server;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import Application.Server.Contracts.GeneralResult;

@Path("/realtime")
public class RealTimeServices {
    private int count = 1;

    @GET
    @Path("/initialize")
    @Produces(MediaType.APPLICATION_JSON)
    public GeneralResult initializeAccount() {
        outputService.showMessage("connecting attempt: " + count);          
        count ++;           
        return new GeneralResult("request made");
    }
}

I'm not sure what the problem is--I under cors is a browser security issue but don't understand what it means to handle cors. My attempt to fix it fails.

I've tried adding 'Access-Control-Allow-Origin' to the javascript http call but that still throws an error and I do not get the results back.

It seems like I need change something in the java code, but Im happy if there is something I can change in the javascript.

Thank you Matt

cweiske
  • 30,033
  • 14
  • 133
  • 194
tatmanblue
  • 1,176
  • 2
  • 14
  • 30

2 Answers2

0

This web service requires a request handler for the OPTIONS preflight request. The standards try and make it hard to disable critical security features like the same-origin policy (SOP), so that you have to be very intentional on what features you expose.

In this particular API call, it doesn't look like a response is required. I'm not sure why you would want to undermine the SOP.

rook
  • 66,304
  • 38
  • 162
  • 239
  • I intentionally left out all of the logic so to keep the code as concise as possible. Please assume I need to fix cors/SOP problem. – tatmanblue Apr 22 '17 at 00:13
  • @tatmanblue then please assume you need an `OPTIONS` pre-flight request handler. I know for a **absolute fact** that if you don't need to read the response, then you don't need CORS. This is the point of cross-site request forgery (CSRF) and I exploit this on a regular basis. SOP is never a problem, unless it is keeping you from writing an exploit. – rook Apr 22 '17 at 01:00
0

I solved the cors issue by adding a response filter to the grizzly server instance. I started with the filter:

import java.io.IOException;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.Provider;

import com.google.inject.Singleton;

@Singleton
@Provider
public class ServerResponses implements ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
            throws IOException {
        MultivaluedMap<String, Object> headers = responseContext.getHeaders();

        headers.add("Access-Control-Allow-Origin", "*");
        headers.add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
        headers.add("Access-Control-Allow-Credentials", "true");
        headers.add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");       

    }

}

Then I added that class during the server start up code like this:

public HttpServer startServer() {
    final WebServerResourceConfig rc = new WebServerResourceConfig();

    rc.register(Application.Server.ServerResponses.class);

    return GrizzlyHttpServerFactory.createHttpServer(URI.create(configurationService.RootWebServiceURI()), rc);
}

My answer is based on this stackexchange post. As @rook pointed out, this may be an insecure solution. It works for me as I will not be deploying my server.

Thank you Matt

Community
  • 1
  • 1
tatmanblue
  • 1,176
  • 2
  • 14
  • 30