aws-sdk-s3 1.148.0 → 1.149.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -1
- 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/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: d4d91f16763c42e349f2e6d50ff4f37926096c5148ae5f78b953685e4d2f171e
|
4
|
+
data.tar.gz: 2e72de55c5c10a86437e89200db3b357bb89f083ca5b1c044c20ed90143b66b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '078c6651b2bc5d4c4cf9abb678303f3dc41250eb24ee66fcbbb22d9c96064dc8dbade173862964021948234fff6e9d38b4a9eb255949891fc047a0b06ac785f6'
|
7
|
+
data.tar.gz: d17a3204313a0977ee8f108c057fefbcbca80eb48e54e146274be01b9f2d9d4c33502cf2474c49fffe560d4a134d8e985a0f8db7a3f83ff533b898e725236473
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
Unreleased Changes
|
2
2
|
------------------
|
3
3
|
|
4
|
+
1.149.0 (2024-04-30)
|
5
|
+
------------------
|
6
|
+
|
7
|
+
* 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.
|
8
|
+
|
9
|
+
* Feature - Add RBS signatures for customizations of S3.
|
10
|
+
|
4
11
|
1.148.0 (2024-04-25)
|
5
12
|
------------------
|
6
13
|
|
@@ -38,7 +45,6 @@ Unreleased Changes
|
|
38
45
|
|
39
46
|
* Issue - Include original part errors in message when aborting multipart upload fails (#2990).
|
40
47
|
|
41
|
-
|
42
48
|
1.143.0 (2024-01-26)
|
43
49
|
------------------
|
44
50
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.149.0
|
@@ -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.0'
|
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
|
@@ -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.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Amazon Web Services
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-04-
|
11
|
+
date: 2024-04-30 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
|