From ea2eb4811b8db0ae2e4d0bb151fecbc7cf5d4766 Mon Sep 17 00:00:00 2001 From: Alessandra Romero Date: Fri, 3 Jan 2025 11:23:45 -0500 Subject: [PATCH 1/3] Add account_id to credentials object --- botocore/credentials.py | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/botocore/credentials.py b/botocore/credentials.py index dd7e718255..c78ab54011 100644 --- a/botocore/credentials.py +++ b/botocore/credentials.py @@ -55,7 +55,9 @@ logger = logging.getLogger(__name__) ReadOnlyCredentials = namedtuple( - 'ReadOnlyCredentials', ['access_key', 'secret_key', 'token'] + 'ReadOnlyCredentials', + ['access_key', 'secret_key', 'token', 'account_id'], + defaults=(None,), ) _DEFAULT_MANDATORY_REFRESH_TIMEOUT = 10 * 60 # 10 min @@ -312,7 +314,9 @@ class Credentials: were found. """ - def __init__(self, access_key, secret_key, token=None, method=None): + def __init__( + self, access_key, secret_key, token=None, method=None, account_id=None + ): self.access_key = access_key self.secret_key = secret_key self.token = token @@ -320,6 +324,7 @@ def __init__(self, access_key, secret_key, token=None, method=None): if method is None: method = 'explicit' self.method = method + self.account_id = account_id self._normalize() @@ -335,7 +340,7 @@ def _normalize(self): def get_frozen_credentials(self): return ReadOnlyCredentials( - self.access_key, self.secret_key, self.token + self.access_key, self.secret_key, self.token, self.account_id ) @@ -372,17 +377,19 @@ def __init__( time_fetcher=_local_now, advisory_timeout=None, mandatory_timeout=None, + account_id=None, ): self._refresh_using = refresh_using self._access_key = access_key self._secret_key = secret_key self._token = token + self._account_id = account_id self._expiry_time = expiry_time self._time_fetcher = time_fetcher self._refresh_lock = threading.Lock() self.method = method self._frozen_credentials = ReadOnlyCredentials( - access_key, secret_key, token + access_key, secret_key, token, account_id ) self._normalize() if advisory_timeout is not None: @@ -416,6 +423,7 @@ def create_from_metadata( expiry_time=cls._expiry_datetime(metadata['expiry_time']), method=method, refresh_using=refresh_using, + account_id=metadata['account_id'], **kwargs, ) return instance @@ -459,6 +467,19 @@ def token(self): def token(self, value): self._token = value + @property + def account_id(self): + """Warning: Using this property can lead to race conditions if you + access another property subsequently along the refresh boundary. + Please use get_frozen_credentials instead. + """ + self._refresh() + return self._account_id + + @account_id.setter + def account_id(self, value): + self._account_id = value + def _seconds_remaining(self): delta = self._expiry_time - self._time_fetcher() return total_seconds(delta) @@ -555,7 +576,7 @@ def _protected_refresh(self, is_mandatory): return self._set_from_data(metadata) self._frozen_credentials = ReadOnlyCredentials( - self._access_key, self._secret_key, self._token + self._access_key, self._secret_key, self._token, self._account_id ) if self._is_expired(): # We successfully refreshed credentials but for whatever @@ -575,7 +596,13 @@ def _expiry_datetime(time_str): return parse(time_str) def _set_from_data(self, data): - expected_keys = ['access_key', 'secret_key', 'token', 'expiry_time'] + expected_keys = [ + 'access_key', + 'secret_key', + 'token', + 'expiry_time', + 'account_id', + ] if not data: missing_keys = expected_keys else: @@ -592,6 +619,7 @@ def _set_from_data(self, data): self.secret_key = data['secret_key'] self.token = data['token'] self._expiry_time = parse(data['expiry_time']) + self.account_id = data['account_id'] logger.debug( "Retrieved credentials will expire at: %s", self._expiry_time ) @@ -646,6 +674,7 @@ def __init__(self, refresh_using, method, time_fetcher=_local_now): self._access_key = None self._secret_key = None self._token = None + self._account_id = None self._expiry_time = None self._time_fetcher = time_fetcher self._refresh_lock = threading.Lock() From e8b7d8aedc689e6e1bd05a9355806fdfc333ceae Mon Sep 17 00:00:00 2001 From: Alessandra Romero Date: Fri, 3 Jan 2025 13:48:36 -0500 Subject: [PATCH 2/3] Fix failing tests by using .get() for 'account_id' and removing it from expected_keys list --- botocore/credentials.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/botocore/credentials.py b/botocore/credentials.py index c78ab54011..acb7532ff1 100644 --- a/botocore/credentials.py +++ b/botocore/credentials.py @@ -423,7 +423,7 @@ def create_from_metadata( expiry_time=cls._expiry_datetime(metadata['expiry_time']), method=method, refresh_using=refresh_using, - account_id=metadata['account_id'], + account_id=metadata.get('account_id'), **kwargs, ) return instance @@ -601,7 +601,6 @@ def _set_from_data(self, data): 'secret_key', 'token', 'expiry_time', - 'account_id', ] if not data: missing_keys = expected_keys @@ -619,7 +618,7 @@ def _set_from_data(self, data): self.secret_key = data['secret_key'] self.token = data['token'] self._expiry_time = parse(data['expiry_time']) - self.account_id = data['account_id'] + self.account_id = data.get('account_id') logger.debug( "Retrieved credentials will expire at: %s", self._expiry_time ) From 2c9299f66eb2721b430d2830818045e32b4edd45 Mon Sep 17 00:00:00 2001 From: Alessandra Romero Date: Fri, 3 Jan 2025 14:00:44 -0500 Subject: [PATCH 3/3] Fix formatting of expected_keys list --- botocore/credentials.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/botocore/credentials.py b/botocore/credentials.py index acb7532ff1..a3b01a3fa8 100644 --- a/botocore/credentials.py +++ b/botocore/credentials.py @@ -596,12 +596,7 @@ def _expiry_datetime(time_str): return parse(time_str) def _set_from_data(self, data): - expected_keys = [ - 'access_key', - 'secret_key', - 'token', - 'expiry_time', - ] + expected_keys = ['access_key', 'secret_key', 'token', 'expiry_time'] if not data: missing_keys = expected_keys else: