Apache Camel Restlet - CORS Issue - apache-camel

This route works, and works nicely using SoapUI:
from("restlet:http://localhost:8484/restletTestService/submit?restletMethod=POST")
.routeId("myRestletSubmitRoute")
.unmarshal().json(JsonLibrary.Jackson, MyRequest.class)
.to("bean:myServiceSubmitProcessor")
.marshal().json(JsonLibrary.Jackson, MyResponse.class);
Using SoapUI, I can post jsons that conform to the structure of the MyRequest class and I get a json back with the info I think I should.
However, when I created a quick angularjs page to allow users to build a request on the fly and then 'POST' to my rest endpoint, well:
XMLHttpRequest cannot load http://localhost:8484/restletAddressService/addressPersonator/submit. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 405.
I'm pretty sure that I have to somehow set the header Access-Control-Allow-Origin to some value on the restlet URI, but I haven't a clue how to do that. I researched the documentation (http://camel.apache.org/restlet.html) and googled it, but I'm not finding anything that has helped.
Does anyone know the answer? Thanks!
UPDATE
So the answer from fiw gave me the hint I needed along with some google research on HOW a call to a rest resource determines what's allowed (plus quite a bit of good-ole-fashioned trial and error :) ). This is what wound up working:
from("restlet:http://localhost:8484/restletTestService/submit?restletMethod=POST")
.routeId("myRestletSubmitRoutePOST")
.unmarshal().json(JsonLibrary.Jackson, MyRequest.class)
.to("bean:myServiceSubmitProcessor")
.marshal().json(JsonLibrary.Jackson, MyResponse.class)
.setHeader("Access-Control-Allow-Headers", constant("Content-Type"))
.setHeader("Access-Control-Allow-Origin", constant("*"));
from("restlet:http://localhost:8484/restletTestService/submit?restletMethod=OPTIONS")
.routeId("myRestletSubmitRouteOPTIONS")
.setHeader("Access-Control-Allow-Headers", constant("Content-Type"))
.setHeader("Access-Control-Allow-Origin", constant("*"));
Thanks!

I think you need to set Access-Control-Allow-Origin as a header on the response with a value of * as you've suggested. So to do this in camel:
from("restlet:http://localhost:8484/restletTestService/submit?restletMethod=POST")
.routeId("myRestletSubmitRoute")
.unmarshal().json(JsonLibrary.Jackson, MyRequest.class)
.to("bean:myServiceSubmitProcessor")
.marshal().json(JsonLibrary.Jackson, MyResponse.class)
.setHeader("Access-Control-Allow-Origin", constant("*"));
This came from reading: enable cors on your server.

Related

Chrome is ignoring Access-Control-Allow-Origin header and fails CORS with preflight error when calling AWS Lambda

I'm building a ReactJS frontend that has to gather some data from AWS Lambdas using a JS fetch.
I cannot make it work, no mater what CORS technique I apply. I've looked into other answers here to no avail.
I am definitely adding Access-Control-Allow-Origin with "*" value in my response (verified this using postman to call the endpoint). Also, Chrome complains about the preflight with Response to preflight request doesn't pass access control check, but no preflight request (OPTIONS method) is ever actually fired by chrome, all I see is the GET I'm trying to make on the first place, which is really confusing.
What am I missing? Why is chrome complaining about preflight when no OPTIONS preflight request is made? Why adding Access-Control-Allow-Origin with "*" in my response is not enough?
Thanks!
TL;DR: There was a preflight request happening, it just wasn't showing on chrome (there's a way to make them show up). Also, there's a tweak to make if you use custom headers for authorization tokens for example.
Summary
Well, after looking into this for a day and checking several other answers I'm posting this because none quite fit my problem, with the hope it will help anyone else facing this.
First, I'll summarize the several parts involved in the error and then how to fix it, without resorting to any "hackish" solution like bypassing CORS with a chrome extension, or using any 3rd party service, like many posts suggest. My setup looked like this:
ReactJS frontend, try to make a GET request using fetch javascript method, running on http://localhost:3000 for development
AWS Lambda Backend, that answers the GET with a JSON payload (coded in python, not important but anyways). This lambda is adding Access-Control-Allow-Origin:"*" header to its response.
The above AWS Lambda is behind what AWS calls an "Authorizer", which is a function that runs before your lambda to check whatever authorization header you want to use to protect access to your API. This is important as we'll see later, because due to some nonsense on AWS inner workings, sometimes you cannot use the standard HTTP Authorization header, and it defaults to using authorizationToken as they suggest in their documentation and samples (and changing it not always works, there are plenty of users reporting this in their forums). We'll keep a note on this for later.
Both API methods (actual API and its Authorizer) routed and published on the internet using AWS API Gateway, which in short is a way to pair your lambda with a public URL to call it from elsewhere.
Google Chrome used as browser (with its developer tools enabled to monitor things)
The error
When trying to call the lambda, chrome blocks the GET request with this error showing on the console: Response to preflight request doesn't pass access control check. My lambda is already answering with the correct Access-Control-Allow-Origin header so, what's wrong? Also, no preflight OPTIONS request are being made anyways, so this was confusing.
Some debugging
AWS Lambda is great but their debugging tools are not as fluid as I would like, so I replaced the lambda with a local expressjs server, implementing just two methods: GET /foo and OPTIONS /foo. To my surprise, when from my ReactJS frontend I fetched /foo, it did call OPTIONS /foo first (I confirmed this by adding logs to my endpoint, etc, something you can also do in lambdas but its not as easy).
What was actually happening
A "preflight" request is an OPTIONS request to validate what is actually allowed when doing the following GET, but the Network tab in Chrome was not showing any OPTIONS request actually happening (I remember they used to show up here). Well, they changed it at some point, and now they are hidden by default. If you want them to show again (as a developer, I do), you can re-enable that by changing the out-of-blink-cors flag to disabled as explained here.
After changing this flag, now the OPTIONS request does show on the network tab. From there I could craft the OPTIONS response so it would enable the required GET afterwards. There are other considerations when using credentials and other cases (I found this article from Mozilla helpful with that), but in short my OPTIONS response headers look like this:
Access-Control-Allow-Origin: "http://localhost:3000"
Access-Control-Allow-Methods: "GET, POST, OPTIONS"
Access-Control-Allow-Headers: "authorizationToken"
(That last one, Access-Control-Allow-Headers, comes into play when dealing with AWS Lambdas Authorizers. If you are using that custom header to send your tokens, you need to allow it here).
After making CORS work locally, to solve it for my lambdas I did two things:
You need your API Gateway to be able to answer OPTIONS request. There are a number of ways to achieve this, from writing your own lambda to answer it to having AWS to mock-response it for you. More info on that here.
You need to make sure your GET lambda adds the Access-Control-Allow-Origin header, pointing to the same value your OPTIONS response did (In my case, http://localhost:3000).
After that, all worked as expected.
Final Notes
I wrote this answer because I found the conjunction of "React-CORS-AWS-Authorization" was not actually covered by any questions I found around.
Also there are a number of problems that may arise from using localhost for development on chrome, leading to suggestions of using an external service like lvh.me, but this was not the case, and some answers misleadingly relate this CORS problem to that. Moreover, some answers suggest disabling CORS checks altogether with some chrome extension, which is really bad security advice.
Finally, I found the idea of making a simple expressJS server to debug the server-side of things pretty helpful in understanding what was happening, because sometimes you simply cannot access what's happening on the other side, so maybe this suggestion might help people shorten the time dealing with things like this.

Allowing CORS only for my domain?

I have an AngularJs website and when I am trying to post data then when I am opening my website without using www then I am getting
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource
Otherwise, I am not getting any error.
I tried to search and found that I should implement CORS on my backend which is in NodeJs but can anyone please tell me how can I only implement CORS Headers such that for both www and without, it would work but for any other domain trying to access my API must result in preflight error.
I am trying to do this because I read here which-security-risks-do-cors-imply that allowing all domains can increase security overhead for my website which I do not want.
Thanks.
I'm afraid this is not something you can tweak just in your client-side code. In order for cross-origin requests to work, you need to set an http response header: it's the server, who serves the resource, who will need the change, not the client side code from angularJs.
I believe that you should update your question stating what your server side language is and how are you handling http requests in the server side. As far as I know, just adding a header like:
Access-Control-Allow-Origin: http://client.domain.com
In your responses will do the trick. Where client.domain.com is the domain of your client, angularJs application.

Eliminate CORS in Angular2 and Solr5.5

I'm using Solr 5.5 to speed up the search for information in a news manager.
But when I try to send the url with the search parameters to Solr, the browser sends me the following error:
XMLHttpRequest cannot load '127.0.0.1:8983/solr/prueba/select?q=id:*&wt=json'.
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'localhost:4200' is therefore not allowed access.
How can i fix this?
You have to enable CORS on your Solr instance.
There are many options to do this, I will modify the Jetty configuration.
I found an interesting article,
Going Cross-Origin with Solr, that explain how to do this.

Access-Control-Allow-Origin Issue with API

I have written a pretty simple API in PHP and am running it as a service (https://protoapi-dot-rehash-148415.appspot.com/events/).
When I try to load a data grid with the JSON from the API, I am getting the dreaded "No 'Access-Control-Allow-Origin' header is present on the requested resource." error on the page on which I want to consume the JSON. (http://proto-angular-dot-rehash-148415.appspot.com/events.php)
I've tried a couple of different methods to add Access-Control-Allow-Origin: "*" to the app.yaml file and to the header in the PHP file that produces the API. I think it doesn't work in the yaml because you cannot apply http_headers to dynamic files, and it doesn't work in the file because of the compression.
Is there any other way to make this work, short of putting the API and the app in the same service? I'd hate to do that because I am using mod_rewrite for the API and it will probably cause chaos on my app.
Any insights would be greatly appreciated!
-Mike
The header won't do any good unless you add it server-side, on the events API. The server is what dictates CORS permissions. You could send it messages or files all day with the right headers at the top and it will just ignore them. The allow-origin header has to come from the server to allow the cross-origin resource sharing (CORS) to take place.
I would recommend prepending the header in the function that offers up the API or handles the requests. Your events API spits out a lot of JSON. Right before that JSON, have your API spit out the header Access-Control-Allow-Origin: * and you should be all set.
As a sanity check you can also try adding Access-Control-Allow-Headers: Content-Type and see if that helps. Based on your comment about the Content-Type header, this may be part of the problem. It should be added the same way as the other one; have your API send it prior to your events JSON on its own line (put a \n to make a new line inside the string literal).

CORS and the new ASPNET5

I've trying to make a request to my aspnet Web Api, with angular, with the $http module inside a factory, like:
http.get('http://localhost:5000/api/todo').success(function(r){ return r; }).error(function(err){ return err; });
But I'm getting the following error:
XMLHttpRequest cannot load http://localhost:5000/api/todo. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin http://localhost:9000/ is therefore not allowed access.
I know that the request arrive to the server because I log a message when I request the resource.
I found that I had to implement CORS at the server. I added the CORS middleware and configure my Startup file, but nothing changed.
I suppose that the middleware should add the configured headers to the response, but It doesn't.
¿What is the problem in this context?
Ok, after a small research. I found that .WithOrigins("...") method is not adding the Access-Control-Allow-Origin header, I don't know if it's the context or what, I just made an issue about it. I replace it with .AllowAnyOrigin() by now.
And also added an attribute to my controller class.
[EnableCorsAttribute("AllowAll")]
Of course you need to add the namespace where EnableCorsAttribute class is.
using Microsoft.AspNet.Cors.Core;
This worked for me I hope it help you, thanks for the comments.

Resources