aws-sigv4 1.5.2 → 1.9.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 +4 -4
- data/CHANGELOG.md +30 -0
- data/VERSION +1 -1
- data/lib/aws-sigv4/asymmetric_credentials.rb +91 -0
- data/lib/aws-sigv4/signature.rb +3 -0
- data/lib/aws-sigv4/signer.rb +134 -40
- data/lib/aws-sigv4.rb +1 -0
- metadata +9 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6c968ea3d1cff2c3e6ff056a38658ce9af6f2f9b3d5fce948003a063c1f785e
|
4
|
+
data.tar.gz: '008ac56a37950824779768b8e3e942a711a0cae225231e9f9897e0426a18d121'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49dfbb860585de3ca7f1f84e3ff2fa059025098fe3a0baf4ab4c4fd1ff6bdb4dab85b17b040ebc7fa5db743d1f5da9a4b0975187d2bf60aabfc29e9674b22ee3
|
7
|
+
data.tar.gz: 315d89e1c67bfc3938f267dcf50e47842f7cac514b07df07cc642be2bc99fbc55dd7256f564868c6f3e61ee125aa71d26a98af01c734a924aaa0ae5ac8e084e4
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,36 @@
|
|
1
1
|
Unreleased Changes
|
2
2
|
------------------
|
3
3
|
|
4
|
+
1.9.1 (2024-07-29)
|
5
|
+
------------------
|
6
|
+
|
7
|
+
* Issue - Add missing require of `pathname` to `Signer`.
|
8
|
+
|
9
|
+
1.9.0 (2024-07-23)
|
10
|
+
------------------
|
11
|
+
|
12
|
+
* Feature - Support `sigv4a` signing algorithm without `aws-crt`.
|
13
|
+
|
14
|
+
1.8.0 (2023-11-28)
|
15
|
+
------------------
|
16
|
+
|
17
|
+
* Feature - Support `sigv4-s3express` signing algorithm.
|
18
|
+
|
19
|
+
1.7.0 (2023-11-22)
|
20
|
+
------------------
|
21
|
+
|
22
|
+
* Feature - AWS SDK for Ruby no longer supports Ruby runtime versions 2.3 and 2.4.
|
23
|
+
|
24
|
+
1.6.1 (2023-10-25)
|
25
|
+
------------------
|
26
|
+
|
27
|
+
* Issue - (Static Stability) use provided `expires_in` in presigned url when credentials are expired.
|
28
|
+
|
29
|
+
1.6.0 (2023-06-28)
|
30
|
+
------------------
|
31
|
+
|
32
|
+
* Feature - Select the minimum expiration time for presigned urls between the expiration time option and the credential expiration time.
|
33
|
+
|
4
34
|
1.5.2 (2022-09-30)
|
5
35
|
------------------
|
6
36
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.9.1
|
@@ -0,0 +1,91 @@
|
|
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
|
+
# Prior to openssl3 we could directly set public and private key on EC
|
64
|
+
# However, openssl3 deprecated those methods and we must now construct
|
65
|
+
# a der with the keys and load the EC from it.
|
66
|
+
def self.generate_ec(public_key, d)
|
67
|
+
# format reversed from: OpenSSL::ASN1.decode_all(OpenSSL::PKey::EC.new.to_der)
|
68
|
+
asn1 = OpenSSL::ASN1::Sequence([
|
69
|
+
OpenSSL::ASN1::Integer(OpenSSL::BN.new(1)),
|
70
|
+
OpenSSL::ASN1::OctetString([d.to_s(16)].pack('H*')),
|
71
|
+
OpenSSL::ASN1::ASN1Data.new([OpenSSL::ASN1::ObjectId("prime256v1")], 0, :CONTEXT_SPECIFIC),
|
72
|
+
OpenSSL::ASN1::ASN1Data.new(
|
73
|
+
[OpenSSL::ASN1::BitString(public_key.to_octet_string(:uncompressed))],
|
74
|
+
1, :CONTEXT_SPECIFIC
|
75
|
+
)
|
76
|
+
])
|
77
|
+
OpenSSL::PKey::EC.new(asn1.to_der)
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.check_openssl_support!
|
81
|
+
return true unless defined?(JRUBY_VERSION)
|
82
|
+
|
83
|
+
# See: https://github.com/jruby/jruby-openssl/issues/306
|
84
|
+
# JRuby-openssl < 0.15 does not support OpenSSL::PKey::EC::Point#mul
|
85
|
+
return true if OpenSSL::PKey::EC::Point.instance_methods.include?(:mul)
|
86
|
+
|
87
|
+
raise 'Sigv4a Asymmetric Credential derivation requires jruby-openssl >= 0.15'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/aws-sigv4/signature.rb
CHANGED
@@ -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
|
data/lib/aws-sigv4/signer.rb
CHANGED
@@ -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
|
@@ -84,14 +85,16 @@ module Aws
|
|
84
85
|
|
85
86
|
# @overload initialize(service:, region:, access_key_id:, secret_access_key:, session_token:nil, **options)
|
86
87
|
# @param [String] :service The service signing name, e.g. 's3'.
|
87
|
-
# @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.
|
88
90
|
# @param [String] :access_key_id
|
89
91
|
# @param [String] :secret_access_key
|
90
92
|
# @param [String] :session_token (nil)
|
91
93
|
#
|
92
94
|
# @overload initialize(service:, region:, credentials:, **options)
|
93
95
|
# @param [String] :service The service signing name, e.g. 's3'.
|
94
|
-
# @param [String] :region The region name, e.g. 'us-east-1'.
|
96
|
+
# @param [String] :region The region name, e.g. 'us-east-1'. When signing
|
97
|
+
# with sigv4a, this should be a comma separated list of regions.
|
95
98
|
# @param [Credentials] :credentials Any object that responds to the following
|
96
99
|
# methods:
|
97
100
|
#
|
@@ -102,7 +105,8 @@ module Aws
|
|
102
105
|
#
|
103
106
|
# @overload initialize(service:, region:, credentials_provider:, **options)
|
104
107
|
# @param [String] :service The service signing name, e.g. 's3'.
|
105
|
-
# @param [String] :region The region name, e.g. 'us-east-1'.
|
108
|
+
# @param [String] :region The region name, e.g. 'us-east-1'. When signing
|
109
|
+
# with sigv4a, this should be a comma separated list of regions.
|
106
110
|
# @param [#credentials] :credentials_provider An object that responds
|
107
111
|
# to `#credentials`, returning an object that responds to the following
|
108
112
|
# methods:
|
@@ -127,8 +131,7 @@ module Aws
|
|
127
131
|
# every other AWS service as of late 2016.
|
128
132
|
#
|
129
133
|
# @option options [Symbol] :signing_algorithm (:sigv4) The
|
130
|
-
# algorithm to use for signing.
|
131
|
-
# `aws-crt` is available.
|
134
|
+
# algorithm to use for signing.
|
132
135
|
#
|
133
136
|
# @option options [Boolean] :omit_session_token (false)
|
134
137
|
# (Supported only when `aws-crt` is available) If `true`,
|
@@ -136,8 +139,8 @@ module Aws
|
|
136
139
|
# but is treated as "unsigned" and does not contribute
|
137
140
|
# to the authorization signature.
|
138
141
|
#
|
139
|
-
# @option options [Boolean] :normalize_path (true)
|
140
|
-
#
|
142
|
+
# @option options [Boolean] :normalize_path (true) When `true`, the
|
143
|
+
# uri paths will be normalized when building the canonical request.
|
141
144
|
def initialize(options = {})
|
142
145
|
@service = extract_service(options)
|
143
146
|
@region = extract_region(options)
|
@@ -152,10 +155,11 @@ module Aws
|
|
152
155
|
@normalize_path = options.fetch(:normalize_path, true)
|
153
156
|
@omit_session_token = options.fetch(:omit_session_token, false)
|
154
157
|
|
155
|
-
if @signing_algorithm ==
|
156
|
-
|
157
|
-
|
158
|
-
'
|
158
|
+
if @signing_algorithm == 'sigv4-s3express'.to_sym &&
|
159
|
+
Signer.use_crt? && Aws::Crt::GEM_VERSION <= '0.1.9'
|
160
|
+
raise ArgumentError,
|
161
|
+
'This version of aws-crt does not support S3 Express. Please
|
162
|
+
update this gem to at least version 0.2.0.'
|
159
163
|
end
|
160
164
|
end
|
161
165
|
|
@@ -235,10 +239,11 @@ module Aws
|
|
235
239
|
|
236
240
|
return crt_sign_request(request) if Signer.use_crt?
|
237
241
|
|
238
|
-
creds = fetch_credentials
|
242
|
+
creds, _ = fetch_credentials
|
239
243
|
|
240
244
|
http_method = extract_http_method(request)
|
241
245
|
url = extract_url(request)
|
246
|
+
Signer.normalize_path(url) if @normalize_path
|
242
247
|
headers = downcase_headers(request[:headers])
|
243
248
|
|
244
249
|
datetime = headers['x-amz-date']
|
@@ -251,29 +256,55 @@ module Aws
|
|
251
256
|
sigv4_headers = {}
|
252
257
|
sigv4_headers['host'] = headers['host'] || host(url)
|
253
258
|
sigv4_headers['x-amz-date'] = datetime
|
254
|
-
|
259
|
+
if creds.session_token && !@omit_session_token
|
260
|
+
if @signing_algorithm == 'sigv4-s3express'.to_sym
|
261
|
+
sigv4_headers['x-amz-s3session-token'] = creds.session_token
|
262
|
+
else
|
263
|
+
sigv4_headers['x-amz-security-token'] = creds.session_token
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
255
267
|
sigv4_headers['x-amz-content-sha256'] ||= content_sha256 if @apply_checksum_header
|
256
268
|
|
269
|
+
if @signing_algorithm == :sigv4a && @region && !@region.empty?
|
270
|
+
sigv4_headers['x-amz-region-set'] = @region
|
271
|
+
end
|
257
272
|
headers = headers.merge(sigv4_headers) # merge so we do not modify given headers hash
|
258
273
|
|
274
|
+
algorithm = sts_algorithm
|
275
|
+
|
259
276
|
# compute signature parts
|
260
277
|
creq = canonical_request(http_method, url, headers, content_sha256)
|
261
|
-
sts = string_to_sign(datetime, creq)
|
262
|
-
|
278
|
+
sts = string_to_sign(datetime, creq, algorithm)
|
279
|
+
|
280
|
+
sig =
|
281
|
+
if @signing_algorithm == :sigv4a
|
282
|
+
asymmetric_signature(creds, sts)
|
283
|
+
else
|
284
|
+
signature(creds.secret_access_key, date, sts)
|
285
|
+
end
|
286
|
+
|
287
|
+
algorithm = sts_algorithm
|
263
288
|
|
264
289
|
# apply signature
|
265
290
|
sigv4_headers['authorization'] = [
|
266
|
-
"
|
291
|
+
"#{algorithm} Credential=#{credential(creds, date)}",
|
267
292
|
"SignedHeaders=#{signed_headers(headers)}",
|
268
293
|
"Signature=#{sig}",
|
269
294
|
].join(', ')
|
270
295
|
|
296
|
+
# skip signing the session token, but include it in the headers
|
297
|
+
if creds.session_token && @omit_session_token
|
298
|
+
sigv4_headers['x-amz-security-token'] = creds.session_token
|
299
|
+
end
|
300
|
+
|
271
301
|
# Returning the signature components.
|
272
302
|
Signature.new(
|
273
303
|
headers: sigv4_headers,
|
274
304
|
string_to_sign: sts,
|
275
305
|
canonical_request: creq,
|
276
|
-
content_sha256: content_sha256
|
306
|
+
content_sha256: content_sha256,
|
307
|
+
signature: sig
|
277
308
|
)
|
278
309
|
end
|
279
310
|
|
@@ -314,7 +345,7 @@ module Aws
|
|
314
345
|
# hex-encoded string using #unpack
|
315
346
|
def sign_event(prior_signature, payload, encoder)
|
316
347
|
# Note: CRT does not currently provide event stream signing, so we always use the ruby implementation.
|
317
|
-
creds = fetch_credentials
|
348
|
+
creds, _ = fetch_credentials
|
318
349
|
time = Time.now
|
319
350
|
headers = {}
|
320
351
|
|
@@ -403,10 +434,11 @@ module Aws
|
|
403
434
|
|
404
435
|
return crt_presign_url(options) if Signer.use_crt?
|
405
436
|
|
406
|
-
creds = fetch_credentials
|
437
|
+
creds, expiration = fetch_credentials
|
407
438
|
|
408
439
|
http_method = extract_http_method(options)
|
409
440
|
url = extract_url(options)
|
441
|
+
Signer.normalize_path(url) if @normalize_path
|
410
442
|
|
411
443
|
headers = downcase_headers(options[:headers])
|
412
444
|
headers['host'] ||= host(url)
|
@@ -419,14 +451,26 @@ module Aws
|
|
419
451
|
content_sha256 ||= options[:body_digest]
|
420
452
|
content_sha256 ||= sha256_hexdigest(options[:body] || '')
|
421
453
|
|
454
|
+
algorithm = sts_algorithm
|
455
|
+
|
422
456
|
params = {}
|
423
|
-
params['X-Amz-Algorithm'] =
|
457
|
+
params['X-Amz-Algorithm'] = algorithm
|
424
458
|
params['X-Amz-Credential'] = credential(creds, date)
|
425
459
|
params['X-Amz-Date'] = datetime
|
426
|
-
params['X-Amz-Expires'] =
|
427
|
-
|
460
|
+
params['X-Amz-Expires'] = presigned_url_expiration(options, expiration, Time.strptime(datetime, "%Y%m%dT%H%M%S%Z")).to_s
|
461
|
+
if creds.session_token
|
462
|
+
if @signing_algorithm == 'sigv4-s3express'.to_sym
|
463
|
+
params['X-Amz-S3session-Token'] = creds.session_token
|
464
|
+
else
|
465
|
+
params['X-Amz-Security-Token'] = creds.session_token
|
466
|
+
end
|
467
|
+
end
|
428
468
|
params['X-Amz-SignedHeaders'] = signed_headers(headers)
|
429
469
|
|
470
|
+
if @signing_algorithm == :sigv4a && @region
|
471
|
+
params['X-Amz-Region-Set'] = @region
|
472
|
+
end
|
473
|
+
|
430
474
|
params = params.map do |key, value|
|
431
475
|
"#{uri_escape(key)}=#{uri_escape(value)}"
|
432
476
|
end.join('&')
|
@@ -438,13 +482,23 @@ module Aws
|
|
438
482
|
end
|
439
483
|
|
440
484
|
creq = canonical_request(http_method, url, headers, content_sha256)
|
441
|
-
sts = string_to_sign(datetime, creq)
|
442
|
-
|
485
|
+
sts = string_to_sign(datetime, creq, algorithm)
|
486
|
+
signature =
|
487
|
+
if @signing_algorithm == :sigv4a
|
488
|
+
asymmetric_signature(creds, sts)
|
489
|
+
else
|
490
|
+
signature(creds.secret_access_key, date, sts)
|
491
|
+
end
|
492
|
+
url.query += '&X-Amz-Signature=' + signature
|
443
493
|
url
|
444
494
|
end
|
445
495
|
|
446
496
|
private
|
447
497
|
|
498
|
+
def sts_algorithm
|
499
|
+
@signing_algorithm == :sigv4a ? 'AWS4-ECDSA-P256-SHA256' : 'AWS4-HMAC-SHA256'
|
500
|
+
end
|
501
|
+
|
448
502
|
def canonical_request(http_method, url, headers, content_sha256)
|
449
503
|
[
|
450
504
|
http_method,
|
@@ -456,9 +510,9 @@ module Aws
|
|
456
510
|
].join("\n")
|
457
511
|
end
|
458
512
|
|
459
|
-
def string_to_sign(datetime, canonical_request)
|
513
|
+
def string_to_sign(datetime, canonical_request, algorithm)
|
460
514
|
[
|
461
|
-
|
515
|
+
algorithm,
|
462
516
|
datetime,
|
463
517
|
credential_scope(datetime[0,8]),
|
464
518
|
sha256_hexdigest(canonical_request),
|
@@ -491,10 +545,10 @@ module Aws
|
|
491
545
|
def credential_scope(date)
|
492
546
|
[
|
493
547
|
date,
|
494
|
-
@region,
|
548
|
+
(@region unless @signing_algorithm == :sigv4a),
|
495
549
|
@service,
|
496
|
-
'aws4_request'
|
497
|
-
].join('/')
|
550
|
+
'aws4_request'
|
551
|
+
].compact.join('/')
|
498
552
|
end
|
499
553
|
|
500
554
|
def credential(credentials, date)
|
@@ -509,6 +563,16 @@ module Aws
|
|
509
563
|
hexhmac(k_credentials, string_to_sign)
|
510
564
|
end
|
511
565
|
|
566
|
+
def asymmetric_signature(creds, string_to_sign)
|
567
|
+
ec, _ = Aws::Sigv4::AsymmetricCredentials.derive_asymmetric_key(
|
568
|
+
creds.access_key_id, creds.secret_access_key
|
569
|
+
)
|
570
|
+
sts_digest = OpenSSL::Digest::SHA256.digest(string_to_sign)
|
571
|
+
s = ec.dsa_sign_asn1(sts_digest)
|
572
|
+
|
573
|
+
Digest.hexencode(s)
|
574
|
+
end
|
575
|
+
|
512
576
|
# Comparing to original signature v4 algorithm,
|
513
577
|
# returned signature is a binary string instread of
|
514
578
|
# hex-encoded string. (Since ':chunk-signature' requires
|
@@ -526,7 +590,6 @@ module Aws
|
|
526
590
|
hmac(k_credentials, string_to_sign)
|
527
591
|
end
|
528
592
|
|
529
|
-
|
530
593
|
def path(url)
|
531
594
|
path = url.path
|
532
595
|
path = '/' if path == ''
|
@@ -682,8 +745,8 @@ module Aws
|
|
682
745
|
|
683
746
|
def extract_expires_in(options)
|
684
747
|
case options[:expires_in]
|
685
|
-
when nil then 900
|
686
|
-
when Integer then options[:expires_in]
|
748
|
+
when nil then 900
|
749
|
+
when Integer then options[:expires_in]
|
687
750
|
else
|
688
751
|
msg = "expected :expires_in to be a number of seconds"
|
689
752
|
raise ArgumentError, msg
|
@@ -698,11 +761,14 @@ module Aws
|
|
698
761
|
self.class.uri_escape_path(string)
|
699
762
|
end
|
700
763
|
|
701
|
-
|
702
764
|
def fetch_credentials
|
703
765
|
credentials = @credentials_provider.credentials
|
704
766
|
if credentials_set?(credentials)
|
705
|
-
|
767
|
+
expiration = nil
|
768
|
+
if @credentials_provider.respond_to?(:expiration)
|
769
|
+
expiration = @credentials_provider.expiration
|
770
|
+
end
|
771
|
+
[credentials, expiration]
|
706
772
|
else
|
707
773
|
raise Errors::MissingCredentialsError,
|
708
774
|
'unable to sign request without credentials set'
|
@@ -720,21 +786,37 @@ module Aws
|
|
720
786
|
!credentials.secret_access_key.empty?
|
721
787
|
end
|
722
788
|
|
789
|
+
def presigned_url_expiration(options, expiration, datetime)
|
790
|
+
expires_in = extract_expires_in(options)
|
791
|
+
return expires_in unless expiration
|
792
|
+
|
793
|
+
expiration_seconds = (expiration - datetime).to_i
|
794
|
+
# In the static stability case, credentials may expire in the past
|
795
|
+
# but still be valid. For those cases, use the user configured
|
796
|
+
# expires_in and ingore expiration.
|
797
|
+
if expiration_seconds <= 0
|
798
|
+
expires_in
|
799
|
+
else
|
800
|
+
[expires_in, expiration_seconds].min
|
801
|
+
end
|
802
|
+
end
|
803
|
+
|
723
804
|
### CRT Code
|
724
805
|
|
725
806
|
# the credentials used by CRT must be a
|
726
807
|
# CRT StaticCredentialsProvider object
|
727
808
|
def crt_fetch_credentials
|
728
|
-
creds = fetch_credentials
|
729
|
-
Aws::Crt::Auth::StaticCredentialsProvider.new(
|
809
|
+
creds, expiration = fetch_credentials
|
810
|
+
crt_creds = Aws::Crt::Auth::StaticCredentialsProvider.new(
|
730
811
|
creds.access_key_id,
|
731
812
|
creds.secret_access_key,
|
732
813
|
creds.session_token
|
733
814
|
)
|
815
|
+
[crt_creds, expiration]
|
734
816
|
end
|
735
817
|
|
736
818
|
def crt_sign_request(request)
|
737
|
-
creds = crt_fetch_credentials
|
819
|
+
creds, _ = crt_fetch_credentials
|
738
820
|
http_method = extract_http_method(request)
|
739
821
|
url = extract_url(request)
|
740
822
|
headers = downcase_headers(request[:headers])
|
@@ -793,14 +875,14 @@ module Aws
|
|
793
875
|
end
|
794
876
|
|
795
877
|
def crt_presign_url(options)
|
796
|
-
creds = crt_fetch_credentials
|
878
|
+
creds, expiration = crt_fetch_credentials
|
797
879
|
|
798
880
|
http_method = extract_http_method(options)
|
799
881
|
url = extract_url(options)
|
800
882
|
headers = downcase_headers(options[:headers])
|
801
883
|
headers['host'] ||= host(url)
|
802
884
|
|
803
|
-
datetime = headers.delete('x-amz-date')
|
885
|
+
datetime = Time.strptime(headers.delete('x-amz-date'), "%Y%m%dT%H%M%S%Z") if headers['x-amz-date']
|
804
886
|
datetime ||= (options[:time] || Time.now)
|
805
887
|
|
806
888
|
content_sha256 = headers.delete('x-amz-content-sha256')
|
@@ -821,7 +903,7 @@ module Aws
|
|
821
903
|
use_double_uri_encode: @uri_escape_path,
|
822
904
|
should_normalize_uri_path: @normalize_path,
|
823
905
|
omit_session_token: @omit_session_token,
|
824
|
-
expiration_in_seconds: options
|
906
|
+
expiration_in_seconds: presigned_url_expiration(options, expiration, datetime)
|
825
907
|
)
|
826
908
|
http_request = Aws::Crt::Http::Message.new(
|
827
909
|
http_method, url.to_s, headers
|
@@ -858,6 +940,18 @@ module Aws
|
|
858
940
|
end
|
859
941
|
end
|
860
942
|
|
943
|
+
# @api private
|
944
|
+
def normalize_path(uri)
|
945
|
+
normalized_path = Pathname.new(uri.path).cleanpath.to_s
|
946
|
+
# Pathname is probably not correct to use. Empty paths will
|
947
|
+
# resolve to "." and should be disregarded
|
948
|
+
normalized_path = '' if normalized_path == '.'
|
949
|
+
# Ensure trailing slashes are correctly preserved
|
950
|
+
if uri.path.end_with?('/') && !normalized_path.end_with?('/')
|
951
|
+
normalized_path << '/'
|
952
|
+
end
|
953
|
+
uri.path = normalized_path
|
954
|
+
end
|
861
955
|
end
|
862
956
|
end
|
863
957
|
end
|
data/lib/aws-sigv4.rb
CHANGED
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.
|
4
|
+
version: 1.9.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:
|
11
|
+
date: 2024-07-29 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.
|
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.
|
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: []
|