0
votes

In working with the Tableau Server API for beta version 2018.2, the documentation lists a REST api call that signs out / ends a secured session between the custom application and the Tableau Server.

The session is secured by executing a POST request (signin) utilizing a username and password that obtains a token to be used for further requests.

When the session is finished the proper security protocol to follow is to sign out/close the session. This is done much in the same way as the request flow process, by creating a custom authentication header string that includes the token.

When performing signout there is one significant difference, in that the request to 'signout' is a POST request, not a GET request. While this should not pose a problem, it seems to be one.

The main difference between the signout POST request and any other POST request is that the data for the signout request is nil/null. Based on the fact that the API documentation makes no mention of this, but rather gives a simple CURL example:

curl "http://MY-SERVER/api/3.0/auth/signout" -X POST -H "X-Tableau-Auth:12ab34cd56ef78ab90cd12ef34ab56cd"

...one has to assume that the act of performing a POST request without sending data is perceived to be a normal function.

I have tried this request using the TIdHTTP component, and supplying an empty TStringStream or an empty TStringList for the POST data parameters in the post call:

try
  tss := TStringStream.Create('');
  http.Request.RawHeaders.AddValue('X-Tableau-Auth',FToken);
  http.Post('http://<myserver>/api/3.0/auth/signout',tss);
finally
  tss.Free;
end;

...but receive an 'HTTP/1.1 401 Unauthorized' exception.

If I attempt to do this with a TWebBrowser interface:

var
  flags,headers,postdata,targetframe,url: OleVariant;
begin
  url := 'http://<myserver>/api/3.0/auth/signout';
  headers := 'X-Tableau-Auth: ' + FToken + #13#10;
  targetframe := 1;
  flags := 1;
  postdata := VarArrayCreate([0,1],varByte);
  postdata[0] := 1;
  Navigate2(URL,flags,targetframe,postdata,Headers);
end;

...the first time I get an undesired launch of Internet Exploder, with the signout url in the url box, and a page displayed that says 'Navigation canceled'.

If I run the code again I get another undesired Internet Exploder launch, this time with the the following response/page:

<?xml version="1.0" encoding="UTF-8"?>
-<tsResponse xsi:schemaLocation="http://tableau.com/api http://tableau.com/api/ts-api-3.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tableau.com/api">
-<error code="401002">
<summary>Unauthorized Access</summary>
<detail>Invalid authentication credentials were provided.</detail>
</error>

I would much rather use the TIdHttp component for this minor task, but have to use the TWebBrowser for the visual tasks, so I could use that as well.

Here is the link to the Tableau Server documentation for the signout api call:

https://onlinehelp.tableau.com/current/api/rest_api/en-us/help.htm#REST/rest_api_ref.htm#Sign_Out%3FTocPath%3DAPI%2520Reference|_____90

2

2 Answers

0
votes

When TIdHTTP is preparing a new HTTP request for sending, the TIdHTTP.Request.RawHeaders property is cleared out and re-populated with the actual headers that are to be sent. Since you are storing your session token in the RawHeaders, it gets wiped out and not sent to the server, which is why you get the 401 error.

You need to use the TIdHTTP.Request.CustomHeaders property instead, which is added to the RawHeaders while preparing the request:

tss := TStringStream.Create('');
try
  http.Request.CustomHeaders.AddValue('X-Tableau-Auth',FToken);
  // or:
  // http.Request.CustomHeaders.Values['X-Tableau-Auth'] := FToken;
  http.Post('http://<myserver>/api/3.0/auth/signout', tss);
finally
  tss.Free;
end;

FYI, if you want to post empty data, you can pass in a nil source pointer instead:

http.Post('http://<myserver>/api/3.0/auth/signout', TStream(nil));

http.Post('http://<myserver>/api/3.0/auth/signout', TStrings(nil));
0
votes

Ok, figured it out. In my code the header with auth info was not being added. Also, set http.Connection to 'close'.

That solved the issue.