botocore icon indicating copy to clipboard operation
botocore copied to clipboard

SSOTokenLoader expiration check

Open aemous opened this issue 8 months ago • 1 comments

Context

This is a port of https://github.com/aws/aws-cli/pull/9356

Changes

  • Updated SSOCredentialFetcher to check if the cached legacy token is expired according to the local clock. If expired, it will raise an UnauthorizedSSOTokenError instead of sending an expired token to Identity Center's GetRoleCredentials API.
  • Added a unit test to verify when an expired token is cached, that GetRoleCredentials is not called and UnauthorizedSSOTokenError is raised.

Tests

  • Ran all test suites (unit, functional, integration, etc.) and CI.

boto3

  • The following script was used in boto3 to test the code.
import logging
import boto3

from boto3 import client, set_stream_logger

boto3.setup_default_session(profile_name='SSO-PROFILE-NAME')
client = client('s3')
set_stream_logger('', logging.DEBUG)

response = client.list_objects_v2(
    Bucket='BUCKET-NAME',
)

Stacktrace from script built against this branch

Traceback (most recent call last):
  File "/Users/aemous/GitHub/boto3/py312/src/botocore/botocore/credentials.py", line 568, in _protected_refresh
    metadata = self._refresh_using()
               ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/aemous/GitHub/boto3/py312/src/botocore/botocore/credentials.py", line 717, in fetch_credentials
    return self._get_cached_credentials()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/aemous/GitHub/boto3/py312/src/botocore/botocore/credentials.py", line 727, in _get_cached_credentials
    response = self._get_credentials()
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/aemous/GitHub/boto3/py312/src/botocore/botocore/credentials.py", line 2257, in _get_credentials
    raise UnauthorizedSSOTokenError()

Stacktrace from script built against develop

Traceback (most recent call last):
  File "/Users/aemous/GitHub/boto3/py312/lib/python3.12/site-packages/botocore/credentials.py", line 2253, in _get_credentials
    response = client.get_role_credentials(**kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/aemous/GitHub/boto3/py312/lib/python3.12/site-packages/botocore/client.py", line 570, in _api_call
    return self._make_api_call(operation_name, kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/aemous/GitHub/boto3/py312/lib/python3.12/site-packages/botocore/context.py", line 124, in wrapper
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/aemous/GitHub/boto3/py312/lib/python3.12/site-packages/botocore/client.py", line 1031, 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

Notice the latter exception is raised due to a returned UnauthorizedException from making an API call to GetRoleCredentials, while this is not the case in the former stacktrace.

AWS CLI v1

  • The following manual workflow was completed in AWS CLI v1 to test the code.
    1. Login to a user account using the legacy flow via aws sso login.
    2. Let the cached token expire.
    3. Ran a command using the SSO profile (e.g. aws s3 ls --profile SSOProfile --debug)
    4. Verified an UnauthorizedSSOTokenError was raised, and checked the stacktrace (pasted below) to verify this exception was raised without GetRoleCredentials being called.

Stacktrace from manual workflow on AWS CLI v1 built against this branch

Traceback (most recent call last):
  File "/Users/aemous/.local/lib/aws/lib/python3.8/site-packages/botocore/credentials.py", line 568, in _protected_refresh
    metadata = self._refresh_using()
  File "/Users/aemous/.local/lib/aws/lib/python3.8/site-packages/botocore/credentials.py", line 717, in fetch_credentials
    return self._get_cached_credentials()
  File "/Users/aemous/.local/lib/aws/lib/python3.8/site-packages/botocore/credentials.py", line 727, in _get_cached_credentials
    response = self._get_credentials()
  File "/Users/aemous/.local/lib/aws/lib/python3.8/site-packages/botocore/credentials.py", line 2257, 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.

Stacktrace from manual workflow on AWS CLI v1 built against develop

Traceback (most recent call last):
  File "/usr/local/aws/lib/python3.9/site-packages/botocore/credentials.py", line 2253, in _get_credentials
    response = client.get_role_credentials(**kwargs)
  File "/usr/local/aws/lib/python3.9/site-packages/botocore/client.py", line 570, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/usr/local/aws/lib/python3.9/site-packages/botocore/context.py", line 124, in wrapper
    return func(*args, **kwargs)
  File "/usr/local/aws/lib/python3.9/site-packages/botocore/client.py", line 1031, 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

Notice the latter exception is raised due to a returned UnauthorizedException from making an API call to GetRoleCredentials, while this is not the case in the former stacktrace.

aemous avatar Apr 07 '25 14:04 aemous

:warning: Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

All modified and coverable lines are covered by tests :white_check_mark:

Project coverage is 93.02%. Comparing base (6300f6b) to head (6497909). Report is 450 commits behind head on develop.

:exclamation: Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3441      +/-   ##
===========================================
+ Coverage    92.94%   93.02%   +0.08%     
===========================================
  Files           66       67       +1     
  Lines        14956    15116     +160     
===========================================
+ Hits         13901    14062     +161     
+ Misses        1055     1054       -1     

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

:rocket: New features to boost your workflow:
  • :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

codecov-commenter avatar Apr 07 '25 14:04 codecov-commenter