0

With a Python app, using Boto3 v1.26.59 (and botocore of same version) about the first thing done is to try to get the username of the user. We have Identity Center (SSO) users. With aged credentials (token), two exceptions are thrown and I don't seem to be able to catch them. Here is a snippet:

import boto3  # type: ignore
import botocore.errorfactory as ef
import botocore.exceptions as bcexp


def profile_user_name(profile_name: str) -> Optional[str]:
    session = boto3.Session(profile_name=profile_name)
    sts = session.client("sts")
    try:
        user_id = sts.get_caller_identity().get("UserId")
        return user_id.split(":")[-1].split("@")[0]
    except ef.UnauthorizedException as e:
        _logger.error(f'Not authenticated. Please execute:  aws sso login --profile {profile_name}')
        return None
    except bcexp.UnauthorizedSSOTokenError as e:
        _logger.error(f'Not authenticated. Please execute:  aws sso login --profile {profile_name}')
        return None
    except Exception as e:
        _logger.error(f"Encountered exception '{str(e)}'!")
        return None

Exceptions thrown by the above code look like these:

Refreshing temporary credentials failed during mandatory refresh period.
Traceback (most recent call last):
  File "/Users/kevinbuchs/lib/python3.11/site-packages/botocore/credentials.py", line 2121, in _get_credentials
    response = client.get_role_credentials(**kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kevinbuchs/lib/python3.11/site-packages/botocore/client.py", line 530, in _api_call
    return self._make_api_call(operation_name, kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kevinbuchs/lib/python3.11/site-packages/botocore/client.py", line 960, in _make_api_call
    raise error_class(parsed_response, operation_name)
botocore.errorfactory.UnauthorizedException: An error occurred (UnauthorizedException) when calling the GetRoleCredentials operation: Session token not found or invalid

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/kevinbuchs/lib/python3.11/site-packages/botocore/credentials.py", line 510, in _protected_refresh
    metadata = self._refresh_using()
               ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kevinbuchs/lib/python3.11/site-packages/botocore/credentials.py", line 657, in fetch_credentials
    return self._get_cached_credentials()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kevinbuchs/lib/python3.11/site-packages/botocore/credentials.py", line 667, in _get_cached_credentials
    response = self._get_credentials()
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kevinbuchs/lib/python3.11/site-packages/botocore/credentials.py", line 2123, in _get_credentials
    raise UnauthorizedSSOTokenError()
botocore.exceptions.UnauthorizedSSOTokenError: The SSO session associated with this profile has expired or is otherwise invalid. To refresh this SSO session run aws sso login with the corresponding profile.
Encountered exception 'The SSO session associated with this profile has expired or is otherwise invalid. To refresh this SSO session run aws sso login with the corresponding profile.'!
The auth profile 'dev-devaccess-default' is not logged in. Login with 'aws sso login --profile dev-devaccess-default' and retry!

I thought I would check to see if I am missing some trick before submitting a GitHub issue.

Kevin Buchs
  • 2,520
  • 4
  • 36
  • 55
  • `bcexp..UnauthorizedSSOTokenError`. is that a typo? – Asdfg Feb 10 '23 at 20:53
  • It seems like `botocore.errorfactory` does not have `UnauthorizedException`. Can you try moving it down or removing it so that `except bcexp.UnauthorizedSSOTokenError as e:` is executed before `except ef.UnauthorizedException as e:`? – Asdfg Feb 10 '23 at 21:08
  • Yes, @Asdfg, that ".." got entered as a typo, after I tried my code. What I actually tested only had one period. When I went back to the code I needed to correct it before it would execute again. And, botocore.errorfactory.UnauthorizedException can be seen in the exceptions. Anyway, if that was not the exception hitting the series of exception blocks, it would just move on to the next. But, I will try removing it too (once my creds expire). Thanks for the ideas. – Kevin Buchs Feb 10 '23 at 21:10
  • Some ideas at [How to handle errors with boto3?](https://stackoverflow.com/a/33663484/271415) – jarmod Feb 10 '23 at 22:13
  • Thanks, @jarmod for the suggestion. The problem here, is the client is never returning the exception, but handling, or juggling them itself. So, there is no opportunity for my code to catch them. – Kevin Buchs Feb 13 '23 at 23:02

1 Answers1

1

Your question had been bugging me so I setup something on my end during the weekend. This is what works for me.

import boto3
import botocore.exceptions as bcexp

def profile_user_name(profile_name: str):
    session = boto3.Session(profile_name=profile_name)
    sts = session.client("sts")
    try:
        user_id = sts.get_caller_identity().get("UserId")
        print(user_id.split(":")[-1].split("@")[0])
    except bcexp.UnauthorizedSSOTokenError as e:
        _logger.error(f'Not authenticated. Please execute:  aws sso login --profile {profile_name}')
        return None
    except bcexp.ClientError as e:
        if e.response['Error']['Code'] == "ExpiredToken":
            _logger.error(f'Not authenticated. Please execute:  aws sso login --profile {profile_name}')
            return None
        return None

Kevin Buchs
  • 2,520
  • 4
  • 36
  • 55
Asdfg
  • 11,362
  • 24
  • 98
  • 175