aws-sigv4 1.8.0 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 482b4ffa8bd9e9e2d7dab0d61ab15553f0e8d05e1be2923b388157664a47a9fa
4
- data.tar.gz: c5caa84527ca213826f8c802195430caacb25750530609f1b8d7267810808574
3
+ metadata.gz: 58318b8045877e5842f7c0793c856e30b6bba8425988a4929bca3aaaf64fcc06
4
+ data.tar.gz: c9de352d0dee1c35637e86d1d4a3a8817d3ee6a4c3595f8e86436cf216d0a35d
5
5
  SHA512:
6
- metadata.gz: c16c5df7f8c6ca10cf073c25984506ce938f26823f99d82813b5bde3fb283d23a3c480adec2945b98975946a7b32efe57a0058cd65bb383606c5ee5228711381
7
- data.tar.gz: b72ea1894eb1c419179325f8e715fb454ab02ae2d1ac243b90ed2f4032c0fd966ba157287a12009587908d0a6a2f62261c78e319a230196792b6ec4206a20718
6
+ metadata.gz: b22918d3e6a784f4198b9b3583b6ce34e492819ec401862333d29f7c456402fe10718f7e9f30479d5097b89b19d8030400647572ee7204b8729093b16290f3f2
7
+ data.tar.gz: c15f22f66888fa2bbe1822bd833c2bc87c216b3c082ba1961682e0dcd2f5c0f427c2126ffb04354a3ba2b47c5a3fb375ad2381be543021b089687f589a4565fd
data/CHANGELOG.md CHANGED
@@ -1,6 +1,41 @@
1
1
  Unreleased Changes
2
2
  ------------------
3
3
 
4
+ 1.12.1 (2025-06-10)
5
+ ------------------
6
+
7
+ * Issue - Only load required `cgi` modules for Ruby 3.5.
8
+
9
+ 1.12.0 (2025-06-02)
10
+ ------------------
11
+
12
+ * Feature - AWS SDK for Ruby no longer supports Ruby runtime versions 2.5 and 2.6.
13
+
14
+ 1.11.0 (2025-01-10)
15
+ ------------------
16
+
17
+ * Feature - Add RBS signature files to support static type checking
18
+
19
+ 1.10.1 (2024-10-21)
20
+ ------------------
21
+
22
+ * Issue - Fix sigv4a signing issue with derive_asymmetric_key for certain credentials.
23
+
24
+ 1.10.0 (2024-09-17)
25
+ ------------------
26
+
27
+ * Feature - Remove CRT `sigv4a` signing capability.
28
+
29
+ 1.9.1 (2024-07-29)
30
+ ------------------
31
+
32
+ * Issue - Add missing require of `pathname` to `Signer`.
33
+
34
+ 1.9.0 (2024-07-23)
35
+ ------------------
36
+
37
+ * Feature - Support `sigv4a` signing algorithm without `aws-crt`.
38
+
4
39
  1.8.0 (2023-11-28)
5
40
  ------------------
6
41
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.8.0
1
+ 1.12.1
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Sigv4
5
+ # To make it easier to support mixed mode, we have created an asymmetric
6
+ # key derivation mechanism. This module derives
7
+ # asymmetric keys from the current secret for use with
8
+ # Asymmetric signatures.
9
+ # @api private
10
+ module AsymmetricCredentials
11
+
12
+ N_MINUS_2 = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 - 2
13
+
14
+ # @return [OpenSSL::PKey::EC, Hash]
15
+ def self.derive_asymmetric_key(access_key_id, secret_access_key)
16
+ check_openssl_support!
17
+ label = 'AWS4-ECDSA-P256-SHA256'
18
+ bit_len = 256
19
+ counter = 0x1
20
+ input_key = "AWS4A#{secret_access_key}"
21
+ d = 0 # d will end up being the private key
22
+ while true do
23
+
24
+ kdf_context = access_key_id.unpack('C*') + [counter].pack('C').unpack('C') #1 byte for counter
25
+ input = label.unpack('C*') + [0x00] + kdf_context + [bit_len].pack('L>').unpack('CCCC') # 4 bytes (change endianess)
26
+ k0 = OpenSSL::HMAC.digest("SHA256", input_key, ([0, 0, 0, 0x01] + input).pack('C*'))
27
+ c = be_bytes_to_num( k0.unpack('C*') )
28
+ if c <= N_MINUS_2
29
+ d = c + 1
30
+ break
31
+ elsif counter > 0xFF
32
+ raise 'Counter exceeded 1 byte - unable to get asym creds'
33
+ else
34
+ counter += 1
35
+ end
36
+ end
37
+
38
+ # compute the public key
39
+ group = OpenSSL::PKey::EC::Group.new('prime256v1')
40
+ public_key = group.generator.mul(d)
41
+
42
+ ec = generate_ec(public_key, d)
43
+
44
+ # pk_x and pk_y are not needed for signature, but useful in verification/testing
45
+ pk_b = public_key.to_octet_string(:uncompressed).unpack('C*') # 0x04 byte followed by 2 32-byte integers
46
+ pk_x = be_bytes_to_num(pk_b[1,32])
47
+ pk_y = be_bytes_to_num(pk_b[33,32])
48
+ [ec, {ec: ec, public_key: public_key, pk_x: pk_x, pk_y: pk_y, d: d}]
49
+ end
50
+
51
+ private
52
+
53
+ # @return [Number] The value of the bytes interpreted as a big-endian
54
+ # unsigned integer.
55
+ def self.be_bytes_to_num(bytes)
56
+ x = 0
57
+ bytes.each { |b| x = (x*256) + b }
58
+ x
59
+ end
60
+
61
+ # @return [Array] value of the BigNumber as a big-endian unsigned byte array.
62
+ def self.bn_to_be_bytes(bn)
63
+ bytes = []
64
+ while bn > 0
65
+ bytes << (bn & 0xff)
66
+ bn = bn >> 8
67
+ end
68
+ bytes.reverse
69
+ end
70
+
71
+ # Prior to openssl3 we could directly set public and private key on EC
72
+ # However, openssl3 deprecated those methods and we must now construct
73
+ # a der with the keys and load the EC from it.
74
+ def self.generate_ec(public_key, d)
75
+ # format reversed from: OpenSSL::ASN1.decode_all(OpenSSL::PKey::EC.new.to_der)
76
+ asn1 = OpenSSL::ASN1::Sequence([
77
+ OpenSSL::ASN1::Integer(OpenSSL::BN.new(1)),
78
+ OpenSSL::ASN1::OctetString(bn_to_be_bytes(d).pack('C*')),
79
+ OpenSSL::ASN1::ASN1Data.new([OpenSSL::ASN1::ObjectId("prime256v1")], 0, :CONTEXT_SPECIFIC),
80
+ OpenSSL::ASN1::ASN1Data.new(
81
+ [OpenSSL::ASN1::BitString(public_key.to_octet_string(:uncompressed))],
82
+ 1, :CONTEXT_SPECIFIC
83
+ )
84
+ ])
85
+ OpenSSL::PKey::EC.new(asn1.to_der)
86
+ end
87
+
88
+ def self.check_openssl_support!
89
+ return true unless defined?(JRUBY_VERSION)
90
+
91
+ # See: https://github.com/jruby/jruby-openssl/issues/306
92
+ # JRuby-openssl < 0.15 does not support OpenSSL::PKey::EC::Point#mul
93
+ return true if OpenSSL::PKey::EC::Point.instance_methods.include?(:mul)
94
+
95
+ raise 'Sigv4a Asymmetric Credential derivation requires jruby-openssl >= 0.15'
96
+ end
97
+ end
98
+ end
99
+ end
@@ -7,7 +7,7 @@ module Aws
7
7
  class Request
8
8
 
9
9
  # @option options [required, String] :http_method
10
- # @option options [required, HTTP::URI, HTTPS::URI, String] :endpoint
10
+ # @option options [required, String, URI::HTTP, URI::HTTPS] :endpoint
11
11
  # @option options [Hash<String,String>] :headers ({})
12
12
  # @option options [String, IO] :body ('')
13
13
  def initialize(options = {})
@@ -30,12 +30,12 @@ module Aws
30
30
  @http_method
31
31
  end
32
32
 
33
- # @param [String, HTTP::URI, HTTPS::URI] endpoint
33
+ # @param [String, URI::HTTP, URI::HTTPS] endpoint
34
34
  def endpoint=(endpoint)
35
35
  @endpoint = URI.parse(endpoint.to_s)
36
36
  end
37
37
 
38
- # @return [HTTP::URI, HTTPS::URI]
38
+ # @return [URI::HTTP, URI::HTTPS]
39
39
  def endpoint
40
40
  @endpoint
41
41
  end
@@ -32,6 +32,9 @@ module Aws
32
32
  # @return [String] For debugging purposes.
33
33
  attr_accessor :content_sha256
34
34
 
35
+ # @return [String] For debugging purposes.
36
+ attr_accessor :signature
37
+
35
38
  # @return [Hash] Internal data for debugging purposes.
36
39
  attr_accessor :extra
37
40
  end
@@ -5,7 +5,9 @@ require 'tempfile'
5
5
  require 'time'
6
6
  require 'uri'
7
7
  require 'set'
8
- require 'cgi'
8
+ require "cgi/escape"
9
+ require "cgi/util" if RUBY_VERSION < "3.5"
10
+ require 'pathname'
9
11
  require 'aws-eventstream'
10
12
 
11
13
  module Aws
@@ -73,25 +75,18 @@ module Aws
73
75
  # and `#session_token`.
74
76
  #
75
77
  class Signer
76
-
77
- @@use_crt =
78
- begin
79
- require 'aws-crt'
80
- true
81
- rescue LoadError
82
- false
83
- end
84
-
85
78
  # @overload initialize(service:, region:, access_key_id:, secret_access_key:, session_token:nil, **options)
86
79
  # @param [String] :service The service signing name, e.g. 's3'.
87
- # @param [String] :region The region name, e.g. 'us-east-1'.
80
+ # @param [String] :region The region name, e.g. 'us-east-1'. When signing
81
+ # with sigv4a, this should be a comma separated list of regions.
88
82
  # @param [String] :access_key_id
89
83
  # @param [String] :secret_access_key
90
84
  # @param [String] :session_token (nil)
91
85
  #
92
86
  # @overload initialize(service:, region:, credentials:, **options)
93
87
  # @param [String] :service The service signing name, e.g. 's3'.
94
- # @param [String] :region The region name, e.g. 'us-east-1'.
88
+ # @param [String] :region The region name, e.g. 'us-east-1'. When signing
89
+ # with sigv4a, this should be a comma separated list of regions.
95
90
  # @param [Credentials] :credentials Any object that responds to the following
96
91
  # methods:
97
92
  #
@@ -102,7 +97,8 @@ module Aws
102
97
  #
103
98
  # @overload initialize(service:, region:, credentials_provider:, **options)
104
99
  # @param [String] :service The service signing name, e.g. 's3'.
105
- # @param [String] :region The region name, e.g. 'us-east-1'.
100
+ # @param [String] :region The region name, e.g. 'us-east-1'. When signing
101
+ # with sigv4a, this should be a comma separated list of regions.
106
102
  # @param [#credentials] :credentials_provider An object that responds
107
103
  # to `#credentials`, returning an object that responds to the following
108
104
  # methods:
@@ -127,8 +123,7 @@ module Aws
127
123
  # every other AWS service as of late 2016.
128
124
  #
129
125
  # @option options [Symbol] :signing_algorithm (:sigv4) The
130
- # algorithm to use for signing. :sigv4a is only supported when
131
- # `aws-crt` is available.
126
+ # algorithm to use for signing.
132
127
  #
133
128
  # @option options [Boolean] :omit_session_token (false)
134
129
  # (Supported only when `aws-crt` is available) If `true`,
@@ -136,8 +131,8 @@ module Aws
136
131
  # but is treated as "unsigned" and does not contribute
137
132
  # to the authorization signature.
138
133
  #
139
- # @option options [Boolean] :normalize_path (true) (Supported only when `aws-crt` is available)
140
- # When `true`, the uri paths will be normalized when building the canonical request
134
+ # @option options [Boolean] :normalize_path (true) When `true`, the
135
+ # uri paths will be normalized when building the canonical request.
141
136
  def initialize(options = {})
142
137
  @service = extract_service(options)
143
138
  @region = extract_region(options)
@@ -151,19 +146,6 @@ module Aws
151
146
  @signing_algorithm = options.fetch(:signing_algorithm, :sigv4)
152
147
  @normalize_path = options.fetch(:normalize_path, true)
153
148
  @omit_session_token = options.fetch(:omit_session_token, false)
154
-
155
- if @signing_algorithm == :sigv4a && !Signer.use_crt?
156
- raise ArgumentError, 'You are attempting to sign a' \
157
- ' request with sigv4a which requires the `aws-crt` gem.'\
158
- ' Please install the gem or add it to your gemfile.'
159
- end
160
-
161
- if @signing_algorithm == 'sigv4-s3express'.to_sym &&
162
- Signer.use_crt? && Aws::Crt::GEM_VERSION <= '0.1.9'
163
- raise ArgumentError,
164
- 'This version of aws-crt does not support S3 Express. Please
165
- update this gem to at least version 0.2.0.'
166
- end
167
149
  end
168
150
 
169
151
  # @return [String]
@@ -224,7 +206,7 @@ module Aws
224
206
  # @option request [required, String] :http_method One of
225
207
  # 'GET', 'HEAD', 'PUT', 'POST', 'PATCH', or 'DELETE'
226
208
  #
227
- # @option request [required, String, URI::HTTPS, URI::HTTP] :url
209
+ # @option request [required, String, URI::HTTP, URI::HTTPS] :url
228
210
  # The request URI. Must be a valid HTTP or HTTPS URI.
229
211
  #
230
212
  # @option request [optional, Hash] :headers ({}) A hash of headers
@@ -239,13 +221,11 @@ module Aws
239
221
  # a `#headers` method. The headers must be applied to your request.
240
222
  #
241
223
  def sign_request(request)
242
-
243
- return crt_sign_request(request) if Signer.use_crt?
244
-
245
224
  creds, _ = fetch_credentials
246
225
 
247
226
  http_method = extract_http_method(request)
248
227
  url = extract_url(request)
228
+ Signer.normalize_path(url) if @normalize_path
249
229
  headers = downcase_headers(request[:headers])
250
230
 
251
231
  datetime = headers['x-amz-date']
@@ -258,7 +238,7 @@ module Aws
258
238
  sigv4_headers = {}
259
239
  sigv4_headers['host'] = headers['host'] || host(url)
260
240
  sigv4_headers['x-amz-date'] = datetime
261
- if creds.session_token
241
+ if creds.session_token && !@omit_session_token
262
242
  if @signing_algorithm == 'sigv4-s3express'.to_sym
263
243
  sigv4_headers['x-amz-s3session-token'] = creds.session_token
264
244
  else
@@ -268,26 +248,45 @@ module Aws
268
248
 
269
249
  sigv4_headers['x-amz-content-sha256'] ||= content_sha256 if @apply_checksum_header
270
250
 
251
+ if @signing_algorithm == :sigv4a && @region && !@region.empty?
252
+ sigv4_headers['x-amz-region-set'] = @region
253
+ end
271
254
  headers = headers.merge(sigv4_headers) # merge so we do not modify given headers hash
272
255
 
256
+ algorithm = sts_algorithm
257
+
273
258
  # compute signature parts
274
259
  creq = canonical_request(http_method, url, headers, content_sha256)
275
- sts = string_to_sign(datetime, creq)
276
- sig = signature(creds.secret_access_key, date, sts)
260
+ sts = string_to_sign(datetime, creq, algorithm)
261
+
262
+ sig =
263
+ if @signing_algorithm == :sigv4a
264
+ asymmetric_signature(creds, sts)
265
+ else
266
+ signature(creds.secret_access_key, date, sts)
267
+ end
268
+
269
+ algorithm = sts_algorithm
277
270
 
278
271
  # apply signature
279
272
  sigv4_headers['authorization'] = [
280
- "AWS4-HMAC-SHA256 Credential=#{credential(creds, date)}",
273
+ "#{algorithm} Credential=#{credential(creds, date)}",
281
274
  "SignedHeaders=#{signed_headers(headers)}",
282
275
  "Signature=#{sig}",
283
276
  ].join(', ')
284
277
 
278
+ # skip signing the session token, but include it in the headers
279
+ if creds.session_token && @omit_session_token
280
+ sigv4_headers['x-amz-security-token'] = creds.session_token
281
+ end
282
+
285
283
  # Returning the signature components.
286
284
  Signature.new(
287
285
  headers: sigv4_headers,
288
286
  string_to_sign: sts,
289
287
  canonical_request: creq,
290
- content_sha256: content_sha256
288
+ content_sha256: content_sha256,
289
+ signature: sig
291
290
  )
292
291
  end
293
292
 
@@ -327,7 +326,6 @@ module Aws
327
326
  # signature value (a binary string) used at ':chunk-signature' needs to converted to
328
327
  # hex-encoded string using #unpack
329
328
  def sign_event(prior_signature, payload, encoder)
330
- # Note: CRT does not currently provide event stream signing, so we always use the ruby implementation.
331
329
  creds, _ = fetch_credentials
332
330
  time = Time.now
333
331
  headers = {}
@@ -386,7 +384,7 @@ module Aws
386
384
  # @option options [required, String] :http_method The HTTP request method,
387
385
  # e.g. 'GET', 'HEAD', 'PUT', 'POST', 'PATCH', or 'DELETE'.
388
386
  #
389
- # @option options [required, String, HTTPS::URI, HTTP::URI] :url
387
+ # @option options [required, String, URI::HTTP, URI::HTTPS] :url
390
388
  # The URI to sign.
391
389
  #
392
390
  # @option options [Hash] :headers ({}) Headers that should
@@ -414,13 +412,11 @@ module Aws
414
412
  # @return [HTTPS::URI, HTTP::URI]
415
413
  #
416
414
  def presign_url(options)
417
-
418
- return crt_presign_url(options) if Signer.use_crt?
419
-
420
415
  creds, expiration = fetch_credentials
421
416
 
422
417
  http_method = extract_http_method(options)
423
418
  url = extract_url(options)
419
+ Signer.normalize_path(url) if @normalize_path
424
420
 
425
421
  headers = downcase_headers(options[:headers])
426
422
  headers['host'] ||= host(url)
@@ -433,8 +429,10 @@ module Aws
433
429
  content_sha256 ||= options[:body_digest]
434
430
  content_sha256 ||= sha256_hexdigest(options[:body] || '')
435
431
 
432
+ algorithm = sts_algorithm
433
+
436
434
  params = {}
437
- params['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256'
435
+ params['X-Amz-Algorithm'] = algorithm
438
436
  params['X-Amz-Credential'] = credential(creds, date)
439
437
  params['X-Amz-Date'] = datetime
440
438
  params['X-Amz-Expires'] = presigned_url_expiration(options, expiration, Time.strptime(datetime, "%Y%m%dT%H%M%S%Z")).to_s
@@ -447,6 +445,10 @@ module Aws
447
445
  end
448
446
  params['X-Amz-SignedHeaders'] = signed_headers(headers)
449
447
 
448
+ if @signing_algorithm == :sigv4a && @region
449
+ params['X-Amz-Region-Set'] = @region
450
+ end
451
+
450
452
  params = params.map do |key, value|
451
453
  "#{uri_escape(key)}=#{uri_escape(value)}"
452
454
  end.join('&')
@@ -458,13 +460,23 @@ module Aws
458
460
  end
459
461
 
460
462
  creq = canonical_request(http_method, url, headers, content_sha256)
461
- sts = string_to_sign(datetime, creq)
462
- url.query += '&X-Amz-Signature=' + signature(creds.secret_access_key, date, sts)
463
+ sts = string_to_sign(datetime, creq, algorithm)
464
+ signature =
465
+ if @signing_algorithm == :sigv4a
466
+ asymmetric_signature(creds, sts)
467
+ else
468
+ signature(creds.secret_access_key, date, sts)
469
+ end
470
+ url.query += '&X-Amz-Signature=' + signature
463
471
  url
464
472
  end
465
473
 
466
474
  private
467
475
 
476
+ def sts_algorithm
477
+ @signing_algorithm == :sigv4a ? 'AWS4-ECDSA-P256-SHA256' : 'AWS4-HMAC-SHA256'
478
+ end
479
+
468
480
  def canonical_request(http_method, url, headers, content_sha256)
469
481
  [
470
482
  http_method,
@@ -476,9 +488,9 @@ module Aws
476
488
  ].join("\n")
477
489
  end
478
490
 
479
- def string_to_sign(datetime, canonical_request)
491
+ def string_to_sign(datetime, canonical_request, algorithm)
480
492
  [
481
- 'AWS4-HMAC-SHA256',
493
+ algorithm,
482
494
  datetime,
483
495
  credential_scope(datetime[0,8]),
484
496
  sha256_hexdigest(canonical_request),
@@ -511,10 +523,10 @@ module Aws
511
523
  def credential_scope(date)
512
524
  [
513
525
  date,
514
- @region,
526
+ (@region unless @signing_algorithm == :sigv4a),
515
527
  @service,
516
- 'aws4_request',
517
- ].join('/')
528
+ 'aws4_request'
529
+ ].compact.join('/')
518
530
  end
519
531
 
520
532
  def credential(credentials, date)
@@ -529,6 +541,16 @@ module Aws
529
541
  hexhmac(k_credentials, string_to_sign)
530
542
  end
531
543
 
544
+ def asymmetric_signature(creds, string_to_sign)
545
+ ec, _ = Aws::Sigv4::AsymmetricCredentials.derive_asymmetric_key(
546
+ creds.access_key_id, creds.secret_access_key
547
+ )
548
+ sts_digest = OpenSSL::Digest::SHA256.digest(string_to_sign)
549
+ s = ec.dsa_sign_asn1(sts_digest)
550
+
551
+ Digest.hexencode(s)
552
+ end
553
+
532
554
  # Comparing to original signature v4 algorithm,
533
555
  # returned signature is a binary string instread of
534
556
  # hex-encoded string. (Since ':chunk-signature' requires
@@ -757,129 +779,12 @@ module Aws
757
779
  end
758
780
  end
759
781
 
760
- ### CRT Code
761
-
762
- # the credentials used by CRT must be a
763
- # CRT StaticCredentialsProvider object
764
- def crt_fetch_credentials
765
- creds, expiration = fetch_credentials
766
- crt_creds = Aws::Crt::Auth::StaticCredentialsProvider.new(
767
- creds.access_key_id,
768
- creds.secret_access_key,
769
- creds.session_token
770
- )
771
- [crt_creds, expiration]
772
- end
773
-
774
- def crt_sign_request(request)
775
- creds, _ = crt_fetch_credentials
776
- http_method = extract_http_method(request)
777
- url = extract_url(request)
778
- headers = downcase_headers(request[:headers])
779
-
780
- datetime =
781
- if headers.include? 'x-amz-date'
782
- Time.parse(headers.delete('x-amz-date'))
783
- end
784
-
785
- content_sha256 = headers.delete('x-amz-content-sha256')
786
- content_sha256 ||= sha256_hexdigest(request[:body] || '')
787
-
788
- sigv4_headers = {}
789
- sigv4_headers['host'] = headers['host'] || host(url)
790
-
791
- # Modify the user-agent to add usage of crt-signer
792
- # This should be temporary during developer preview only
793
- if headers.include? 'user-agent'
794
- headers['user-agent'] = "#{headers['user-agent']} crt-signer/#{@signing_algorithm}/#{Aws::Sigv4::VERSION}"
795
- sigv4_headers['user-agent'] = headers['user-agent']
796
- end
797
-
798
- headers = headers.merge(sigv4_headers) # merge so we do not modify given headers hash
799
-
800
- config = Aws::Crt::Auth::SigningConfig.new(
801
- algorithm: @signing_algorithm,
802
- signature_type: :http_request_headers,
803
- region: @region,
804
- service: @service,
805
- date: datetime,
806
- signed_body_value: content_sha256,
807
- signed_body_header_type: @apply_checksum_header ?
808
- :sbht_content_sha256 : :sbht_none,
809
- credentials: creds,
810
- unsigned_headers: @unsigned_headers,
811
- use_double_uri_encode: @uri_escape_path,
812
- should_normalize_uri_path: @normalize_path,
813
- omit_session_token: @omit_session_token
814
- )
815
- http_request = Aws::Crt::Http::Message.new(
816
- http_method, url.to_s, headers
817
- )
818
- signable = Aws::Crt::Auth::Signable.new(http_request)
819
-
820
- signing_result = Aws::Crt::Auth::Signer.sign_request(config, signable)
821
-
822
- Signature.new(
823
- headers: sigv4_headers.merge(
824
- downcase_headers(signing_result[:headers])
825
- ),
826
- string_to_sign: 'CRT_INTERNAL',
827
- canonical_request: 'CRT_INTERNAL',
828
- content_sha256: content_sha256,
829
- extra: {config: config, signable: signable}
830
- )
831
- end
832
-
833
- def crt_presign_url(options)
834
- creds, expiration = crt_fetch_credentials
835
-
836
- http_method = extract_http_method(options)
837
- url = extract_url(options)
838
- headers = downcase_headers(options[:headers])
839
- headers['host'] ||= host(url)
840
-
841
- datetime = Time.strptime(headers.delete('x-amz-date'), "%Y%m%dT%H%M%S%Z") if headers['x-amz-date']
842
- datetime ||= (options[:time] || Time.now)
843
-
844
- content_sha256 = headers.delete('x-amz-content-sha256')
845
- content_sha256 ||= options[:body_digest]
846
- content_sha256 ||= sha256_hexdigest(options[:body] || '')
847
-
848
- config = Aws::Crt::Auth::SigningConfig.new(
849
- algorithm: @signing_algorithm,
850
- signature_type: :http_request_query_params,
851
- region: @region,
852
- service: @service,
853
- date: datetime,
854
- signed_body_value: content_sha256,
855
- signed_body_header_type: @apply_checksum_header ?
856
- :sbht_content_sha256 : :sbht_none,
857
- credentials: creds,
858
- unsigned_headers: @unsigned_headers,
859
- use_double_uri_encode: @uri_escape_path,
860
- should_normalize_uri_path: @normalize_path,
861
- omit_session_token: @omit_session_token,
862
- expiration_in_seconds: presigned_url_expiration(options, expiration, datetime)
863
- )
864
- http_request = Aws::Crt::Http::Message.new(
865
- http_method, url.to_s, headers
866
- )
867
- signable = Aws::Crt::Auth::Signable.new(http_request)
868
-
869
- signing_result = Aws::Crt::Auth::Signer.sign_request(config, signable, http_method, url.to_s)
870
- url = URI.parse(signing_result[:path])
871
-
872
- if options[:extra] && options[:extra].is_a?(Hash)
873
- options[:extra][:config] = config
874
- options[:extra][:signable] = signable
875
- end
876
- url
877
- end
878
-
879
782
  class << self
880
783
 
784
+ # Kept for backwards compatability
785
+ # Always return false since we are not using crt signing functionality
881
786
  def use_crt?
882
- @@use_crt
787
+ false
883
788
  end
884
789
 
885
790
  # @api private
@@ -896,6 +801,18 @@ module Aws
896
801
  end
897
802
  end
898
803
 
804
+ # @api private
805
+ def normalize_path(uri)
806
+ normalized_path = Pathname.new(uri.path).cleanpath.to_s
807
+ # Pathname is probably not correct to use. Empty paths will
808
+ # resolve to "." and should be disregarded
809
+ normalized_path = '' if normalized_path == '.'
810
+ # Ensure trailing slashes are correctly preserved
811
+ if uri.path.end_with?('/') && !normalized_path.end_with?('/')
812
+ normalized_path << '/'
813
+ end
814
+ uri.path = normalized_path
815
+ end
899
816
  end
900
817
  end
901
818
  end
data/lib/aws-sigv4.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'aws-sigv4/asymmetric_credentials'
3
4
  require_relative 'aws-sigv4/credentials'
4
5
  require_relative 'aws-sigv4/errors'
5
6
  require_relative 'aws-sigv4/signature'
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws-sigv4
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.12.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amazon Web Services
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-11-28 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: aws-eventstream
@@ -32,7 +31,6 @@ dependencies:
32
31
  version: 1.0.2
33
32
  description: Amazon Web Services Signature Version 4 signing library. Generates sigv4
34
33
  signature for HTTP requests.
35
- email:
36
34
  executables: []
37
35
  extensions: []
38
36
  extra_rdoc_files: []
@@ -41,6 +39,7 @@ files:
41
39
  - LICENSE.txt
42
40
  - VERSION
43
41
  - lib/aws-sigv4.rb
42
+ - lib/aws-sigv4/asymmetric_credentials.rb
44
43
  - lib/aws-sigv4/credentials.rb
45
44
  - lib/aws-sigv4/errors.rb
46
45
  - lib/aws-sigv4/request.rb
@@ -52,7 +51,6 @@ licenses:
52
51
  metadata:
53
52
  source_code_uri: https://github.com/aws/aws-sdk-ruby/tree/version-3/gems/aws-sigv4
54
53
  changelog_uri: https://github.com/aws/aws-sdk-ruby/tree/version-3/gems/aws-sigv4/CHANGELOG.md
55
- post_install_message:
56
54
  rdoc_options: []
57
55
  require_paths:
58
56
  - lib
@@ -60,15 +58,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
60
58
  requirements:
61
59
  - - ">="
62
60
  - !ruby/object:Gem::Version
63
- version: '2.5'
61
+ version: '2.7'
64
62
  required_rubygems_version: !ruby/object:Gem::Requirement
65
63
  requirements:
66
64
  - - ">="
67
65
  - !ruby/object:Gem::Version
68
66
  version: '0'
69
67
  requirements: []
70
- rubygems_version: 3.1.6
71
- signing_key:
68
+ rubygems_version: 3.6.7
72
69
  specification_version: 4
73
70
  summary: AWS Signature Version 4 library.
74
71
  test_files: []