diff --git a/gems/aws-sdk-core/CHANGELOG.md b/gems/aws-sdk-core/CHANGELOG.md index 58eb6bda504..6131b3863dc 100644 --- a/gems/aws-sdk-core/CHANGELOG.md +++ b/gems/aws-sdk-core/CHANGELOG.md @@ -1,6 +1,8 @@ Unreleased Changes ------------------ +* Feature - Support `sigv4a` endpoint auth without CRT. + 3.205.0 (2024-09-11) ------------------ diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/endpoints.rb b/gems/aws-sdk-core/lib/aws-sdk-core/endpoints.rb index a20e9374e42..60d93cb7d5b 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/endpoints.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/endpoints.rb @@ -19,9 +19,12 @@ module Aws # @api private module Endpoints - supported_auth_traits = %w[aws.auth#sigv4 smithy.api#httpBearerAuth smithy.api#noAuth] - supported_auth_traits += ['aws.auth#sigv4a'] if Aws::Sigv4::Signer.use_crt? - SUPPORTED_AUTH_TRAITS = supported_auth_traits.freeze + SUPPORTED_AUTH_TRAITS = %w[ + aws.auth#sigv4 + aws.auth#sigv4a + smithy.api#httpBearerAuth + smithy.api#noAuth + ].freeze class << self def resolve_auth_scheme(context, endpoint) diff --git a/gems/aws-sdk-s3/features/client/step_definitions.rb b/gems/aws-sdk-s3/features/client/step_definitions.rb index d74da36de0c..309b84a2657 100644 --- a/gems/aws-sdk-s3/features/client/step_definitions.rb +++ b/gems/aws-sdk-s3/features/client/step_definitions.rb @@ -464,10 +464,6 @@ def create_bucket(options = {}) end When(/I have access to an MRAP bucket and CRT/) do - unless Aws::Sigv4::Signer.use_crt? - pending("CRT is not available") - end - begin @client.head_bucket(bucket: 'ruby-sdk-integtest-mrap-bucket') rescue diff --git a/gems/aws-sdk-s3/spec/presigner_spec.rb b/gems/aws-sdk-s3/spec/presigner_spec.rb index 10f11ae5454..e306489f3af 100644 --- a/gems/aws-sdk-s3/spec/presigner_spec.rb +++ b/gems/aws-sdk-s3/spec/presigner_spec.rb @@ -103,8 +103,6 @@ def initialize(expiration_time) end it 'can sign with additional whitelisted headers' do - skip("CRT does not support whitelisting user-agent") if Aws::Sigv4::Signer.use_crt? - actual_url = subject.presigned_url( :get_object, bucket: 'examplebucket', @@ -256,8 +254,6 @@ def initialize(expiration_time) end it 'can sign with additional whitelisted headers' do - skip("CRT is unable to whitelist user-agent") if Aws::Sigv4::Signer.use_crt? - actual_url, = subject.presigned_request( :get_object, bucket: 'examplebucket', diff --git a/gems/aws-sigv4/CHANGELOG.md b/gems/aws-sigv4/CHANGELOG.md index 2c450fbc80f..5bf4c230cc2 100644 --- a/gems/aws-sigv4/CHANGELOG.md +++ b/gems/aws-sigv4/CHANGELOG.md @@ -1,6 +1,8 @@ Unreleased Changes ------------------ +* Feature - Remove CRT `sigv4a` signing capability. + 1.9.1 (2024-07-29) ------------------ diff --git a/gems/aws-sigv4/lib/aws-sigv4/signer.rb b/gems/aws-sigv4/lib/aws-sigv4/signer.rb index e1083939efd..a005d151657 100644 --- a/gems/aws-sigv4/lib/aws-sigv4/signer.rb +++ b/gems/aws-sigv4/lib/aws-sigv4/signer.rb @@ -74,15 +74,6 @@ module Sigv4 # and `#session_token`. # class Signer - - @@use_crt = - begin - require 'aws-crt' - true - rescue LoadError - false - end - # @overload initialize(service:, region:, access_key_id:, secret_access_key:, session_token:nil, **options) # @param [String] :service The service signing name, e.g. 's3'. # @param [String] :region The region name, e.g. 'us-east-1'. When signing @@ -154,13 +145,6 @@ def initialize(options = {}) @signing_algorithm = options.fetch(:signing_algorithm, :sigv4) @normalize_path = options.fetch(:normalize_path, true) @omit_session_token = options.fetch(:omit_session_token, false) - - if @signing_algorithm == 'sigv4-s3express'.to_sym && - Signer.use_crt? && Aws::Crt::GEM_VERSION <= '0.1.9' - raise ArgumentError, - 'This version of aws-crt does not support S3 Express. Please - update this gem to at least version 0.2.0.' - end end # @return [String] @@ -236,9 +220,6 @@ def initialize(options = {}) # a `#headers` method. The headers must be applied to your request. # def sign_request(request) - - return crt_sign_request(request) if Signer.use_crt? - creds, _ = fetch_credentials http_method = extract_http_method(request) @@ -344,7 +325,6 @@ def sign_request(request) # signature value (a binary string) used at ':chunk-signature' needs to converted to # hex-encoded string using #unpack def sign_event(prior_signature, payload, encoder) - # Note: CRT does not currently provide event stream signing, so we always use the ruby implementation. creds, _ = fetch_credentials time = Time.now headers = {} @@ -431,9 +411,6 @@ def sign_event(prior_signature, payload, encoder) # @return [HTTPS::URI, HTTP::URI] # def presign_url(options) - - return crt_presign_url(options) if Signer.use_crt? - creds, expiration = fetch_credentials http_method = extract_http_method(options) @@ -801,131 +778,7 @@ def presigned_url_expiration(options, expiration, datetime) end end - ### CRT Code - - # the credentials used by CRT must be a - # CRT StaticCredentialsProvider object - def crt_fetch_credentials - creds, expiration = fetch_credentials - crt_creds = Aws::Crt::Auth::StaticCredentialsProvider.new( - creds.access_key_id, - creds.secret_access_key, - creds.session_token - ) - [crt_creds, expiration] - end - - def crt_sign_request(request) - creds, _ = crt_fetch_credentials - http_method = extract_http_method(request) - url = extract_url(request) - headers = downcase_headers(request[:headers]) - - datetime = - if headers.include? 'x-amz-date' - Time.parse(headers.delete('x-amz-date')) - end - - content_sha256 = headers.delete('x-amz-content-sha256') - content_sha256 ||= sha256_hexdigest(request[:body] || '') - - sigv4_headers = {} - sigv4_headers['host'] = headers['host'] || host(url) - - # Modify the user-agent to add usage of crt-signer - # This should be temporary during developer preview only - if headers.include? 'user-agent' - headers['user-agent'] = "#{headers['user-agent']} crt-signer/#{@signing_algorithm}/#{Aws::Sigv4::VERSION}" - sigv4_headers['user-agent'] = headers['user-agent'] - end - - headers = headers.merge(sigv4_headers) # merge so we do not modify given headers hash - - config = Aws::Crt::Auth::SigningConfig.new( - algorithm: @signing_algorithm, - signature_type: :http_request_headers, - region: @region, - service: @service, - date: datetime, - signed_body_value: content_sha256, - signed_body_header_type: @apply_checksum_header ? - :sbht_content_sha256 : :sbht_none, - credentials: creds, - unsigned_headers: @unsigned_headers, - use_double_uri_encode: @uri_escape_path, - should_normalize_uri_path: @normalize_path, - omit_session_token: @omit_session_token - ) - http_request = Aws::Crt::Http::Message.new( - http_method, url.to_s, headers - ) - signable = Aws::Crt::Auth::Signable.new(http_request) - - signing_result = Aws::Crt::Auth::Signer.sign_request(config, signable) - - Signature.new( - headers: sigv4_headers.merge( - downcase_headers(signing_result[:headers]) - ), - string_to_sign: 'CRT_INTERNAL', - canonical_request: 'CRT_INTERNAL', - content_sha256: content_sha256, - extra: {config: config, signable: signable} - ) - end - - def crt_presign_url(options) - creds, expiration = crt_fetch_credentials - - http_method = extract_http_method(options) - url = extract_url(options) - headers = downcase_headers(options[:headers]) - headers['host'] ||= host(url) - - datetime = Time.strptime(headers.delete('x-amz-date'), "%Y%m%dT%H%M%S%Z") if headers['x-amz-date'] - datetime ||= (options[:time] || Time.now) - - content_sha256 = headers.delete('x-amz-content-sha256') - content_sha256 ||= options[:body_digest] - content_sha256 ||= sha256_hexdigest(options[:body] || '') - - config = Aws::Crt::Auth::SigningConfig.new( - algorithm: @signing_algorithm, - signature_type: :http_request_query_params, - region: @region, - service: @service, - date: datetime, - signed_body_value: content_sha256, - signed_body_header_type: @apply_checksum_header ? - :sbht_content_sha256 : :sbht_none, - credentials: creds, - unsigned_headers: @unsigned_headers, - use_double_uri_encode: @uri_escape_path, - should_normalize_uri_path: @normalize_path, - omit_session_token: @omit_session_token, - expiration_in_seconds: presigned_url_expiration(options, expiration, datetime) - ) - http_request = Aws::Crt::Http::Message.new( - http_method, url.to_s, headers - ) - signable = Aws::Crt::Auth::Signable.new(http_request) - - signing_result = Aws::Crt::Auth::Signer.sign_request(config, signable, http_method, url.to_s) - url = URI.parse(signing_result[:path]) - - if options[:extra] && options[:extra].is_a?(Hash) - options[:extra][:config] = config - options[:extra][:signable] = signable - end - url - end - class << self - - def use_crt? - @@use_crt - end - # @api private def uri_escape_path(path) path.gsub(/[^\/]+/) { |part| uri_escape(part) } diff --git a/gems/aws-sigv4/spec/signer_spec.rb b/gems/aws-sigv4/spec/signer_spec.rb index 642dae3570e..24da8c2f520 100644 --- a/gems/aws-sigv4/spec/signer_spec.rb +++ b/gems/aws-sigv4/spec/signer_spec.rb @@ -357,8 +357,6 @@ module Sigv4 end it 'escapes path for the canonical request by default' do - skip("CRT does not provide canonical request") if Signer.use_crt? - signature = Signer.new(options).sign_request( http_method: 'GET', url: 'https://domain.com/foo%bar' @@ -367,8 +365,6 @@ module Sigv4 end it 'escapes path for the canonical request if :uri_escape_path is true' do - skip("CRT does not provide canonical request") if Signer.use_crt? - options[:uri_escape_path] = true signature = Signer.new(options).sign_request( http_method: 'GET', @@ -378,8 +374,6 @@ module Sigv4 end it 'does not escape path for the canonical request if :uri_escape_path is false' do - skip("CRT does not provide canonical request") if Signer.use_crt? - options[:uri_escape_path] = false signature = Signer.new(options).sign_request( http_method: 'GET', @@ -427,9 +421,6 @@ module Sigv4 end context ':canonical_request' do - - before { skip("CRT Signer does not expose canonical request") if Signer.use_crt? } - it 'lower-cases and sort all header keys except authorization' do signature = Signer.new(options).sign_request( http_method: 'PUT', diff --git a/gems/aws-sigv4/spec/sigv4a_suite_spec.rb b/gems/aws-sigv4/spec/sigv4a_suite_spec.rb index 9afd46bee4f..6f9316f4feb 100644 --- a/gems/aws-sigv4/spec/sigv4a_suite_spec.rb +++ b/gems/aws-sigv4/spec/sigv4a_suite_spec.rb @@ -90,51 +90,45 @@ def skip_if_test_missing(path, file_name) end context 'header' do - # CRT does not provide canonical request - unless Signer.use_crt? - it 'verifies canonical request' do - skip_if_test_missing(path, 'header-canonical-request.txt') + it 'verifies canonical request' do + skip_if_test_missing(path, 'header-canonical-request.txt') - signature = signer.sign_request(request) + signature = signer.sign_request(request) - computed = signature.canonical_request - SpecHelper.debug("COMPUTED CANONICAL_REQUEST: |#{computed}|") - expected = File.read( - File.join(path, 'header-canonical-request.txt'), - encoding: 'utf-8' - ) - SpecHelper.debug("EXPECTED CANONICAL_REQUEST: |#{expected}|") + computed = signature.canonical_request + SpecHelper.debug("COMPUTED CANONICAL_REQUEST: |#{computed}|") + expected = File.read( + File.join(path, 'header-canonical-request.txt'), + encoding: 'utf-8' + ) + SpecHelper.debug("EXPECTED CANONICAL_REQUEST: |#{expected}|") - expect(computed).to eq(expected) - end + expect(computed).to eq(expected) end - # CRT does not provide signature or pk - unless Signer.use_crt? - it 'computes the public key' do - skip_if_test_missing(path, 'public-key.json') - expected_pk = JSON.parse(File.read(File.join(path, 'public-key.json'))) + it 'computes the public key' do + skip_if_test_missing(path, 'public-key.json') + expected_pk = JSON.parse(File.read(File.join(path, 'public-key.json'))) - expect(extra[:pk_x].to_s(16)).to eq expected_pk['X'] - expect(extra[:pk_y].to_s(16)).to eq expected_pk['Y'] - end + expect(extra[:pk_x].to_s(16)).to eq expected_pk['X'] + expect(extra[:pk_y].to_s(16)).to eq expected_pk['Y'] + end - it 'verifies signature' do - skip_if_test_missing(path, 'header-signature.txt') + it 'verifies signature' do + skip_if_test_missing(path, 'header-signature.txt') - signature = signer.sign_request(request) + signature = signer.sign_request(request) - computed = signature.signature - SpecHelper.debug("COMPUTED SIGNATURE: |#{computed}|") - expected = File.read( - File.join(path, 'header-signature.txt'), - encoding: 'utf-8' - ) - SpecHelper.debug("EXPECTED SIGNATURE: |#{expected}|") + computed = signature.signature + SpecHelper.debug("COMPUTED SIGNATURE: |#{computed}|") + expected = File.read( + File.join(path, 'header-signature.txt'), + encoding: 'utf-8' + ) + SpecHelper.debug("EXPECTED SIGNATURE: |#{expected}|") - sts_digest = OpenSSL::Digest::SHA256.digest(signature.string_to_sign) - verify_signature(computed, expected, extra, sts_digest) - end + sts_digest = OpenSSL::Digest::SHA256.digest(signature.string_to_sign) + verify_signature(computed, expected, extra, sts_digest) end it 'verifies signed request' do @@ -174,23 +168,20 @@ def skip_if_test_missing(path, file_name) end end - # CRT does not provide string to sign - unless Signer.use_crt? - it 'verifies string to sign' do - skip_if_test_missing(path, 'header-string-to-sign.txt') + it 'verifies string to sign' do + skip_if_test_missing(path, 'header-string-to-sign.txt') - signature = signer.sign_request(request) + signature = signer.sign_request(request) - computed = signature.string_to_sign - SpecHelper.debug("COMPUTED STRING TO SIGN: |#{computed}|") - expected = File.read( - File.join(path, 'header-string-to-sign.txt'), - encoding: 'utf-8' - ) - SpecHelper.debug("EXPECTED STRING TO SIGN: |#{expected}|") + computed = signature.string_to_sign + SpecHelper.debug("COMPUTED STRING TO SIGN: |#{computed}|") + expected = File.read( + File.join(path, 'header-string-to-sign.txt'), + encoding: 'utf-8' + ) + SpecHelper.debug("EXPECTED STRING TO SIGN: |#{expected}|") - expect(computed).to eq(expected) - end + expect(computed).to eq(expected) end end diff --git a/gems/aws-sigv4/spec/suite_spec.rb b/gems/aws-sigv4/spec/suite_spec.rb index 4790945e3ac..923a272c85e 100644 --- a/gems/aws-sigv4/spec/suite_spec.rb +++ b/gems/aws-sigv4/spec/suite_spec.rb @@ -36,7 +36,6 @@ module Sigv4 } it 'computes the canonical request' do # creq - skip("CRT Signer does not provide canonical request") if Signer.use_crt? signature = signer.sign_request(request) computed = signature.canonical_request expected = File.read("#{prefix}.creq", encoding: "utf-8") @@ -46,8 +45,6 @@ module Sigv4 end it 'computes the string to sign' do # sts - skip("CRT Signer does not provide string to sign") if Signer.use_crt? - signature = signer.sign_request(request) computed = signature.string_to_sign expected = File.read("#{prefix}.sts", encoding: "utf-8")