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
3
  • 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. Commented Mar 5, 2016 at 0:15
  • 'RESTful web service without any additional framework like Jersey or RESTeasy' - are you sure? see: stackoverflow.com/tags/jax-rs/info Commented Mar 5, 2016 at 0:15
  • Sorry, you are right, I use javax: <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> 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. Commented Mar 5, 2016 at 0:21

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

5 Comments

OK, I tried this way and I was sticking to the tutorial here. 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?
Basically this is my Application class: @ApplicationPath("/api/v1/brain") public class ApplicationConfig extends Application { public Set<Class<?>> getClasses() { Set<Class<?>> s = new HashSet<Class<?>>(); s.add(StudyManagerService.class); return s; } }
Try to register the filters ("providers") the same way like your StudyManagerService.
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
You are welcome, maybe you could mark an answer as correct ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.