Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 3 additions & 16 deletions tableauserverapi/models/tableau_auth.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
import xml.etree.ElementTree as ET
from .. import NAMESPACE


class TableauAuth(object):
def __init__(self, username, password, site='', impersonate_id=None):
# CHECK FOR USERNAME AND PASSWORD
def __init__(self, username, password, site='', user_id_to_impersonate=None):
self.user_id_to_impersonate = user_id_to_impersonate
self.password = password
self.username = username
self.site = site
self.impersonate_id = impersonate_id

@staticmethod
def from_response(parent_srv, resp):
parsed_response = ET.fromstring(resp)
parent_srv._site_id = parsed_response.find('.//t:site', namespaces=NAMESPACE).get('id', None)
parent_srv._user_id = parsed_response.find('.//t:user', namespaces=NAMESPACE).get('id', None)
auth_token = parsed_response.find('t:credentials', namespaces=NAMESPACE).get('token', None)
parent_srv._auth_token = auth_token
self.username = username
9 changes: 7 additions & 2 deletions tableauserverapi/server/endpoint/auth_endpoint.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from endpoint import Endpoint
from .. import RequestFactory, TableauAuth
from .. import RequestFactory, NAMESPACE
import xml.etree.ElementTree as ET
import logging

logger = logging.getLogger('tableau.endpoint.auth')
Expand Down Expand Up @@ -27,7 +28,11 @@ def sign_in(self, auth_req):
server_response = self.parent_srv.session.post(url, data=signin_req,
**self.parent_srv.http_options)
Endpoint._check_status(server_response)
TableauAuth.from_response(self.parent_srv, server_response.text)
parsed_response = ET.fromstring(server_response.text)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there might be a subtle unicode bug here?

What happens if Server.text contains Chinese characters (Say as the username or something) -- I can't remember if ET.fromstring is graceful about it. If so, it's good!

site_id = parsed_response.find('.//t:site', namespaces=NAMESPACE).get('id', None)
user_id = parsed_response.find('.//t:user', namespaces=NAMESPACE).get('id', None)
auth_token = parsed_response.find('t:credentials', namespaces=NAMESPACE).get('token', None)
self.parent_srv._set_auth(site_id, user_id, auth_token)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly style, but if this is getting called from outside the class/module, maybe it isn't really 'private' and doesn't need the '_' prefix.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our convention is any function call that is not intended for users to use should start with _. In this case, I think this fits that definition. @shinchris Do the users of the library ever have a handle to the endpoints? I don't remember

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Users can access the endpoints through the server class. Is that what you're asking?
Also I used the _ prefix because it's not intended for users to set the site_id, user_id, and auth_token.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense -- I do like the convention, wasn't sure if it was supposed to be user-facing or not.

@graysonarts graysonarts Sep 3, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shinchris That's exactly what I was asking :) I thought that was the case, but couldn't remember off the top of my head. 🚀 🚀 🚀

logger.info('Signed into {0} as {1}'.format(self.parent_srv.server_address, auth_req.username))
return Auth.contextmgr(self.sign_out)

Expand Down
8 changes: 4 additions & 4 deletions tableauserverapi/server/request_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ def _add_multipart(parts):
multipart_part = RequestField(name=name, data=data, filename=filename)
multipart_part.make_multipart(content_type=content_type)
mime_multipart_parts.append(multipart_part)
post_body, content_type = encode_multipart_formdata(mime_multipart_parts)
xml_request, content_type = encode_multipart_formdata(mime_multipart_parts)
content_type = ''.join(('multipart/mixed',) + content_type.partition(';')[1:])
return post_body, content_type
return xml_request, content_type


class AuthRequest(object):
Expand All @@ -23,9 +23,9 @@ def signin_req(self, auth_item):
credentials_element.attrib['password'] = auth_item.password
site_element = ET.SubElement(credentials_element, 'site')
site_element.attrib['contentUrl'] = auth_item.site
if auth_item.impersonate_id:
if auth_item.user_id_to_impersonate:
user_element = ET.SubElement(credentials_element, 'user')
user_element.attrib['id'] = auth_item.impersonate_id
user_element.attrib['id'] = auth_item.user_id_to_impersonate
return ET.tostring(xml_request)


Expand Down
7 changes: 6 additions & 1 deletion tableauserverapi/server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,16 @@ def clear_http_options(self):
self._http_options = dict()

def _clear_auth(self):
self._auth_token = None
self._site_id = None
self._user_id = None
self._auth_token = None
self._session = requests.Session()

def _set_auth(self, site_id, user_id, auth_token):
self._site_id = site_id
self._user_id = user_id
self._auth_token = auth_token

@property
def baseurl(self):
return "{0}/api/{1}".format(self._server_address, str(self.version))
Expand Down
5 changes: 2 additions & 3 deletions test/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,8 @@ def test_sign_in_impersonate(self):
response_xml = file.read()
with requests_mock.mock() as m:
m.post(self.baseurl + '/signin', text=response_xml)
tableau_auth = TSA.TableauAuth('testuser',
'password',
impersonate_id='dd2239f6-ddf1-4107-981a-4cf94e415794')
tableau_auth = TSA.TableauAuth('testuser', 'password',
user_id_to_impersonate='dd2239f6-ddf1-4107-981a-4cf94e415794')
self.server.auth.sign_in(tableau_auth)

self.assertEqual('MJonFA6HDyy2C3oqR13fRGqE6cmgzwq3', self.server.auth_token)
Expand Down