aws-sigv4 1.6.0 → 1.10.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed95d4ec56e15f5b06d202643cebf73e89d69efbe461d03035dc309f0aa32b11
4
- data.tar.gz: f235824f3bf7ea35aa4fb7e666250f72be1d8592709f522c8fae42fb36e40a9a
3
+ metadata.gz: 05aa41853460311d09022d38c02afd09077ca66517160c73022f650168a6efbc
4
+ data.tar.gz: b9e7a93a0007cb185b93fc4939d254e1ac263a442ff470ec1ba9bd8d2975e0aa
5
5
  SHA512:
6
- metadata.gz: 62ddb59e6cf4fd5ca5a704db3a7f8f8707329cd8b66fec124de5bc56bc5cc2fac20622987e5a6cbeaec1ce55941ee66ab36ed25178ee82e287515622a33bc314
7
- data.tar.gz: e05f2a2ada39d28681df35b7365e7c71e6eda34b250cd2259312d9b6cc0e810fceb0dffeddd785a4b5e08cea1989eb5e2e4e27303d1cf4ce51ad251952d7047d
6
+ metadata.gz: b12f9e162a36d33d405ab66ccb2c8bdb1d3c0f7d66ec4c4460a59a95b78a178dbc6e270a524901a3e689b496dbed4b1422e6fa5f27786159e46cd2e13e26a2c0
7
+ data.tar.gz: f18c1d784aeec37245654255f4abb14ba0183f8a1bb33836c2167df66c3005bb0d7d7c190c8d8cff7dedc0a2d8c8f4debf631fc6716b6d8a2db24eadf9926a47
data/CHANGELOG.md CHANGED
@@ -1,6 +1,41 @@
1
1
  Unreleased Changes
2
2
  ------------------
3
3
 
4
+ 1.10.1 (2024-10-21)
5
+ ------------------
6
+
7
+ * Issue - Fix sigv4a signing issue with derive_asymmetric_key for certain credentials.
8
+
9
+ 1.10.0 (2024-09-17)
10
+ ------------------
11
+
12
+ * Feature - Remove CRT `sigv4a` signing capability.
13
+
14
+ 1.9.1 (2024-07-29)
15
+ ------------------
16
+
17
+ * Issue - Add missing require of `pathname` to `Signer`.
18
+
19
+ 1.9.0 (2024-07-23)
20
+ ------------------
21
+
22
+ * Feature - Support `sigv4a` signing algorithm without `aws-crt`.
23
+
24
+ 1.8.0 (2023-11-28)
25
+ ------------------
26
+
27
+ * Feature - Support `sigv4-s3express` signing algorithm.
28
+
29
+ 1.7.0 (2023-11-22)
30
+ ------------------
31
+
32
+ * Feature - AWS SDK for Ruby no longer supports Ruby runtime versions 2.3 and 2.4.
33
+
34
+ 1.6.1 (2023-10-25)
35
+ ------------------
36
+
37
+ * Issue - (Static Stability) use provided `expires_in` in presigned url when credentials are expired.
38
+
4
39
  1.6.0 (2023-06-28)
5
40
  ------------------
6
41
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.6.0
1
+ 1.10.1
@@ -0,0 +1,101 @@
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
+ # @param [String] :access_key_id
15
+ # @param [String] :secret_access_key
16
+ # @return [OpenSSL::PKey::EC, Hash]
17
+ def self.derive_asymmetric_key(access_key_id, secret_access_key)
18
+ check_openssl_support!
19
+ label = 'AWS4-ECDSA-P256-SHA256'
20
+ bit_len = 256
21
+ counter = 0x1
22
+ input_key = "AWS4A#{secret_access_key}"
23
+ d = 0 # d will end up being the private key
24
+ while true do
25
+
26
+ kdf_context = access_key_id.unpack('C*') + [counter].pack('C').unpack('C') #1 byte for counter
27
+ input = label.unpack('C*') + [0x00] + kdf_context + [bit_len].pack('L>').unpack('CCCC') # 4 bytes (change endianess)
28
+ k0 = OpenSSL::HMAC.digest("SHA256", input_key, ([0, 0, 0, 0x01] + input).pack('C*'))
29
+ c = be_bytes_to_num( k0.unpack('C*') )
30
+ if c <= N_MINUS_2
31
+ d = c + 1
32
+ break
33
+ elsif counter > 0xFF
34
+ raise 'Counter exceeded 1 byte - unable to get asym creds'
35
+ else
36
+ counter += 1
37
+ end
38
+ end
39
+
40
+ # compute the public key
41
+ group = OpenSSL::PKey::EC::Group.new('prime256v1')
42
+ public_key = group.generator.mul(d)
43
+
44
+ ec = generate_ec(public_key, d)
45
+
46
+ # pk_x and pk_y are not needed for signature, but useful in verification/testing
47
+ pk_b = public_key.to_octet_string(:uncompressed).unpack('C*') # 0x04 byte followed by 2 32-byte integers
48
+ pk_x = be_bytes_to_num(pk_b[1,32])
49
+ pk_y = be_bytes_to_num(pk_b[33,32])
50
+ [ec, {ec: ec, public_key: public_key, pk_x: pk_x, pk_y: pk_y, d: d}]
51
+ end
52
+
53
+ private
54
+
55
+ # @return [Number] The value of the bytes interpreted as a big-endian
56
+ # unsigned integer.
57
+ def self.be_bytes_to_num(bytes)
58
+ x = 0
59
+ bytes.each { |b| x = (x*256) + b }
60
+ x
61
+ end
62
+
63
+ # @return [Array] value of the BigNumber as a big-endian unsigned byte array.
64
+ def self.bn_to_be_bytes(bn)
65
+ bytes = []
66
+ while bn > 0
67
+ bytes << (bn & 0xff)
68
+ bn = bn >> 8
69
+ end
70
+ bytes.reverse
71
+ end
72
+
73
+ # Prior to openssl3 we could directly set public and private key on EC
74
+ # However, openssl3 deprecated those methods and we must now construct
75
+ # a der with the keys and load the EC from it.
76
+ def self.generate_ec(public_key, d)
77
+ # format reversed from: OpenSSL::ASN1.decode_all(OpenSSL::PKey::EC.new.to_der)
78
+ asn1 = OpenSSL::ASN1::Sequence([
79
+ OpenSSL::ASN1::Integer(OpenSSL::BN.new(1)),
80
+ OpenSSL::ASN1::OctetString(bn_to_be_bytes(d).pack('C*')),
81
+ OpenSSL::ASN1::ASN1Data.new([OpenSSL::ASN1::ObjectId("prime256v1")], 0, :CONTEXT_SPECIFIC),
82
+ OpenSSL::ASN1::ASN1Data.new(
83
+ [OpenSSL::ASN1::BitString(public_key.to_octet_string(:uncompressed))],
84
+ 1, :CONTEXT_SPECIFIC
85
+ )
86
+ ])
87
+ OpenSSL::PKey::EC.new(asn1.to_der)
88
+ end
89
+
90
+ def self.check_openssl_support!
91
+ return true unless defined?(JRUBY_VERSION)
92
+
93
+ # See: https://github.com/jruby/jruby-openssl/issues/306
94
+ # JRuby-openssl < 0.15 does not support OpenSSL::PKey::EC::Point#mul
95
+ return true if OpenSSL::PKey::EC::Point.instance_methods.include?(:mul)
96
+
97
+ raise 'Sigv4a Asymmetric Credential derivation requires jruby-openssl >= 0.15'
98
+ end
99
+ end
100
+ end
101
+ 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
@@ -6,6 +6,7 @@ require 'time'
6
6
  require 'uri'
7
7
  require 'set'
8
8
  require 'cgi'
9
+ require 'pathname'
9
10
  require 'aws-eventstream'
10
11
 
11
12
  module Aws
@@ -73,25 +74,18 @@ module Aws
73
74
  # and `#session_token`.
74
75
  #
75
76
  class Signer
76
-
77
- @@use_crt =
78
- begin
79
- require 'aws-crt'
80
- true
81
- rescue LoadError
82
- false
83
- end
84
-
85
77
  # @overload initialize(service:, region:, access_key_id:, secret_access_key:, session_token:nil, **options)
86
78
  # @param [String] :service The service signing name, e.g. 's3'.
87
- # @param [String] :region The region name, e.g. 'us-east-1'.
79
+ # @param [String] :region The region name, e.g. 'us-east-1'. When signing
80
+ # with sigv4a, this should be a comma separated list of regions.
88
81
  # @param [String] :access_key_id
89
82
  # @param [String] :secret_access_key
90
83
  # @param [String] :session_token (nil)
91
84
  #
92
85
  # @overload initialize(service:, region:, credentials:, **options)
93
86
  # @param [String] :service The service signing name, e.g. 's3'.
94
- # @param [String] :region The region name, e.g. 'us-east-1'.
87
+ # @param [String] :region The region name, e.g. 'us-east-1'. When signing
88
+ # with sigv4a, this should be a comma separated list of regions.
95
89
  # @param [Credentials] :credentials Any object that responds to the following
96
90
  # methods:
97
91
  #
@@ -102,7 +96,8 @@ module Aws
102
96
  #
103
97
  # @overload initialize(service:, region:, credentials_provider:, **options)
104
98
  # @param [String] :service The service signing name, e.g. 's3'.
105
- # @param [String] :region The region name, e.g. 'us-east-1'.
99
+ # @param [String] :region The region name, e.g. 'us-east-1'. When signing
100
+ # with sigv4a, this should be a comma separated list of regions.
106
101
  # @param [#credentials] :credentials_provider An object that responds
107
102
  # to `#credentials`, returning an object that responds to the following
108
103
  # methods:
@@ -127,8 +122,7 @@ module Aws
127
122
  # every other AWS service as of late 2016.
128
123
  #
129
124
  # @option options [Symbol] :signing_algorithm (:sigv4) The
130
- # algorithm to use for signing. :sigv4a is only supported when
131
- # `aws-crt` is available.
125
+ # algorithm to use for signing.
132
126
  #
133
127
  # @option options [Boolean] :omit_session_token (false)
134
128
  # (Supported only when `aws-crt` is available) If `true`,
@@ -136,8 +130,8 @@ module Aws
136
130
  # but is treated as "unsigned" and does not contribute
137
131
  # to the authorization signature.
138
132
  #
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
133
+ # @option options [Boolean] :normalize_path (true) When `true`, the
134
+ # uri paths will be normalized when building the canonical request.
141
135
  def initialize(options = {})
142
136
  @service = extract_service(options)
143
137
  @region = extract_region(options)
@@ -151,12 +145,6 @@ module Aws
151
145
  @signing_algorithm = options.fetch(:signing_algorithm, :sigv4)
152
146
  @normalize_path = options.fetch(:normalize_path, true)
153
147
  @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
148
  end
161
149
 
162
150
  # @return [String]
@@ -232,13 +220,11 @@ module Aws
232
220
  # a `#headers` method. The headers must be applied to your request.
233
221
  #
234
222
  def sign_request(request)
235
-
236
- return crt_sign_request(request) if Signer.use_crt?
237
-
238
223
  creds, _ = fetch_credentials
239
224
 
240
225
  http_method = extract_http_method(request)
241
226
  url = extract_url(request)
227
+ Signer.normalize_path(url) if @normalize_path
242
228
  headers = downcase_headers(request[:headers])
243
229
 
244
230
  datetime = headers['x-amz-date']
@@ -251,29 +237,55 @@ module Aws
251
237
  sigv4_headers = {}
252
238
  sigv4_headers['host'] = headers['host'] || host(url)
253
239
  sigv4_headers['x-amz-date'] = datetime
254
- sigv4_headers['x-amz-security-token'] = creds.session_token if creds.session_token
240
+ if creds.session_token && !@omit_session_token
241
+ if @signing_algorithm == 'sigv4-s3express'.to_sym
242
+ sigv4_headers['x-amz-s3session-token'] = creds.session_token
243
+ else
244
+ sigv4_headers['x-amz-security-token'] = creds.session_token
245
+ end
246
+ end
247
+
255
248
  sigv4_headers['x-amz-content-sha256'] ||= content_sha256 if @apply_checksum_header
256
249
 
250
+ if @signing_algorithm == :sigv4a && @region && !@region.empty?
251
+ sigv4_headers['x-amz-region-set'] = @region
252
+ end
257
253
  headers = headers.merge(sigv4_headers) # merge so we do not modify given headers hash
258
254
 
255
+ algorithm = sts_algorithm
256
+
259
257
  # compute signature parts
260
258
  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)
259
+ sts = string_to_sign(datetime, creq, algorithm)
260
+
261
+ sig =
262
+ if @signing_algorithm == :sigv4a
263
+ asymmetric_signature(creds, sts)
264
+ else
265
+ signature(creds.secret_access_key, date, sts)
266
+ end
267
+
268
+ algorithm = sts_algorithm
263
269
 
264
270
  # apply signature
265
271
  sigv4_headers['authorization'] = [
266
- "AWS4-HMAC-SHA256 Credential=#{credential(creds, date)}",
272
+ "#{algorithm} Credential=#{credential(creds, date)}",
267
273
  "SignedHeaders=#{signed_headers(headers)}",
268
274
  "Signature=#{sig}",
269
275
  ].join(', ')
270
276
 
277
+ # skip signing the session token, but include it in the headers
278
+ if creds.session_token && @omit_session_token
279
+ sigv4_headers['x-amz-security-token'] = creds.session_token
280
+ end
281
+
271
282
  # Returning the signature components.
272
283
  Signature.new(
273
284
  headers: sigv4_headers,
274
285
  string_to_sign: sts,
275
286
  canonical_request: creq,
276
- content_sha256: content_sha256
287
+ content_sha256: content_sha256,
288
+ signature: sig
277
289
  )
278
290
  end
279
291
 
@@ -313,7 +325,6 @@ module Aws
313
325
  # signature value (a binary string) used at ':chunk-signature' needs to converted to
314
326
  # hex-encoded string using #unpack
315
327
  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
328
  creds, _ = fetch_credentials
318
329
  time = Time.now
319
330
  headers = {}
@@ -400,13 +411,11 @@ module Aws
400
411
  # @return [HTTPS::URI, HTTP::URI]
401
412
  #
402
413
  def presign_url(options)
403
-
404
- return crt_presign_url(options) if Signer.use_crt?
405
-
406
414
  creds, expiration = fetch_credentials
407
415
 
408
416
  http_method = extract_http_method(options)
409
417
  url = extract_url(options)
418
+ Signer.normalize_path(url) if @normalize_path
410
419
 
411
420
  headers = downcase_headers(options[:headers])
412
421
  headers['host'] ||= host(url)
@@ -419,14 +428,26 @@ module Aws
419
428
  content_sha256 ||= options[:body_digest]
420
429
  content_sha256 ||= sha256_hexdigest(options[:body] || '')
421
430
 
431
+ algorithm = sts_algorithm
432
+
422
433
  params = {}
423
- params['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256'
434
+ params['X-Amz-Algorithm'] = algorithm
424
435
  params['X-Amz-Credential'] = credential(creds, date)
425
436
  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
437
+ params['X-Amz-Expires'] = presigned_url_expiration(options, expiration, Time.strptime(datetime, "%Y%m%dT%H%M%S%Z")).to_s
438
+ if creds.session_token
439
+ if @signing_algorithm == 'sigv4-s3express'.to_sym
440
+ params['X-Amz-S3session-Token'] = creds.session_token
441
+ else
442
+ params['X-Amz-Security-Token'] = creds.session_token
443
+ end
444
+ end
428
445
  params['X-Amz-SignedHeaders'] = signed_headers(headers)
429
446
 
447
+ if @signing_algorithm == :sigv4a && @region
448
+ params['X-Amz-Region-Set'] = @region
449
+ end
450
+
430
451
  params = params.map do |key, value|
431
452
  "#{uri_escape(key)}=#{uri_escape(value)}"
432
453
  end.join('&')
@@ -438,13 +459,23 @@ module Aws
438
459
  end
439
460
 
440
461
  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)
462
+ sts = string_to_sign(datetime, creq, algorithm)
463
+ signature =
464
+ if @signing_algorithm == :sigv4a
465
+ asymmetric_signature(creds, sts)
466
+ else
467
+ signature(creds.secret_access_key, date, sts)
468
+ end
469
+ url.query += '&X-Amz-Signature=' + signature
443
470
  url
444
471
  end
445
472
 
446
473
  private
447
474
 
475
+ def sts_algorithm
476
+ @signing_algorithm == :sigv4a ? 'AWS4-ECDSA-P256-SHA256' : 'AWS4-HMAC-SHA256'
477
+ end
478
+
448
479
  def canonical_request(http_method, url, headers, content_sha256)
449
480
  [
450
481
  http_method,
@@ -456,9 +487,9 @@ module Aws
456
487
  ].join("\n")
457
488
  end
458
489
 
459
- def string_to_sign(datetime, canonical_request)
490
+ def string_to_sign(datetime, canonical_request, algorithm)
460
491
  [
461
- 'AWS4-HMAC-SHA256',
492
+ algorithm,
462
493
  datetime,
463
494
  credential_scope(datetime[0,8]),
464
495
  sha256_hexdigest(canonical_request),
@@ -491,10 +522,10 @@ module Aws
491
522
  def credential_scope(date)
492
523
  [
493
524
  date,
494
- @region,
525
+ (@region unless @signing_algorithm == :sigv4a),
495
526
  @service,
496
- 'aws4_request',
497
- ].join('/')
527
+ 'aws4_request'
528
+ ].compact.join('/')
498
529
  end
499
530
 
500
531
  def credential(credentials, date)
@@ -509,6 +540,16 @@ module Aws
509
540
  hexhmac(k_credentials, string_to_sign)
510
541
  end
511
542
 
543
+ def asymmetric_signature(creds, string_to_sign)
544
+ ec, _ = Aws::Sigv4::AsymmetricCredentials.derive_asymmetric_key(
545
+ creds.access_key_id, creds.secret_access_key
546
+ )
547
+ sts_digest = OpenSSL::Digest::SHA256.digest(string_to_sign)
548
+ s = ec.dsa_sign_asn1(sts_digest)
549
+
550
+ Digest.hexencode(s)
551
+ end
552
+
512
553
  # Comparing to original signature v4 algorithm,
513
554
  # returned signature is a binary string instread of
514
555
  # hex-encoded string. (Since ':chunk-signature' requires
@@ -722,137 +763,27 @@ module Aws
722
763
  !credentials.secret_access_key.empty?
723
764
  end
724
765
 
725
- def presigned_url_expiration(options, expiration)
766
+ def presigned_url_expiration(options, expiration, datetime)
726
767
  expires_in = extract_expires_in(options)
727
768
  return expires_in unless expiration
728
769
 
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
770
+ expiration_seconds = (expiration - datetime).to_i
771
+ # In the static stability case, credentials may expire in the past
772
+ # but still be valid. For those cases, use the user configured
773
+ # expires_in and ingore expiration.
774
+ if expiration_seconds <= 0
775
+ expires_in
776
+ else
777
+ [expires_in, expiration_seconds].min
848
778
  end
849
- url
850
779
  end
851
780
 
852
781
  class << self
853
782
 
783
+ # Kept for backwards compatability
784
+ # Always return false since we are not using crt signing functionality
854
785
  def use_crt?
855
- @@use_crt
786
+ false
856
787
  end
857
788
 
858
789
  # @api private
@@ -869,6 +800,18 @@ module Aws
869
800
  end
870
801
  end
871
802
 
803
+ # @api private
804
+ def normalize_path(uri)
805
+ normalized_path = Pathname.new(uri.path).cleanpath.to_s
806
+ # Pathname is probably not correct to use. Empty paths will
807
+ # resolve to "." and should be disregarded
808
+ normalized_path = '' if normalized_path == '.'
809
+ # Ensure trailing slashes are correctly preserved
810
+ if uri.path.end_with?('/') && !normalized_path.end_with?('/')
811
+ normalized_path << '/'
812
+ end
813
+ uri.path = normalized_path
814
+ end
872
815
  end
873
816
  end
874
817
  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,14 @@
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.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amazon Web Services
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-28 00:00:00.000000000 Z
11
+ date: 2024-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-eventstream
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: 1.0.2
33
33
  description: Amazon Web Services Signature Version 4 signing library. Generates sigv4
34
34
  signature for HTTP requests.
35
- email:
35
+ email:
36
36
  executables: []
37
37
  extensions: []
38
38
  extra_rdoc_files: []
@@ -41,6 +41,7 @@ files:
41
41
  - LICENSE.txt
42
42
  - VERSION
43
43
  - lib/aws-sigv4.rb
44
+ - lib/aws-sigv4/asymmetric_credentials.rb
44
45
  - lib/aws-sigv4/credentials.rb
45
46
  - lib/aws-sigv4/errors.rb
46
47
  - lib/aws-sigv4/request.rb
@@ -52,7 +53,7 @@ licenses:
52
53
  metadata:
53
54
  source_code_uri: https://github.com/aws/aws-sdk-ruby/tree/version-3/gems/aws-sigv4
54
55
  changelog_uri: https://github.com/aws/aws-sdk-ruby/tree/version-3/gems/aws-sigv4/CHANGELOG.md
55
- post_install_message:
56
+ post_install_message:
56
57
  rdoc_options: []
57
58
  require_paths:
58
59
  - lib
@@ -60,15 +61,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
60
61
  requirements:
61
62
  - - ">="
62
63
  - !ruby/object:Gem::Version
63
- version: '2.3'
64
+ version: '2.5'
64
65
  required_rubygems_version: !ruby/object:Gem::Requirement
65
66
  requirements:
66
67
  - - ">="
67
68
  - !ruby/object:Gem::Version
68
69
  version: '0'
69
70
  requirements: []
70
- rubygems_version: 3.1.6
71
- signing_key:
71
+ rubygems_version: 3.4.10
72
+ signing_key:
72
73
  specification_version: 4
73
74
  summary: AWS Signature Version 4 library.
74
75
  test_files: []