0

I do not manage to get my application running. I was reading about this the whole day, tried a bunch of stuff, but in the end nothing did work. In the last attempt I tried this link. I have the java back end as a RESTful web service without any additional framework like Jersey or RESTeasy, just pure java. There I have my login POST method:

@POST
@Path("login")
@Produces(value = "application/json")
public Response login() {

    AccountAuthentificator authentificator = AccountAuthentificator.getInstance();
    Status status = Response.Status.OK;

    String credentialValue = getHeaderValue(AccountAuthentificator.AUTH_CREDENTIALS);
    if (credentialValue == null) {
        status = Response.Status.FORBIDDEN;
        return WebServiceUtil.createResponse(status, "Missing account credentials in header.");
    }

    try {
        LoginResponse res = authentificator.login(credentialValue);
        return WebServiceUtil.createResponse(status, res);
    } catch (AccessControlException e) {
        status = Response.Status.FORBIDDEN;
        return WebServiceUtil.createResponse(status,
                "User does not exist. Please verify your user name and password.");
    }
}

The WebServiceUtil.createResponse method basically adds the necessary headers as you can see here:

public static Response createResponse(Status status, Object responseContent) {

    ResponseBuilder resBuilder = Response.status(status.getStatusCode());

    resBuilder.header("Access-Control-Allow-Origin", "*");
    resBuilder.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
    resBuilder.header("Access-Control-Allow-Credentials", "true");
    resBuilder.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");

    resBuilder.allow("OPTIONS");

    resBuilder.entity(getJSONAsString(responseContent));

    return resBuilder.build();
}

I also saw people used another approach. It was with filters, like this example. I was also wondering if my implementation differs from this and where exactly is the preflight defined - in my implementation it is the .allow("OPTIONS") which does that, but you can correct me of I am wrong.

And then I have my web application where I call this POST method. I am using AngularJS for this. In my AuthenticateController controller I have the Login method, which is called on submit in the login form. The implementation looks like this:

function Login(username, password) {
        // CreateLoginHeader creates the authorization token through the login values username and password
        var authdata = CreateLoginHeader(username, password);
        var config = {
                withCredentials: true,
                headers:  { 'Authorization': authdata }
        };
        $http.post('http://XXXX', config).then(SuccessLogin, ErrorLogin);
    }

Does anybody know what is wrong here? Through the chrome developer tools I can see I get the error "XMLHttpRequest cannot load 'placeholder-server-URL'. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'placeholder-client-URL' is therefore not allowed access.".

Should I be adding those two header values on the client side, when calling my back end:

  • Access-Control-Request-Method
  • Access-Control-Request-Headers
Flexo
  • 87,323
  • 22
  • 191
  • 272
Jernej K
  • 1,602
  • 2
  • 25
  • 38
  • So why are you making a cross domain call? The CORS headers has nothing to do with the clientside, the server would need to add them. – epascarello Mar 05 '16 at 00:15
  • 'RESTful web service without any additional framework like Jersey or RESTeasy' - are you sure? see: http://stackoverflow.com/tags/jax-rs/info – Meiko Rachimow Mar 05 '16 at 00:15
  • Sorry, you are right, I use javax: javax javaee-api 7.0 provided in my maven pom.xml file. And yeah, I also thought from what I was reading that the CORS header has to be implemented only on the server side @epascarello .It just happen that I followed another example and added those values programatically. But as far as I learned, they should be already created through the browser. – Jernej K Mar 05 '16 at 00:21

1 Answers1

2

The Options request is not handled by login, so createResponse is not called.

Have a look at: https://blogs.oracle.com/theaquarium/entry/supporting_cors_in_jax_rs (you should implement a javax.ws.rs.container.ContainerResponseFilter, see How to handle CORS using JAX-RS with Jersey)

Another possibility for your code here (but not if you develop a 'real' application): add @javax.ws.rs.OPTIONS to your method like you did with @javax.ws.rs.POST.

Community
  • 1
  • 1
Meiko Rachimow
  • 4,664
  • 2
  • 25
  • 43
  • OK, I tried this way and I was sticking to the tutorial [here](http://www.developerscrappad.com/1781/java/java-ee/rest-jax-rs/java-ee-7-jax-rs-2-0-cors-on-rest-how-to-make-rest-apis-accessible-from-a-different-domain/). The only thing I did not do is changed the web.xml file like he did. I am extending the Application class and adding there my class with all the defined post/get methods. I also use the logger for the filters and it seems the filters are not called on the requests and responses. Any idea why is that the case? – Jernej K Mar 05 '16 at 02:43
  • Basically this is my Application class: `@ApplicationPath("/api/v1/brain") public class ApplicationConfig extends Application { public Set> getClasses() { Set> s = new HashSet>(); s.add(StudyManagerService.class); return s; } }` – Jernej K Mar 05 '16 at 02:45
  • Try to register the filters ("providers") the same way like your StudyManagerService. – Meiko Rachimow Mar 05 '16 at 08:03
  • That change did the job. I added my two filter classes: `s.add(StudyManagerService.class); s.add(RESTRequestFilter.class); s.add(RESTResponseFilter.class);` It seems I have an exception in the front end now, but at least I got one step further. Thanks @meiko – Jernej K Mar 05 '16 at 16:15
  • You are welcome, maybe you could mark an answer as correct ;) – Meiko Rachimow Mar 06 '16 at 00:48