aws-sigv4 1.4.0 → 1.8.0
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 +35 -0
- data/VERSION +1 -1
- data/lib/aws-sigv4/signature.rb +2 -0
- data/lib/aws-sigv4/signer.rb +204 -17
- data/lib/aws-sigv4.rb +6 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 482b4ffa8bd9e9e2d7dab0d61ab15553f0e8d05e1be2923b388157664a47a9fa
|
4
|
+
data.tar.gz: c5caa84527ca213826f8c802195430caacb25750530609f1b8d7267810808574
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c16c5df7f8c6ca10cf073c25984506ce938f26823f99d82813b5bde3fb283d23a3c480adec2945b98975946a7b32efe57a0058cd65bb383606c5ee5228711381
|
7
|
+
data.tar.gz: b72ea1894eb1c419179325f8e715fb454ab02ae2d1ac243b90ed2f4032c0fd966ba157287a12009587908d0a6a2f62261c78e319a230196792b6ec4206a20718
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,41 @@
|
|
1
1
|
Unreleased Changes
|
2
2
|
------------------
|
3
3
|
|
4
|
+
1.8.0 (2023-11-28)
|
5
|
+
------------------
|
6
|
+
|
7
|
+
* Feature - Support `sigv4-s3express` signing algorithm.
|
8
|
+
|
9
|
+
1.7.0 (2023-11-22)
|
10
|
+
------------------
|
11
|
+
|
12
|
+
* Feature - AWS SDK for Ruby no longer supports Ruby runtime versions 2.3 and 2.4.
|
13
|
+
|
14
|
+
1.6.1 (2023-10-25)
|
15
|
+
------------------
|
16
|
+
|
17
|
+
* Issue - (Static Stability) use provided `expires_in` in presigned url when credentials are expired.
|
18
|
+
|
19
|
+
1.6.0 (2023-06-28)
|
20
|
+
------------------
|
21
|
+
|
22
|
+
* Feature - Select the minimum expiration time for presigned urls between the expiration time option and the credential expiration time.
|
23
|
+
|
24
|
+
1.5.2 (2022-09-30)
|
25
|
+
------------------
|
26
|
+
|
27
|
+
* Issue - Fix an issue where quoted strings with multiple spaces are not trimmed. (#2758)
|
28
|
+
|
29
|
+
1.5.1 (2022-07-19)
|
30
|
+
------------------
|
31
|
+
|
32
|
+
* Issue - Fix performance regression when checking if `aws-crt` is available. (#2729)
|
33
|
+
|
34
|
+
1.5.0 (2022-04-20)
|
35
|
+
------------------
|
36
|
+
|
37
|
+
* Feature - Use CRT based signers if `aws-crt` is available - provides support for `sigv4a`.
|
38
|
+
|
4
39
|
1.4.0 (2021-09-02)
|
5
40
|
------------------
|
6
41
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.8.0
|
data/lib/aws-sigv4/signature.rb
CHANGED
data/lib/aws-sigv4/signer.rb
CHANGED
@@ -74,6 +74,14 @@ module Aws
|
|
74
74
|
#
|
75
75
|
class Signer
|
76
76
|
|
77
|
+
@@use_crt =
|
78
|
+
begin
|
79
|
+
require 'aws-crt'
|
80
|
+
true
|
81
|
+
rescue LoadError
|
82
|
+
false
|
83
|
+
end
|
84
|
+
|
77
85
|
# @overload initialize(service:, region:, access_key_id:, secret_access_key:, session_token:nil, **options)
|
78
86
|
# @param [String] :service The service signing name, e.g. 's3'.
|
79
87
|
# @param [String] :region The region name, e.g. 'us-east-1'.
|
@@ -118,6 +126,18 @@ module Aws
|
|
118
126
|
# headers. This is required for AWS Glacier, and optional for
|
119
127
|
# every other AWS service as of late 2016.
|
120
128
|
#
|
129
|
+
# @option options [Symbol] :signing_algorithm (:sigv4) The
|
130
|
+
# algorithm to use for signing. :sigv4a is only supported when
|
131
|
+
# `aws-crt` is available.
|
132
|
+
#
|
133
|
+
# @option options [Boolean] :omit_session_token (false)
|
134
|
+
# (Supported only when `aws-crt` is available) If `true`,
|
135
|
+
# then security token is added to the final signing result,
|
136
|
+
# but is treated as "unsigned" and does not contribute
|
137
|
+
# to the authorization signature.
|
138
|
+
#
|
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
|
121
141
|
def initialize(options = {})
|
122
142
|
@service = extract_service(options)
|
123
143
|
@region = extract_region(options)
|
@@ -126,15 +146,24 @@ module Aws
|
|
126
146
|
@unsigned_headers << 'authorization'
|
127
147
|
@unsigned_headers << 'x-amzn-trace-id'
|
128
148
|
@unsigned_headers << 'expect'
|
129
|
-
|
130
|
-
|
131
|
-
|
149
|
+
@uri_escape_path = options.fetch(:uri_escape_path, true)
|
150
|
+
@apply_checksum_header = options.fetch(:apply_checksum_header, true)
|
151
|
+
@signing_algorithm = options.fetch(:signing_algorithm, :sigv4)
|
152
|
+
@normalize_path = options.fetch(:normalize_path, true)
|
153
|
+
@omit_session_token = options.fetch(:omit_session_token, false)
|
132
154
|
|
133
|
-
if
|
155
|
+
if @signing_algorithm == :sigv4a && !Signer.use_crt?
|
134
156
|
raise ArgumentError, 'You are attempting to sign a' \
|
135
|
-
' request with sigv4a which requires
|
157
|
+
' request with sigv4a which requires the `aws-crt` gem.'\
|
136
158
|
' Please install the gem or add it to your gemfile.'
|
137
159
|
end
|
160
|
+
|
161
|
+
if @signing_algorithm == 'sigv4-s3express'.to_sym &&
|
162
|
+
Signer.use_crt? && Aws::Crt::GEM_VERSION <= '0.1.9'
|
163
|
+
raise ArgumentError,
|
164
|
+
'This version of aws-crt does not support S3 Express. Please
|
165
|
+
update this gem to at least version 0.2.0.'
|
166
|
+
end
|
138
167
|
end
|
139
168
|
|
140
169
|
# @return [String]
|
@@ -211,7 +240,9 @@ module Aws
|
|
211
240
|
#
|
212
241
|
def sign_request(request)
|
213
242
|
|
214
|
-
|
243
|
+
return crt_sign_request(request) if Signer.use_crt?
|
244
|
+
|
245
|
+
creds, _ = fetch_credentials
|
215
246
|
|
216
247
|
http_method = extract_http_method(request)
|
217
248
|
url = extract_url(request)
|
@@ -227,7 +258,14 @@ module Aws
|
|
227
258
|
sigv4_headers = {}
|
228
259
|
sigv4_headers['host'] = headers['host'] || host(url)
|
229
260
|
sigv4_headers['x-amz-date'] = datetime
|
230
|
-
|
261
|
+
if creds.session_token
|
262
|
+
if @signing_algorithm == 'sigv4-s3express'.to_sym
|
263
|
+
sigv4_headers['x-amz-s3session-token'] = creds.session_token
|
264
|
+
else
|
265
|
+
sigv4_headers['x-amz-security-token'] = creds.session_token
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
231
269
|
sigv4_headers['x-amz-content-sha256'] ||= content_sha256 if @apply_checksum_header
|
232
270
|
|
233
271
|
headers = headers.merge(sigv4_headers) # merge so we do not modify given headers hash
|
@@ -289,7 +327,8 @@ module Aws
|
|
289
327
|
# signature value (a binary string) used at ':chunk-signature' needs to converted to
|
290
328
|
# hex-encoded string using #unpack
|
291
329
|
def sign_event(prior_signature, payload, encoder)
|
292
|
-
|
330
|
+
# Note: CRT does not currently provide event stream signing, so we always use the ruby implementation.
|
331
|
+
creds, _ = fetch_credentials
|
293
332
|
time = Time.now
|
294
333
|
headers = {}
|
295
334
|
|
@@ -376,7 +415,9 @@ module Aws
|
|
376
415
|
#
|
377
416
|
def presign_url(options)
|
378
417
|
|
379
|
-
|
418
|
+
return crt_presign_url(options) if Signer.use_crt?
|
419
|
+
|
420
|
+
creds, expiration = fetch_credentials
|
380
421
|
|
381
422
|
http_method = extract_http_method(options)
|
382
423
|
url = extract_url(options)
|
@@ -396,8 +437,14 @@ module Aws
|
|
396
437
|
params['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256'
|
397
438
|
params['X-Amz-Credential'] = credential(creds, date)
|
398
439
|
params['X-Amz-Date'] = datetime
|
399
|
-
params['X-Amz-Expires'] =
|
400
|
-
|
440
|
+
params['X-Amz-Expires'] = presigned_url_expiration(options, expiration, Time.strptime(datetime, "%Y%m%dT%H%M%S%Z")).to_s
|
441
|
+
if creds.session_token
|
442
|
+
if @signing_algorithm == 'sigv4-s3express'.to_sym
|
443
|
+
params['X-Amz-S3session-Token'] = creds.session_token
|
444
|
+
else
|
445
|
+
params['X-Amz-Security-Token'] = creds.session_token
|
446
|
+
end
|
447
|
+
end
|
401
448
|
params['X-Amz-SignedHeaders'] = signed_headers(headers)
|
402
449
|
|
403
450
|
params = params.map do |key, value|
|
@@ -499,7 +546,6 @@ module Aws
|
|
499
546
|
hmac(k_credentials, string_to_sign)
|
500
547
|
end
|
501
548
|
|
502
|
-
|
503
549
|
def path(url)
|
504
550
|
path = url.path
|
505
551
|
path = '/' if path == ''
|
@@ -562,7 +608,7 @@ module Aws
|
|
562
608
|
end
|
563
609
|
|
564
610
|
def canonical_header_value(value)
|
565
|
-
value.
|
611
|
+
value.gsub(/\s+/, ' ').strip
|
566
612
|
end
|
567
613
|
|
568
614
|
def host(uri)
|
@@ -655,8 +701,8 @@ module Aws
|
|
655
701
|
|
656
702
|
def extract_expires_in(options)
|
657
703
|
case options[:expires_in]
|
658
|
-
when nil then 900
|
659
|
-
when Integer then options[:expires_in]
|
704
|
+
when nil then 900
|
705
|
+
when Integer then options[:expires_in]
|
660
706
|
else
|
661
707
|
msg = "expected :expires_in to be a number of seconds"
|
662
708
|
raise ArgumentError, msg
|
@@ -671,11 +717,14 @@ module Aws
|
|
671
717
|
self.class.uri_escape_path(string)
|
672
718
|
end
|
673
719
|
|
674
|
-
|
675
720
|
def fetch_credentials
|
676
721
|
credentials = @credentials_provider.credentials
|
677
722
|
if credentials_set?(credentials)
|
678
|
-
|
723
|
+
expiration = nil
|
724
|
+
if @credentials_provider.respond_to?(:expiration)
|
725
|
+
expiration = @credentials_provider.expiration
|
726
|
+
end
|
727
|
+
[credentials, expiration]
|
679
728
|
else
|
680
729
|
raise Errors::MissingCredentialsError,
|
681
730
|
'unable to sign request without credentials set'
|
@@ -693,8 +742,146 @@ module Aws
|
|
693
742
|
!credentials.secret_access_key.empty?
|
694
743
|
end
|
695
744
|
|
745
|
+
def presigned_url_expiration(options, expiration, datetime)
|
746
|
+
expires_in = extract_expires_in(options)
|
747
|
+
return expires_in unless expiration
|
748
|
+
|
749
|
+
expiration_seconds = (expiration - datetime).to_i
|
750
|
+
# In the static stability case, credentials may expire in the past
|
751
|
+
# but still be valid. For those cases, use the user configured
|
752
|
+
# expires_in and ingore expiration.
|
753
|
+
if expiration_seconds <= 0
|
754
|
+
expires_in
|
755
|
+
else
|
756
|
+
[expires_in, expiration_seconds].min
|
757
|
+
end
|
758
|
+
end
|
759
|
+
|
760
|
+
### CRT Code
|
761
|
+
|
762
|
+
# the credentials used by CRT must be a
|
763
|
+
# CRT StaticCredentialsProvider object
|
764
|
+
def crt_fetch_credentials
|
765
|
+
creds, expiration = fetch_credentials
|
766
|
+
crt_creds = Aws::Crt::Auth::StaticCredentialsProvider.new(
|
767
|
+
creds.access_key_id,
|
768
|
+
creds.secret_access_key,
|
769
|
+
creds.session_token
|
770
|
+
)
|
771
|
+
[crt_creds, expiration]
|
772
|
+
end
|
773
|
+
|
774
|
+
def crt_sign_request(request)
|
775
|
+
creds, _ = crt_fetch_credentials
|
776
|
+
http_method = extract_http_method(request)
|
777
|
+
url = extract_url(request)
|
778
|
+
headers = downcase_headers(request[:headers])
|
779
|
+
|
780
|
+
datetime =
|
781
|
+
if headers.include? 'x-amz-date'
|
782
|
+
Time.parse(headers.delete('x-amz-date'))
|
783
|
+
end
|
784
|
+
|
785
|
+
content_sha256 = headers.delete('x-amz-content-sha256')
|
786
|
+
content_sha256 ||= sha256_hexdigest(request[:body] || '')
|
787
|
+
|
788
|
+
sigv4_headers = {}
|
789
|
+
sigv4_headers['host'] = headers['host'] || host(url)
|
790
|
+
|
791
|
+
# Modify the user-agent to add usage of crt-signer
|
792
|
+
# This should be temporary during developer preview only
|
793
|
+
if headers.include? 'user-agent'
|
794
|
+
headers['user-agent'] = "#{headers['user-agent']} crt-signer/#{@signing_algorithm}/#{Aws::Sigv4::VERSION}"
|
795
|
+
sigv4_headers['user-agent'] = headers['user-agent']
|
796
|
+
end
|
797
|
+
|
798
|
+
headers = headers.merge(sigv4_headers) # merge so we do not modify given headers hash
|
799
|
+
|
800
|
+
config = Aws::Crt::Auth::SigningConfig.new(
|
801
|
+
algorithm: @signing_algorithm,
|
802
|
+
signature_type: :http_request_headers,
|
803
|
+
region: @region,
|
804
|
+
service: @service,
|
805
|
+
date: datetime,
|
806
|
+
signed_body_value: content_sha256,
|
807
|
+
signed_body_header_type: @apply_checksum_header ?
|
808
|
+
:sbht_content_sha256 : :sbht_none,
|
809
|
+
credentials: creds,
|
810
|
+
unsigned_headers: @unsigned_headers,
|
811
|
+
use_double_uri_encode: @uri_escape_path,
|
812
|
+
should_normalize_uri_path: @normalize_path,
|
813
|
+
omit_session_token: @omit_session_token
|
814
|
+
)
|
815
|
+
http_request = Aws::Crt::Http::Message.new(
|
816
|
+
http_method, url.to_s, headers
|
817
|
+
)
|
818
|
+
signable = Aws::Crt::Auth::Signable.new(http_request)
|
819
|
+
|
820
|
+
signing_result = Aws::Crt::Auth::Signer.sign_request(config, signable)
|
821
|
+
|
822
|
+
Signature.new(
|
823
|
+
headers: sigv4_headers.merge(
|
824
|
+
downcase_headers(signing_result[:headers])
|
825
|
+
),
|
826
|
+
string_to_sign: 'CRT_INTERNAL',
|
827
|
+
canonical_request: 'CRT_INTERNAL',
|
828
|
+
content_sha256: content_sha256,
|
829
|
+
extra: {config: config, signable: signable}
|
830
|
+
)
|
831
|
+
end
|
832
|
+
|
833
|
+
def crt_presign_url(options)
|
834
|
+
creds, expiration = crt_fetch_credentials
|
835
|
+
|
836
|
+
http_method = extract_http_method(options)
|
837
|
+
url = extract_url(options)
|
838
|
+
headers = downcase_headers(options[:headers])
|
839
|
+
headers['host'] ||= host(url)
|
840
|
+
|
841
|
+
datetime = Time.strptime(headers.delete('x-amz-date'), "%Y%m%dT%H%M%S%Z") if headers['x-amz-date']
|
842
|
+
datetime ||= (options[:time] || Time.now)
|
843
|
+
|
844
|
+
content_sha256 = headers.delete('x-amz-content-sha256')
|
845
|
+
content_sha256 ||= options[:body_digest]
|
846
|
+
content_sha256 ||= sha256_hexdigest(options[:body] || '')
|
847
|
+
|
848
|
+
config = Aws::Crt::Auth::SigningConfig.new(
|
849
|
+
algorithm: @signing_algorithm,
|
850
|
+
signature_type: :http_request_query_params,
|
851
|
+
region: @region,
|
852
|
+
service: @service,
|
853
|
+
date: datetime,
|
854
|
+
signed_body_value: content_sha256,
|
855
|
+
signed_body_header_type: @apply_checksum_header ?
|
856
|
+
:sbht_content_sha256 : :sbht_none,
|
857
|
+
credentials: creds,
|
858
|
+
unsigned_headers: @unsigned_headers,
|
859
|
+
use_double_uri_encode: @uri_escape_path,
|
860
|
+
should_normalize_uri_path: @normalize_path,
|
861
|
+
omit_session_token: @omit_session_token,
|
862
|
+
expiration_in_seconds: presigned_url_expiration(options, expiration, datetime)
|
863
|
+
)
|
864
|
+
http_request = Aws::Crt::Http::Message.new(
|
865
|
+
http_method, url.to_s, headers
|
866
|
+
)
|
867
|
+
signable = Aws::Crt::Auth::Signable.new(http_request)
|
868
|
+
|
869
|
+
signing_result = Aws::Crt::Auth::Signer.sign_request(config, signable, http_method, url.to_s)
|
870
|
+
url = URI.parse(signing_result[:path])
|
871
|
+
|
872
|
+
if options[:extra] && options[:extra].is_a?(Hash)
|
873
|
+
options[:extra][:config] = config
|
874
|
+
options[:extra][:signable] = signable
|
875
|
+
end
|
876
|
+
url
|
877
|
+
end
|
878
|
+
|
696
879
|
class << self
|
697
880
|
|
881
|
+
def use_crt?
|
882
|
+
@@use_crt
|
883
|
+
end
|
884
|
+
|
698
885
|
# @api private
|
699
886
|
def uri_escape_path(path)
|
700
887
|
path.gsub(/[^\/]+/) { |part| uri_escape(part) }
|
data/lib/aws-sigv4.rb
CHANGED
@@ -4,3 +4,9 @@ require_relative 'aws-sigv4/credentials'
|
|
4
4
|
require_relative 'aws-sigv4/errors'
|
5
5
|
require_relative 'aws-sigv4/signature'
|
6
6
|
require_relative 'aws-sigv4/signer'
|
7
|
+
|
8
|
+
module Aws
|
9
|
+
module Sigv4
|
10
|
+
VERSION = File.read(File.expand_path('../VERSION', __dir__)).strip
|
11
|
+
end
|
12
|
+
end
|
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.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Amazon Web Services
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-eventstream
|
@@ -60,7 +60,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
60
60
|
requirements:
|
61
61
|
- - ">="
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
-
version: '2.
|
63
|
+
version: '2.5'
|
64
64
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ">="
|