Skip to content
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
1 change: 1 addition & 0 deletions awscli/botocore/useragent.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
'FLEXIBLE_CHECKSUMS_REQ_XXHASH3': 'AG',
'FLEXIBLE_CHECKSUMS_REQ_XXHASH64': 'AH',
'FLEXIBLE_CHECKSUMS_REQ_XXHASH128': 'AI',
'SSO_LOGIN_VANITY_URL': 'AM',
}


Expand Down
19 changes: 18 additions & 1 deletion awscli/botocore/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
UnsupportedS3ControlArnError,
UnsupportedS3ControlConfigurationError,
)
from botocore.useragent import register_feature_id
from dateutil.tz import tzutc
from urllib3.exceptions import LocationParseError

Expand Down Expand Up @@ -3221,11 +3222,13 @@ def __init__(
cache=None,
on_pending_authorization=None,
time_fetcher=None,
feature_ids=None,
):
self._sso_region = sso_region
self._client_creator = client_creator
self._parsed_globals = parsed_globals
self._on_pending_authorization = on_pending_authorization
self._feature_ids = feature_ids or []

if time_fetcher is None:
time_fetcher = self._utc_now
Expand Down Expand Up @@ -3275,11 +3278,21 @@ def _client(self):
signature_version=botocore.UNSIGNED,
user_agent_extra=self._USER_AGENT_EXTRA,
)
return self._client_creator(
client = self._client_creator(
'sso-oidc',
config=config,
verify=self._parsed_globals.verify_ssl,
)
if self._feature_ids:
client.meta.events.register(
'before-parameter-build.sso-oidc.*',
self._register_feature_ids,
)
Comment on lines +3286 to +3290

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need all this plumbing of feature_ids and the event? register_feature_ids should work under the start_as_current_context in clidriver.

return client

def _register_feature_ids(self, **kwargs):
for feature_id in self._feature_ids:
register_feature_id(feature_id)

def _generate_client_name(self, session_name):
if session_name is None:
Expand Down Expand Up @@ -3330,6 +3343,7 @@ def __init__(
on_pending_authorization=None,
time_fetcher=None,
sleep=None,
feature_ids=None,
):
super().__init__(
sso_region,
Expand All @@ -3338,6 +3352,7 @@ def __init__(
cache,
on_pending_authorization,
time_fetcher,
feature_ids=feature_ids,
)

if sleep is None:
Expand Down Expand Up @@ -3553,6 +3568,7 @@ def __init__(
cache=None,
on_pending_authorization=None,
time_fetcher=None,
feature_ids=None,
):
super().__init__(
sso_region,
Expand All @@ -3561,6 +3577,7 @@ def __init__(
cache,
on_pending_authorization,
time_fetcher,
feature_ids=feature_ids,
)

self._auth_code_fetcher = auth_code_fetcher
Expand Down
3 changes: 0 additions & 3 deletions awscli/customizations/agenttoolkit/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,9 +276,6 @@ def __init__(self, agent, name, path):
self.path = path


# TODO: Verify detection, skills, and MCP config paths against actual
# installations before release. Currently only tested with Kiro and
# simulated agent directories.
AGENT_CONFIGS = [
# https://docs.anthropic.com/en/docs/claude-code/mcp
AgentConfig(
Expand Down
2 changes: 2 additions & 0 deletions awscli/customizations/configure/sso_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ def _prompt_for_registration_args_with_legacy_format(self, verify=None):
args = {'start_url': start_url, 'sso_region': sso_region}
if resolved_url:
args['resolved_start_url'] = resolved_url
args['feature_ids'] = ['SSO_LOGIN_VANITY_URL']
return args

def _get_sso_registration_args_from_sso_config(self, sso_session):
Expand Down Expand Up @@ -415,6 +416,7 @@ def _prompt_for_registration_args_for_new_sso_session(
}
if resolved_url:
args['resolved_start_url'] = resolved_url
args['feature_ids'] = ['SSO_LOGIN_VANITY_URL']
return args

def _store_sso_session_prompter_answers_to_profile_config(self):
Expand Down
5 changes: 5 additions & 0 deletions awscli/customizations/sso/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ def _run_main(self, parsed_args, parsed_globals):
verify=verify,
)

feature_ids = []
if resolved_url != start_url:
feature_ids.append('SSO_LOGIN_VANITY_URL')

on_pending_authorization = None
if parsed_args.no_browser:
on_pending_authorization = PrintOnlyHandler()
Expand All @@ -76,6 +80,7 @@ def _run_main(self, parsed_args, parsed_globals):
session_name=sso_config.get('session_name'),
registration_scopes=sso_config.get('registration_scopes'),
use_device_code=parsed_args.use_device_code,
feature_ids=feature_ids,
)

# Only rewrite sso_region after successful login.
Expand Down
3 changes: 3 additions & 0 deletions awscli/customizations/sso/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def do_sso_login(
session_name=None,
use_device_code=False,
resolved_start_url=None,
feature_ids=None,
):
if token_cache is None:
token_cache = JSONFileCache(SSO_TOKEN_DIR, dumps_func=_sso_json_dumps)
Expand All @@ -104,6 +105,7 @@ def do_sso_login(
auth_code_fetcher=AuthCodeFetcher(),
cache=token_cache,
on_pending_authorization=on_pending_authorization,
feature_ids=feature_ids,
)
else:
token_fetcher = SSOTokenFetcher(
Expand All @@ -112,6 +114,7 @@ def do_sso_login(
parsed_globals=parsed_globals,
cache=token_cache,
on_pending_authorization=on_pending_authorization,
feature_ids=feature_ids,
)

return token_fetcher.fetch_token(
Expand Down
11 changes: 11 additions & 0 deletions tests/functional/sso/test_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,11 @@ def test_config_not_rewritten_when_region_matches(self):
config_content = f.read()
self.assertIn('sso_region=us-east-1', config_content)

def test_vanity_url_sets_feature_id_in_user_agent(self):
self.add_oidc_auth_code_responses(self.access_token)
self.run_cmd('sso login')
self.assertIn('AM', self.last_request_dict['headers']['User-Agent'])


class TestLoginWithVanityUrlLegacy(BaseSSOTest):
def setUp(self):
Expand Down Expand Up @@ -628,3 +633,9 @@ def test_login_uses_configured_region(self):
self.add_oidc_auth_code_responses(self.access_token)
self.run_cmd('sso login')
self.assert_used_expected_sso_region('us-west-2')

def test_direct_url_does_not_set_vanity_feature_id(self):
self.add_oidc_auth_code_responses(self.access_token)
self.run_cmd('sso login')
user_agent = self.last_request_dict['headers']['User-Agent']
self.assertNotIn('AM', user_agent.split('m/')[-1])
Loading