aws-sdk-s3 1.48.0 → 1.183.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.
Files changed (134) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1352 -0
  3. data/LICENSE.txt +202 -0
  4. data/VERSION +1 -0
  5. data/lib/aws-sdk-s3/access_grants_credentials.rb +57 -0
  6. data/lib/aws-sdk-s3/access_grants_credentials_provider.rb +250 -0
  7. data/lib/aws-sdk-s3/bucket.rb +1005 -106
  8. data/lib/aws-sdk-s3/bucket_acl.rb +65 -18
  9. data/lib/aws-sdk-s3/bucket_cors.rb +80 -18
  10. data/lib/aws-sdk-s3/bucket_lifecycle.rb +71 -20
  11. data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +126 -21
  12. data/lib/aws-sdk-s3/bucket_logging.rb +68 -16
  13. data/lib/aws-sdk-s3/bucket_notification.rb +52 -20
  14. data/lib/aws-sdk-s3/bucket_policy.rb +108 -17
  15. data/lib/aws-sdk-s3/bucket_region_cache.rb +11 -5
  16. data/lib/aws-sdk-s3/bucket_request_payment.rb +60 -15
  17. data/lib/aws-sdk-s3/bucket_tagging.rb +71 -18
  18. data/lib/aws-sdk-s3/bucket_versioning.rb +133 -17
  19. data/lib/aws-sdk-s3/bucket_website.rb +78 -21
  20. data/lib/aws-sdk-s3/client.rb +14517 -941
  21. data/lib/aws-sdk-s3/client_api.rb +1296 -197
  22. data/lib/aws-sdk-s3/customizations/bucket.rb +56 -37
  23. data/lib/aws-sdk-s3/customizations/errors.rb +40 -0
  24. data/lib/aws-sdk-s3/customizations/multipart_upload.rb +2 -0
  25. data/lib/aws-sdk-s3/customizations/object.rb +288 -68
  26. data/lib/aws-sdk-s3/customizations/object_summary.rb +10 -0
  27. data/lib/aws-sdk-s3/customizations/object_version.rb +13 -0
  28. data/lib/aws-sdk-s3/customizations/types/list_object_versions_output.rb +2 -0
  29. data/lib/aws-sdk-s3/customizations/types/permanent_redirect.rb +26 -0
  30. data/lib/aws-sdk-s3/customizations.rb +27 -28
  31. data/lib/aws-sdk-s3/encryption/client.rb +28 -7
  32. data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +71 -29
  33. data/lib/aws-sdk-s3/encryption/default_cipher_provider.rb +43 -5
  34. data/lib/aws-sdk-s3/encryption/default_key_provider.rb +2 -0
  35. data/lib/aws-sdk-s3/encryption/encrypt_handler.rb +13 -2
  36. data/lib/aws-sdk-s3/encryption/errors.rb +2 -0
  37. data/lib/aws-sdk-s3/encryption/io_auth_decrypter.rb +2 -0
  38. data/lib/aws-sdk-s3/encryption/io_decrypter.rb +11 -3
  39. data/lib/aws-sdk-s3/encryption/io_encrypter.rb +2 -0
  40. data/lib/aws-sdk-s3/encryption/key_provider.rb +2 -0
  41. data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +46 -11
  42. data/lib/aws-sdk-s3/encryption/materials.rb +8 -6
  43. data/lib/aws-sdk-s3/encryption/utils.rb +25 -0
  44. data/lib/aws-sdk-s3/encryption.rb +4 -0
  45. data/lib/aws-sdk-s3/encryptionV2/client.rb +570 -0
  46. data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +223 -0
  47. data/lib/aws-sdk-s3/encryptionV2/default_cipher_provider.rb +170 -0
  48. data/lib/aws-sdk-s3/encryptionV2/default_key_provider.rb +40 -0
  49. data/lib/aws-sdk-s3/encryptionV2/encrypt_handler.rb +65 -0
  50. data/lib/aws-sdk-s3/encryptionV2/errors.rb +37 -0
  51. data/lib/aws-sdk-s3/encryptionV2/io_auth_decrypter.rb +58 -0
  52. data/lib/aws-sdk-s3/encryptionV2/io_decrypter.rb +37 -0
  53. data/lib/aws-sdk-s3/encryptionV2/io_encrypter.rb +73 -0
  54. data/lib/aws-sdk-s3/encryptionV2/key_provider.rb +31 -0
  55. data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +173 -0
  56. data/lib/aws-sdk-s3/encryptionV2/materials.rb +60 -0
  57. data/lib/aws-sdk-s3/encryptionV2/utils.rb +103 -0
  58. data/lib/aws-sdk-s3/encryption_v2.rb +23 -0
  59. data/lib/aws-sdk-s3/endpoint_parameters.rb +181 -0
  60. data/lib/aws-sdk-s3/endpoint_provider.rb +716 -0
  61. data/lib/aws-sdk-s3/endpoints.rb +1434 -0
  62. data/lib/aws-sdk-s3/errors.rb +170 -1
  63. data/lib/aws-sdk-s3/event_streams.rb +8 -1
  64. data/lib/aws-sdk-s3/express_credentials.rb +55 -0
  65. data/lib/aws-sdk-s3/express_credentials_provider.rb +59 -0
  66. data/lib/aws-sdk-s3/file_downloader.rb +161 -46
  67. data/lib/aws-sdk-s3/file_part.rb +11 -6
  68. data/lib/aws-sdk-s3/file_uploader.rb +39 -18
  69. data/lib/aws-sdk-s3/legacy_signer.rb +17 -25
  70. data/lib/aws-sdk-s3/multipart_file_uploader.rb +104 -27
  71. data/lib/aws-sdk-s3/multipart_stream_uploader.rb +61 -21
  72. data/lib/aws-sdk-s3/multipart_upload.rb +342 -32
  73. data/lib/aws-sdk-s3/multipart_upload_error.rb +2 -0
  74. data/lib/aws-sdk-s3/multipart_upload_part.rb +384 -46
  75. data/lib/aws-sdk-s3/object.rb +2600 -231
  76. data/lib/aws-sdk-s3/object_acl.rb +103 -25
  77. data/lib/aws-sdk-s3/object_copier.rb +9 -5
  78. data/lib/aws-sdk-s3/object_multipart_copier.rb +48 -22
  79. data/lib/aws-sdk-s3/object_summary.rb +2174 -204
  80. data/lib/aws-sdk-s3/object_version.rb +539 -80
  81. data/lib/aws-sdk-s3/plugins/accelerate.rb +17 -64
  82. data/lib/aws-sdk-s3/plugins/access_grants.rb +178 -0
  83. data/lib/aws-sdk-s3/plugins/arn.rb +70 -0
  84. data/lib/aws-sdk-s3/plugins/bucket_dns.rb +7 -43
  85. data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +20 -3
  86. data/lib/aws-sdk-s3/plugins/checksum_algorithm.rb +31 -0
  87. data/lib/aws-sdk-s3/plugins/dualstack.rb +7 -50
  88. data/lib/aws-sdk-s3/plugins/endpoints.rb +86 -0
  89. data/lib/aws-sdk-s3/plugins/expect_100_continue.rb +5 -4
  90. data/lib/aws-sdk-s3/plugins/express_session_auth.rb +88 -0
  91. data/lib/aws-sdk-s3/plugins/get_bucket_location_fix.rb +3 -1
  92. data/lib/aws-sdk-s3/plugins/http_200_errors.rb +62 -17
  93. data/lib/aws-sdk-s3/plugins/iad_regional_endpoint.rb +44 -0
  94. data/lib/aws-sdk-s3/plugins/location_constraint.rb +5 -1
  95. data/lib/aws-sdk-s3/plugins/md5s.rb +14 -70
  96. data/lib/aws-sdk-s3/plugins/redirects.rb +2 -0
  97. data/lib/aws-sdk-s3/plugins/s3_host_id.rb +2 -0
  98. data/lib/aws-sdk-s3/plugins/s3_signer.rb +63 -94
  99. data/lib/aws-sdk-s3/plugins/sse_cpk.rb +3 -1
  100. data/lib/aws-sdk-s3/plugins/streaming_retry.rb +139 -0
  101. data/lib/aws-sdk-s3/plugins/url_encoded_keys.rb +2 -0
  102. data/lib/aws-sdk-s3/presigned_post.rb +160 -99
  103. data/lib/aws-sdk-s3/presigner.rb +141 -62
  104. data/lib/aws-sdk-s3/resource.rb +156 -17
  105. data/lib/aws-sdk-s3/types.rb +13021 -4106
  106. data/lib/aws-sdk-s3/waiters.rb +67 -1
  107. data/lib/aws-sdk-s3.rb +46 -32
  108. data/sig/bucket.rbs +222 -0
  109. data/sig/bucket_acl.rbs +78 -0
  110. data/sig/bucket_cors.rbs +69 -0
  111. data/sig/bucket_lifecycle.rbs +88 -0
  112. data/sig/bucket_lifecycle_configuration.rbs +115 -0
  113. data/sig/bucket_logging.rbs +76 -0
  114. data/sig/bucket_notification.rbs +114 -0
  115. data/sig/bucket_policy.rbs +59 -0
  116. data/sig/bucket_request_payment.rbs +54 -0
  117. data/sig/bucket_tagging.rbs +65 -0
  118. data/sig/bucket_versioning.rbs +77 -0
  119. data/sig/bucket_website.rbs +93 -0
  120. data/sig/client.rbs +2472 -0
  121. data/sig/customizations/bucket.rbs +19 -0
  122. data/sig/customizations/object.rbs +38 -0
  123. data/sig/customizations/object_summary.rbs +35 -0
  124. data/sig/errors.rbs +42 -0
  125. data/sig/multipart_upload.rbs +120 -0
  126. data/sig/multipart_upload_part.rbs +109 -0
  127. data/sig/object.rbs +459 -0
  128. data/sig/object_acl.rbs +86 -0
  129. data/sig/object_summary.rbs +345 -0
  130. data/sig/object_version.rbs +143 -0
  131. data/sig/resource.rbs +134 -0
  132. data/sig/types.rbs +2712 -0
  133. data/sig/waiters.rbs +95 -0
  134. metadata +74 -15
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module S3
5
+ module Plugins
6
+ # @api private
7
+ class ExpressSessionAuth < Seahorse::Client::Plugin
8
+ # This should be s3_disable_express_auth instead
9
+ # But this is not a built in. We're overwriting the generated value
10
+ option(:disable_s3_express_session_auth,
11
+ default: false,
12
+ doc_type: 'Boolean',
13
+ docstring: <<-DOCS) do |cfg|
14
+ When `true`, S3 Express session authentication is disabled.
15
+ DOCS
16
+ resolve_disable_s3_express_session_auth(cfg)
17
+ end
18
+
19
+ option(:express_credentials_provider,
20
+ doc_type: 'Aws::S3::ExpressCredentialsProvider',
21
+ rbs_type: 'untyped',
22
+ docstring: <<-DOCS) do |_cfg|
23
+ Credential Provider for S3 Express endpoints. Manages credentials
24
+ for different buckets.
25
+ DOCS
26
+ Aws::S3::ExpressCredentialsProvider.new
27
+ end
28
+
29
+ # @api private
30
+ class Handler < Seahorse::Client::Handler
31
+ def call(context)
32
+ context[:s3_express_endpoint] = true if s3_express_endpoint?(context)
33
+
34
+ # if s3 express auth, use new credentials and sign additional header
35
+ if context[:auth_scheme]['name'] == 'sigv4-s3express' &&
36
+ !context.config.disable_s3_express_session_auth
37
+ bucket = context.params[:bucket]
38
+ credentials_provider = context.config.express_credentials_provider
39
+ credentials = credentials_provider.express_credentials_for(bucket)
40
+ context[:sigv4_credentials] = credentials # Sign will use this
41
+ end
42
+
43
+ with_metric(credentials) { @handler.call(context) }
44
+ end
45
+
46
+ private
47
+
48
+ def with_metric(credentials, &block)
49
+ return block.call unless credentials
50
+
51
+ Aws::Plugins::UserAgent.metric('S3_EXPRESS_BUCKET', &block)
52
+ end
53
+
54
+ def s3_express_endpoint?(context)
55
+ context[:endpoint_properties]['backend'] == 'S3Express'
56
+ end
57
+ end
58
+
59
+ handler(Handler)
60
+
61
+ # Optimization - sets this client as the client to create sessions.
62
+ def after_initialize(client)
63
+ provider = client.config.express_credentials_provider
64
+ provider.client = client unless provider.client
65
+ end
66
+
67
+ class << self
68
+ private
69
+
70
+ def resolve_disable_s3_express_session_auth(cfg)
71
+ value = ENV['AWS_S3_DISABLE_EXPRESS_SESSION_AUTH'] ||
72
+ Aws.shared_config.s3_disable_express_session_auth(profile: cfg.profile) ||
73
+ 'false'
74
+ value = Aws::Util.str_2_bool(value)
75
+ # Raise if provided value is not true or false
76
+ if value.nil?
77
+ raise ArgumentError,
78
+ 'Must provide either `true` or `false` for the '\
79
+ '`s3_disable_express_session_auth` profile option or for '\
80
+ "ENV['AWS_S3_DISABLE_EXPRESS_SESSION_AUTH']."
81
+ end
82
+ value
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins
@@ -9,7 +11,7 @@ module Aws
9
11
  @handler.call(context).on(200) do |response|
10
12
  response.data = S3::Types::GetBucketLocationOutput.new
11
13
  xml = context.http_response.body_contents
12
- matches = xml.match(/>(.+?)<\/LocationConstraint>/)
14
+ matches = xml.match(/<LocationConstraint.*?>(.+?)<\/LocationConstraint>/)
13
15
  response.data[:location_constraint] = matches ? matches[1] : ''
14
16
  end
15
17
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins
@@ -13,34 +15,77 @@ module Aws
13
15
 
14
16
  def call(context)
15
17
  @handler.call(context).on(200) do |response|
16
- if error = check_for_error(context)
17
- context.http_response.status_code = 500
18
- response.data = nil
19
- response.error = error
18
+ return response if streaming_output?(context.operation.output)
19
+
20
+ error = check_for_error(context)
21
+ return response unless error
22
+
23
+ context.http_response.status_code = 500
24
+ response.data = nil
25
+ response.error = error
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ # Streaming outputs are not subject to 200 errors.
32
+ def streaming_output?(output)
33
+ if (payload = output[:payload_member])
34
+ # checking ref and shape
35
+ payload['streaming'] || payload.shape['streaming'] ||
36
+ payload.eventstream
37
+ else
38
+ false
39
+ end
40
+ end
41
+
42
+ # Checks if the output shape is a structure shape and has members that
43
+ # are in the body for the case of a payload and a normal structure. A
44
+ # non-structure shape will not have members in the body. In the case
45
+ # of a string or blob, the body contents would have been checked first
46
+ # before this method is called in incomplete_xml_body?.
47
+ def members_in_body?(output)
48
+ shape =
49
+ if output[:payload_member]
50
+ output[:payload_member].shape
51
+ else
52
+ output.shape
20
53
  end
54
+
55
+ if structure_shape?(shape)
56
+ shape.members.any? { |_, k| k.location.nil? }
57
+ else
58
+ false
21
59
  end
22
60
  end
23
61
 
62
+ def structure_shape?(shape)
63
+ shape.is_a?(Seahorse::Model::Shapes::StructureShape)
64
+ end
65
+
66
+ # Must have a member in the body and have the start of an XML Tag.
67
+ # Other incomplete xml bodies will result in an XML ParsingError.
68
+ def incomplete_xml_body?(xml, output)
69
+ members_in_body?(output) && !xml.match(/<\w/)
70
+ end
71
+
24
72
  def check_for_error(context)
25
73
  xml = context.http_response.body_contents
26
- if xml.match(/<Error>/)
27
- error_code = xml.match(/<Code>(.+?)<\/Code>/)[1]
28
- error_message = xml.match(/<Message>(.+?)<\/Message>/)[1]
74
+ if xml.match(/<\?xml\s[^>]*\?>\s*<Error>/)
75
+ error_code = xml.match(%r{<Code>(.+?)</Code>})[1]
76
+ error_message = xml.match(%r{<Message>(.+?)</Message>})[1]
29
77
  S3::Errors.error_class(error_code).new(context, error_message)
78
+ elsif incomplete_xml_body?(xml, context.operation.output)
79
+ Seahorse::Client::NetworkingError.new(
80
+ S3::Errors
81
+ .error_class('InternalError')
82
+ .new(context, 'Empty or incomplete response body')
83
+ )
30
84
  end
31
85
  end
32
-
33
86
  end
34
87
 
35
- handler(Handler,
36
- step: :sign,
37
- operations: [
38
- :complete_multipart_upload,
39
- :copy_object,
40
- :upload_part_copy,
41
- ]
42
- )
43
-
88
+ handler(Handler, step: :sign)
44
89
  end
45
90
  end
46
91
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module S3
5
+ module Plugins
6
+
7
+ class IADRegionalEndpoint < Seahorse::Client::Plugin
8
+
9
+ option(:s3_us_east_1_regional_endpoint,
10
+ default: 'legacy',
11
+ doc_type: String,
12
+ docstring: <<-DOCS) do |cfg|
13
+ Pass in `regional` to enable the `us-east-1` regional endpoint.
14
+ Defaults to `legacy` mode which uses the global endpoint.
15
+ DOCS
16
+ resolve_iad_regional_endpoint(cfg)
17
+ end
18
+
19
+ private
20
+
21
+ def self.resolve_iad_regional_endpoint(cfg)
22
+ default_mode_value =
23
+ if cfg.respond_to?(:defaults_mode_config_resolver)
24
+ cfg.defaults_mode_config_resolver.resolve(:s3_us_east_1_regional_endpoint)
25
+ end
26
+
27
+ mode = ENV['AWS_S3_US_EAST_1_REGIONAL_ENDPOINT'] ||
28
+ Aws.shared_config.s3_us_east_1_regional_endpoint(profile: cfg.profile) ||
29
+ default_mode_value ||
30
+ 'legacy'
31
+ mode = mode.downcase
32
+ unless %w(legacy regional).include?(mode)
33
+ raise ArgumentError, "expected :s3_us_east_1_regional_endpoint or"\
34
+ " ENV['AWS_S3_US_EAST_1_REGIONAL_ENDPOINT'] to be `legacy` or"\
35
+ " `regional`."
36
+ end
37
+ mode
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins
@@ -20,7 +22,9 @@ module Aws
20
22
 
21
23
  def populate_location_constraint(params, region)
22
24
  params[:create_bucket_configuration] ||= {}
23
- params[:create_bucket_configuration][:location_constraint] ||= region
25
+ unless params[:create_bucket_configuration][:location]
26
+ params[:create_bucket_configuration][:location_constraint] ||= region
27
+ end
24
28
  end
25
29
 
26
30
  end
@@ -1,81 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'openssl'
2
- require 'base64'
3
4
 
4
5
  module Aws
5
6
  module S3
6
7
  module Plugins
8
+ # @api private
9
+ # This plugin is deprecated in favor of modeled
10
+ # httpChecksumRequired traits.
7
11
  class Md5s < Seahorse::Client::Plugin
8
-
9
- # Amazon S3 requires these operations to have an MD5 checksum
10
- REQUIRED_OPERATIONS = [
11
- :delete_objects,
12
- :put_bucket_cors,
13
- :put_bucket_lifecycle,
14
- :put_bucket_policy,
15
- :put_bucket_tagging,
16
- :put_object_legal_hold,
17
- :put_object_lock_configuration,
18
- :put_object_retention
19
- ]
20
-
21
- # @api private
22
- class Handler < Seahorse::Client::Handler
23
-
24
- CHUNK_SIZE = 1 * 1024 * 1024 # one MB
25
-
26
- def call(context)
27
- body = context.http_request.body
28
- if body.size > 0
29
- context.http_request.headers['Content-Md5'] ||= md5(body)
30
- end
31
- @handler.call(context)
32
- end
33
-
34
- private
35
-
36
- # @param [File, Tempfile, IO#read, String] value
37
- # @return [String<MD5>]
38
- def md5(value)
39
- if (File === value || Tempfile === value) && !value.path.nil? && File.exist?(value.path)
40
- Base64.encode64(OpenSSL::Digest::MD5.file(value).digest).strip
41
- elsif value.respond_to?(:read)
42
- md5 = OpenSSL::Digest::MD5.new
43
- update_in_chunks(md5, value)
44
- Base64.encode64(md5.digest).strip
45
- else
46
- Base64.encode64(OpenSSL::Digest::MD5.digest(value)).strip
47
- end
48
- end
49
-
50
- def update_in_chunks(digest, io)
51
- while chunk = io.read(CHUNK_SIZE, buffer ||= "")
52
- digest.update(chunk)
53
- end
54
- io.rewind
55
- end
56
-
57
- end
58
-
59
12
  option(:compute_checksums,
60
- default: true,
61
- doc_type: 'Boolean',
62
- docstring: <<-DOCS)
63
- When `true` a MD5 checksum will be computed for every request that
64
- sends a body. When `false`, MD5 checksums will only be computed
65
- for operations that require them. Checksum errors returned by Amazon
66
- S3 are automatically retried up to `:retry_limit` times.
67
- DOCS
68
-
69
- def add_handlers(handlers, config)
70
- # priority set low to ensure md5 is computed AFTER the request is
71
- # built but before it is signed
72
- handlers.add(Handler, {
73
- priority: 10,
74
- step: :build,
75
- operations: config.compute_checksums ? nil : REQUIRED_OPERATIONS,
76
- })
13
+ default: true,
14
+ doc_type: 'Boolean',
15
+ docstring: <<~DOCS)
16
+ This option is deprecated. Please use `:request_checksum_calculation` instead.
17
+ When `false`, `request_checksum_calculation` is overridden to `when_required`.
18
+ DOCS
19
+
20
+ def after_initialize(client)
21
+ client.config.request_checksum_calculation = 'when_required' unless client.config.compute_checksums
77
22
  end
78
-
79
23
  end
80
24
  end
81
25
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins
@@ -1,25 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'aws-sigv4'
2
4
 
3
5
  module Aws
4
6
  module S3
7
+ # @api private
8
+ def self.bucket_region_cache
9
+ @bucket_region_cache ||= BucketRegionCache.new
10
+ end
11
+
5
12
  module Plugins
6
- # This plugin is an implementation detail and may be modified.
13
+ # This plugin used to have a V4 signer but it was removed in favor of
14
+ # generic Sign plugin that uses endpoint auth scheme.
15
+ #
7
16
  # @api private
8
17
  class S3Signer < Seahorse::Client::Plugin
9
-
10
18
  option(:signature_version, 'v4')
11
19
 
12
- option(:sigv4_signer) do |cfg|
13
- S3Signer.build_v4_signer(
14
- region: cfg.sigv4_region,
15
- credentials: cfg.credentials
16
- )
17
- end
18
-
19
- option(:sigv4_region) do |cfg|
20
- Aws::Partitions::EndpointProvider.signing_region(cfg.region, 's3')
21
- end
22
-
23
20
  def add_handlers(handlers, cfg)
24
21
  case cfg.signature_version
25
22
  when 'v4' then add_v4_handlers(handlers)
@@ -32,11 +29,11 @@ module Aws
32
29
 
33
30
  def add_v4_handlers(handlers)
34
31
  handlers.add(CachedBucketRegionHandler, step: :sign, priority: 60)
35
- handlers.add(V4Handler, step: :sign)
36
32
  handlers.add(BucketRegionErrorHandler, step: :sign, priority: 40)
37
33
  end
38
34
 
39
35
  def add_legacy_handler(handlers)
36
+ # generic Sign plugin will be skipped if it sees sigv2
40
37
  handlers.add(LegacyHandler, step: :sign)
41
38
  end
42
39
 
@@ -47,40 +44,9 @@ module Aws
47
44
  end
48
45
  end
49
46
 
50
- class V4Handler < Seahorse::Client::Handler
51
-
52
- def call(context)
53
- Aws::Plugins::SignatureV4.apply_signature(
54
- context: context,
55
- signer: sigv4_signer(context)
56
- )
57
- @handler.call(context)
58
- end
59
-
60
- private
61
-
62
- def sigv4_signer(context)
63
- # If the client was configured with the wrong region,
64
- # we have to build a new signer.
65
- if
66
- context[:cached_sigv4_region] &&
67
- context[:cached_sigv4_region] != context.config.sigv4_signer.region
68
- then
69
- S3Signer.build_v4_signer(
70
- region: context[:cached_sigv4_region],
71
- credentials: context.config.credentials
72
- )
73
- else
74
- context.config.sigv4_signer
75
- end
76
- end
77
-
78
- end
79
-
80
47
  # This handler will update the http endpoint when the bucket region
81
48
  # is known/cached.
82
49
  class CachedBucketRegionHandler < Seahorse::Client::Handler
83
-
84
50
  def call(context)
85
51
  bucket = context.params[:bucket]
86
52
  check_for_cached_region(context, bucket) if bucket
@@ -90,21 +56,24 @@ module Aws
90
56
  private
91
57
 
92
58
  def check_for_cached_region(context, bucket)
93
- cached_region = S3::BUCKET_REGIONS[bucket]
94
- if cached_region && cached_region != context.config.region
95
- context.http_request.endpoint.host = S3Signer.new_hostname(context, cached_region)
96
- context[:cached_sigv4_region] = cached_region
59
+ cached_region = Aws::S3.bucket_region_cache[bucket]
60
+ if cached_region &&
61
+ cached_region != context.config.region &&
62
+ !S3Signer.custom_endpoint?(context)
63
+ context.http_request.endpoint.host = S3Signer.new_hostname(
64
+ context, cached_region
65
+ )
66
+ context[:sigv4_region] = cached_region # Sign plugin will use this
97
67
  end
98
68
  end
99
-
100
69
  end
101
70
 
102
71
  # This handler detects when a request fails because of a mismatched bucket
103
72
  # region. It follows up by making a request to determine the correct
104
73
  # region, then finally a version 4 signed request against the correct
105
- # regional endpoint.
74
+ # regional endpoint. This is intended for s3's global endpoint which
75
+ # will return 400 if the bucket is not in region.
106
76
  class BucketRegionErrorHandler < Seahorse::Client::Handler
107
-
108
77
  def call(context)
109
78
  response = @handler.call(context)
110
79
  handle_region_errors(response)
@@ -113,7 +82,10 @@ module Aws
113
82
  private
114
83
 
115
84
  def handle_region_errors(response)
116
- if wrong_sigv4_region?(response) && !fips_region?(response)
85
+ if wrong_sigv4_region?(response) &&
86
+ !fips_region?(response) &&
87
+ !S3Signer.custom_endpoint?(response.context) &&
88
+ !expired_credentials?(response)
117
89
  get_region_and_retry(response.context)
118
90
  else
119
91
  response
@@ -130,37 +102,42 @@ module Aws
130
102
  end
131
103
 
132
104
  def update_bucket_cache(context, actual_region)
133
- S3::BUCKET_REGIONS[context.params[:bucket]] = actual_region
105
+ Aws::S3.bucket_region_cache[context.params[:bucket]] = actual_region
134
106
  end
135
107
 
136
108
  def fips_region?(resp)
137
- resp.context.http_request.endpoint.host.include?('fips')
109
+ resp.context.http_request.endpoint.host.include?('s3-fips.')
110
+ end
111
+
112
+ def expired_credentials?(resp)
113
+ resp.context.http_response.body_contents.match(/<Code>ExpiredToken<\/Code>/)
138
114
  end
139
115
 
140
116
  def wrong_sigv4_region?(resp)
141
117
  resp.context.http_response.status_code == 400 &&
142
- (
143
- resp.context.http_response.headers['x-amz-bucket-region'] ||
144
- resp.context.http_response.body_contents.match(/<Region>.+?<\/Region>/)
145
- )
118
+ (resp.context.http_response.headers['x-amz-bucket-region'] ||
119
+ resp.context.http_response.body_contents.match(/<Region>.+?<\/Region>/))
146
120
  end
147
121
 
148
122
  def resign_with_new_region(context, actual_region)
149
123
  context.http_response.body.truncate(0)
150
- context.http_request.endpoint.host = S3Signer.new_hostname(context, actual_region)
124
+ context.http_request.endpoint.host = S3Signer.new_hostname(
125
+ context, actual_region
126
+ )
151
127
  context.metadata[:redirect_region] = actual_region
152
- Aws::Plugins::SignatureV4.apply_signature(
153
- context: context,
154
- signer: S3Signer.build_v4_signer(
155
- region: actual_region,
156
- credentials: context.config.credentials
157
- )
128
+
129
+ signer = Aws::Plugins::Sign.signer_for(
130
+ context[:auth_scheme],
131
+ context.config,
132
+ actual_region
158
133
  )
134
+
135
+ signer.sign(context)
159
136
  end
160
137
 
161
138
  def region_from_body(body)
162
139
  region = body.match(/<Region>(.+?)<\/Region>/)[1]
163
- if region.nil? || region == ""
140
+ if region.nil? || region == ''
164
141
  raise "couldn't get region from body: #{body}"
165
142
  else
166
143
  region
@@ -168,44 +145,36 @@ module Aws
168
145
  end
169
146
 
170
147
  def log_warning(context, actual_region)
171
- msg = "S3 client configured for #{context.config.region.inspect} " +
172
- "but the bucket #{context.params[:bucket].inspect} is in " +
173
- "#{actual_region.inspect}; Please configure the proper region " +
174
- "to avoid multiple unnecessary redirects and signing attempts\n"
175
- if logger = context.config.logger
148
+ msg = "S3 client configured for #{context.config.region.inspect} " \
149
+ "but the bucket #{context.params[:bucket].inspect} is in " \
150
+ "#{actual_region.inspect}; Please configure the proper region " \
151
+ "to avoid multiple unnecessary redirects and signing attempts\n"
152
+ if (logger = context.config.logger)
176
153
  logger.warn(msg)
177
154
  else
178
155
  warn(msg)
179
156
  end
180
157
  end
181
-
182
158
  end
183
159
 
184
160
  class << self
185
-
186
- # @option options [required, String] :region
187
- # @option options [required, #credentials] :credentials
188
- # @api private
189
- def build_v4_signer(options = {})
190
- Aws::Sigv4::Signer.new({
191
- service: 's3',
192
- region: options[:region],
193
- credentials_provider: options[:credentials],
194
- uri_escape_path: false,
195
- unsigned_headers: ['content-length', 'x-amzn-trace-id'],
196
- })
197
- end
198
-
199
161
  def new_hostname(context, region)
200
- bucket = context.params[:bucket]
201
- if region == 'us-east-1'
202
- "#{bucket}.s3.amazonaws.com"
203
- else
204
- endpoint = Aws::Partitions::EndpointProvider.resolve(region, 's3')
205
- bucket + '.' + URI.parse(endpoint).host
206
- end
162
+ endpoint_params = context[:endpoint_params].dup
163
+ endpoint_params.region = region
164
+ endpoint_params.endpoint = nil
165
+ endpoint =
166
+ context.config.endpoint_provider.resolve_endpoint(endpoint_params)
167
+ URI(endpoint.url).host
207
168
  end
208
169
 
170
+ def custom_endpoint?(context)
171
+ region = context.config.region
172
+ partition = Aws::Endpoints::Matchers.aws_partition(region)
173
+ endpoint = context.http_request.endpoint
174
+
175
+ !endpoint.hostname.include?(partition['dnsSuffix']) &&
176
+ !endpoint.hostname.include?(partition['dualStackDnsSuffix'])
177
+ end
209
178
  end
210
179
  end
211
180
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'uri'
2
4
  require 'openssl'
3
5
 
@@ -18,7 +20,7 @@ This should only be disabled for local testing.
18
20
  class Handler < Seahorse::Client::Handler
19
21
 
20
22
  def call(context)
21
- compute_key_md5(context)
23
+ compute_key_md5(context) if context.params.is_a?(Hash)
22
24
  @handler.call(context)
23
25
  end
24
26