From e2fb86f6fae9600cfcd39e7bb9389bf41f579f37 Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Wed, 2 Jul 2025 12:48:36 -0400 Subject: [PATCH 1/8] Support bearer tokens through environment for Bedrock --- .../lib/aws-sdk-bedrock/client.rb | 2 + .../plugins/bearer_authorization.rb | 34 +++++++++++++ gems/aws-sdk-bedrock/spec/client_spec.rb | 43 ++++++++++++++++ .../aws-sdk-bedrockruntime/async_client.rb | 2 + .../lib/aws-sdk-bedrockruntime/client.rb | 2 + .../plugins/bearer_authorization.rb | 34 +++++++++++++ .../spec/client_spec.rb | 49 +++++++++++++++++++ .../plugins/credentials_configuration.rb | 7 +-- .../lib/aws-sdk-core/plugins/sign.rb | 8 +-- .../aws-sdk-core/plugins/stub_responses.rb | 6 +++ .../lib/aws-sdk-core/plugins/user_agent.rb | 3 +- .../lib/aws-sdk-core/token_provider_chain.rb | 8 +-- services.json | 10 +++- 13 files changed, 187 insertions(+), 21 deletions(-) create mode 100644 gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/plugins/bearer_authorization.rb create mode 100644 gems/aws-sdk-bedrock/spec/client_spec.rb create mode 100644 gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/plugins/bearer_authorization.rb create mode 100644 gems/aws-sdk-bedrockruntime/spec/client_spec.rb diff --git a/gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/client.rb b/gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/client.rb index ad03e937d0c..8796c697cbb 100644 --- a/gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/client.rb +++ b/gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/client.rb @@ -35,6 +35,7 @@ require 'aws-sdk-core/plugins/telemetry' require 'aws-sdk-core/plugins/sign' require 'aws-sdk-core/plugins/protocols/rest_json' +require 'aws-sdk-bedrock/plugins/bearer_authorization' module Aws::Bedrock # An API client for Bedrock. To construct a client, you need to configure a `:region` and `:credentials`. @@ -85,6 +86,7 @@ class Client < Seahorse::Client::Base add_plugin(Aws::Plugins::Telemetry) add_plugin(Aws::Plugins::Sign) add_plugin(Aws::Plugins::Protocols::RestJson) + add_plugin(Aws::Bedrock::Plugins::BearerAuthorization) add_plugin(Aws::Bedrock::Plugins::Endpoints) # @overload initialize(options) diff --git a/gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/plugins/bearer_authorization.rb b/gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/plugins/bearer_authorization.rb new file mode 100644 index 00000000000..20b304dc908 --- /dev/null +++ b/gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/plugins/bearer_authorization.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Aws::Bedrock + module Plugins + # @api private + class BearerAuthorization < Seahorse::Client::Plugin + def after_initialize(client) + return unless (token = ENV['AWS_BEARER_TOKEN_BEDROCK']) + + client.config.token_provider ||= Aws::StaticTokenProvider.new(token) + end + + class Handler < Seahorse::Client::Handler + def call(context) + # This also sets the preferred auth scheme even if the code token has precedence. + context[:auth_scheme] = { 'name' => 'bearer' } if ENV['AWS_BEARER_TOKEN_BEDROCK'] + with_metric { @handler.call(context) } + end + + private + + def with_metric(&block) + if ENV['AWS_BEARER_TOKEN_BEDROCK'] + Aws::Plugins::UserAgent.metric('BEARER_SERVICE_ENV_VARS', &block) + else + block.call + end + end + end + + handle(Handler) + end + end +end diff --git a/gems/aws-sdk-bedrock/spec/client_spec.rb b/gems/aws-sdk-bedrock/spec/client_spec.rb new file mode 100644 index 00000000000..9e1e2bf3979 --- /dev/null +++ b/gems/aws-sdk-bedrock/spec/client_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require_relative 'spec_helper' + +module Aws + module Bedrock + describe Client do + it 'uses a bearer token from the environment' do + ENV['AWS_BEARER_TOKEN_BEDROCK'] = 'bedrock-token' + client = Client.new(stub_responses: true, token_provider: nil) + expect(client.config.token_provider.token.token).to eq('bedrock-token') + resp = client.list_imported_models + expect(resp.context.http_request.headers['Authorization']).to eq('Bearer bedrock-token') + end + + it 'does not use a token for a different service' do + ENV['AWS_BEARER_TOKEN_FOO'] = 'foo-token' + client = Client.new(stub_responses: true, token_provider: nil) + expect(client.config.token_provider).to be_nil + resp = client.list_imported_models + expect(resp.context.http_request.headers['Authorization']).to_not eq('Bearer foo-token') + end + + it 'still prefers bearer token when given an auth scheme preference' do + ENV['AWS_BEARER_TOKEN_BEDROCK'] = 'bedrock-token' + ENV['AWS_AUTH_SCHEME_PREFERENCE'] = 'sigv4,httpBearerAuth' + client = Client.new(stub_responses: true, token_provider: nil) + resp = client.list_imported_models + expect(resp.context.http_request.headers['Authorization']).to eq('Bearer bedrock-token') + end + + it 'uses explicit config over the environment token' do + ENV['AWS_BEARER_TOKEN_BEDROCK'] = 'bedrock-token' + client = Client.new( + stub_responses: true, + token_provider: Aws::StaticTokenProvider.new('explicit-code-token') + ) + resp = client.list_imported_models + expect(resp.context.http_request.headers['Authorization']).to eq('Bearer explicit-code-token') + end + end + end +end diff --git a/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/async_client.rb b/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/async_client.rb index d497c86e161..a683ef07cc2 100644 --- a/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/async_client.rb +++ b/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/async_client.rb @@ -31,6 +31,7 @@ require 'aws-sdk-core/plugins/telemetry' require 'aws-sdk-core/plugins/sign' require 'aws-sdk-core/plugins/protocols/rest_json' +require 'aws-sdk-bedrockruntime/plugins/bearer_authorization' require 'aws-sdk-core/plugins/event_stream_configuration' Aws::Plugins::GlobalConfiguration.add_identifier(:bedrockruntime) @@ -77,6 +78,7 @@ class AsyncClient < Seahorse::Client::AsyncBase add_plugin(Aws::Plugins::Telemetry) add_plugin(Aws::Plugins::Sign) add_plugin(Aws::Plugins::Protocols::RestJson) + add_plugin(Aws::BedrockRuntime::Plugins::BearerAuthorization) add_plugin(Aws::Plugins::EventStreamConfiguration) add_plugin(Aws::BedrockRuntime::Plugins::Endpoints) diff --git a/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/client.rb b/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/client.rb index d18c36c2084..9547f7dab63 100644 --- a/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/client.rb +++ b/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/client.rb @@ -35,6 +35,7 @@ require 'aws-sdk-core/plugins/telemetry' require 'aws-sdk-core/plugins/sign' require 'aws-sdk-core/plugins/protocols/rest_json' +require 'aws-sdk-bedrockruntime/plugins/bearer_authorization' require 'aws-sdk-core/plugins/event_stream_configuration' module Aws::BedrockRuntime @@ -86,6 +87,7 @@ class Client < Seahorse::Client::Base add_plugin(Aws::Plugins::Telemetry) add_plugin(Aws::Plugins::Sign) add_plugin(Aws::Plugins::Protocols::RestJson) + add_plugin(Aws::BedrockRuntime::Plugins::BearerAuthorization) add_plugin(Aws::Plugins::EventStreamConfiguration) add_plugin(Aws::BedrockRuntime::Plugins::Endpoints) diff --git a/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/plugins/bearer_authorization.rb b/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/plugins/bearer_authorization.rb new file mode 100644 index 00000000000..47c9cf7951d --- /dev/null +++ b/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/plugins/bearer_authorization.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Aws::BedrockRuntime + module Plugins + # @api private + class BearerAuthorization < Seahorse::Client::Plugin + def after_initialize(client) + return unless (token = ENV['AWS_BEARER_TOKEN_BEDROCK']) + + client.config.token_provider ||= Aws::StaticTokenProvider.new(token) + end + + class Handler < Seahorse::Client::Handler + def call(context) + # This also sets the preferred auth scheme even if the code token has precedence. + context[:auth_scheme] = { 'name' => 'bearer' } if ENV['AWS_BEARER_TOKEN_BEDROCK'] + with_metric { @handler.call(context) } + end + + private + + def with_metric(&block) + if ENV['AWS_BEARER_TOKEN_BEDROCK'] + Aws::Plugins::UserAgent.metric('BEARER_SERVICE_ENV_VARS', &block) + else + block.call + end + end + end + + handle(Handler) + end + end +end diff --git a/gems/aws-sdk-bedrockruntime/spec/client_spec.rb b/gems/aws-sdk-bedrockruntime/spec/client_spec.rb new file mode 100644 index 00000000000..f486114422e --- /dev/null +++ b/gems/aws-sdk-bedrockruntime/spec/client_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require_relative 'spec_helper' + +module Aws + module BedrockRuntime + describe Client do + def invoke_model(client) + stub = client.stub_data(:invoke_model, body: 'test') + client.stub_responses(:invoke_model, stub) + client.invoke_model(model_id: 'test') + end + + it 'uses a bearer token from the environment' do + ENV['AWS_BEARER_TOKEN_BEDROCK'] = 'bedrock-token' + client = Client.new(stub_responses: true, token_provider: nil) + expect(client.config.token_provider.token.token).to eq('bedrock-token') + resp = invoke_model(client) + expect(resp.context.http_request.headers['Authorization']).to eq('Bearer bedrock-token') + end + + it 'does not use a token for a different service' do + ENV['AWS_BEARER_TOKEN_FOO'] = 'foo-token' + client = Client.new(stub_responses: true, token_provider: nil) + expect(client.config.token_provider).to be_nil + resp = invoke_model(client) + expect(resp.context.http_request.headers['Authorization']).to_not eq('Bearer foo-token') + end + + it 'still prefers bearer token when given an auth scheme preference' do + ENV['AWS_BEARER_TOKEN_BEDROCK'] = 'bedrock-token' + ENV['AWS_AUTH_SCHEME_PREFERENCE'] = 'sigv4,httpBearerAuth' + client = Client.new(stub_responses: true, token_provider: nil) + resp = invoke_model(client) + expect(resp.context.http_request.headers['Authorization']).to eq('Bearer bedrock-token') + end + + it 'uses explicit config over the environment token' do + ENV['AWS_BEARER_TOKEN_BEDROCK'] = 'bedrock-token' + client = Client.new( + stub_responses: true, + token_provider: Aws::StaticTokenProvider.new('explicit-code-token') + ) + resp = invoke_model(client) + expect(resp.context.http_request.headers['Authorization']).to eq('Bearer explicit-code-token') + end + end + end +end diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/credentials_configuration.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/credentials_configuration.rb index 39904a631ab..efe9422663b 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/credentials_configuration.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/credentials_configuration.rb @@ -99,13 +99,8 @@ class CredentialsConfiguration < Seahorse::Client::Plugin will be used to search for tokens configured for your profile in shared configuration files. DOCS ) do |config| - if config.stub_responses - StaticTokenProvider.new('token') - else - TokenProviderChain.new(config).resolve - end + TokenProviderChain.new(config).resolve end - end end end diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb index eba2235498f..5cfc4fb526f 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb @@ -77,16 +77,12 @@ def initialize def sign(context) if context.http_request.endpoint.scheme != 'https' - raise ArgumentError, - 'Unable to use bearer authorization on non https endpoint.' + raise ArgumentError, 'Unable to use bearer authorization on non https endpoint.' end - token_provider = context.config.token_provider - raise Errors::MissingBearerTokenError unless token_provider&.set? - context.http_request.headers['Authorization'] = - "Bearer #{token_provider.token.token}" + context.http_request.headers['Authorization'] = "Bearer #{token_provider.token.token}" end def presign_url(*args) diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/stub_responses.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/stub_responses.rb index e2e17ef2e1a..ada65dfd60c 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/stub_responses.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/stub_responses.rb @@ -29,6 +29,12 @@ class StubResponses < Seahorse::Client::Plugin end end + option(:token_provider) do |config| + if config.stub_responses + StaticTokenProvider.new('stubbed-token') + end + end + option(:stubs) { {} } option(:stubs_mutex) { Mutex.new } option(:api_requests) { [] } diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/user_agent.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/user_agent.rb index 5c1c3faada4..da93fcc6d5d 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/user_agent.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/user_agent.rb @@ -54,7 +54,8 @@ class UserAgent < Seahorse::Client::Plugin "CREDENTIALS_HTTP" : "z", "CREDENTIALS_IMDS" : "0", "SSO_LOGIN_DEVICE" : "1", - "SSO_LOGIN_AUTH" : "2" + "SSO_LOGIN_AUTH" : "2", + "BEARER_SERVICE_ENV_VARS": "3" } METRICS diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/token_provider_chain.rb b/gems/aws-sdk-core/lib/aws-sdk-core/token_provider_chain.rb index dfebea13a5b..194ca1e81d9 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/token_provider_chain.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/token_provider_chain.rb @@ -27,17 +27,13 @@ def providers def static_profile_sso_token(options) if Aws.shared_config.config_enabled? && options[:config] && options[:config].profile - Aws.shared_config.sso_token_from_config( - profile: options[:config].profile - ) + Aws.shared_config.sso_token_from_config(profile: options[:config].profile) end end - def sso_token(options) - profile_name = determine_profile_name(options) if Aws.shared_config.config_enabled? - Aws.shared_config.sso_token_from_config(profile: profile_name) + Aws.shared_config.sso_token_from_config(profile: determine_profile_name(options)) end rescue Errors::NoSuchProfileError nil diff --git a/services.json b/services.json index 19cc376127e..7eb573520bd 100644 --- a/services.json +++ b/services.json @@ -127,7 +127,10 @@ "models": "batch/2016-08-10" }, "Bedrock": { - "models": "bedrock/2023-04-20" + "models": "bedrock/2023-04-20", + "addPlugins": [ + "Aws::Bedrock::Plugins::BearerAuthorization" + ] }, "BedrockAgent": { "models": "bedrock-agent/2023-06-05" @@ -142,7 +145,10 @@ "models": "bedrock-data-automation-runtime/2024-06-13" }, "BedrockRuntime": { - "models": "bedrock-runtime/2023-09-30" + "models": "bedrock-runtime/2023-09-30", + "addPlugins": [ + "Aws::BedrockRuntime::Plugins::BearerAuthorization" + ] }, "Billing": { "models": "billing/2023-09-07" From a351ec989d1d83b6b5732edfff4bfce4d6ba8887 Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Wed, 2 Jul 2025 12:51:49 -0400 Subject: [PATCH 2/8] Revert generated clients --- gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/client.rb | 2 -- .../lib/aws-sdk-bedrockruntime/async_client.rb | 2 -- .../aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/client.rb | 2 -- 3 files changed, 6 deletions(-) diff --git a/gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/client.rb b/gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/client.rb index 8796c697cbb..ad03e937d0c 100644 --- a/gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/client.rb +++ b/gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/client.rb @@ -35,7 +35,6 @@ require 'aws-sdk-core/plugins/telemetry' require 'aws-sdk-core/plugins/sign' require 'aws-sdk-core/plugins/protocols/rest_json' -require 'aws-sdk-bedrock/plugins/bearer_authorization' module Aws::Bedrock # An API client for Bedrock. To construct a client, you need to configure a `:region` and `:credentials`. @@ -86,7 +85,6 @@ class Client < Seahorse::Client::Base add_plugin(Aws::Plugins::Telemetry) add_plugin(Aws::Plugins::Sign) add_plugin(Aws::Plugins::Protocols::RestJson) - add_plugin(Aws::Bedrock::Plugins::BearerAuthorization) add_plugin(Aws::Bedrock::Plugins::Endpoints) # @overload initialize(options) diff --git a/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/async_client.rb b/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/async_client.rb index a683ef07cc2..d497c86e161 100644 --- a/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/async_client.rb +++ b/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/async_client.rb @@ -31,7 +31,6 @@ require 'aws-sdk-core/plugins/telemetry' require 'aws-sdk-core/plugins/sign' require 'aws-sdk-core/plugins/protocols/rest_json' -require 'aws-sdk-bedrockruntime/plugins/bearer_authorization' require 'aws-sdk-core/plugins/event_stream_configuration' Aws::Plugins::GlobalConfiguration.add_identifier(:bedrockruntime) @@ -78,7 +77,6 @@ class AsyncClient < Seahorse::Client::AsyncBase add_plugin(Aws::Plugins::Telemetry) add_plugin(Aws::Plugins::Sign) add_plugin(Aws::Plugins::Protocols::RestJson) - add_plugin(Aws::BedrockRuntime::Plugins::BearerAuthorization) add_plugin(Aws::Plugins::EventStreamConfiguration) add_plugin(Aws::BedrockRuntime::Plugins::Endpoints) diff --git a/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/client.rb b/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/client.rb index 9547f7dab63..d18c36c2084 100644 --- a/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/client.rb +++ b/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/client.rb @@ -35,7 +35,6 @@ require 'aws-sdk-core/plugins/telemetry' require 'aws-sdk-core/plugins/sign' require 'aws-sdk-core/plugins/protocols/rest_json' -require 'aws-sdk-bedrockruntime/plugins/bearer_authorization' require 'aws-sdk-core/plugins/event_stream_configuration' module Aws::BedrockRuntime @@ -87,7 +86,6 @@ class Client < Seahorse::Client::Base add_plugin(Aws::Plugins::Telemetry) add_plugin(Aws::Plugins::Sign) add_plugin(Aws::Plugins::Protocols::RestJson) - add_plugin(Aws::BedrockRuntime::Plugins::BearerAuthorization) add_plugin(Aws::Plugins::EventStreamConfiguration) add_plugin(Aws::BedrockRuntime::Plugins::Endpoints) From feda2510790c7d44fbea2ff84c0a65ffb88e9afc Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Wed, 2 Jul 2025 12:55:55 -0400 Subject: [PATCH 3/8] Add changelogs --- gems/aws-sdk-bedrock/CHANGELOG.md | 2 ++ gems/aws-sdk-bedrockruntime/CHANGELOG.md | 2 ++ gems/aws-sdk-core/CHANGELOG.md | 2 ++ 3 files changed, 6 insertions(+) diff --git a/gems/aws-sdk-bedrock/CHANGELOG.md b/gems/aws-sdk-bedrock/CHANGELOG.md index 59dbe950c5a..a7426bafb33 100644 --- a/gems/aws-sdk-bedrock/CHANGELOG.md +++ b/gems/aws-sdk-bedrock/CHANGELOG.md @@ -1,6 +1,8 @@ Unreleased Changes ------------------ +* Feature - Support `ENV['AWS_BEARER_TOKEN_BEDROCK']` for authentication with Amazon Bedrock APIs. + 1.53.0 (2025-06-30) ------------------ diff --git a/gems/aws-sdk-bedrockruntime/CHANGELOG.md b/gems/aws-sdk-bedrockruntime/CHANGELOG.md index bd8425932db..5caa0b1f980 100644 --- a/gems/aws-sdk-bedrockruntime/CHANGELOG.md +++ b/gems/aws-sdk-bedrockruntime/CHANGELOG.md @@ -1,6 +1,8 @@ Unreleased Changes ------------------ +* Feature - Support `ENV['AWS_BEARER_TOKEN_BEDROCK']` for authentication with Amazon Bedrock APIs. + 1.50.0 (2025-06-30) ------------------ diff --git a/gems/aws-sdk-core/CHANGELOG.md b/gems/aws-sdk-core/CHANGELOG.md index a94da1d2da6..d8bb7557c1e 100644 --- a/gems/aws-sdk-core/CHANGELOG.md +++ b/gems/aws-sdk-core/CHANGELOG.md @@ -1,6 +1,8 @@ Unreleased Changes ------------------ +* Feature - Support metric tracking for Bedrock Bearer tokens. + 3.226.2 (2025-07-01) ------------------ From 0ecb370cb3735cf514f0f435d95f5e52bd8284cf Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Wed, 2 Jul 2025 13:11:32 -0400 Subject: [PATCH 4/8] Add metrics test cases --- gems/aws-sdk-bedrock/spec/client_spec.rb | 9 +++++++++ gems/aws-sdk-bedrockruntime/spec/client_spec.rb | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/gems/aws-sdk-bedrock/spec/client_spec.rb b/gems/aws-sdk-bedrock/spec/client_spec.rb index 9e1e2bf3979..216c85b8682 100644 --- a/gems/aws-sdk-bedrock/spec/client_spec.rb +++ b/gems/aws-sdk-bedrock/spec/client_spec.rb @@ -38,6 +38,15 @@ module Bedrock resp = client.list_imported_models expect(resp.context.http_request.headers['Authorization']).to eq('Bearer explicit-code-token') end + + it 'sets a user agent metric' do + ENV['AWS_BEARER_TOKEN_BEDROCK'] = 'bedrock-token' + client = Client.new(stub_responses: true, token_provider: nil) + resp = client.list_imported_models + user_agent = resp.context.http_request.headers['User-Agent'] + metrics = user_agent.match(/ m\/([^ ]+)/)[1].split(',') + expect(metrics).to include(Aws::Plugins::UserAgent::METRICS['BEARER_SERVICE_ENV_VARS']) + end end end end diff --git a/gems/aws-sdk-bedrockruntime/spec/client_spec.rb b/gems/aws-sdk-bedrockruntime/spec/client_spec.rb index f486114422e..2ec722720ad 100644 --- a/gems/aws-sdk-bedrockruntime/spec/client_spec.rb +++ b/gems/aws-sdk-bedrockruntime/spec/client_spec.rb @@ -44,6 +44,15 @@ def invoke_model(client) resp = invoke_model(client) expect(resp.context.http_request.headers['Authorization']).to eq('Bearer explicit-code-token') end + + it 'sets a user agent metric' do + ENV['AWS_BEARER_TOKEN_BEDROCK'] = 'bedrock-token' + client = Client.new(stub_responses: true, token_provider: nil) + resp = invoke_model(client) + user_agent = resp.context.http_request.headers['User-Agent'] + metrics = user_agent.match(/ m\/([^ ]+)/)[1].split(',') + expect(metrics).to include(Aws::Plugins::UserAgent::METRICS['BEARER_SERVICE_ENV_VARS']) + end end end end From d452a72ef7c44f108e59aac4ed3f9516288101fd Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Wed, 2 Jul 2025 16:07:06 -0400 Subject: [PATCH 5/8] More generic metrics tracking --- .../plugins/bearer_authorization.rb | 19 ++++------- gems/aws-sdk-bedrock/spec/client_spec.rb | 23 ++++++++++--- .../plugins/bearer_authorization.rb | 19 ++++------- .../spec/client_spec.rb | 21 ++++++++++-- .../lib/aws-sdk-core/plugins/sign.rb | 33 +++++++++++-------- .../lib/aws-sdk-core/static_token_provider.rb | 3 +- gems/aws-sdk-core/lib/aws-sdk-core/token.rb | 6 ++-- .../lib/aws-sdk-core/token_provider.rb | 4 +++ .../aws/credential_resolution_chain_spec.rb | 1 - 9 files changed, 76 insertions(+), 53 deletions(-) diff --git a/gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/plugins/bearer_authorization.rb b/gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/plugins/bearer_authorization.rb index 20b304dc908..f8bb6f85292 100644 --- a/gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/plugins/bearer_authorization.rb +++ b/gems/aws-sdk-bedrock/lib/aws-sdk-bedrock/plugins/bearer_authorization.rb @@ -7,28 +7,21 @@ class BearerAuthorization < Seahorse::Client::Plugin def after_initialize(client) return unless (token = ENV['AWS_BEARER_TOKEN_BEDROCK']) - client.config.token_provider ||= Aws::StaticTokenProvider.new(token) + token_provider = Aws::StaticTokenProvider.new(token) + token_provider.metrics = ['BEARER_SERVICE_ENV_VARS'] + client.config.token_provider ||= token_provider end class Handler < Seahorse::Client::Handler def call(context) # This also sets the preferred auth scheme even if the code token has precedence. context[:auth_scheme] = { 'name' => 'bearer' } if ENV['AWS_BEARER_TOKEN_BEDROCK'] - with_metric { @handler.call(context) } - end - - private - - def with_metric(&block) - if ENV['AWS_BEARER_TOKEN_BEDROCK'] - Aws::Plugins::UserAgent.metric('BEARER_SERVICE_ENV_VARS', &block) - else - block.call - end + @handler.call(context) end end - handle(Handler) + # After endpoint/auth but before builders. + handle(Handler, priority: 60) end end end diff --git a/gems/aws-sdk-bedrock/spec/client_spec.rb b/gems/aws-sdk-bedrock/spec/client_spec.rb index 216c85b8682..5fb4f165124 100644 --- a/gems/aws-sdk-bedrock/spec/client_spec.rb +++ b/gems/aws-sdk-bedrock/spec/client_spec.rb @@ -5,6 +5,11 @@ module Aws module Bedrock describe Client do + def metrics_from_user_agent_header(resp) + header = resp.context.http_request.headers['User-Agent'] + header.match(%r{ m/([A-Za-z0-9+-,]+)})[1].split(',') + end + it 'uses a bearer token from the environment' do ENV['AWS_BEARER_TOKEN_BEDROCK'] = 'bedrock-token' client = Client.new(stub_responses: true, token_provider: nil) @@ -29,7 +34,7 @@ module Bedrock expect(resp.context.http_request.headers['Authorization']).to eq('Bearer bedrock-token') end - it 'uses explicit config over the environment token' do + it 'uses the token value from code over the environment token' do ENV['AWS_BEARER_TOKEN_BEDROCK'] = 'bedrock-token' client = Client.new( stub_responses: true, @@ -43,9 +48,19 @@ module Bedrock ENV['AWS_BEARER_TOKEN_BEDROCK'] = 'bedrock-token' client = Client.new(stub_responses: true, token_provider: nil) resp = client.list_imported_models - user_agent = resp.context.http_request.headers['User-Agent'] - metrics = user_agent.match(/ m\/([^ ]+)/)[1].split(',') - expect(metrics).to include(Aws::Plugins::UserAgent::METRICS['BEARER_SERVICE_ENV_VARS']) + metrics = metrics_from_user_agent_header(resp) + expect(metrics).to include('3') + end + + it 'does not set a user agent metric when using a token from code' do + ENV['AWS_BEARER_TOKEN_BEDROCK'] = 'bedrock-token' + client = Client.new( + stub_responses: true, + token_provider: Aws::StaticTokenProvider.new('explicit-code-token') + ) + resp = client.list_imported_models + metrics = metrics_from_user_agent_header(resp) + expect(metrics).to_not include('3') end end end diff --git a/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/plugins/bearer_authorization.rb b/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/plugins/bearer_authorization.rb index 47c9cf7951d..028d3017780 100644 --- a/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/plugins/bearer_authorization.rb +++ b/gems/aws-sdk-bedrockruntime/lib/aws-sdk-bedrockruntime/plugins/bearer_authorization.rb @@ -7,28 +7,21 @@ class BearerAuthorization < Seahorse::Client::Plugin def after_initialize(client) return unless (token = ENV['AWS_BEARER_TOKEN_BEDROCK']) - client.config.token_provider ||= Aws::StaticTokenProvider.new(token) + token_provider = Aws::StaticTokenProvider.new(token) + token_provider.metrics = ['BEARER_SERVICE_ENV_VARS'] + client.config.token_provider ||= token_provider end class Handler < Seahorse::Client::Handler def call(context) # This also sets the preferred auth scheme even if the code token has precedence. context[:auth_scheme] = { 'name' => 'bearer' } if ENV['AWS_BEARER_TOKEN_BEDROCK'] - with_metric { @handler.call(context) } - end - - private - - def with_metric(&block) - if ENV['AWS_BEARER_TOKEN_BEDROCK'] - Aws::Plugins::UserAgent.metric('BEARER_SERVICE_ENV_VARS', &block) - else - block.call - end + @handler.call(context) end end - handle(Handler) + # After endpoint/auth but before builders. + handle(Handler, priority: 60) end end end diff --git a/gems/aws-sdk-bedrockruntime/spec/client_spec.rb b/gems/aws-sdk-bedrockruntime/spec/client_spec.rb index 2ec722720ad..53f17bfaf9d 100644 --- a/gems/aws-sdk-bedrockruntime/spec/client_spec.rb +++ b/gems/aws-sdk-bedrockruntime/spec/client_spec.rb @@ -5,6 +5,11 @@ module Aws module BedrockRuntime describe Client do + def metrics_from_user_agent_header(resp) + header = resp.context.http_request.headers['User-Agent'] + header.match(%r{ m/([A-Za-z0-9+-,]+)})[1].split(',') + end + def invoke_model(client) stub = client.stub_data(:invoke_model, body: 'test') client.stub_responses(:invoke_model, stub) @@ -49,9 +54,19 @@ def invoke_model(client) ENV['AWS_BEARER_TOKEN_BEDROCK'] = 'bedrock-token' client = Client.new(stub_responses: true, token_provider: nil) resp = invoke_model(client) - user_agent = resp.context.http_request.headers['User-Agent'] - metrics = user_agent.match(/ m\/([^ ]+)/)[1].split(',') - expect(metrics).to include(Aws::Plugins::UserAgent::METRICS['BEARER_SERVICE_ENV_VARS']) + metrics = metrics_from_user_agent_header(resp) + expect(metrics).to include('3') + end + + it 'does not set a user agent metric when using a token from code' do + ENV['AWS_BEARER_TOKEN_BEDROCK'] = 'bedrock-token' + client = Client.new( + stub_responses: true, + token_provider: Aws::StaticTokenProvider.new('explicit-code-token') + ) + resp = invoke_model(client) + metrics = metrics_from_user_agent_header(resp) + expect(metrics).to_not include('3') end end end diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb index 5cfc4fb526f..d50c83d57ed 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb @@ -32,7 +32,7 @@ def self.signer_for(auth_scheme, config, sigv4_region_override = nil, sigv4_cred } SignatureV4.new(auth_scheme, config, sigv4_overrides) when 'bearer' - Bearer.new + Bearer.new(config) else NullSigner.new end @@ -41,7 +41,6 @@ def self.signer_for(auth_scheme, config, sigv4_region_override = nil, sigv4_cred class Handler < Seahorse::Client::Handler def call(context) # Skip signing if using sigv2 signing from s3_signer in S3 - credentials = nil unless v2_signing?(context.config) signer = Sign.signer_for( context[:auth_scheme], @@ -49,18 +48,22 @@ def call(context) context[:sigv4_region], context[:sigv4_credentials] ) - credentials = signer.credentials if signer.is_a?(SignatureV4) signer.sign(context) end - with_metrics(credentials) { @handler.call(context) } + with_metrics(signer) { @handler.call(context) } end private - def with_metrics(credentials, &block) - return block.call unless credentials&.respond_to?(:metrics) - - Aws::Plugins::UserAgent.metric(*credentials.metrics, &block) + def with_metrics(signer, &block) + case signer + when SignatureV4 + Aws::Plugins::UserAgent.metric(*signer.credentials.metrics, &block) + when Bearer + Aws::Plugins::UserAgent.metric(*signer.token_provider.metrics, &block) + else + block.call + end end def v2_signing?(config) @@ -72,17 +75,19 @@ def v2_signing?(config) # @api private class Bearer - def initialize + def initialize(config) + @token_provider = config.token_provider end + attr_reader :token_provider + def sign(context) if context.http_request.endpoint.scheme != 'https' raise ArgumentError, 'Unable to use bearer authorization on non https endpoint.' end - token_provider = context.config.token_provider - raise Errors::MissingBearerTokenError unless token_provider&.set? + raise Errors::MissingBearerTokenError unless @token_provider.set? - context.http_request.headers['Authorization'] = "Bearer #{token_provider.token.token}" + context.http_request.headers['Authorization'] = "Bearer #{@token_provider.token.token}" end def presign_url(*args) @@ -96,8 +101,6 @@ def sign_event(*args) # @api private class SignatureV4 - attr_reader :signer - def initialize(auth_scheme, config, sigv4_overrides = {}) scheme_name = auth_scheme['name'] @@ -126,6 +129,8 @@ def initialize(auth_scheme, config, sigv4_overrides = {}) end end + attr_reader :signer + def sign(context) req = context.http_request diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/static_token_provider.rb b/gems/aws-sdk-core/lib/aws-sdk-core/static_token_provider.rb index 7786d1ac08e..07c6909f94d 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/static_token_provider.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/static_token_provider.rb @@ -2,12 +2,11 @@ module Aws class StaticTokenProvider - include TokenProvider # @param [String] token # @param [Time] expiration - def initialize(token, expiration=nil) + def initialize(token, expiration = nil) @token = Token.new(token, expiration) end end diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/token.rb b/gems/aws-sdk-core/lib/aws-sdk-core/token.rb index 5126005d604..f27618c3df2 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/token.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/token.rb @@ -3,9 +3,9 @@ module Aws class Token - # @param [String] token - # @param [Time] expiration - def initialize(token, expiration=nil) + # @param [String, nil] token + # @param [Time, nil] expiration + def initialize(token, expiration = nil) @token = token @expiration = expiration end diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/token_provider.rb b/gems/aws-sdk-core/lib/aws-sdk-core/token_provider.rb index 643012f9d0c..8b69b78bb2d 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/token_provider.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/token_provider.rb @@ -6,6 +6,10 @@ module TokenProvider # @return [Token] attr_reader :token + # @api private + # Returns UserAgent metrics for tokens. + attr_accessor :metrics + # @return [Boolean] def set? !!token && token.set? diff --git a/gems/aws-sdk-core/spec/aws/credential_resolution_chain_spec.rb b/gems/aws-sdk-core/spec/aws/credential_resolution_chain_spec.rb index e141482d286..60404c67e6f 100644 --- a/gems/aws-sdk-core/spec/aws/credential_resolution_chain_spec.rb +++ b/gems/aws-sdk-core/spec/aws/credential_resolution_chain_spec.rb @@ -1172,7 +1172,6 @@ def stub_token_file(token) def metrics_from_user_agent_header(resp) header = resp.context.http_request.headers['User-Agent'] - # Parse list of metrics from User-Agent header header.match(%r{ m/([A-Za-z0-9+-,]+)})[1].split(',') end From 56f59352abd3ce1a5e269a7b65893836dfecb926 Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Wed, 2 Jul 2025 18:29:38 -0400 Subject: [PATCH 6/8] Greatly improve sign testing and refactor signer --- .../lib/aws-sdk-core/plugins/sign.rb | 44 +++++-------- .../aws-sdk-core/lib/aws-sdk-sts/presigner.rb | 8 +-- gems/aws-sdk-core/spec/auth_helper.rb | 25 ++++++++ gems/aws-sdk-core/spec/aws/endpoints_spec.rb | 9 +-- .../spec/aws/plugins/sign_spec.rb | 8 +-- gems/aws-sdk-core/spec/shared_spec_helper.rb | 4 +- gems/aws-sdk-core/spec/sigv4_helper.rb | 29 --------- gems/aws-sigv4/CHANGELOG.md | 2 + gems/aws-sigv4/lib/aws-sigv4/signer.rb | 62 +++++++++++-------- gems/aws-sigv4/sig/signer.rbs | 12 ++-- 10 files changed, 97 insertions(+), 106 deletions(-) create mode 100644 gems/aws-sdk-core/spec/auth_helper.rb delete mode 100644 gems/aws-sdk-core/spec/sigv4_helper.rb diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb index d50c83d57ed..1d82ff5b82f 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb @@ -13,8 +13,7 @@ class Sign < Seahorse::Client::Plugin option(:sigv4_region) option(:unsigned_operations, default: []) - supported_auth_types = %w[sigv4 bearer sigv4-s3express sigv4a none] - SUPPORTED_AUTH_TYPES = supported_auth_types.freeze + SUPPORTED_AUTH_TYPES = %w[sigv4 bearer sigv4-s3express sigv4a none].freeze def add_handlers(handlers, cfg) operations = cfg.api.operation_names - cfg.unsigned_operations @@ -23,16 +22,12 @@ def add_handlers(handlers, cfg) # @api private # Return a signer with the `sign(context)` method - def self.signer_for(auth_scheme, config, sigv4_region_override = nil, sigv4_credentials_override = nil) + def self.signer_for(auth_scheme, context) case auth_scheme['name'] when 'sigv4', 'sigv4a', 'sigv4-s3express' - sigv4_overrides = { - region: sigv4_region_override, - credentials: sigv4_credentials_override - } - SignatureV4.new(auth_scheme, config, sigv4_overrides) + SignatureV4.new(auth_scheme, context) when 'bearer' - Bearer.new(config) + Bearer.new(context) else NullSigner.new end @@ -42,12 +37,7 @@ class Handler < Seahorse::Client::Handler def call(context) # Skip signing if using sigv2 signing from s3_signer in S3 unless v2_signing?(context.config) - signer = Sign.signer_for( - context[:auth_scheme], - context.config, - context[:sigv4_region], - context[:sigv4_credentials] - ) + signer = Sign.signer_for(context[:auth_scheme], context) signer.sign(context) end with_metrics(signer) { @handler.call(context) } @@ -75,8 +65,8 @@ def v2_signing?(config) # @api private class Bearer - def initialize(config) - @token_provider = config.token_provider + def initialize(context) + @token_provider = context.config.token_provider end attr_reader :token_provider @@ -85,7 +75,7 @@ def sign(context) if context.http_request.endpoint.scheme != 'https' raise ArgumentError, 'Unable to use bearer authorization on non https endpoint.' end - raise Errors::MissingBearerTokenError unless @token_provider.set? + raise Errors::MissingBearerTokenError unless @token_provider && @token_provider.set? context.http_request.headers['Authorization'] = "Bearer #{@token_provider.token.token}" end @@ -101,14 +91,12 @@ def sign_event(*args) # @api private class SignatureV4 - def initialize(auth_scheme, config, sigv4_overrides = {}) + def initialize(auth_scheme, context) + config = context.config scheme_name = auth_scheme['name'] - unless %w[sigv4 sigv4a sigv4-s3express].include?(scheme_name) - raise ArgumentError, - "Expected sigv4, sigv4a, or sigv4-s3express auth scheme, got #{scheme_name}" + raise ArgumentError, "Expected sigv4, sigv4a, or sigv4-s3express auth scheme, got #{scheme_name}" end - region = if scheme_name == 'sigv4a' auth_scheme['signingRegionSet'].join(',') else @@ -117,11 +105,11 @@ def initialize(auth_scheme, config, sigv4_overrides = {}) begin @signer = config.sigv4_signer || Aws::Sigv4::Signer.new( service: config.sigv4_name || auth_scheme['signingName'], - region: sigv4_overrides[:region] || config.sigv4_region || region, - credentials_provider: sigv4_overrides[:credentials] || config.credentials, - signing_algorithm: scheme_name.to_sym, - uri_escape_path: !!!auth_scheme['disableDoubleEncoding'], - normalize_path: !!!auth_scheme['disableNormalizePath'], + region: context[:sigv4_region] || config.sigv4_region || region, + credentials_provider: context[:sigv4_credentials] || config.credentials, + signing_algorithm: scheme_name, + uri_escape_path: !auth_scheme['disableDoubleEncoding'], + normalize_path: !auth_scheme['disableNormalizePath'], unsigned_headers: %w[content-length user-agent x-amzn-trace-id expect transfer-encoding connection] ) rescue Aws::Sigv4::Errors::MissingCredentialsError diff --git a/gems/aws-sdk-core/lib/aws-sdk-sts/presigner.rb b/gems/aws-sdk-core/lib/aws-sdk-sts/presigner.rb index 7bc66c18c2e..f5e150dffec 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-sts/presigner.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-sts/presigner.rb @@ -53,13 +53,9 @@ def get_caller_identity_presigned_url(options = {}) use_fips: context.config.use_fips_endpoint, use_global_endpoint: context.config.sts_regional_endpoints == 'legacy' ) - endpoint = context.config.endpoint_provider - .resolve_endpoint(endpoint_params) + endpoint = context.config.endpoint_provider.resolve_endpoint(endpoint_params) auth_scheme = Aws::Endpoints.resolve_auth_scheme(context, endpoint) - - signer = Aws::Plugins::Sign.signer_for( - auth_scheme, context.config - ) + signer = Aws::Plugins::Sign.signer_for(auth_scheme, context) signer.presign_url( http_method: 'GET', diff --git a/gems/aws-sdk-core/spec/auth_helper.rb b/gems/aws-sdk-core/spec/auth_helper.rb new file mode 100644 index 00000000000..aed6faa2cbf --- /dev/null +++ b/gems/aws-sdk-core/spec/auth_helper.rb @@ -0,0 +1,25 @@ +module AuthHelper + # Expect the signer to be called with the given auth scheme. + def expect_auth(expected_auth_scheme, region: nil, credentials: nil) + expect(Aws::Plugins::Sign).to receive(:signer_for).and_wrap_original do |m, *args| + actual_auth_scheme, _context = args + expect(actual_auth_scheme).to include(expected_auth_scheme) + signer = m.call(*args) + case signer + when Aws::Plugins::Sign::SignatureV4 + sigv4_signer = signer.signer + expect(sigv4_signer.signing_algorithm).to eq(expected_auth_scheme['name']) if expected_auth_scheme['name'] + + case expected_auth_scheme['name'] + when 'sigv4' + region = region || expected_auth_scheme['signingRegion'] + when 'sigv4a' + region = region || expected_auth_scheme['signingRegionSet']&.join(',') + end + expect(sigv4_signer.region).to eq(region) if region + expect(sigv4_signer.credentials_provider).to eq(credentials) if credentials + end + signer + end + end +end diff --git a/gems/aws-sdk-core/spec/aws/endpoints_spec.rb b/gems/aws-sdk-core/spec/aws/endpoints_spec.rb index 78e84edebe9..ca84ff72f67 100644 --- a/gems/aws-sdk-core/spec/aws/endpoints_spec.rb +++ b/gems/aws-sdk-core/spec/aws/endpoints_spec.rb @@ -114,13 +114,6 @@ module Aws end context 'sigv4a defaults' do - before do - stub_const( - 'Aws::Endpoints::SUPPORTED_AUTH_TRAITS', - Aws::Endpoints::SUPPORTED_AUTH_TRAITS + ['aws.auth#sigv4a'] - ) - end - let(:auth) { ['aws.auth#sigv4a'] } it 'signs with sigv4' do @@ -211,7 +204,7 @@ module Aws ) end - let(:auth) { ['aws.auth#sigv4a', 'aws.auth#sigv4'] } + let(:auth) { %w[aws.auth#sigv4a aws.auth#sigv4] } it 'prefers the first supported auth trait' do expect_auth({ 'name' => 'sigv4' }) diff --git a/gems/aws-sdk-core/spec/aws/plugins/sign_spec.rb b/gems/aws-sdk-core/spec/aws/plugins/sign_spec.rb index 2c456b67e5d..9ea6d294496 100644 --- a/gems/aws-sdk-core/spec/aws/plugins/sign_spec.rb +++ b/gems/aws-sdk-core/spec/aws/plugins/sign_spec.rb @@ -53,10 +53,10 @@ module Plugins class Handler < Seahorse::Client::Handler def call(context) context[:sigv4_region] = 'override-region' - context[:sigv4_credentials] = Aws::Sigv4::StaticCredentialsProvider.new( - access_key_id: 'override-akid', - secret_access_key: 'override-secret', - session_token: 'override-token' + context[:sigv4_credentials] = Aws::Credentials.new( + 'override-akid', + 'override-secret', + 'override-token' ) @handler.call(context) end diff --git a/gems/aws-sdk-core/spec/shared_spec_helper.rb b/gems/aws-sdk-core/spec/shared_spec_helper.rb index 70dd39ab60c..dac6db3d896 100644 --- a/gems/aws-sdk-core/spec/shared_spec_helper.rb +++ b/gems/aws-sdk-core/spec/shared_spec_helper.rb @@ -8,7 +8,7 @@ require 'webmock/rspec' -require_relative './sigv4_helper' +require_relative './auth_helper' # Prevent the SDK unit tests from loading actual credentials while under test. # By default the SDK attempts to load credentials from: @@ -19,7 +19,7 @@ # RSpec.configure do |config| # Module to help check service signing - config.include Sigv4Helper + config.include AuthHelper config.before(:each) do # Clear the current ENV to avoid loading credentials. diff --git a/gems/aws-sdk-core/spec/sigv4_helper.rb b/gems/aws-sdk-core/spec/sigv4_helper.rb deleted file mode 100644 index c909eae3bc0..00000000000 --- a/gems/aws-sdk-core/spec/sigv4_helper.rb +++ /dev/null @@ -1,29 +0,0 @@ -module Sigv4Helper - # perhaps belongs in an AuthHelper but we mainly check Sigv4 these days - def expect_auth(auth_scheme, region: nil, credentials: nil) - if auth_scheme['name'] == 'sigv4a' - stub_const( - 'Aws::Plugins::Sign::SUPPORTED_AUTH_TYPES', - Aws::Plugins::Sign::SUPPORTED_AUTH_TYPES + ['sigv4a'] - ) - end - expect(Aws::Plugins::Sign).to receive(:signer_for).and_wrap_original do |m, *args| - expect(args.first).to include(auth_scheme) - expect(args[2]).to eq(region) if region - expect(args[3]).to eq(credentials) if credentials - - if auth_scheme['name'] == 'sigv4a' - mock_signature = Aws::Sigv4::Signature.new(headers: {}) - signer = double('sigv4a_signer', sign_request: mock_signature) - region = region || args.first['signingRegionSet'].join(',') - - expect(Aws::Sigv4::Signer).to receive(:new) - .with(hash_including(signing_algorithm: :sigv4a, region: region)) - .and_return(signer) - expect(signer).to receive(:credentials_provider).and_return(credentials) - end - - m.call(*args) - end - end -end diff --git a/gems/aws-sigv4/CHANGELOG.md b/gems/aws-sigv4/CHANGELOG.md index 22cdbb5658c..87098b1adea 100644 --- a/gems/aws-sigv4/CHANGELOG.md +++ b/gems/aws-sigv4/CHANGELOG.md @@ -1,6 +1,8 @@ Unreleased Changes ------------------ +* Feature - Add instance variable accessors to `Signer`. + 1.12.1 (2025-06-10) ------------------ diff --git a/gems/aws-sigv4/lib/aws-sigv4/signer.rb b/gems/aws-sigv4/lib/aws-sigv4/signer.rb index 789ccd9ba7b..ae0cfef50d4 100644 --- a/gems/aws-sigv4/lib/aws-sigv4/signer.rb +++ b/gems/aws-sigv4/lib/aws-sigv4/signer.rb @@ -111,19 +111,18 @@ class Signer # @option options [Array] :unsigned_headers ([]) A list of # headers that should not be signed. This is useful when a proxy # modifies headers, such as 'User-Agent', invalidating a signature. + # All header names are downcased. + # + # @option options [Symbol, String] :signing_algorithm ('sigv4') The algorithm to use for signing. + # This can either be `sigv4`, `sigv4a`, or `sigv4-s3express`. # # @option options [Boolean] :uri_escape_path (true) When `true`, # the request URI path is uri-escaped as part of computing the canonical # request string. This is required for every service, except Amazon S3, # as of late 2016. # - # @option options [Boolean] :apply_checksum_header (true) When `true`, - # the computed content checksum is returned in the hash of signature - # headers. This is required for AWS Glacier, and optional for - # every other AWS service as of late 2016. - # - # @option options [Symbol] :signing_algorithm (:sigv4) The - # algorithm to use for signing. + # @option options [Boolean] :normalize_path (true) When `true`, the + # uri paths will be normalized when building the canonical request. # # @option options [Boolean] :omit_session_token (false) # (Supported only when `aws-crt` is available) If `true`, @@ -131,21 +130,23 @@ class Signer # but is treated as "unsigned" and does not contribute # to the authorization signature. # - # @option options [Boolean] :normalize_path (true) When `true`, the - # uri paths will be normalized when building the canonical request. + # @option options [Boolean] :apply_checksum_header (true) When `true`, + # the computed content checksum header (`x-amz-content-sha256`) is signed and returned + # in the hash of signature headers. This is required for AWS Glacier, and optional + # for every other AWS service as of late 2016. def initialize(options = {}) @service = extract_service(options) @region = extract_region(options) @credentials_provider = extract_credentials_provider(options) - @unsigned_headers = Set.new((options.fetch(:unsigned_headers, [])).map(&:downcase)) + @unsigned_headers = Set.new(options.fetch(:unsigned_headers, []).map(&:downcase)) @unsigned_headers << 'authorization' @unsigned_headers << 'x-amzn-trace-id' @unsigned_headers << 'expect' + @signing_algorithm = options.fetch(:signing_algorithm, 'sigv4').to_s @uri_escape_path = options.fetch(:uri_escape_path, true) - @apply_checksum_header = options.fetch(:apply_checksum_header, true) - @signing_algorithm = options.fetch(:signing_algorithm, :sigv4) @normalize_path = options.fetch(:normalize_path, true) @omit_session_token = options.fetch(:omit_session_token, false) + @apply_checksum_header = options.fetch(:apply_checksum_header, true) end # @return [String] @@ -165,12 +166,22 @@ def initialize(options = {}) # attr_reader :credentials_provider - # @return [Set] Returns a set of header names that should not be signed. - # All header names have been downcased. + # @return [Set] attr_reader :unsigned_headers - # @return [Boolean] When `true` the `x-amz-content-sha256` header will be signed and - # returned in the signature headers. + # @return [String] + attr_reader :signing_algorithm + + # @return [Boolean] + attr_reader :uri_escape_path + + # @return [Boolean] + attr_reader :normalize_path + + # @return [Boolean] + attr_reader :omit_session_token + + # @return [Boolean] attr_reader :apply_checksum_header # Computes a version 4 signature signature. Returns the resultant @@ -239,7 +250,7 @@ def sign_request(request) sigv4_headers['host'] = headers['host'] || host(url) sigv4_headers['x-amz-date'] = datetime if creds.session_token && !@omit_session_token - if @signing_algorithm == 'sigv4-s3express'.to_sym + if @signing_algorithm == 'sigv4-s3express' sigv4_headers['x-amz-s3session-token'] = creds.session_token else sigv4_headers['x-amz-security-token'] = creds.session_token @@ -248,7 +259,7 @@ def sign_request(request) sigv4_headers['x-amz-content-sha256'] ||= content_sha256 if @apply_checksum_header - if @signing_algorithm == :sigv4a && @region && !@region.empty? + if @signing_algorithm == 'sigv4a' && @region && !@region.empty? sigv4_headers['x-amz-region-set'] = @region end headers = headers.merge(sigv4_headers) # merge so we do not modify given headers hash @@ -260,7 +271,7 @@ def sign_request(request) sts = string_to_sign(datetime, creq, algorithm) sig = - if @signing_algorithm == :sigv4a + if @signing_algorithm == 'sigv4a' asymmetric_signature(creds, sts) else signature(creds.secret_access_key, date, sts) @@ -437,7 +448,7 @@ def presign_url(options) params['X-Amz-Date'] = datetime params['X-Amz-Expires'] = presigned_url_expiration(options, expiration, Time.strptime(datetime, "%Y%m%dT%H%M%S%Z")).to_s if creds.session_token - if @signing_algorithm == 'sigv4-s3express'.to_sym + if @signing_algorithm == 'sigv4-s3express' params['X-Amz-S3session-Token'] = creds.session_token else params['X-Amz-Security-Token'] = creds.session_token @@ -445,7 +456,7 @@ def presign_url(options) end params['X-Amz-SignedHeaders'] = signed_headers(headers) - if @signing_algorithm == :sigv4a && @region + if @signing_algorithm == 'sigv4a' && @region params['X-Amz-Region-Set'] = @region end @@ -462,7 +473,7 @@ def presign_url(options) creq = canonical_request(http_method, url, headers, content_sha256) sts = string_to_sign(datetime, creq, algorithm) signature = - if @signing_algorithm == :sigv4a + if @signing_algorithm == 'sigv4a' asymmetric_signature(creds, sts) else signature(creds.secret_access_key, date, sts) @@ -474,7 +485,7 @@ def presign_url(options) private def sts_algorithm - @signing_algorithm == :sigv4a ? 'AWS4-ECDSA-P256-SHA256' : 'AWS4-HMAC-SHA256' + @signing_algorithm == 'sigv4a' ? 'AWS4-ECDSA-P256-SHA256' : 'AWS4-HMAC-SHA256' end def canonical_request(http_method, url, headers, content_sha256) @@ -523,7 +534,7 @@ def event_string_to_sign(datetime, headers, payload, prior_signature, encoder) def credential_scope(date) [ date, - (@region unless @signing_algorithm == :sigv4a), + (@region unless @signing_algorithm == 'sigv4a'), @service, 'aws4_request' ].compact.join('/') @@ -543,7 +554,8 @@ def signature(secret_access_key, date, string_to_sign) def asymmetric_signature(creds, string_to_sign) ec, _ = Aws::Sigv4::AsymmetricCredentials.derive_asymmetric_key( - creds.access_key_id, creds.secret_access_key + creds.access_key_id, + creds.secret_access_key ) sts_digest = OpenSSL::Digest::SHA256.digest(string_to_sign) s = ec.dsa_sign_asn1(sts_digest) diff --git a/gems/aws-sigv4/sig/signer.rbs b/gems/aws-sigv4/sig/signer.rbs index 6bf9c8c03f4..30435e29943 100644 --- a/gems/aws-sigv4/sig/signer.rbs +++ b/gems/aws-sigv4/sig/signer.rbs @@ -10,18 +10,22 @@ module Aws ?credentials: _Credentials, ?credentials_provider: _CredentialsProvider, ?unsigned_headers: Array[String], + ?signing_algorithm: 'sigv4' | 'sigv4a' | 'sigv4-s3express', ?uri_escape_path: bool, - ?apply_checksum_header: bool, - ?signing_algorithm: :sigv4 | :sigv4a | :'sigv4-s3express', - ?omit_session_token: bool, ?normalize_path: bool, + ?omit_session_token: bool, + ?apply_checksum_header: bool ) -> void | (?Hash[Symbol, untyped]) -> void attr_reader service: String attr_reader region: String attr_reader credentials_provider: _CredentialsProvider - attr_reader unsigned_headers: Array[String] + attr_reader unsigned_headers: Set[String] + attr_reader signing_algorithm: String + attr_reader uri_escape_path: bool + attr_reader normalize_path: bool + attr_reader omit_session_token: bool attr_reader apply_checksum_header: bool def sign_request: ( From 5a9ab8d3cdf01735229ff09ef803dde4851e1aba Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Wed, 2 Jul 2025 18:43:14 -0400 Subject: [PATCH 7/8] Partially undo ambitious refactor --- .../lib/aws-sdk-core/plugins/sign.rb | 28 ++++++++++++------- .../aws-sdk-core/lib/aws-sdk-sts/presigner.rb | 2 +- gems/aws-sdk-core/spec/auth_helper.rb | 6 +++- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb index 1d82ff5b82f..77d188afe15 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb @@ -22,12 +22,16 @@ def add_handlers(handlers, cfg) # @api private # Return a signer with the `sign(context)` method - def self.signer_for(auth_scheme, context) + def self.signer_for(auth_scheme, config, sigv4_region_override = nil, sigv4_credentials_override = nil) case auth_scheme['name'] when 'sigv4', 'sigv4a', 'sigv4-s3express' - SignatureV4.new(auth_scheme, context) + sigv4_overrides = { + region: sigv4_region_override, + credentials: sigv4_credentials_override + } + SignatureV4.new(auth_scheme, config, sigv4_overrides) when 'bearer' - Bearer.new(context) + Bearer.new(config) else NullSigner.new end @@ -37,7 +41,12 @@ class Handler < Seahorse::Client::Handler def call(context) # Skip signing if using sigv2 signing from s3_signer in S3 unless v2_signing?(context.config) - signer = Sign.signer_for(context[:auth_scheme], context) + signer = Sign.signer_for( + context[:auth_scheme], + context.config, + context[:sigv4_region], + context[:sigv4_credentials] + ) signer.sign(context) end with_metrics(signer) { @handler.call(context) } @@ -65,8 +74,8 @@ def v2_signing?(config) # @api private class Bearer - def initialize(context) - @token_provider = context.config.token_provider + def initialize(config) + @token_provider = config.token_provider end attr_reader :token_provider @@ -91,8 +100,7 @@ def sign_event(*args) # @api private class SignatureV4 - def initialize(auth_scheme, context) - config = context.config + def initialize(auth_scheme, config, sigv4_overrides = {}) scheme_name = auth_scheme['name'] unless %w[sigv4 sigv4a sigv4-s3express].include?(scheme_name) raise ArgumentError, "Expected sigv4, sigv4a, or sigv4-s3express auth scheme, got #{scheme_name}" @@ -105,8 +113,8 @@ def initialize(auth_scheme, context) begin @signer = config.sigv4_signer || Aws::Sigv4::Signer.new( service: config.sigv4_name || auth_scheme['signingName'], - region: context[:sigv4_region] || config.sigv4_region || region, - credentials_provider: context[:sigv4_credentials] || config.credentials, + region: sigv4_overrides[:region] || config.sigv4_region || region, + credentials_provider: sigv4_overrides[:credentials] || config.credentials, signing_algorithm: scheme_name, uri_escape_path: !auth_scheme['disableDoubleEncoding'], normalize_path: !auth_scheme['disableNormalizePath'], diff --git a/gems/aws-sdk-core/lib/aws-sdk-sts/presigner.rb b/gems/aws-sdk-core/lib/aws-sdk-sts/presigner.rb index f5e150dffec..b87050621ac 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-sts/presigner.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-sts/presigner.rb @@ -55,7 +55,7 @@ def get_caller_identity_presigned_url(options = {}) ) endpoint = context.config.endpoint_provider.resolve_endpoint(endpoint_params) auth_scheme = Aws::Endpoints.resolve_auth_scheme(context, endpoint) - signer = Aws::Plugins::Sign.signer_for(auth_scheme, context) + signer = Aws::Plugins::Sign.signer_for(auth_scheme, context.config) signer.presign_url( http_method: 'GET', diff --git a/gems/aws-sdk-core/spec/auth_helper.rb b/gems/aws-sdk-core/spec/auth_helper.rb index aed6faa2cbf..f6985184d00 100644 --- a/gems/aws-sdk-core/spec/auth_helper.rb +++ b/gems/aws-sdk-core/spec/auth_helper.rb @@ -2,7 +2,11 @@ module AuthHelper # Expect the signer to be called with the given auth scheme. def expect_auth(expected_auth_scheme, region: nil, credentials: nil) expect(Aws::Plugins::Sign).to receive(:signer_for).and_wrap_original do |m, *args| - actual_auth_scheme, _context = args + actual_auth_scheme = args[0] + _config = args[1] + _sigv4_region_override = args[2] + _sigv4_credentials_override = args[3] + expect(actual_auth_scheme).to include(expected_auth_scheme) signer = m.call(*args) case signer From 4e0d4f4b8808c2ee948b6c4039c6ebacdd1aab32 Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Wed, 2 Jul 2025 19:01:57 -0400 Subject: [PATCH 8/8] Revert sigv4 signer gem changes --- .../lib/aws-sdk-core/plugins/sign.rb | 4 +- gems/aws-sdk-core/spec/auth_helper.rb | 2 - gems/aws-sigv4/CHANGELOG.md | 2 - gems/aws-sigv4/lib/aws-sigv4/signer.rb | 62 ++++++++----------- gems/aws-sigv4/sig/signer.rbs | 12 ++-- 5 files changed, 31 insertions(+), 51 deletions(-) diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb index 77d188afe15..f2803ee05db 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/sign.rb @@ -114,8 +114,8 @@ def initialize(auth_scheme, config, sigv4_overrides = {}) @signer = config.sigv4_signer || Aws::Sigv4::Signer.new( service: config.sigv4_name || auth_scheme['signingName'], region: sigv4_overrides[:region] || config.sigv4_region || region, - credentials_provider: sigv4_overrides[:credentials] || config.credentials, - signing_algorithm: scheme_name, + credentials_provider: sigv4_overrides[:credentials] || config.credentials, + signing_algorithm: scheme_name.to_sym, uri_escape_path: !auth_scheme['disableDoubleEncoding'], normalize_path: !auth_scheme['disableNormalizePath'], unsigned_headers: %w[content-length user-agent x-amzn-trace-id expect transfer-encoding connection] diff --git a/gems/aws-sdk-core/spec/auth_helper.rb b/gems/aws-sdk-core/spec/auth_helper.rb index f6985184d00..d14c3453cd3 100644 --- a/gems/aws-sdk-core/spec/auth_helper.rb +++ b/gems/aws-sdk-core/spec/auth_helper.rb @@ -12,8 +12,6 @@ def expect_auth(expected_auth_scheme, region: nil, credentials: nil) case signer when Aws::Plugins::Sign::SignatureV4 sigv4_signer = signer.signer - expect(sigv4_signer.signing_algorithm).to eq(expected_auth_scheme['name']) if expected_auth_scheme['name'] - case expected_auth_scheme['name'] when 'sigv4' region = region || expected_auth_scheme['signingRegion'] diff --git a/gems/aws-sigv4/CHANGELOG.md b/gems/aws-sigv4/CHANGELOG.md index 87098b1adea..22cdbb5658c 100644 --- a/gems/aws-sigv4/CHANGELOG.md +++ b/gems/aws-sigv4/CHANGELOG.md @@ -1,8 +1,6 @@ Unreleased Changes ------------------ -* Feature - Add instance variable accessors to `Signer`. - 1.12.1 (2025-06-10) ------------------ diff --git a/gems/aws-sigv4/lib/aws-sigv4/signer.rb b/gems/aws-sigv4/lib/aws-sigv4/signer.rb index ae0cfef50d4..789ccd9ba7b 100644 --- a/gems/aws-sigv4/lib/aws-sigv4/signer.rb +++ b/gems/aws-sigv4/lib/aws-sigv4/signer.rb @@ -111,18 +111,19 @@ class Signer # @option options [Array] :unsigned_headers ([]) A list of # headers that should not be signed. This is useful when a proxy # modifies headers, such as 'User-Agent', invalidating a signature. - # All header names are downcased. - # - # @option options [Symbol, String] :signing_algorithm ('sigv4') The algorithm to use for signing. - # This can either be `sigv4`, `sigv4a`, or `sigv4-s3express`. # # @option options [Boolean] :uri_escape_path (true) When `true`, # the request URI path is uri-escaped as part of computing the canonical # request string. This is required for every service, except Amazon S3, # as of late 2016. # - # @option options [Boolean] :normalize_path (true) When `true`, the - # uri paths will be normalized when building the canonical request. + # @option options [Boolean] :apply_checksum_header (true) When `true`, + # the computed content checksum is returned in the hash of signature + # headers. This is required for AWS Glacier, and optional for + # every other AWS service as of late 2016. + # + # @option options [Symbol] :signing_algorithm (:sigv4) The + # algorithm to use for signing. # # @option options [Boolean] :omit_session_token (false) # (Supported only when `aws-crt` is available) If `true`, @@ -130,23 +131,21 @@ class Signer # but is treated as "unsigned" and does not contribute # to the authorization signature. # - # @option options [Boolean] :apply_checksum_header (true) When `true`, - # the computed content checksum header (`x-amz-content-sha256`) is signed and returned - # in the hash of signature headers. This is required for AWS Glacier, and optional - # for every other AWS service as of late 2016. + # @option options [Boolean] :normalize_path (true) When `true`, the + # uri paths will be normalized when building the canonical request. def initialize(options = {}) @service = extract_service(options) @region = extract_region(options) @credentials_provider = extract_credentials_provider(options) - @unsigned_headers = Set.new(options.fetch(:unsigned_headers, []).map(&:downcase)) + @unsigned_headers = Set.new((options.fetch(:unsigned_headers, [])).map(&:downcase)) @unsigned_headers << 'authorization' @unsigned_headers << 'x-amzn-trace-id' @unsigned_headers << 'expect' - @signing_algorithm = options.fetch(:signing_algorithm, 'sigv4').to_s @uri_escape_path = options.fetch(:uri_escape_path, true) + @apply_checksum_header = options.fetch(:apply_checksum_header, true) + @signing_algorithm = options.fetch(:signing_algorithm, :sigv4) @normalize_path = options.fetch(:normalize_path, true) @omit_session_token = options.fetch(:omit_session_token, false) - @apply_checksum_header = options.fetch(:apply_checksum_header, true) end # @return [String] @@ -166,22 +165,12 @@ def initialize(options = {}) # attr_reader :credentials_provider - # @return [Set] + # @return [Set] Returns a set of header names that should not be signed. + # All header names have been downcased. attr_reader :unsigned_headers - # @return [String] - attr_reader :signing_algorithm - - # @return [Boolean] - attr_reader :uri_escape_path - - # @return [Boolean] - attr_reader :normalize_path - - # @return [Boolean] - attr_reader :omit_session_token - - # @return [Boolean] + # @return [Boolean] When `true` the `x-amz-content-sha256` header will be signed and + # returned in the signature headers. attr_reader :apply_checksum_header # Computes a version 4 signature signature. Returns the resultant @@ -250,7 +239,7 @@ def sign_request(request) sigv4_headers['host'] = headers['host'] || host(url) sigv4_headers['x-amz-date'] = datetime if creds.session_token && !@omit_session_token - if @signing_algorithm == 'sigv4-s3express' + if @signing_algorithm == 'sigv4-s3express'.to_sym sigv4_headers['x-amz-s3session-token'] = creds.session_token else sigv4_headers['x-amz-security-token'] = creds.session_token @@ -259,7 +248,7 @@ def sign_request(request) sigv4_headers['x-amz-content-sha256'] ||= content_sha256 if @apply_checksum_header - if @signing_algorithm == 'sigv4a' && @region && !@region.empty? + if @signing_algorithm == :sigv4a && @region && !@region.empty? sigv4_headers['x-amz-region-set'] = @region end headers = headers.merge(sigv4_headers) # merge so we do not modify given headers hash @@ -271,7 +260,7 @@ def sign_request(request) sts = string_to_sign(datetime, creq, algorithm) sig = - if @signing_algorithm == 'sigv4a' + if @signing_algorithm == :sigv4a asymmetric_signature(creds, sts) else signature(creds.secret_access_key, date, sts) @@ -448,7 +437,7 @@ def presign_url(options) params['X-Amz-Date'] = datetime params['X-Amz-Expires'] = presigned_url_expiration(options, expiration, Time.strptime(datetime, "%Y%m%dT%H%M%S%Z")).to_s if creds.session_token - if @signing_algorithm == 'sigv4-s3express' + if @signing_algorithm == 'sigv4-s3express'.to_sym params['X-Amz-S3session-Token'] = creds.session_token else params['X-Amz-Security-Token'] = creds.session_token @@ -456,7 +445,7 @@ def presign_url(options) end params['X-Amz-SignedHeaders'] = signed_headers(headers) - if @signing_algorithm == 'sigv4a' && @region + if @signing_algorithm == :sigv4a && @region params['X-Amz-Region-Set'] = @region end @@ -473,7 +462,7 @@ def presign_url(options) creq = canonical_request(http_method, url, headers, content_sha256) sts = string_to_sign(datetime, creq, algorithm) signature = - if @signing_algorithm == 'sigv4a' + if @signing_algorithm == :sigv4a asymmetric_signature(creds, sts) else signature(creds.secret_access_key, date, sts) @@ -485,7 +474,7 @@ def presign_url(options) private def sts_algorithm - @signing_algorithm == 'sigv4a' ? 'AWS4-ECDSA-P256-SHA256' : 'AWS4-HMAC-SHA256' + @signing_algorithm == :sigv4a ? 'AWS4-ECDSA-P256-SHA256' : 'AWS4-HMAC-SHA256' end def canonical_request(http_method, url, headers, content_sha256) @@ -534,7 +523,7 @@ def event_string_to_sign(datetime, headers, payload, prior_signature, encoder) def credential_scope(date) [ date, - (@region unless @signing_algorithm == 'sigv4a'), + (@region unless @signing_algorithm == :sigv4a), @service, 'aws4_request' ].compact.join('/') @@ -554,8 +543,7 @@ def signature(secret_access_key, date, string_to_sign) def asymmetric_signature(creds, string_to_sign) ec, _ = Aws::Sigv4::AsymmetricCredentials.derive_asymmetric_key( - creds.access_key_id, - creds.secret_access_key + creds.access_key_id, creds.secret_access_key ) sts_digest = OpenSSL::Digest::SHA256.digest(string_to_sign) s = ec.dsa_sign_asn1(sts_digest) diff --git a/gems/aws-sigv4/sig/signer.rbs b/gems/aws-sigv4/sig/signer.rbs index 30435e29943..6bf9c8c03f4 100644 --- a/gems/aws-sigv4/sig/signer.rbs +++ b/gems/aws-sigv4/sig/signer.rbs @@ -10,22 +10,18 @@ module Aws ?credentials: _Credentials, ?credentials_provider: _CredentialsProvider, ?unsigned_headers: Array[String], - ?signing_algorithm: 'sigv4' | 'sigv4a' | 'sigv4-s3express', ?uri_escape_path: bool, - ?normalize_path: bool, + ?apply_checksum_header: bool, + ?signing_algorithm: :sigv4 | :sigv4a | :'sigv4-s3express', ?omit_session_token: bool, - ?apply_checksum_header: bool + ?normalize_path: bool, ) -> void | (?Hash[Symbol, untyped]) -> void attr_reader service: String attr_reader region: String attr_reader credentials_provider: _CredentialsProvider - attr_reader unsigned_headers: Set[String] - attr_reader signing_algorithm: String - attr_reader uri_escape_path: bool - attr_reader normalize_path: bool - attr_reader omit_session_token: bool + attr_reader unsigned_headers: Array[String] attr_reader apply_checksum_header: bool def sign_request: (