aws-sigv4 1.6.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: ed95d4ec56e15f5b06d202643cebf73e89d69efbe461d03035dc309f0aa32b11
4
- data.tar.gz: f235824f3bf7ea35aa4fb7e666250f72be1d8592709f522c8fae42fb36e40a9a
3
+ metadata.gz: 58318b8045877e5842f7c0793c856e30b6bba8425988a4929bca3aaaf64fcc06
4
+ data.tar.gz: c9de352d0dee1c35637e86d1d4a3a8817d3ee6a4c3595f8e86436cf216d0a35d
5
5
  SHA512:
6
- metadata.gz: 62ddb59e6cf4fd5ca5a704db3a7f8f8707329cd8b66fec124de5bc56bc5cc2fac20622987e5a6cbeaec1ce55941ee66ab36ed25178ee82e287515622a33bc314
7
- data.tar.gz: e05f2a2ada39d28681df35b7365e7c71e6eda34b250cd2259312d9b6cc0e810fceb0dffeddd785a4b5e08cea1989eb5e2e4e27303d1cf4ce51ad251952d7047d
6
+ metadata.gz: b22918d3e6a784f4198b9b3583b6ce34e492819ec401862333d29f7c456402fe10718f7e9f30479d5097b89b19d8030400647572ee7204b8729093b16290f3f2
7
+ data.tar.gz: c15f22f66888fa2bbe1822bd833c2bc87c216b3c082ba1961682e0dcd2f5c0f427c2126ffb04354a3ba2b47c5a3fb375ad2381be543021b089687f589a4565fd
data/CHANGELOG.md CHANGED
@@ -1,6 +1,56 @@
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
+
39
+ 1.8.0 (2023-11-28)
40
+ ------------------
41
+
42
+ * Feature - Support `sigv4-s3express` signing algorithm.
43
+
44
+ 1.7.0 (2023-11-22)
45
+ ------------------
46
+
47
+ * Feature - AWS SDK for Ruby no longer supports Ruby runtime versions 2.3 and 2.4.
48
+
49
+ 1.6.1 (2023-10-25)
50
+ ------------------
51
+
52
+ * Issue - (Static Stability) use provided `expires_in` in presigned url when credentials are expired.
53
+
4
54
  1.6.0 (2023-06-28)
5
55
  ------------------
6
56
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.6.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,12 +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
149
  end
161
150
 
162
151
  # @return [String]
@@ -217,7 +206,7 @@ module Aws
217
206
  # @option request [required, String] :http_method One of
218
207
  # 'GET', 'HEAD', 'PUT', 'POST', 'PATCH', or 'DELETE'
219
208
  #
220
- # @option request [required, String, URI::HTTPS, URI::HTTP] :url
209
+ # @option request [required, String, URI::HTTP, URI::HTTPS] :url
221
210
  # The request URI. Must be a valid HTTP or HTTPS URI.
222
211
  #
223
212
  # @option request [optional, Hash] :headers ({}) A hash of headers
@@ -232,13 +221,11 @@ module Aws
232
221
  # a `#headers` method. The headers must be applied to your request.
233
222
  #
234
223
  def sign_request(request)
235
-
236
- return crt_sign_request(request) if Signer.use_crt?
237
-
238
224
  creds, _ = fetch_credentials
239
225
 
240
226
  http_method = extract_http_method(request)
241
227
  url = extract_url(request)
228
+ Signer.normalize_path(url) if @normalize_path
242
229
  headers = downcase_headers(request[:headers])
243
230
 
244
231
  datetime = headers['x-amz-date']
@@ -251,29 +238,55 @@ module Aws
251
238
  sigv4_headers = {}
252
239
  sigv4_headers['host'] = headers['host'] || host(url)
253
240
  sigv4_headers['x-amz-date'] = datetime
254
- sigv4_headers['x-amz-security-token'] = creds.session_token if creds.session_token
241
+ if creds.session_token && !@omit_session_token
242
+ if @signing_algorithm == 'sigv4-s3express'.to_sym
243
+ sigv4_headers['x-amz-s3session-token'] = creds.session_token
244
+ else
245
+ sigv4_headers['x-amz-security-token'] = creds.session_token
246
+ end
247
+ end
248
+
255
249
  sigv4_headers['x-amz-content-sha256'] ||= content_sha256 if @apply_checksum_header
256
250
 
251
+ if @signing_algorithm == :sigv4a && @region && !@region.empty?
252
+ sigv4_headers['x-amz-region-set'] = @region
253
+ end
257
254
  headers = headers.merge(sigv4_headers) # merge so we do not modify given headers hash
258
255
 
256
+ algorithm = sts_algorithm
257
+
259
258
  # compute signature parts
260
259
  creq = canonical_request(http_method, url, headers, content_sha256)
261
- sts = string_to_sign(datetime, creq)
262
- 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
263
270
 
264
271
  # apply signature
265
272
  sigv4_headers['authorization'] = [
266
- "AWS4-HMAC-SHA256 Credential=#{credential(creds, date)}",
273
+ "#{algorithm} Credential=#{credential(creds, date)}",
267
274
  "SignedHeaders=#{signed_headers(headers)}",
268
275
  "Signature=#{sig}",
269
276
  ].join(', ')
270
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
+
271
283
  # Returning the signature components.
272
284
  Signature.new(
273
285
  headers: sigv4_headers,
274
286
  string_to_sign: sts,
275
287
  canonical_request: creq,
276
- content_sha256: content_sha256
288
+ content_sha256: content_sha256,
289
+ signature: sig
277
290
  )
278
291
  end
279
292
 
@@ -313,7 +326,6 @@ module Aws
313
326
  # signature value (a binary string) used at ':chunk-signature' needs to converted to
314
327
  # hex-encoded string using #unpack
315
328
  def sign_event(prior_signature, payload, encoder)
316
- # Note: CRT does not currently provide event stream signing, so we always use the ruby implementation.
317
329
  creds, _ = fetch_credentials
318
330
  time = Time.now
319
331
  headers = {}
@@ -372,7 +384,7 @@ module Aws
372
384
  # @option options [required, String] :http_method The HTTP request method,
373
385
  # e.g. 'GET', 'HEAD', 'PUT', 'POST', 'PATCH', or 'DELETE'.
374
386
  #
375
- # @option options [required, String, HTTPS::URI, HTTP::URI] :url
387
+ # @option options [required, String, URI::HTTP, URI::HTTPS] :url
376
388
  # The URI to sign.
377
389
  #
378
390
  # @option options [Hash] :headers ({}) Headers that should
@@ -400,13 +412,11 @@ module Aws
400
412
  # @return [HTTPS::URI, HTTP::URI]
401
413
  #
402
414
  def presign_url(options)
403
-
404
- return crt_presign_url(options) if Signer.use_crt?
405
-
406
415
  creds, expiration = fetch_credentials
407
416
 
408
417
  http_method = extract_http_method(options)
409
418
  url = extract_url(options)
419
+ Signer.normalize_path(url) if @normalize_path
410
420
 
411
421
  headers = downcase_headers(options[:headers])
412
422
  headers['host'] ||= host(url)
@@ -419,14 +429,26 @@ module Aws
419
429
  content_sha256 ||= options[:body_digest]
420
430
  content_sha256 ||= sha256_hexdigest(options[:body] || '')
421
431
 
432
+ algorithm = sts_algorithm
433
+
422
434
  params = {}
423
- params['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256'
435
+ params['X-Amz-Algorithm'] = algorithm
424
436
  params['X-Amz-Credential'] = credential(creds, date)
425
437
  params['X-Amz-Date'] = datetime
426
- params['X-Amz-Expires'] = presigned_url_expiration(options, expiration).to_s
427
- params['X-Amz-Security-Token'] = creds.session_token if creds.session_token
438
+ params['X-Amz-Expires'] = presigned_url_expiration(options, expiration, Time.strptime(datetime, "%Y%m%dT%H%M%S%Z")).to_s
439
+ if creds.session_token
440
+ if @signing_algorithm == 'sigv4-s3express'.to_sym
441
+ params['X-Amz-S3session-Token'] = creds.session_token
442
+ else
443
+ params['X-Amz-Security-Token'] = creds.session_token
444
+ end
445
+ end
428
446
  params['X-Amz-SignedHeaders'] = signed_headers(headers)
429
447
 
448
+ if @signing_algorithm == :sigv4a && @region
449
+ params['X-Amz-Region-Set'] = @region
450
+ end
451
+
430
452
  params = params.map do |key, value|
431
453
  "#{uri_escape(key)}=#{uri_escape(value)}"
432
454
  end.join('&')
@@ -438,13 +460,23 @@ module Aws
438
460
  end
439
461
 
440
462
  creq = canonical_request(http_method, url, headers, content_sha256)
441
- sts = string_to_sign(datetime, creq)
442
- 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
443
471
  url
444
472
  end
445
473
 
446
474
  private
447
475
 
476
+ def sts_algorithm
477
+ @signing_algorithm == :sigv4a ? 'AWS4-ECDSA-P256-SHA256' : 'AWS4-HMAC-SHA256'
478
+ end
479
+
448
480
  def canonical_request(http_method, url, headers, content_sha256)
449
481
  [
450
482
  http_method,
@@ -456,9 +488,9 @@ module Aws
456
488
  ].join("\n")
457
489
  end
458
490
 
459
- def string_to_sign(datetime, canonical_request)
491
+ def string_to_sign(datetime, canonical_request, algorithm)
460
492
  [
461
- 'AWS4-HMAC-SHA256',
493
+ algorithm,
462
494
  datetime,
463
495
  credential_scope(datetime[0,8]),
464
496
  sha256_hexdigest(canonical_request),
@@ -491,10 +523,10 @@ module Aws
491
523
  def credential_scope(date)
492
524
  [
493
525
  date,
494
- @region,
526
+ (@region unless @signing_algorithm == :sigv4a),
495
527
  @service,
496
- 'aws4_request',
497
- ].join('/')
528
+ 'aws4_request'
529
+ ].compact.join('/')
498
530
  end
499
531
 
500
532
  def credential(credentials, date)
@@ -509,6 +541,16 @@ module Aws
509
541
  hexhmac(k_credentials, string_to_sign)
510
542
  end
511
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
+
512
554
  # Comparing to original signature v4 algorithm,
513
555
  # returned signature is a binary string instread of
514
556
  # hex-encoded string. (Since ':chunk-signature' requires
@@ -722,137 +764,27 @@ module Aws
722
764
  !credentials.secret_access_key.empty?
723
765
  end
724
766
 
725
- def presigned_url_expiration(options, expiration)
767
+ def presigned_url_expiration(options, expiration, datetime)
726
768
  expires_in = extract_expires_in(options)
727
769
  return expires_in unless expiration
728
770
 
729
- expiration_seconds = (expiration - Time.now).to_i
730
- [expires_in, expiration_seconds].min
731
- end
732
-
733
- ### CRT Code
734
-
735
- # the credentials used by CRT must be a
736
- # CRT StaticCredentialsProvider object
737
- def crt_fetch_credentials
738
- creds, expiration = fetch_credentials
739
- crt_creds = Aws::Crt::Auth::StaticCredentialsProvider.new(
740
- creds.access_key_id,
741
- creds.secret_access_key,
742
- creds.session_token
743
- )
744
- [crt_creds, expiration]
745
- end
746
-
747
- def crt_sign_request(request)
748
- creds, _ = crt_fetch_credentials
749
- http_method = extract_http_method(request)
750
- url = extract_url(request)
751
- headers = downcase_headers(request[:headers])
752
-
753
- datetime =
754
- if headers.include? 'x-amz-date'
755
- Time.parse(headers.delete('x-amz-date'))
756
- end
757
-
758
- content_sha256 = headers.delete('x-amz-content-sha256')
759
- content_sha256 ||= sha256_hexdigest(request[:body] || '')
760
-
761
- sigv4_headers = {}
762
- sigv4_headers['host'] = headers['host'] || host(url)
763
-
764
- # Modify the user-agent to add usage of crt-signer
765
- # This should be temporary during developer preview only
766
- if headers.include? 'user-agent'
767
- headers['user-agent'] = "#{headers['user-agent']} crt-signer/#{@signing_algorithm}/#{Aws::Sigv4::VERSION}"
768
- sigv4_headers['user-agent'] = headers['user-agent']
769
- end
770
-
771
- headers = headers.merge(sigv4_headers) # merge so we do not modify given headers hash
772
-
773
- config = Aws::Crt::Auth::SigningConfig.new(
774
- algorithm: @signing_algorithm,
775
- signature_type: :http_request_headers,
776
- region: @region,
777
- service: @service,
778
- date: datetime,
779
- signed_body_value: content_sha256,
780
- signed_body_header_type: @apply_checksum_header ?
781
- :sbht_content_sha256 : :sbht_none,
782
- credentials: creds,
783
- unsigned_headers: @unsigned_headers,
784
- use_double_uri_encode: @uri_escape_path,
785
- should_normalize_uri_path: @normalize_path,
786
- omit_session_token: @omit_session_token
787
- )
788
- http_request = Aws::Crt::Http::Message.new(
789
- http_method, url.to_s, headers
790
- )
791
- signable = Aws::Crt::Auth::Signable.new(http_request)
792
-
793
- signing_result = Aws::Crt::Auth::Signer.sign_request(config, signable)
794
-
795
- Signature.new(
796
- headers: sigv4_headers.merge(
797
- downcase_headers(signing_result[:headers])
798
- ),
799
- string_to_sign: 'CRT_INTERNAL',
800
- canonical_request: 'CRT_INTERNAL',
801
- content_sha256: content_sha256,
802
- extra: {config: config, signable: signable}
803
- )
804
- end
805
-
806
- def crt_presign_url(options)
807
- creds, expiration = crt_fetch_credentials
808
-
809
- http_method = extract_http_method(options)
810
- url = extract_url(options)
811
- headers = downcase_headers(options[:headers])
812
- headers['host'] ||= host(url)
813
-
814
- datetime = headers.delete('x-amz-date')
815
- datetime ||= (options[:time] || Time.now)
816
-
817
- content_sha256 = headers.delete('x-amz-content-sha256')
818
- content_sha256 ||= options[:body_digest]
819
- content_sha256 ||= sha256_hexdigest(options[:body] || '')
820
-
821
- config = Aws::Crt::Auth::SigningConfig.new(
822
- algorithm: @signing_algorithm,
823
- signature_type: :http_request_query_params,
824
- region: @region,
825
- service: @service,
826
- date: datetime,
827
- signed_body_value: content_sha256,
828
- signed_body_header_type: @apply_checksum_header ?
829
- :sbht_content_sha256 : :sbht_none,
830
- credentials: creds,
831
- unsigned_headers: @unsigned_headers,
832
- use_double_uri_encode: @uri_escape_path,
833
- should_normalize_uri_path: @normalize_path,
834
- omit_session_token: @omit_session_token,
835
- expiration_in_seconds: presigned_url_expiration(options, expiration)
836
- )
837
- http_request = Aws::Crt::Http::Message.new(
838
- http_method, url.to_s, headers
839
- )
840
- signable = Aws::Crt::Auth::Signable.new(http_request)
841
-
842
- signing_result = Aws::Crt::Auth::Signer.sign_request(config, signable, http_method, url.to_s)
843
- url = URI.parse(signing_result[:path])
844
-
845
- if options[:extra] && options[:extra].is_a?(Hash)
846
- options[:extra][:config] = config
847
- options[:extra][:signable] = signable
771
+ expiration_seconds = (expiration - datetime).to_i
772
+ # In the static stability case, credentials may expire in the past
773
+ # but still be valid. For those cases, use the user configured
774
+ # expires_in and ingore expiration.
775
+ if expiration_seconds <= 0
776
+ expires_in
777
+ else
778
+ [expires_in, expiration_seconds].min
848
779
  end
849
- url
850
780
  end
851
781
 
852
782
  class << self
853
783
 
784
+ # Kept for backwards compatability
785
+ # Always return false since we are not using crt signing functionality
854
786
  def use_crt?
855
- @@use_crt
787
+ false
856
788
  end
857
789
 
858
790
  # @api private
@@ -869,6 +801,18 @@ module Aws
869
801
  end
870
802
  end
871
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
872
816
  end
873
817
  end
874
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.6.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-06-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.3'
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: []