FOR BI PROS Tableau
CORS-proxying without Server Headers – In-response to Chris Toomey
August 18, 2015
5
, , , , , , ,

After my post yesterday on CORS vs Tableau vs WDC store on Gateway service Chris released his excellent article on unifying Tableau REST and JS APIs which reflected some of the stuff what I wrote. He is right in many things, but I would argue on the CORS easiness. In addition to my coding skills I have security background as well, so I know how to traverse between servers and services with minimal or no effort. But maybe it needs some explanation for others, like how can you link sites together from different domains.

This is the missing piece from this CORS story, let me explain in details.

The Debate

This is the problem statement from Chris:

However, if you take this method to a logical endpoint, it actually creates more work.

First, you could write a single monolithic page that returns all the REST content for you – which limits your application flexibility.

Second, you could write a bunch of custom web applications that do everything you need, specific to each application’s needs. BUT – that means more maintenance.

Third, regardless of your choice, you would have to write a client-side parser to capture all that content and then use it. That’s not hard, but it’s still more work.

Fourth, you are essentially duplicating the functionality of the current REST API, just transforming its output from XML to DOM-based HTML.

Fifth, if it all lives in web data connectors, you are exposing admin data to people who don’t need to see it.

Let’s answer and refute each and every of them, but first, some deep tech stuff.

Proxying CORS

If your applications are not in the same document domain (which is our case with Tableau Server) the best way to cooperate between sites is messaging. You can send and receive messages to and from all domains in javascript. Using the famous proxy pattern with less than ten lines you can build a generic CORS proxy for your REST API calls, publish it to the webdataconnectors directory and use it from your external domains. That’s it. No double work, just a one time do-and-forget exercise.

How?

Server side

The design is easy. Lets build a simple page which will proxy all requests from non-tableau domain to tableau domain.

What’s going on? We are receiving AJAX requests from other origins, execute them and sending back the results. On line 25 we can even filter to our external server (but we can omit these kind of firewalling). That’s it. We can forget the server side from now.

Client side

Just like yesterday, today we are going to call Tableau Server URLs. But instead of call $.ajax  directly we use $('#frame')[0].contentWindow.postMessage . The message will be sent to the iframe, iframe is on tableau location, executes the query and pass back the fetched dataset. With the same jquery syntax.

Please note the iframe definition on line 21 and how it invoked in line 49:

From now you can build your client javascripts to call tableau API from everywhere, with similar jquery ajax syntax (lines 49-57 are actually executed inside the iframe, on tableau server).

This is how it works in real life, logging in from external server to tableau server, then do it again from the console:

Click here to see the stuff in HD

Click here to see the stuff in HD

Easy, right?

Answers – my perspective

First, you could write a single monolithic page that returns all the REST content for you – which limits your application flexibility.

We don’t need monolithic code, just one 10 lines proxy code which does the security filtering and message passing. One time, no logic inside.

Second, you could write a bunch of custom web applications that do everything you need, specific to each application’s needs. BUT – that means more maintenance.

You need to build your own code on external servers, no difference here between with or without CORS.

Third, regardless of your choice, you would have to write a client-side parser to capture all that content and then use it. That’s not hard, but it’s still more work.

jQuery gives you back everything in XMLObject or serialized XMLObject. The XML is exactly the same as returned. No parsing at all.

Fourth, you are essentially duplicating the functionality of the current REST API, just transforming its output from XML to DOM-based HTML.

There is no function duplication, the logic implemented on client side, one place.

Fifth, if it all lives in web data connectors, you are exposing admin data to people who don’t need to see it.

This is subjective I guess. For me this CORS proxy is a same kind of stuff as a WDC. It takes web data and allows external clients to use it. From security perspective it must be protected (that’s why only tableau admins can deploy WDC or this CORS proxy). It must be available from all workstations, just like other WDCs. And there is definitely no admin data in it.

And wow, good discussions, it’s good to see that Tableau has such a great developer community!

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
  • Anton Grobman

    How do you go about adding Cookies in these requests?

  • Bipindra Shrestha

    You are exposing admin’s username and password in that html page. Is it still subjective? Anyone can hack into such information.

    • realdataboss

      That’s not really the real password, I changed it before I published it here

      Anyway, thanks for letting me know!

      • Bipindra Shrestha

        I did not mean about that particular password published here. What I meant was if you put admin password in a plain html page, isn’t that exposed as that plain text password is accessible from that simple html page?

        • realdataboss

          I see, yes, you’re right (again), but that HTML page is just a proof of concept mockup. I expect that this information will be passed by the users using HTML forms. I will change it in the post and indicate that if you’re reusing this then the credentials must came from dynamic sources, not hardcoded.

          Typical use case could be to create a HTML only portal with static only resources where users can log on and see their starred reports opened immediately in a tiled layout using REST API to query the favorites and JS API to embed them.

Related items

/ You may check this items as well

Tableau Consistency Checker

Tableau Filestore Consistency Checker – How Repository Maps to Filestore

After my post yesterday on CORS vs Tableau vs WDC ...

Read more
TCOT

Pushing the Limits of Tableau Server – Practical Lessons from a Zen Master

After my post yesterday on CORS vs Tableau vs WDC ...

Read more
Sales dashboard embedded into SAP GUI

Embed Tableau Dashboards in SAP ERP and S4/HANA

After my post yesterday on CORS vs Tableau vs WDC ...

Read more