aws-sigv4 1.6.0 → 1.10.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: 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: []