FOR BI PROS Tableau
The big CORS Debate: Tableau Server and external AJAX calls
August 17, 2015
1
, , , , , , ,

The big debate: should or should not Tableau Server allow external sites to call its functions? Sometimes people feel the need to call trusted authentication, REST API or other undocumented URLs in Tableau Server – which are prohibited by the current Tableau Security model. What should we do? When it makes sense to leverage browser based javascript to interact with the server? How to stay supported (at least this time)? How does Tableau 9.1 help us?

Easy, we will answer all of these questions, just read on.

Background

The community's demand

The community’s demand

First things first, what is CORS? CORS stands for Cross-Origin Resource Sharing which basically allows your browser to interact with Tableau Server when rendering stuff for other domains. Practically, if CORS would be enabled then you can create your own static web page which takes data from Tableau Server like list your users’ favorite dashboards, list of projects or anything else. Generally it’s a good idea if the Server is prepared for this kind of stuff. Now the issues:

  • Let’s imagine that one of your server users is logged on to Server (behind your corporate firewall)
  • in an another browser window it opens a web page from the almighty Internet which contains an evil, bad, bad javascript
  • the evil javascript is executed in your user’s browser (it does not access your cookies)
  • it executes several AJAX requests (http calls) which takes data from your server and posts it to the evil destination. No errors will be printed since CORS header allows interactions from external sites. Even if his javascript code does not access the cookie, the browser with send along with the requests. Boom, you’re hacked.
  • Your user will not even know she leaked out. Maybe some boring corporate data with finance stuff.

The other problem is with Trusted Authentication. If a browser (client) is allowed to get a ticket from Tableau Server then the user can ask everything from outside the browser as well. Remember: you MUST not enable trusted ticketing for your end users. Russell wrote a kind explanation as well, I suggest to read it if you plan to use trusted authentication with JS API (and there are much more easier and robust solution for authentication on client side for embedding. really.)

So it’s dangerous, right? Right, but we’re smart as hell, so we know when and how can we invoke the server. Let’s see a few viable examples where we read data from server without breaking the laws of physics.

The Use Case

The use case is simple, list projects from Tableau Server using only JavaScript. In the examples I will use hard coded user name password pair but later we can check what should we do to avoid hard coded credentials.

Tableau Server REST API from Browser

First of all we need the javascript which logs on and took the project list. This is easy, a few lines of code, some hard codes, and the result is:

Now, let’s run it. Oops, we got some strange error:

This is the classic "No 'Access-Control-Allow-Origin' header is present on the requested resource." error

This is the classic “No ‘Access-Control-Allow-Origin’ header is present on the requested resource.” error

This is the issue why people demand CORS immediately. Tableau Server does not return with a “Access-Control-Allow-Origin” header, therefore, our web browser refuses the connection to Tableau Server. Security, security, security.

But we want to connect. What are the options?

Hack the apache configuration files? Easy, but unsupported. Move our files to the server, under the same domain? Yes, but how can we do this in a supported way?

The solution: Web Connector Import

Maybe this is new for some folks, but from Tableau Server 9.1 you definitely can add static HTML and javascript pages to your server! Why don’t we just import this HTML file and use it from there?

This is where you need to import your HTML page with tabadmin import_webconnector command. Lets import mine and check if it works or not:

Importing our HTML page as web data connector - even if it's not

Importing our HTML page as web data connector – even if it’s not

After you imported the HTML page it shows the new URL: <server_name>/webdataconnectors/<our_html_file> . Looks lovely, let’s test it:

Wow, we invoked server API from browser

Wow, we invoked server API from browser

This is exactly what we want. We can get the username and password from an external web page, parse it from client side java script, do the trick and refresh back with the values to the original location. All with client side codes, without CORS heads – but with the same functionality.

And there is more. You can move your code to a different server. If you add an IFRAME to your almost WDC HTML code and set the document.domain  the same on your external server – then your browser will skip the CORS header checks. This allows you to securely link two servers (Tableau and your external application server) together, allowing your app server to execute code on your Tableau Server.

Update: I just explained this CORS Proxying method in my new blog post, here.

Wrap up

No, you don’t need CORS headers, you can upload your HTML/JS codes to the server as tableau web data connectors even if they are not web data connectors. This allows those codes to interact with the server, call any function securely. You can even link Tableau Server with your own web server with document.domain s. But you have to know what you are doing: one bad move and you open to your server to anyone.

And the best: it’s supported.

Read more: CORS-proxying without Server Headers – In-response to Chris Toomey

Tamás Földi

Tamás Földi

Director of IT Development at Starschema
Decades of experience with data processing and state of the art programming. From nuclear bomb explosion simulation to distributed file systems. ethical hacking, real time stream processing practically I always had a great fun with those geeky ones and zeros.
Tamás Földi
  • Maciek Darf Łazęcki

    great reading! could you please elaborate more on using document.domain? I am having Tableau server with multiple public IPs and I am having issues with CORS for imported .html files :/.. unfortunately adding multiple IPs in the XML is not an option…

Related items

/ You may check this items as well

Pasted image at 2018_01_09 04_59 PM

Python Experiments in Tableau 1. – Add live currency conversion to Tableau Dashboards using TabPy

The big debate: should or should not Tableau Serve...

Read more
Tableau Docker

HOWTO: Tableau Server Linux in Docker Container

The big debate: should or should not Tableau Serve...

Read more
Tableau Consistency Checker

Tableau Filestore Consistency Checker – How Repository Maps to Filestore

The big debate: should or should not Tableau Serve...

Read more