aws-sdk-s3 1.148.0 → 1.149.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c817bc8207d8500bc9331e8198e5fcee84802db7a7befa3373f80a79b938b8d2
4
- data.tar.gz: f3075c172289429810da25563688c1bd707087dd144ab91ff9a8c9b22d6187ac
3
+ metadata.gz: f7e829d836e606576346cf328245de26a473222ab50d8d8b7fbbecc88efebb92
4
+ data.tar.gz: bcf4d589ca8ae7caebd3f1ea07da416ed3c01221309dbd27768313173c96ba70
5
5
  SHA512:
6
- metadata.gz: 6518f064b5d92e529bb21882b4fda44335ff8eaaa07785c9148269557a1137f81a09e07fe6b613098875160c68e9b4224930607e6bf16bf8f4394070402a4926
7
- data.tar.gz: 3f02bef2de6fda4e5353bfad855bf97322cd92ce5d0f1d37f5ecbb4ba425600c3c8f731bd29adb24dea4e14f81c921fc536014b26af48753ee3d71917a14a466
6
+ metadata.gz: 79cbefd5b7c02a53da10516def3cb467a379074f9eebfbdbbec29d440101bb9331f79c9cd6369fbdde56c65ba724a431cf6931f9630e121416ab2251ef672ddc
7
+ data.tar.gz: 174a2ad0bb115e7d13c5d97131d2ed6338ce26f8e24fa40aa7708ecb4015d6ac5ea354e04461443097317236dd1803bac8161d17dc7013b6471c88fe79328e21
data/CHANGELOG.md CHANGED
@@ -1,6 +1,18 @@
1
1
  Unreleased Changes
2
2
  ------------------
3
3
 
4
+ 1.149.1 (2024-05-06)
5
+ ------------------
6
+
7
+ * Issue - Fix bug where destination bucket default encryption was inadvertently overridden by source object encryption.
8
+
9
+ 1.149.0 (2024-04-30)
10
+ ------------------
11
+
12
+ * Feature - Support S3 Access Grants authentication. Access Grants can be enabled with the `access_grants` option, and custom options can be passed into the `access_grants_credentials_provider` option. This feature requires `aws-sdk-s3control` to be installed.
13
+
14
+ * Feature - Add RBS signatures for customizations of S3.
15
+
4
16
  1.148.0 (2024-04-25)
5
17
  ------------------
6
18
 
@@ -38,7 +50,6 @@ Unreleased Changes
38
50
 
39
51
  * Issue - Include original part errors in message when aborting multipart upload fails (#2990).
40
52
 
41
-
42
53
  1.143.0 (2024-01-26)
43
54
  ------------------
44
55
 
@@ -161,7 +172,7 @@ Unreleased Changes
161
172
  1.123.2 (2023-06-12)
162
173
  ------------------
163
174
 
164
- * Issue - Fix issue when decrypting noncurrent versions of objects when using client side encryption (#2866).
175
+ * Issue - Fix issue when decrypting noncurrent versions of objects when using client side encryption (#2866).
165
176
 
166
177
  1.123.1 (2023-06-02)
167
178
  ------------------
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.148.0
1
+ 1.149.1
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module Aws
6
+ module S3
7
+ # @api private
8
+ class AccessGrantsCredentials
9
+ include CredentialProvider
10
+ include RefreshingCredentials
11
+
12
+ def initialize(options = {})
13
+ @client = options[:client]
14
+ @get_data_access_params = {}
15
+ options.each_pair do |key, value|
16
+ if self.class.get_data_access_options.include?(key)
17
+ @get_data_access_params[key] = value
18
+ end
19
+ end
20
+ @async_refresh = true
21
+ super
22
+ end
23
+
24
+ # @return [S3Control::Client]
25
+ attr_reader :client
26
+
27
+ # @return [String]
28
+ attr_reader :matched_grant_target
29
+
30
+ private
31
+
32
+ def refresh
33
+ c = @client.get_data_access(@get_data_access_params)
34
+ credentials = c.credentials
35
+ @matched_grant_target = c.matched_grant_target
36
+ @credentials = Credentials.new(
37
+ credentials.access_key_id,
38
+ credentials.secret_access_key,
39
+ credentials.session_token
40
+ )
41
+ @expiration = credentials.expiration
42
+ end
43
+
44
+ class << self
45
+
46
+ # @api private
47
+ def get_data_access_options
48
+ @gdao ||= begin
49
+ input = Aws::S3Control::Client.api.operation(:get_data_access).input
50
+ Set.new(input.shape.member_names)
51
+ end
52
+ end
53
+
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,241 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module S3
5
+ # @api private
6
+ def self.access_grants_credentials_cache
7
+ @access_grants_credentials_cache ||= LRUCache.new(max_entries: 100)
8
+ end
9
+
10
+ # @api private
11
+ def self.access_grants_account_id_cache
12
+ @access_grants_account_id_cache ||= LRUCache.new(
13
+ max_entries: 100,
14
+ expiration: 60 * 10
15
+ )
16
+ end
17
+
18
+ # Returns Credentials class for S3 Access Grants. Accepts GetDataAccess
19
+ # params and other configuration as options. See
20
+ # {Aws::S3Control::Client#get_data_access} for details.
21
+ class AccessGrantsCredentialsProvider
22
+ # @param [Hash] options
23
+ # @option options [Hash] :s3_control_client_options The S3 Control
24
+ # client options used to create regional S3 Control clients to
25
+ # create the session. Region will be set to the region of the
26
+ # bucket.
27
+ # @option options [Aws::STS::Client] :sts_client The STS client used for
28
+ # fetching the Account ID for the credentials if credentials do not
29
+ # include an Account ID.
30
+ # @option options [Aws::S3::Client] :s3_client The S3 client used for
31
+ # fetching the location of the bucket so that a regional S3 Control
32
+ # client can be created. Defaults to the S3 client from the access
33
+ # grants plugin.
34
+ # @option options [String] :privilege ('Default') The privilege to use
35
+ # when requesting credentials. (see: {Aws::S3Control::Client#get_data_access})
36
+ # @option options [Boolean] :fallback (false) When true, if access is
37
+ # denied, the provider will fall back to the configured credentials.
38
+ # @option options [Boolean] :caching (true) When true, credentials and
39
+ # bucket account ids will be cached.
40
+ # @option options [Callable] :before_refresh Proc called before
41
+ # credentials are refreshed.
42
+ def initialize(options = {})
43
+ @s3_control_options = options.delete(:s3_control_client_options) || {}
44
+ @s3_client = options.delete(:s3_client)
45
+ @sts_client = options.delete(:sts_client)
46
+ @fallback = options.delete(:fallback) || false
47
+ @caching = options.delete(:caching) != false
48
+ @s3_control_clients = {}
49
+ @bucket_region_cache = Aws::S3.bucket_region_cache
50
+ return unless @caching
51
+
52
+ @credentials_cache = Aws::S3.access_grants_credentials_cache
53
+ @account_id_cache = Aws::S3.access_grants_account_id_cache
54
+ end
55
+
56
+ def access_grants_credentials_for(options = {})
57
+ target = target_prefix(
58
+ options[:bucket],
59
+ options[:key],
60
+ options[:prefix]
61
+ )
62
+ credentials = s3_client.config.credentials.credentials # resolves
63
+
64
+ if @caching
65
+ cached_credentials_for(target, options[:permission], credentials)
66
+ else
67
+ new_credentials_for(target, options[:permission], credentials)
68
+ end
69
+ rescue Aws::S3Control::Errors::AccessDenied
70
+ raise unless @fallback
71
+
72
+ warn 'Access denied for S3 Access Grants. Falling back to ' \
73
+ 'configured credentials.'
74
+ s3_client.config.credentials
75
+ end
76
+
77
+ attr_accessor :s3_client
78
+
79
+ private
80
+
81
+ def s3_control_client(bucket_region)
82
+ @s3_control_clients[bucket_region] ||= begin
83
+ credentials = s3_client.config.credentials
84
+ config = { credentials: credentials }.merge(@s3_control_options)
85
+ Aws::S3Control::Client.new(config.merge(
86
+ region: bucket_region,
87
+ use_fips_endpoint: s3_client.config.use_fips_endpoint,
88
+ use_dualstack_endpoint: s3_client.config.use_dualstack_endpoint
89
+ ))
90
+ end
91
+ end
92
+
93
+ def cached_credentials_for(target, permission, credentials)
94
+ cached_creds = broad_search_credentials_cache_prefix(target, permission, credentials)
95
+ return cached_creds if cached_creds
96
+
97
+ if %w[READ WRITE].include?(permission)
98
+ cached_creds = broad_search_credentials_cache_prefix(target, 'READWRITE', credentials)
99
+ return cached_creds if cached_creds
100
+ end
101
+
102
+ cached_creds = broad_search_credentials_cache_characters(target, permission, credentials)
103
+ return cached_creds if cached_creds
104
+
105
+ if %w[READ WRITE].include?(permission)
106
+ cached_creds = broad_search_credentials_cache_characters(target, 'READWRITE', credentials)
107
+ return cached_creds if cached_creds
108
+ end
109
+
110
+ creds = new_credentials_for(target, permission, credentials)
111
+ if creds.matched_grant_target.end_with?('*')
112
+ # remove /* from the end of the target
113
+ key = credentials_cache_key(creds.matched_grant_target[0...-2], permission, credentials)
114
+ @credentials_cache[key] = creds
115
+ end
116
+
117
+ creds
118
+ end
119
+
120
+ def broad_search_credentials_cache_prefix(target, permission, credentials)
121
+ prefix = target
122
+ while prefix != 's3:'
123
+ key = credentials_cache_key(prefix, permission, credentials)
124
+ return @credentials_cache[key] if @credentials_cache.key?(key)
125
+
126
+ prefix = prefix.split('/', -1)[0..-2].join('/')
127
+ end
128
+ nil
129
+ end
130
+
131
+ def broad_search_credentials_cache_characters(target, permission, credentials)
132
+ prefix = target
133
+ while prefix != 's3://'
134
+ key = credentials_cache_key("#{prefix}*", permission, credentials)
135
+ return @credentials_cache[key] if @credentials_cache.key?(key)
136
+
137
+ prefix = prefix[0..-2]
138
+ end
139
+ nil
140
+ end
141
+
142
+ def new_credentials_for(target, permission, credentials)
143
+ bucket_region = bucket_region_for_access_grants(target)
144
+ client = s3_control_client(bucket_region)
145
+
146
+ AccessGrantsCredentials.new(
147
+ target: target,
148
+ account_id: account_id_for_access_grants(target, credentials),
149
+ permission: permission,
150
+ client: client
151
+ )
152
+ end
153
+
154
+ def account_id_for_access_grants(target, credentials)
155
+ if @caching
156
+ cached_account_id_for(target, credentials)
157
+ else
158
+ new_account_id_for(target, credentials)
159
+ end
160
+ end
161
+
162
+ def cached_account_id_for(target, credentials)
163
+ bucket = bucket_name_from(target)
164
+
165
+ if @account_id_cache.key?(bucket)
166
+ @account_id_cache[bucket]
167
+ else
168
+ @account_id_cache[bucket] = new_account_id_for(target, credentials)
169
+ end
170
+ end
171
+
172
+ # returns the account id associated with the access grants instance
173
+ def new_account_id_for(target, credentials)
174
+ bucket_region = bucket_region_for_access_grants(target)
175
+ s3_control_client = s3_control_client(bucket_region)
176
+ resp = s3_control_client.get_access_grants_instance_for_prefix(
177
+ s3_prefix: target,
178
+ account_id: account_id_for_credentials(bucket_region, credentials)
179
+ )
180
+ ARNParser.parse(resp.access_grants_instance_arn).account_id
181
+ end
182
+
183
+ def bucket_region_for_access_grants(target)
184
+ bucket = bucket_name_from(target)
185
+ # regardless of caching option, bucket region cache is always shared
186
+ cached_bucket_region_for(bucket)
187
+ end
188
+
189
+ def cached_bucket_region_for(bucket)
190
+ if @bucket_region_cache.key?(bucket)
191
+ @bucket_region_cache[bucket]
192
+ else
193
+ @bucket_region_cache[bucket] = new_bucket_region_for(bucket)
194
+ end
195
+ end
196
+
197
+ def new_bucket_region_for(bucket)
198
+ @s3_client.head_bucket(bucket: bucket).bucket_region
199
+ rescue Aws::S3::Errors::Http301Error => e
200
+ e.data.region
201
+ end
202
+
203
+ # returns the account id for the configured credentials
204
+ def account_id_for_credentials(region, credentials)
205
+ # use resolved credentials to check for account id
206
+ if credentials.respond_to?(:account_id) && credentials.account_id &&
207
+ !credentials.account_id.empty?
208
+ credentials.account_id
209
+ else
210
+ @sts_client ||= Aws::STS::Client.new(
211
+ credentials: s3_client.config.credentials,
212
+ region: region,
213
+ use_fips_endpoint: s3_client.config.use_fips_endpoint,
214
+ use_dualstack_endpoint: s3_client.config.use_dualstack_endpoint
215
+ )
216
+ @sts_client.get_caller_identity.account
217
+ end
218
+ end
219
+
220
+ def target_prefix(bucket, key, prefix)
221
+ if key && !key.empty?
222
+ "s3://#{bucket}/#{key}"
223
+ elsif prefix && !prefix.empty?
224
+ "s3://#{bucket}/#{prefix}"
225
+ else
226
+ "s3://#{bucket}/*"
227
+ end
228
+ end
229
+
230
+ def credentials_cache_key(target, permission, credentials)
231
+ "#{credentials.access_key_id}-#{credentials.secret_access_key}" \
232
+ "-#{permission}-#{target}"
233
+ end
234
+
235
+ # extracts bucket name from target prefix
236
+ def bucket_name_from(target)
237
+ URI(target).host
238
+ end
239
+ end
240
+ end
241
+ end
@@ -15,7 +15,7 @@ module Aws
15
15
  # Registers a block as a callback. This listener is called when a
16
16
  # new bucket/region pair is added to the cache.
17
17
  #
18
- # S3::BUCKET_REGIONS.bucket_added do |bucket_name, region_name|
18
+ # Aws::S3.bucket_region_cache.bucket_added do |bucket_name, region_name|
19
19
  # # ...
20
20
  # end
21
21
  #
@@ -59,6 +59,14 @@ module Aws
59
59
  end
60
60
  end
61
61
 
62
+ # @param [String] key
63
+ # @return [Boolean]
64
+ def key?(key)
65
+ @mutex.synchronize do
66
+ @regions.key?(key)
67
+ end
68
+ end
69
+
62
70
  # @api private
63
71
  def clear
64
72
  @mutex.synchronize { @regions = {} }
@@ -73,9 +81,5 @@ module Aws
73
81
  alias to_h to_hash
74
82
 
75
83
  end
76
-
77
- # @api private
78
- BUCKET_REGIONS = BucketRegionCache.new
79
-
80
84
  end
81
85
  end
@@ -35,6 +35,7 @@ require 'aws-sdk-core/plugins/recursion_detection.rb'
35
35
  require 'aws-sdk-core/plugins/sign.rb'
36
36
  require 'aws-sdk-core/plugins/protocols/rest_xml.rb'
37
37
  require 'aws-sdk-s3/plugins/accelerate.rb'
38
+ require 'aws-sdk-s3/plugins/access_grants.rb'
38
39
  require 'aws-sdk-s3/plugins/arn.rb'
39
40
  require 'aws-sdk-s3/plugins/bucket_dns.rb'
40
41
  require 'aws-sdk-s3/plugins/bucket_name_restrictions.rb'
@@ -106,6 +107,7 @@ module Aws::S3
106
107
  add_plugin(Aws::Plugins::Sign)
107
108
  add_plugin(Aws::Plugins::Protocols::RestXml)
108
109
  add_plugin(Aws::S3::Plugins::Accelerate)
110
+ add_plugin(Aws::S3::Plugins::AccessGrants)
109
111
  add_plugin(Aws::S3::Plugins::ARN)
110
112
  add_plugin(Aws::S3::Plugins::BucketDns)
111
113
  add_plugin(Aws::S3::Plugins::BucketNameRestrictions)
@@ -186,6 +188,16 @@ module Aws::S3
186
188
  # * `~/.aws/credentials`
187
189
  # * `~/.aws/config`
188
190
  #
191
+ # @option options [Boolean] :access_grants (false)
192
+ # When `true`, the S3 client will use the S3 Access Grants feature to
193
+ # authenticate requests. Bucket credentials will be fetched from S3
194
+ # Control using the `get_data_access` API.
195
+ #
196
+ # @option options [Aws::S3::AccessGrantsCredentialsProvider] :access_grants_credentials_provider
197
+ # When `access_grants` is `true`, this option can be used to provide
198
+ # additional options to the credentials provider, including a privilege
199
+ # setting, caching, and fallback behavior.
200
+ #
189
201
  # @option options [String] :access_key_id
190
202
  #
191
203
  # @option options [Boolean] :active_endpoint_cache (false)
@@ -18815,7 +18827,7 @@ module Aws::S3
18815
18827
  params: params,
18816
18828
  config: config)
18817
18829
  context[:gem_name] = 'aws-sdk-s3'
18818
- context[:gem_version] = '1.148.0'
18830
+ context[:gem_version] = '1.149.1'
18819
18831
  Seahorse::Client::Request.new(handlers, context)
18820
18832
  end
18821
18833
 
@@ -3,8 +3,8 @@
3
3
  module Aws
4
4
  module S3
5
5
  module Errors
6
- # Hijack PermanentRedirect dynamic error to also include endpoint
7
- # and bucket.
6
+ # Hijack PermanentRedirect dynamic error to include the bucket, region,
7
+ # and endpoint.
8
8
  class PermanentRedirect < ServiceError
9
9
  # @param [Seahorse::Client::RequestContext] context
10
10
  # @param [String] message
@@ -22,6 +22,19 @@ module Aws
22
22
  super(context, message, data)
23
23
  end
24
24
  end
25
+
26
+ # Hijack PermanentRedirect (HeadBucket case - no body) dynamic error to
27
+ # include the region.
28
+ class Http301Error < ServiceError
29
+ # @param [Seahorse::Client::RequestContext] context
30
+ # @param [String] message
31
+ # @param [Aws::S3::Types::PermanentRedirect] _data
32
+ def initialize(context, message, _data = Aws::EmptyStructure.new)
33
+ data = Aws::S3::Types::PermanentRedirect.new(message: message)
34
+ data.region = context.http_response.headers['x-amz-bucket-region']
35
+ super(context, message, data)
36
+ end
37
+ end
25
38
  end
26
39
  end
27
40
  end
@@ -18,9 +18,12 @@ require 'aws-sdk-s3/presigner'
18
18
 
19
19
  # s3 express session auth
20
20
  require 'aws-sdk-s3/express_credentials'
21
- require 'aws-sdk-s3/express_credentials_cache'
22
21
  require 'aws-sdk-s3/express_credentials_provider'
23
22
 
23
+ # s3 access grants auth
24
+ require 'aws-sdk-s3/access_grants_credentials'
25
+ require 'aws-sdk-s3/access_grants_credentials_provider'
26
+
24
27
  # customizations to generated classes
25
28
  require 'aws-sdk-s3/customizations/bucket'
26
29
  require 'aws-sdk-s3/customizations/errors'
@@ -2,30 +2,53 @@
2
2
 
3
3
  module Aws
4
4
  module S3
5
+ # @api private
6
+ def self.express_credentials_cache
7
+ @express_credentials_cache ||= LRUCache.new(max_entries: 100)
8
+ end
9
+
5
10
  # Returns Credentials class for S3 Express. Accepts CreateSession
6
11
  # params as options. See {Client#create_session} for details.
7
12
  class ExpressCredentialsProvider
8
13
  # @param [Hash] options
9
- # @option options [Client] :client The S3 client used to create the session.
14
+ # @option options [Client] :client The S3 client used to create the
15
+ # session.
10
16
  # @option options [String] :session_mode (see: {Client#create_session})
17
+ # @option options [Boolean] :caching (true) When true, credentials will
18
+ # be cached.
11
19
  # @option options [Callable] :before_refresh Proc called before
12
20
  # credentials are refreshed.
13
21
  def initialize(options = {})
14
22
  @client = options.delete(:client)
23
+ @caching = options.delete(:caching) != false
15
24
  @options = options
16
- @cache = EXPRESS_CREDENTIALS_CACHE
25
+ return unless @caching
26
+
27
+ @cache = Aws::S3.express_credentials_cache
17
28
  end
18
29
 
19
30
  def express_credentials_for(bucket)
20
- @cache[bucket] || new_credentials_for(bucket)
31
+ if @caching
32
+ cached_credentials_for(bucket)
33
+ else
34
+ new_credentials_for(bucket)
35
+ end
21
36
  end
22
37
 
23
38
  attr_accessor :client
24
39
 
25
40
  private
26
41
 
42
+ def cached_credentials_for(bucket)
43
+ if @cache.key?(bucket)
44
+ @cache[bucket]
45
+ else
46
+ @cache[bucket] = new_credentials_for(bucket)
47
+ end
48
+ end
49
+
27
50
  def new_credentials_for(bucket)
28
- @cache[bucket] = ExpressCredentials.new(
51
+ ExpressCredentials.new(
29
52
  bucket: bucket,
30
53
  client: @client,
31
54
  **@options
@@ -138,9 +138,7 @@ module Aws
138
138
  end
139
139
 
140
140
  def source_metadata(options)
141
- if options[:content_length]
142
- return { content_length: options.delete(:content_length) }
143
- end
141
+ return options.slice(:content_length) if options[:content_length]
144
142
 
145
143
  client = options[:copy_source_client] || @client
146
144
 
@@ -150,11 +148,15 @@ module Aws
150
148
  bucket, key = options[:copy_source].match(/([^\/]+?)\/(.+)/)[1,2]
151
149
  end
152
150
 
153
- key = CGI.unescape(key)
154
- opts = { bucket: bucket, key: key }
155
- opts[:version_id] = version_id if version_id
156
- opts[:part_number] = options[:part_number] if options[:part_number]
157
- client.head_object(opts).to_h
151
+ head_opts = { bucket: bucket, key: CGI.unescape(key) }.tap { |opts|
152
+ opts[:version_id] = version_id if version_id
153
+ opts[:part_number] = options[:part_number] if options[:part_number]
154
+ }
155
+
156
+ client.head_object(head_opts).to_h.tap { |head|
157
+ head.delete(:server_side_encryption)
158
+ head.delete(:ssekms_key_id)
159
+ }
158
160
  end
159
161
 
160
162
  def default_part_size(source_size)
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module S3
5
+ module Plugins
6
+ # @api private
7
+ class AccessGrants < Seahorse::Client::Plugin
8
+ @s3control =
9
+ begin
10
+ require 'aws-sdk-s3control'
11
+ true
12
+ rescue LoadError
13
+ false
14
+ end
15
+
16
+ option(
17
+ :access_grants,
18
+ default: false,
19
+ doc_type: 'Boolean',
20
+ docstring: <<-DOCS)
21
+ When `true`, the S3 client will use the S3 Access Grants feature to
22
+ authenticate requests. Bucket credentials will be fetched from S3
23
+ Control using the `get_data_access` API.
24
+ DOCS
25
+
26
+ option(:access_grants_credentials_provider,
27
+ doc_type: 'Aws::S3::AccessGrantsCredentialsProvider',
28
+ rbs_type: 'untyped',
29
+ docstring: <<-DOCS) do |_cfg|
30
+ When `access_grants` is `true`, this option can be used to provide
31
+ additional options to the credentials provider, including a privilege
32
+ setting, caching, and fallback behavior.
33
+ DOCS
34
+ Aws::S3::AccessGrantsCredentialsProvider.new
35
+ end
36
+
37
+ # @api private
38
+ class Handler < Seahorse::Client::Handler
39
+ PERMISSION_MAP = {
40
+ head_object: 'READ',
41
+ get_object: 'READ',
42
+ get_object_acl: 'READ',
43
+ list_multipart_uploads: 'READ',
44
+ list_objects_v2: 'READ',
45
+ list_object_versions: 'READ',
46
+ list_parts: 'READ',
47
+ put_object: 'WRITE',
48
+ put_object_acl: 'WRITE',
49
+ delete_object: 'WRITE',
50
+ abort_multipart_upload: 'WRITE',
51
+ create_multipart_upload: 'WRITE',
52
+ upload_part: 'WRITE',
53
+ complete_multipart_upload: 'WRITE'
54
+ }.freeze
55
+
56
+ def call(context)
57
+ if access_grants_operation?(context) &&
58
+ !s3_express_endpoint?(context)
59
+ params = context[:endpoint_params]
60
+ permission = PERMISSION_MAP[context.operation_name]
61
+
62
+ provider = context.config.access_grants_credentials_provider
63
+ credentials = provider.access_grants_credentials_for(
64
+ bucket: params[:bucket],
65
+ key: params[:key],
66
+ prefix: params[:prefix],
67
+ permission: permission
68
+ )
69
+ context[:sigv4_credentials] = credentials # Sign will use this
70
+ end
71
+
72
+ @handler.call(context)
73
+ end
74
+
75
+ private
76
+
77
+ def access_grants_operation?(context)
78
+ params = context[:endpoint_params]
79
+ params[:bucket] && PERMISSION_MAP[context.operation_name]
80
+ end
81
+
82
+ def s3_express_endpoint?(context)
83
+ context[:endpoint_properties]['backend'] == 'S3Express'
84
+ end
85
+ end
86
+
87
+ def add_handlers(handlers, config)
88
+ return unless AccessGrants.s3control? && config.access_grants
89
+
90
+ handlers.add(Handler)
91
+ end
92
+
93
+ def after_initialize(client)
94
+ return unless AccessGrants.s3control? && client.config.access_grants
95
+
96
+ provider = client.config.access_grants_credentials_provider
97
+ provider.s3_client = client unless provider.s3_client
98
+ end
99
+
100
+ class << self
101
+ def s3control?
102
+ @s3control
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -31,7 +31,7 @@ for different buckets.
31
31
  def call(context)
32
32
  if (props = context[:endpoint_properties])
33
33
  # S3 Express endpoint - turn off md5 and enable crc32 default
34
- if (backend = props['backend']) && backend == 'S3Express'
34
+ if props['backend'] == 'S3Express'
35
35
  if context.operation_name == :put_object || checksum_required?(context)
36
36
  context[:default_request_checksum_algorithm] = 'CRC32'
37
37
  end
@@ -4,6 +4,11 @@ require 'aws-sigv4'
4
4
 
5
5
  module Aws
6
6
  module S3
7
+ # @api private
8
+ def self.bucket_region_cache
9
+ @bucket_region_cache ||= BucketRegionCache.new
10
+ end
11
+
7
12
  module Plugins
8
13
  # This plugin used to have a V4 signer but it was removed in favor of
9
14
  # generic Sign plugin that uses endpoint auth scheme.
@@ -51,7 +56,7 @@ module Aws
51
56
  private
52
57
 
53
58
  def check_for_cached_region(context, bucket)
54
- cached_region = S3::BUCKET_REGIONS[bucket]
59
+ cached_region = Aws::S3.bucket_region_cache[bucket]
55
60
  if cached_region &&
56
61
  cached_region != context.config.region &&
57
62
  !S3Signer.custom_endpoint?(context)
@@ -97,7 +102,7 @@ module Aws
97
102
  end
98
103
 
99
104
  def update_bucket_cache(context, actual_region)
100
- S3::BUCKET_REGIONS[context.params[:bucket]] = actual_region
105
+ Aws::S3.bucket_region_cache[context.params[:bucket]] = actual_region
101
106
  end
102
107
 
103
108
  def fips_region?(resp)
data/lib/aws-sdk-s3.rb CHANGED
@@ -73,6 +73,6 @@ require_relative 'aws-sdk-s3/event_streams'
73
73
  # @!group service
74
74
  module Aws::S3
75
75
 
76
- GEM_VERSION = '1.148.0'
76
+ GEM_VERSION = '1.149.1'
77
77
 
78
78
  end
data/sig/client.rbs CHANGED
@@ -14,6 +14,8 @@ module Aws
14
14
  def self.new: (
15
15
  ?credentials: untyped,
16
16
  ?region: String,
17
+ ?access_grants: bool,
18
+ ?access_grants_credentials_provider: untyped,
17
19
  ?access_key_id: String,
18
20
  ?active_endpoint_cache: bool,
19
21
  ?adaptive_retry_wait_to_fill: bool,
@@ -0,0 +1,19 @@
1
+ module Aws
2
+ module S3
3
+ class Bucket
4
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Bucket.html#clear!-instance_method
5
+ def clear!: () -> void
6
+
7
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Bucket.html#delete!-instance_method
8
+ def delete!: (?max_attempts: ::Integer, ?initial_wait: ::Float) -> void
9
+ | (?Hash[Symbol, untyped]) -> void
10
+
11
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Bucket.html#url-instance_method
12
+ def url: (?virtual_host: boolish, ?secure: boolish) -> String
13
+ | (?Hash[Symbol, untyped]) -> String
14
+
15
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Bucket.html#presigned_post-instance_method
16
+ def presigned_post: (Hash[Symbol, untyped]) -> untyped
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,38 @@
1
+ module Aws
2
+ module S3
3
+ class Object
4
+ alias size content_length
5
+
6
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#copy_from-instance_method
7
+ def copy_from: (untyped source, ?Hash[Symbol, untyped] options) -> void
8
+ | ...
9
+
10
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#copy_to-instance_method
11
+ def copy_to: (untyped target, ?Hash[Symbol, untyped] options) -> void
12
+
13
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#move_to-instance_method
14
+ def move_to: (untyped target, ?Hash[Symbol, untyped] options) -> void
15
+
16
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#presigned_post-instance_method
17
+ def presigned_post: (?Hash[Symbol, untyped]) -> untyped
18
+
19
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#presigned_url-instance_method
20
+ def presigned_url: (Symbol | String method, ?Hash[Symbol, untyped] params) -> String
21
+
22
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#presigned_request-instance_method
23
+ def presigned_request: (Symbol | String method, ?Hash[Symbol, untyped] params) -> [String, Hash[String, String]]
24
+
25
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#public_url-instance_method
26
+ def public_url: (?Hash[Symbol, untyped] options) -> String
27
+
28
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#upload_stream-instance_method
29
+ def upload_stream: (?Hash[Symbol, untyped] options) { (IO write_stream) -> void } -> bool
30
+
31
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#upload_file-instance_method
32
+ def upload_file: (untyped source, ?Hash[Symbol, untyped] options) ?{ (untyped response) -> void } -> bool
33
+
34
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#download_file-instance_method
35
+ def download_file: (String destination, ?Hash[Symbol, untyped] options) -> bool
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,35 @@
1
+ module Aws
2
+ module S3
3
+ class ObjectSummary
4
+ alias content_length size
5
+
6
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/ObjectSummary.html#copy_from-instance_method
7
+ def copy_from: (untyped source, ?Hash[Symbol, untyped] options) -> void
8
+ | ...
9
+
10
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/ObjectSummary.html#copy_to-instance_method
11
+ def copy_to: (untyped target, ?Hash[Symbol, untyped] options) -> void
12
+
13
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/ObjectSummary.html#move_to-instance_method
14
+ def move_to: (untyped target, ?Hash[Symbol, untyped] options) -> void
15
+
16
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/ObjectSummary.html#presigned_post-instance_method
17
+ def presigned_post: (Hash[Symbol, untyped]) -> untyped
18
+
19
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/ObjectSummary.html#presigned_url-instance_method
20
+ def presigned_url: (Symbol | String method, ?Hash[Symbol, untyped] params) -> String
21
+
22
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/ObjectSummary.html#public_url-instance_method
23
+ def public_url: (?Hash[Symbol, untyped] options) -> String
24
+
25
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/ObjectSummary.html#upload_file-instance_method
26
+ def upload_file: (untyped source, ?Hash[Symbol, untyped] options) ?{ (untyped response) -> void } -> bool
27
+
28
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/ObjectSummary.html#upload_stream-instance_method
29
+ def upload_stream: (?Hash[Symbol, untyped] options) { (IO write_stream) -> void } -> bool
30
+
31
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/ObjectSummary.html#download_file-instance_method
32
+ def download_file: (String destination, ?Hash[Symbol, untyped] options) -> bool
33
+ end
34
+ end
35
+ end
data/sig/resource.rbs CHANGED
@@ -14,6 +14,8 @@ module Aws
14
14
  ?client: Client,
15
15
  ?credentials: untyped,
16
16
  ?region: String,
17
+ ?access_grants: bool,
18
+ ?access_grants_credentials_provider: untyped,
17
19
  ?access_key_id: String,
18
20
  ?active_endpoint_cache: bool,
19
21
  ?adaptive_retry_wait_to_fill: bool,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws-sdk-s3
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.148.0
4
+ version: 1.149.1
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: 2024-04-25 00:00:00.000000000 Z
11
+ date: 2024-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-kms
@@ -47,7 +47,7 @@ dependencies:
47
47
  version: '3'
48
48
  - - ">="
49
49
  - !ruby/object:Gem::Version
50
- version: 3.193.0
50
+ version: 3.194.0
51
51
  type: :runtime
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
@@ -57,7 +57,7 @@ dependencies:
57
57
  version: '3'
58
58
  - - ">="
59
59
  - !ruby/object:Gem::Version
60
- version: 3.193.0
60
+ version: 3.194.0
61
61
  description: Official AWS Ruby gem for Amazon Simple Storage Service (Amazon S3).
62
62
  This gem is part of the AWS SDK for Ruby.
63
63
  email:
@@ -70,6 +70,8 @@ files:
70
70
  - LICENSE.txt
71
71
  - VERSION
72
72
  - lib/aws-sdk-s3.rb
73
+ - lib/aws-sdk-s3/access_grants_credentials.rb
74
+ - lib/aws-sdk-s3/access_grants_credentials_provider.rb
73
75
  - lib/aws-sdk-s3/bucket.rb
74
76
  - lib/aws-sdk-s3/bucket_acl.rb
75
77
  - lib/aws-sdk-s3/bucket_cors.rb
@@ -127,7 +129,6 @@ files:
127
129
  - lib/aws-sdk-s3/errors.rb
128
130
  - lib/aws-sdk-s3/event_streams.rb
129
131
  - lib/aws-sdk-s3/express_credentials.rb
130
- - lib/aws-sdk-s3/express_credentials_cache.rb
131
132
  - lib/aws-sdk-s3/express_credentials_provider.rb
132
133
  - lib/aws-sdk-s3/file_downloader.rb
133
134
  - lib/aws-sdk-s3/file_part.rb
@@ -145,6 +146,7 @@ files:
145
146
  - lib/aws-sdk-s3/object_summary.rb
146
147
  - lib/aws-sdk-s3/object_version.rb
147
148
  - lib/aws-sdk-s3/plugins/accelerate.rb
149
+ - lib/aws-sdk-s3/plugins/access_grants.rb
148
150
  - lib/aws-sdk-s3/plugins/arn.rb
149
151
  - lib/aws-sdk-s3/plugins/bucket_dns.rb
150
152
  - lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb
@@ -182,6 +184,9 @@ files:
182
184
  - sig/bucket_versioning.rbs
183
185
  - sig/bucket_website.rbs
184
186
  - sig/client.rbs
187
+ - sig/customizations/bucket.rbs
188
+ - sig/customizations/object.rbs
189
+ - sig/customizations/object_summary.rbs
185
190
  - sig/errors.rbs
186
191
  - sig/multipart_upload.rbs
187
192
  - sig/multipart_upload_part.rbs
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Aws
4
- module S3
5
- # @api private
6
- class ExpressCredentialsCache
7
- def initialize
8
- @credentials = {}
9
- @mutex = Mutex.new
10
- end
11
-
12
- def [](bucket_name)
13
- @mutex.synchronize { @credentials[bucket_name] }
14
- end
15
-
16
- def []=(bucket_name, credential_provider)
17
- @mutex.synchronize do
18
- @credentials[bucket_name] = credential_provider
19
- end
20
- end
21
-
22
- def clear
23
- @mutex.synchronize { @credentials = {} }
24
- end
25
- end
26
-
27
- # @api private
28
- EXPRESS_CREDENTIALS_CACHE = ExpressCredentialsCache.new
29
- end
30
- end