Cross domain requests for liferay 6.06 web services - javascript

I'm already able to access json data from liferay web services using this url and with a proper authentication :
http://login:password#localhost:8080/tunnel-web/secure/json
But I'll need to interrogate this in javascript from another domain name.
I've run into the classic error :
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://my.origin.com/' is therefore not allowed access.
I know I have to allow this origin on the server response header which can be done in jsp like this :
response.setHeader("Access-Control-Allow-Origin", "http://my.origin.com");
The question is, how can I allow this origin for liferay's default webservices ?
edit :
I've tried to add a portal-ext.properties file with :
axis.servlet.hosts.allowed=
axis.servlet.https.required=false
tunnel.servlet.hosts.allowed=
tunnel.servlet.https.required=false
//empty values are meant to allow any IP...
But it doesn't change anything :(
PS : I'm using liferay 6.06

If you want to alter Tomcat you have to alter liferay web.xml to enable Cors Filter, follow this post:
Access-Control-Allow-Origin: * in tomcat
But to me the best way is having an Apache Web Server (httpd) in front of tomcat/liferay using proxypass module. Apache server runs as reverse proxy for tomcat.
In the proxypass rule you can setup apache to fill the response with some extra headers.
Refer this big post:
How to correctly configure a reverse proxy with Apache, to be used for cross-domain AJAX?

Related

CORS request blocked in locally opened html file

I've started to write a HTML file which displays data with JavaScript. Since it shall be done as easy as possible I don't want to run nodejs oder any other local http server. I've just opened the HTML file in a browser (url is file:///home/visu/index.htm).
Everything is fine, till a jquery ajax request to a online API is done in the index.htm. The browser blocks the request with the message:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://x.x.x.x. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)."
How can I get rid of the problem without starting a local http server?
A possible solution is to start the browser with some "no security flags" or disable CORS with plugins, but this I've to do manually all the time so I don't like it.
When your browser will perform an AJAX request to a different server than the one hosting the current page, it first sends an OPTIONS HTTP message. In that message it sends the following header:
origin: http://my-web-server.com
And the backend server will respond with:
access-control-allow-origin: http://my-web-server.com
But, when you don't have a webserver, there is no address for your browser to put in that origin header. That's why your browser disallows you to do any AJAX request from a local file (maybe you can disable the browser's CORS security as someone mentioned in the comments, but that can put you at risk of malicious sites).
Another option
You can tell your browser to allow to connect from localhost to a backend if you change your backend to return the following header:
access-control-allow-origin: https://localhost:8888
And, you also need to tell your localhost server to serve your page in HTTPS instead of HTTP. Once both conditions are met, CORS validations won't fail.
Notice that to enable HTTPS you'll need to have a SSL cert and key, you can generate them with the following command:
openssl req -x509 -out localhost.crt -keyout localhost.key \
-newkey rsa:2048 -nodes -sha256 \
-subj '/CN=localhost' -extensions EXT -config <( \
printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")
The source of that command and more information are found in this page from Let's Encrypt.
On Firefox, you can install this addon: https://addons.mozilla.org/en-US/firefox/addon/cors-everywhere/ to disable CORS for the respective tab. Then, any request will also work on file:/// URIs. Be careful though!
Either mock Ajax calls, or start web server with reverse proxy and HTTP rewriting configured, since I'm sure you don't want, or have not access to configure API server CORS headers.
If you don't want to mock ajax calls, then use either:
node-http-proxy
nginx - if you don't have nodejs and you don't want to install it.
Not Possible By Design
CORS are always blocked when attempted from a file on disk (web pages using the file:// protocol). There is nothing you can do to make it work from a file. It is simply impossible.
The reasoning for this is that files on disk have no real "origin" to allow the backend server to determine the validity of the request. You can have a file for an issue tracking html on the same disk as a file for a blog html. The server cannot know which html requested the data (you can even have someone else's file shared via Dropbox with embedded javascript that may attempt to access your server's data when you open it - nobody expects a hacking attempt when they simply open a plain html file!!).
This is why no browser vendor will allow you do make CORS requests from a file.
You Need a Server
To make it work you will need a HTTP server. There are lots of options for this from installing Apache/Nginx on your machine to running dev servers like webpack-dev-server or local-web-server. As long as the protocol is http:// or https:// you are allowed to make CORS requests.
Once you have a server serving your html file you can configure CORS on your backend as usual.
If you can not set it up access-control-allow-origin, you can try this.
Use "callback" function if your data is not in same domain.
And wrap your data "jsonCallback(" ... data ... ") as my example: http://www.ceducation.cz/akce-plnytext.json?short=1&callback=?
function jsonCallback(json) {
$.each(json, function(key, val) {
// your data is here
console.log('date: ' + val.date);
console.log('address: ' + val.address);
console.log('---');
});
}
$(document).ready(function() {
$.getJSON("http://www.ceducation.cz/akce-plnytext.json?short=1&callback=?", function(data) {
});
});
Working example

How to call an API on a different subdomain in Javascript/Jquery

I have 2 sub domains (1 site we host one we don't) - they both have SSL certs.
api.mydomain.co.uk (the domain we do host with a valid ssl cert)
test.mydomain.co.uk (the domain we don't host with an invalid cert but the same domain)
I have an AJAX call from test.mydomain.co.uk to api.mydomain.co.uk. Now obviously I get a No 'Access-Control-Allow-Origin' header is present on the requested resource error which I would expect.
But then a put document.domain = "mydomain.co.uk" in the code on test.mydomain.co.uk.
I thought that would solve the issue (I've never done this before though) as it is a subdomain. So my question is - is the invalid SSL causing a problem, or do I need to do something more like CORS etc?
Yes, you need to config cors on your subdomain to make it behave like an api.
Let's say your page is requested from test.mydomain.co.uk, all ajax calls made to test.mydomain.co.uk are from the same origin, so no CORS config needed.
When you try to make calls to api.mydomain.co.uk, it will see it as another origin, even tough it's the same domain, so you gotta configure it to accept CORS requests. You do it on your NGINX, node, or whatever you're using as a webserver.
Here's how you'd do it on NGINX.
http://enable-cors.org/server_nginx.html

CORS implementation IN Javascript

I want to access a resource placed in someother server. I want to access it from javascript , I tried implementing CORS , by following tutorial here . But didn't get how to configure other server with Access-Control-Allow-Origin header, so still browser didnt allowed access . I then tried installing CORS extension for chrome , it worked , but the issue with chrome extension is that , if I access any resource from the same server , where web page is hoisted , I get this error : The 'Access-Control-Allow-Origin' header contains multiple values, but only one is allowed. Origin _ ,is therefore not allowed access.
In case of chrome extension cross domain resource access works but from same domain fails.
I want to implement CORS through code , rather than extension .
There are two ways to do it :
Add the chrome extension CORS to chrome , then if you try to make a cross domain XMLHTTPRequest , the browser won't complain , it would load the cross domain resource.
If you dont want extension , other way is to configure the cross domain server.Below is the process for wamp server
open file apache/conf/httpd.conf and uncomment below line :
LoadModule headers_module modules/mod_headers.so
Add below lines under "Directory" tag
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
Use * if you want to allow cross domain from all servers else give the name of server explicitly.
Now save the httpd.conf file and restart the wamp server.
Besides the two opetions mentioned by #Bhupendra, You could also run a proxy. The Proxy goes between your browser and the actual server, and adds the headers on the fly. For development, this is a perfectly fine solution.
Two node projects that i have used:
https://github.com/Rob--W/cors-anywhere
https://github.com/gr2m/CORS-Proxy
You will need node.js and npm for both.

Restify and Angular CORS No 'Access-Control-Allow-Origin' header is present on the requested resource

I faced with that problem when implementing REST api with Restify secured with bearer token authorization type.
when I sending simple get request to API server it fails with CORS problem
405 (Method Not Allowed) angular.js:7962
OPTIONS http://api.host.com/tests No 'Access-Control-Allow-Origin' header is
present on the requested resource. Origin 'http://local.host.com' is
therefore not allowed access.
Solution described in my answer, so it's not real question for me, because I placed it when already know the answer, but hope it will save time for someone else in future.
The problem was faced because of restify has internal CORS module who manage CORS logic. in this module you could find list of allowed headers, by default it's
[
'accept',
'accept-version',
'content-type',
'request-id',
'origin',
'x-api-version',
'x-request-id'
]
As I say in the question, I use bearer token auth, so I send my request with Authorization header. It's not included in default list, and that's why my request fails.
To fix that problem we need to add this header to the list of ALLOW_HEADERS. for that in my restify configuration code I add this line:
restify.CORS.ALLOW_HEADERS.push('authorization');
Think that info could be helpfull if you faced with similar problem, because I spend a lot to find the solution.
You won't be able to access the URL http://api.host.com/tests from a file deployed at http://local.host.com due to the same-origin policy.
As the source (origin) page and the target URL are at different domains, your code is actually attempting to make a Cross-domain (CORS) request (thus the error with OPTIONS -- see the explanation below), not an ordinary GET.
In a few words, the same-origin policy enforces that browsers only allow Ajax calls to services in the same domain as the HTML page.
Example: A page in http://www.example.com/myPage.html can only directly request services that are in http://www.example.com, like http://www.example.com/testservice/etc. If the service is in other domain, the browser won't make the direct call (as you'd expect). Instead, it will try to make a CORS request.
To put it shortly, to perform a CORS request, your browser:
Will first send an OPTION request to the target URL
And then only if the server response to that OPTIONS contains the adequate headers (Access-Control-Allow-Origin is one of them) to allow the CORS request, the browse will perform the call (almost exactly the way it would if the HTML page was at the same domain).
If the expected headers don't come in the OPTIONS, the browser will give up, informing the error (that it attempted a CORS request and didn't find the necessary headers).
How to solve it?
Place the target service in the same domain of the origin page; or
Enable CORS (enable the necessary headers) on the server; or
If you don't have server-side access to the service, you could also mirror it (create a copy of it in the server you own).
JSONP is also a solution if you just want to request information (but this would require server-side access to setup as well).

Chrome app: Reading and writing data from/to a file on a server

I basically want to do an AJAX call to a PHP file on a server. This doesn't seem to work using the XMLHttpRequest.
Lets say i have the following files:
A PHP file: http://abc.de.fg/folder/data.php
and a txt file: http://abc.de.fg/folder/data.txt
I want to, from my chrome app, pass some data to that PHP file and wait for the response. The PHP file will read and write the data.txt file.
When I try to do this in a chrome app (I know this code works when run through a standard webpage) i get the following errors:
Refused to set unsafe header "Content-length" main.js:250
(anonymous function) main.js:250
Refused to set unsafe header "Connection" main.js:251
(anonymous function) main.js:251
OPTIONS http://abc.de.fg/folder/data.php No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'chrome-extension://ndakgilfeodmfkdmoojoeeckpajmflcd' is therefore not allowed access. main.js:253
(anonymous function) main.js:253
XMLHttpRequest cannot load http://abc.de.fg/folder/data.php. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'chrome-extension://ndakgilfeodmfkdmoojoeeckpajmflcd' is therefore not allowed access.
Have you ever heard of Cross-Origin Resource Sharing? It's what prevents your client-side scripts from accessing information from a different domain. A different domain may be a totally different namespace, a subdomain, or even a different port.
The linked Wikipedia Article names the header that you'll need to send in your PHP generated response: Access-Control-Allow-Origin which your browser already sais is lacking.
Depending on your situation, you're probably better off using JSONP since it does not require that header to be set. It's hard to set a proper allowed URI if it follows such an obscure pattern: chrome-extension://ndakgilfeodmfkdmoojoeeckpajmflcd
I'm not sure if that's an browser-generated UID created during installation, or if it's the UUID of your plugin as it is available in the Chrome App Store. I'm not a frequent Chrome App Developer...
It's hard to be certain but I would check to make sure you have the right permissions in the manifest file (could you export a HAR from the network tab of the app for the request that fails?). You are allowed to make cross-domain requests in apps if you have declared that host in your permissions, see the first entry in the table on this page: http://developer.chrome.com/extensions/declare_permissions.html
In short, the permission "[scheme]:[host]/*" -
Specifies a host permission. Required if the extension or app wants to interact with the code running on pages. Many capabilities, such as cross-origin XMLHttpRequests, programmatically injected content scripts, and the extension's cookies API require host permissions.
So you could have in your manifest file, for your above PHP example:
"permissions": [
"http://abc.de.fg/*",
...
]

Categories