It’s common for Tableau Server users to want to embed content into a separate web application while maintaining tight security restrictions. If you want your web application to handle all of the authentication, it’s possible to use the trusted ticket authentication system offered by Tableau Server. It’s important, however, to understand the request workflow that Tableau Server will use. In this example, we’ll build a simple PHP script that will proxy Tableau Server content using the trusted ticket authentication system.
It’s important to note that this example script does not perform any authentication. When building a production version of this script, you’ll want to be sure that the user is authenticated properly. Tableau Server, in this case, is simply trusting the web app server running the script to perform whatever authentication is necessary.
Before we begin, you’ll want to make sure of the following:
- The web app server you’ll be running your PHP script on needs to be “trusted” by Tableau Server. This is done by whitelisting your web app server’s IP address using the following tabadmin commands. Note: this will restart Tableau Server.
tabadmin set wgserver.trusted_hosts "xxx.xxx.xxx.xxx, xxx.xxx.xxx.xxx" tabadmin restart
- Ensure that the cURL PHP extension is installed and enabled on your web app server. We’ll be using cURL in this example script so that we can properly handle cookies and redirects.
Now that you’ve configured Tableau Server, let’s walk through the request process. Let’s say we’d like to retrieve “http://tbsrv/views/foo/bar?format=png” as the user “jvarner”. Here are the steps we will follow:
- App requests trusted ticket from Tableau Server:
POST (username=jvarner, client_ip=123.123.123.123) http://tbsrv/trusted
- Server returns integer ticket ID (or negative number in case of error)
- App requests content (normally at /views/foo/bar?format=png):
GET http://tbsrv/trusted/{$ticketId}/views/foo/bar?format=png
- Server sets “workgroup_session_id” cookie and redirects to final URL (full response source below for reference)
HTTP/1.1 302 Moved Temporarily Date: Thu, 12 Jul 2012 23:05:40 GMT Server: Apache-Coyote/1.1 Pragma: no-cache Expires: Thu, 01 Jan 1970 00:00:00 GMT Cache-Control: no-cache Cache-Control: no-store Location: http://tbsrv/views/foo/bar?format=png Content-Length: 0 Set-Cookie: workgroup_session_id=abkcowijQ1eMeh59jdkvP3mlyJMvYZoE; Path=/; Expires=Fri, 13-Jul-2012 3:5:40 GMT; HttpOnly P3P: CP="NON" Content-Type: text/plain
- App follows redirect, passing the cookie that was set, and fetches content:
GET http://tbsrv/views/foo/bar?format=png
- Server returns the PNG image
Below is our example PHP script, with the workflow annotated within the code’s comments. To use this, you’ll want to change the variables at the top, add/integrate authentication, and add any additional error handling as necessary.
The code below has also been posted as a GitHub Gist. If you have any questions or comments about the code, please visit the GitHub Gist. If you’d like to read more about trusted tickets, please visit this Tableau Server knowledgebase article.
http://kb.tableausoftware.com/articles/knowledgebase/integrating-trusted... */ $server = 'tbsrv'; $username = 'jvarner'; $clientIp = (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : ''); // To get a PNG $url = 'views/foo/bar?format=png'; $contentType = 'image/png'; // To get a PDF you could use: // $url = 'views/foo/bar?format=pdf'; // $contentType = 'application/pdf'; // Request the trusted ticket ID by sending username & client_ip via POST fields to "/trusted" $params = compact('username'); if ($clientIp) { $params['client_ip'] = $clientIp; } $ch = curl_init(); curl_setopt_array($ch, array( CURLOPT_URL => "http://{$server}/trusted", CURLOPT_POST => true, CURLOPT_POSTFIELDS => $params, CURLOPT_RETURNTRANSFER => true, )); $ticket = (int) curl_exec($ch); curl_close($ch); // Valid ticket IDs are positive integers if ($ticket $fullUrl, // Tell cURL to follow the redirect from Tableau Server CURLOPT_FOLLOWLOCATION => true, // Enable cookies so that cURL handles the session ID cookie, but don't load any existing // cookies from a file (since we don't have any) CURLOPT_COOKIEFILE => '', CURLOPT_FAILONERROR => true, CURLOPT_HEADER => false, )); // Simply output the content to the browser header("Content-Type: {$contentType}"); curl_exec($ch); curl_close($ch);