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 +4 -4
- data/CHANGELOG.md +13 -2
- data/VERSION +1 -1
- data/lib/aws-sdk-s3/access_grants_credentials.rb +57 -0
- data/lib/aws-sdk-s3/access_grants_credentials_provider.rb +241 -0
- data/lib/aws-sdk-s3/bucket_region_cache.rb +9 -5
- data/lib/aws-sdk-s3/client.rb +13 -1
- data/lib/aws-sdk-s3/customizations/errors.rb +15 -2
- data/lib/aws-sdk-s3/customizations.rb +4 -1
- data/lib/aws-sdk-s3/express_credentials_provider.rb +27 -4
- data/lib/aws-sdk-s3/object_multipart_copier.rb +10 -8
- data/lib/aws-sdk-s3/plugins/access_grants.rb +108 -0
- data/lib/aws-sdk-s3/plugins/express_session_auth.rb +1 -1
- data/lib/aws-sdk-s3/plugins/s3_signer.rb +7 -2
- data/lib/aws-sdk-s3.rb +1 -1
- data/sig/client.rbs +2 -0
- data/sig/customizations/bucket.rbs +19 -0
- data/sig/customizations/object.rbs +38 -0
- data/sig/customizations/object_summary.rbs +35 -0
- data/sig/resource.rbs +2 -0
- metadata +10 -5
- data/lib/aws-sdk-s3/express_credentials_cache.rb +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7e829d836e606576346cf328245de26a473222ab50d8d8b7fbbecc88efebb92
|
4
|
+
data.tar.gz: bcf4d589ca8ae7caebd3f1ea07da416ed3c01221309dbd27768313173c96ba70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
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
|
data/lib/aws-sdk-s3/client.rb
CHANGED
@@ -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.
|
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
|
7
|
-
# and
|
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
|
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
|
-
|
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
|
-
@
|
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
|
-
|
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
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
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
|
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
|
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
|
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
data/sig/client.rbs
CHANGED
@@ -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
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.
|
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-
|
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.
|
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.
|
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
|