Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement sudo_as_login for Toolkit #791

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
8 changes: 7 additions & 1 deletion python/tank/authentication/shotgun_authenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,9 @@ def create_session_user(
return user.ShotgunWebUser(impl)
return user.ShotgunUser(impl)

def create_script_user(self, api_script, api_key, host=None, http_proxy=None):
def create_script_user(
self, api_script, api_key, host=None, http_proxy=None, sudo_as_login=None
):
"""
Create an AuthenticatedUser given a set of script credentials.

Expand All @@ -194,6 +196,8 @@ def create_script_user(self, api_script, api_key, host=None, http_proxy=None):
be used.
:param http_proxy: Shotgun proxy to use. If None, the default http proxy
will be used.
:param sudo_as_login: A Shotgun user login string for the user whose permissions will be applied
to all actions. If None, api_script permissions will be used.

:returns: A :class:`ShotgunUser` derived instance.
"""
Expand All @@ -203,6 +207,7 @@ def create_script_user(self, api_script, api_key, host=None, http_proxy=None):
api_script,
api_key,
http_proxy or self._defaults_manager.get_http_proxy(),
sudo_as_login,
)
)

Expand Down Expand Up @@ -245,6 +250,7 @@ def get_default_user(self):
api_key=credentials.get("api_key"),
host=credentials.get("host"),
http_proxy=credentials.get("http_proxy"),
sudo_as_login=credentials.get("sudo_as_login"),
)
# If this looks like a session user, delegate to create_session_user.
# If some of the arguments are missing, don't worry, create_session_user
Expand Down
4 changes: 4 additions & 0 deletions python/tank/authentication/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ def login(self):
"""
return self._impl.get_login()

@property
def sudo_as_login(self):
return self._impl.get_sudo_as_login()

def resolve_entity(self):
"""
Resolves the Shotgun entity associated with this user.
Expand Down
46 changes: 42 additions & 4 deletions python/tank/authentication/user_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ def get_login(self):
"""
self.__class__._not_implemented("get_login")

def get_sudo_as_login(self):
"""
Returns the sudo_as_login for this user.

:returns: The sudo_as_login string."
"""
self.__class__._not_implemented("get_sudo_as_login")

def get_session_metadata(self):
"""
Returns the session metadata for this user.
Expand Down Expand Up @@ -236,6 +244,14 @@ def get_login(self):
"""
return self._login

def get_sudo_as_login(self):
"""
Returns the user used for sudo_as_login for this user.

:returns: The sudo_as_login user login string.
"""
return None

def get_session_token(self):
"""
Returns the session token for this user.
Expand Down Expand Up @@ -421,7 +437,7 @@ class ScriptUser(ShotgunUserImpl):
User that authenticates to the Shotgun server using a api name and api key.
"""

def __init__(self, host, api_script, api_key, http_proxy):
def __init__(self, host, api_script, api_key, http_proxy, sudo_as_login):
"""
Constructor.

Expand All @@ -437,6 +453,7 @@ def __init__(self, host, api_script, api_key, http_proxy):

self._api_script = api_script
self._api_key = api_key
self._sudo_as_login = sudo_as_login

def create_sg_connection(self):
"""
Expand All @@ -452,6 +469,7 @@ def create_sg_connection(self):
self._host,
script_name=self._api_script,
api_key=self._api_key,
sudo_as_login=self._sudo_as_login,
http_proxy=self._http_proxy,
connect=False,
)
Expand Down Expand Up @@ -509,7 +527,7 @@ def get_login(self):
:returns: The login name string.
"""
# Script user has no login.
return None
return self._sudo_as_login

def get_session_metadata(self):
"""
Expand All @@ -520,6 +538,14 @@ def get_session_metadata(self):
# Script user has no session_metadata.
return None

def get_sudo_as_login(self):
"""
Returns the user used for sudo_as_login for this user.

:returns: The sudo_as_login user login string.
"""
return self._sudo_as_login

def to_dict(self):
"""
Converts the user into a dictionary object.
Expand All @@ -529,6 +555,7 @@ def to_dict(self):
data = super(ScriptUser, self).to_dict()
data["api_script"] = self.get_script()
data["api_key"] = self.get_key()
data["sudo_as_login"] = self.get_sudo_as_login()
return data

def __repr__(self):
Expand All @@ -537,15 +564,25 @@ def __repr__(self):

:returns: A string containing script name and site.
"""
return "<ScriptUser %s @ %s>" % (self._api_script, self._host)
sudo_as_login_repr = (
" (as %s)" % self._sudo_as_login if self._sudo_as_login else ""
)
return "<ScriptUser %s%s @ %s>" % (
self._api_script,
sudo_as_login_repr,
self._host,
)

def __str__(self):
"""
Returns the name of the user.

:returns: A string.
"""
return self._api_script
value = self._api_script
if self._sudo_as_login:
value += " (as %s)" % self._sudo_as_login
return value

@staticmethod
def from_dict(payload):
Expand All @@ -560,6 +597,7 @@ def from_dict(payload):
host=payload.get("host"),
api_script=payload.get("api_script"),
api_key=payload.get("api_key"),
sudo_as_login=payload.get("sudo_as_login"),
http_proxy=payload.get("http_proxy"),
)

Expand Down
5 changes: 3 additions & 2 deletions python/tank/bootstrap/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,14 +283,15 @@ def _set_authenticated_user(
project_user = None

# If the project core's authentication code found a user...
# (Note that in the following code, a user with no login is a script user.)
# (Note that in the following code, a user with no login or a user with a sudo_as_login is a script user.)

if default_user:
# If the project uses a script user, we'll use that.
if not default_user.login:
log.debug("User retrieved for the project is a script user.")
project_user = default_user
# If the project didn't use a script, but the bootstrap did, we'll keep using it.
elif not bootstrap_user_login:
elif not bootstrap_user_login or bootstrap_user.sudo_as_login:
# We'll keep using the bootstrap user. This is because configurations like tk-
# config-basic or tk-config-default are meant to be used with whatever credentials
# were used during bootstrapping when used with a CachedDescriptor. The bootstrap
Expand Down
9 changes: 9 additions & 0 deletions tests/authentication_tests/test_shotgun_authenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,15 @@ def test_create_script_user(self, server_caps_mock):
self.assertEqual(connection.config.script_name, "api_script")
self.assertEqual(connection.config.api_key, "api_key")

# Test using sudo_as_login
user = ShotgunAuthenticator(CustomDefaultManager()).create_script_user(
"api_script", "api_key", "https://host.shotgunstudio.com", None, "sudouser"
)
connection = user.create_sg_connection()
self.assertEqual(connection.config.script_name, "api_script")
self.assertEqual(connection.config.api_key, "api_key")
self.assertEqual(connection.config.sudo_as_login, "sudouser")

@patch("tank.authentication.session_cache.get_current_host", return_value=None)
def test_no_current_host(self, _):
"""
Expand Down
16 changes: 16 additions & 0 deletions tests/authentication_tests/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ def _create_script_user(self):
api_script="api_script",
api_key="api_key",
http_proxy="http_proxy",
sudo_as_login=None,
)
)

def _create_script_sudo_as_login_user(self):
return user.ShotgunUser(
user_impl.ScriptUser(
host="host",
api_script="api_script",
api_key="api_key",
http_proxy="http_proxy",
sudo_as_login="sudo_as_login",
)
)

Expand Down Expand Up @@ -96,6 +108,10 @@ def test_login_value(self):
script_user = self._create_script_user()
self.assertIsNone(script_user.login)

sudo_user = self._create_script_sudo_as_login_user()
self.assertEqual(sudo_user.login, "sudo_as_login")
self.assertEqual(sudo_user.sudo_as_login, "sudo_as_login")

class CustomUser(user_impl.ShotgunUserImpl):
def __init__(self):
super(CustomUser, self).__init__("https://test.shotgunstudio.com", None)
Expand Down