Skip to content

403141: Forbidden when assigning a new owner to a datasource in 2022.1 #1072

Closed

Description

@ashterenberg-paramount

Describe the bug
The code works in 2021.4.3

Versions
Details of your environment, including:

  • Tableau Server version - 2022.1.2
  • Python version - 3.8.5
  • TSC library version - 0.19

To Reproduce
Trying to assign a new owner to a datasource. Logged as a server administrator.

tableau_server_address = "https://mytableau"

tableau_auth = TSC.TableauAuth('userx', 'mypass', site_id='')
server = TSC.Server(tableau_server_address, use_server_version=True)
server.auth.sign_in(tableau_auth) 

datasource = server.datasources.get_by_id (ds_luid)
datasource.owner_id = new_owner_luid
updated_datasource = server.datasources.update(datasource)

Results

  File "fix_users.py", line 264, in <module>
    updated_datasource = server.datasources.update(datasource)
  File "/usr/local/lib/python3.8/site-packages/tableauserverclient/server/endpoint/endpoint.py", line 186, in wrapper
    return func(self, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/tableauserverclient/server/endpoint/datasources_endpoint.py", line 184, in update
    server_response = self.put_request(url, update_req)
  File "/usr/local/lib/python3.8/site-packages/tableauserverclient/server/endpoint/endpoint.py", line 133, in put_request
    return self._make_request(
  File "/usr/local/lib/python3.8/site-packages/tableauserverclient/server/endpoint/endpoint.py", line 66, in _make_request
    self._check_status(server_response)
  File "/usr/local/lib/python3.8/site-packages/tableauserverclient/server/endpoint/endpoint.py", line 82, in _check_status
    raise ServerResponseError.from_response(server_response.content, self.parent_srv.namespace)
tableauserverclient.server.endpoint.exceptions.ServerResponseError:

        403141: Forbidden
                'userx' isn't authorized to update the datasource 'xyz'.

Activity

  1. ashterenberg-paramount commented on Jul 22, 2022

    @ashterenberg-paramount
    Author

    Here's the code that works - same credentials, same ds and user luid, but going directly against the rest api using requests.

    import boto3
    import requests
    from xml.etree import ElementTree
    import urllib
    import html
    import json
    
    uname = tableau_api_user_name
    pw = tableau_api_user_pwd
    tableau_server =  tableau_server_url
    api_version = tableau_server_api_version
    
    base_url = 'https://{}/api/{}'.format (tableau_server, api_version)
    
    headers = {'content-type': 'text/xml'}
    
    signin_data='<tsRequest><credentials name="{}" password="{}" ><site contentUrl="" /></credentials></tsRequest>'.format (uname, pw)
    
    url = '{}/auth/signin'.format (base_url)
    
    r = requests.post(url, data=signin_data, headers=headers)
    
    if r.status_code!=200:
    
        raise Exception('Tableau server {} signin unsuccessful'.format (tableau_server))
    
    root = ElementTree.fromstring(r.content)
    
    token = root.find('.//t:credentials', namespaces={'t': "http://tableau.com/api"}).attrib['token']
    headers = {'X-Tableau-Auth': token}
    site_id = root.find('.//t:site', namespaces={'t': "http://tableau.com/api"}).attrib['id']
    content_url = root.find('.//t:site', namespaces={'t': "http://tableau.com/api"}).attrib['contentUrl']
    if not content_url or content_url=='':
        content_url='Default'
    
    datasource_id = ds_luid
    new_owner_id = new_owner_luid
    url = '{}/sites/{}/datasources/{}'.format (base_url, site_id, datasource_id)
    request_data = """<tsRequest>
                       <datasource>
                          <owner id="{}"/>
                       </datasource>
                     </tsRequest>""".format (new_owner_id)
    
    r = requests.put(url, data=request_data, headers=headers)
    
    if r.status_code!=200:
        raise Exception('Tableau server {}, data source {} owner reassignment request unsuccessful'.format (tableau_server, datasource_id))
    
    root = ElementTree.fromstring(r.content)
    
    result = root.find('.//t:owner', namespaces={'t': "http://tableau.com/api"}).attrib['id']
    print (result)
  2. jacalata commented on Sep 2, 2022

    @jacalata
    Contributor

    Thanks @ashterenberg-paramount - I think have an idea of what's happening. Could you tell me what the value of
    tableau_server_api_version is in your program?

  3. ashterenberg-paramount commented on Sep 2, 2022

    @ashterenberg-paramount
    Author

    I’ll save you some precious time.
    In versions of the rest api lower than 3.15 you need to pass the project id of the datasource id along with the new owner id in the put call updating the datasource.
    This was confirmed (reluctantly) by Tableau support via a support case.
    They promised to update the documentation but no idea when it will happen.

  4. ashterenberg-paramount commented on Oct 11, 2022

    @ashterenberg-paramount
    Author
  5. mustiem commented on Feb 24, 2023

    @mustiem

    Have tried both 3.16 and 3.17 API versions and the exact same issue.

  6. added a commit that references this issue on May 7, 2024
    e4fbe41
  7. added a commit that references this issue on May 5, 2026
    c85d619
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugin-progressIssues that are in-progress of being fixed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions