aws-sdk-core 3.125.5 → 3.130.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 +59 -0
- data/VERSION +1 -1
- data/lib/aws-sdk-core/assume_role_credentials.rb +19 -0
- data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +7 -1
- data/lib/aws-sdk-core/client_stubs.rb +5 -1
- data/lib/aws-sdk-core/ec2_metadata.rb +3 -2
- data/lib/aws-sdk-core/ecs_credentials.rb +5 -0
- data/lib/aws-sdk-core/errors.rb +1 -1
- data/lib/aws-sdk-core/instance_profile_credentials.rb +80 -14
- data/lib/aws-sdk-core/pageable_response.rb +72 -32
- data/lib/aws-sdk-core/plugins/checksum_algorithm.rb +340 -0
- data/lib/aws-sdk-core/plugins/http_checksum.rb +8 -1
- data/lib/aws-sdk-core/plugins/recursion_detection.rb +27 -0
- data/lib/aws-sdk-core/plugins/response_paging.rb +1 -1
- data/lib/aws-sdk-core/plugins/retries/error_inspector.rb +1 -1
- data/lib/aws-sdk-core/plugins/signature_v4.rb +2 -1
- data/lib/aws-sdk-core/plugins/stub_responses.rb +5 -1
- data/lib/aws-sdk-core/process_credentials.rb +3 -2
- data/lib/aws-sdk-core/refreshing_credentials.rb +40 -11
- data/lib/aws-sdk-core/shared_config.rb +1 -6
- data/lib/aws-sdk-core/sso_credentials.rb +6 -0
- data/lib/aws-sdk-sso/client.rb +5 -1
- data/lib/aws-sdk-sso.rb +1 -1
- data/lib/aws-sdk-sts/client.rb +57 -51
- data/lib/aws-sdk-sts/types.rb +7 -7
- data/lib/aws-sdk-sts.rb +1 -1
- data/lib/seahorse/model/operation.rb +3 -0
- metadata +4 -2
@@ -0,0 +1,340 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Plugins
|
5
|
+
# @api private
|
6
|
+
class ChecksumAlgorithm < Seahorse::Client::Plugin
|
7
|
+
CHUNK_SIZE = 1 * 1024 * 1024 # one MB
|
8
|
+
|
9
|
+
# determine the set of supported client side checksum algorithms
|
10
|
+
# CRC32c requires aws-crt (optional sdk dependency) for support
|
11
|
+
CLIENT_ALGORITHMS = begin
|
12
|
+
supported = %w[SHA256 SHA1 CRC32]
|
13
|
+
begin
|
14
|
+
require 'aws-crt'
|
15
|
+
supported << 'CRC32C'
|
16
|
+
rescue LoadError
|
17
|
+
end
|
18
|
+
supported
|
19
|
+
end.freeze
|
20
|
+
|
21
|
+
# priority order of checksum algorithms to validate responses against
|
22
|
+
# Remove any algorithms not supported by client (ie, depending on CRT availability)
|
23
|
+
CHECKSUM_ALGORITHM_PRIORITIES = %w[CRC32C SHA1 CRC32 SHA256] & CLIENT_ALGORITHMS
|
24
|
+
|
25
|
+
# byte size of checksums, used in computing the trailer length
|
26
|
+
CHECKSUM_SIZE = {
|
27
|
+
'CRC32' => 16,
|
28
|
+
'CRC32C' => 16,
|
29
|
+
'SHA1' => 36,
|
30
|
+
'SHA256' => 52
|
31
|
+
}
|
32
|
+
|
33
|
+
# Interface for computing digests on request/response bodies
|
34
|
+
# which may be files, strings or IO like objects
|
35
|
+
# Applies only to digest functions that produce 32 bit integer checksums
|
36
|
+
# (eg CRC32)
|
37
|
+
class Digest32
|
38
|
+
|
39
|
+
attr_reader :value
|
40
|
+
|
41
|
+
# @param [Object] digest_fn
|
42
|
+
def initialize(digest_fn)
|
43
|
+
@digest_fn = digest_fn
|
44
|
+
@value = 0
|
45
|
+
end
|
46
|
+
|
47
|
+
def update(chunk)
|
48
|
+
@value = @digest_fn.call(chunk, @value)
|
49
|
+
end
|
50
|
+
|
51
|
+
def base64digest
|
52
|
+
Base64.encode64([@value].pack('N')).chomp
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_handlers(handlers, _config)
|
57
|
+
handlers.add(OptionHandler, step: :initialize)
|
58
|
+
# priority set low to ensure checksum is computed AFTER the request is
|
59
|
+
# built but before it is signed
|
60
|
+
handlers.add(ChecksumHandler, priority: 15, step: :build)
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def self.request_algorithm_selection(context)
|
66
|
+
return unless context.operation.http_checksum
|
67
|
+
|
68
|
+
input_member = context.operation.http_checksum['requestAlgorithmMember']
|
69
|
+
context.params[input_member.to_sym]&.upcase if input_member
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.request_validation_mode(context)
|
73
|
+
return unless context.operation.http_checksum
|
74
|
+
|
75
|
+
input_member = context.operation.http_checksum['requestValidationModeMember']
|
76
|
+
context.params[input_member.to_sym] if input_member
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.operation_response_algorithms(context)
|
80
|
+
return unless context.operation.http_checksum
|
81
|
+
|
82
|
+
context.operation.http_checksum['responseAlgorithms']
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
# @api private
|
87
|
+
class OptionHandler < Seahorse::Client::Handler
|
88
|
+
def call(context)
|
89
|
+
context[:http_checksum] ||= {}
|
90
|
+
|
91
|
+
# validate request configuration
|
92
|
+
if (request_input = ChecksumAlgorithm.request_algorithm_selection(context))
|
93
|
+
unless CLIENT_ALGORITHMS.include? request_input
|
94
|
+
if (request_input == 'CRC32C')
|
95
|
+
raise ArgumentError, "CRC32C requires crt support - install the aws-crt gem for support."
|
96
|
+
else
|
97
|
+
raise ArgumentError, "#{request_input} is not a supported checksum algorithm."
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# validate response configuration
|
103
|
+
if (ChecksumAlgorithm.request_validation_mode(context))
|
104
|
+
# Compute an ordered list as the union between priority supported and the
|
105
|
+
# operation's modeled response algorithms.
|
106
|
+
validation_list = CHECKSUM_ALGORITHM_PRIORITIES &
|
107
|
+
ChecksumAlgorithm.operation_response_algorithms(context)
|
108
|
+
context[:http_checksum][:validation_list] = validation_list
|
109
|
+
end
|
110
|
+
|
111
|
+
@handler.call(context)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# @api private
|
116
|
+
class ChecksumHandler < Seahorse::Client::Handler
|
117
|
+
|
118
|
+
def call(context)
|
119
|
+
if should_calculate_request_checksum?(context)
|
120
|
+
request_algorithm_input = ChecksumAlgorithm.request_algorithm_selection(context)
|
121
|
+
context[:checksum_algorithms] = request_algorithm_input
|
122
|
+
|
123
|
+
request_checksum_property = {
|
124
|
+
'algorithm' => request_algorithm_input,
|
125
|
+
'in' => checksum_request_in(context),
|
126
|
+
'name' => "x-amz-checksum-#{request_algorithm_input.downcase}"
|
127
|
+
}
|
128
|
+
|
129
|
+
calculate_request_checksum(context, request_checksum_property)
|
130
|
+
end
|
131
|
+
|
132
|
+
if should_verify_response_checksum?(context)
|
133
|
+
add_verify_response_checksum_handlers(context)
|
134
|
+
end
|
135
|
+
|
136
|
+
@handler.call(context)
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
def should_calculate_request_checksum?(context)
|
142
|
+
context.operation.http_checksum &&
|
143
|
+
ChecksumAlgorithm.request_algorithm_selection(context)
|
144
|
+
end
|
145
|
+
|
146
|
+
def should_verify_response_checksum?(context)
|
147
|
+
context[:http_checksum][:validation_list] && !context[:http_checksum][:validation_list].empty?
|
148
|
+
end
|
149
|
+
|
150
|
+
def calculate_request_checksum(context, checksum_properties)
|
151
|
+
case checksum_properties['in']
|
152
|
+
when 'header'
|
153
|
+
header_name = checksum_properties['name']
|
154
|
+
body = context.http_request.body_contents
|
155
|
+
if body
|
156
|
+
context.http_request.headers[header_name] ||=
|
157
|
+
ChecksumAlgorithm.calculate_checksum(checksum_properties['algorithm'], body)
|
158
|
+
end
|
159
|
+
when 'trailer'
|
160
|
+
apply_request_trailer_checksum(context, checksum_properties)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def apply_request_trailer_checksum(context, checksum_properties)
|
165
|
+
location_name = checksum_properties['name']
|
166
|
+
|
167
|
+
# set required headers
|
168
|
+
headers = context.http_request.headers
|
169
|
+
headers['Content-Encoding'] = 'aws-chunked'
|
170
|
+
headers['X-Amz-Content-Sha256'] = 'STREAMING-UNSIGNED-PAYLOAD-TRAILER'
|
171
|
+
headers['X-Amz-Trailer'] = location_name
|
172
|
+
|
173
|
+
# We currently always compute the size in the modified body wrapper - allowing us
|
174
|
+
# to set the Content-Length header (set by content_length plugin).
|
175
|
+
# This means we cannot use Transfer-Encoding=chunked
|
176
|
+
|
177
|
+
if !context.http_request.body.respond_to?(:size)
|
178
|
+
raise Aws::Errors::ChecksumError, 'Could not determine length of the body'
|
179
|
+
end
|
180
|
+
headers['X-Amz-Decoded-Content-Length'] = context.http_request.body.size
|
181
|
+
|
182
|
+
context.http_request.body = AwsChunkedTrailerDigestIO.new(
|
183
|
+
context.http_request.body,
|
184
|
+
checksum_properties['algorithm'],
|
185
|
+
location_name
|
186
|
+
)
|
187
|
+
end
|
188
|
+
|
189
|
+
# Add events to the http_response to verify the checksum as its read
|
190
|
+
# This prevents the body from being read multiple times
|
191
|
+
# verification is done only once a successful response has completed
|
192
|
+
def add_verify_response_checksum_handlers(context)
|
193
|
+
http_response = context.http_response
|
194
|
+
checksum_context = { }
|
195
|
+
http_response.on_headers do |_status, headers|
|
196
|
+
header_name, algorithm = response_header_to_verify(headers, context[:http_checksum][:validation_list])
|
197
|
+
if header_name
|
198
|
+
expected = headers[header_name]
|
199
|
+
|
200
|
+
unless context[:http_checksum][:skip_on_suffix] && /-[\d]+$/.match(expected)
|
201
|
+
checksum_context[:algorithm] = algorithm
|
202
|
+
checksum_context[:header_name] = header_name
|
203
|
+
checksum_context[:digest] = ChecksumAlgorithm.digest_for_algorithm(algorithm)
|
204
|
+
checksum_context[:expected] = expected
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
http_response.on_data do |chunk|
|
210
|
+
checksum_context[:digest].update(chunk) if checksum_context[:digest]
|
211
|
+
end
|
212
|
+
|
213
|
+
http_response.on_success do
|
214
|
+
if checksum_context[:digest] &&
|
215
|
+
(computed = checksum_context[:digest].base64digest)
|
216
|
+
|
217
|
+
if computed != checksum_context[:expected]
|
218
|
+
raise Aws::Errors::ChecksumError,
|
219
|
+
"Checksum validation failed on #{checksum_context[:header_name]} "\
|
220
|
+
"computed: #{computed}, expected: #{checksum_context[:expected]}"
|
221
|
+
end
|
222
|
+
|
223
|
+
context[:http_checksum][:validated] = checksum_context[:algorithm]
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# returns nil if no headers to verify
|
229
|
+
def response_header_to_verify(headers, validation_list)
|
230
|
+
validation_list.each do |algorithm|
|
231
|
+
header_name = "x-amz-checksum-#{algorithm}"
|
232
|
+
return [header_name, algorithm] if headers[header_name]
|
233
|
+
end
|
234
|
+
nil
|
235
|
+
end
|
236
|
+
|
237
|
+
# determine where (header vs trailer) a request checksum should be added
|
238
|
+
def checksum_request_in(context)
|
239
|
+
if context.operation['authtype'].eql?('v4-unsigned-body')
|
240
|
+
'trailer'
|
241
|
+
else
|
242
|
+
'header'
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
|
248
|
+
def self.calculate_checksum(algorithm, body)
|
249
|
+
digest = ChecksumAlgorithm.digest_for_algorithm(algorithm)
|
250
|
+
if body.respond_to?(:read)
|
251
|
+
ChecksumAlgorithm.update_in_chunks(digest, body)
|
252
|
+
else
|
253
|
+
digest.update(body)
|
254
|
+
end
|
255
|
+
digest.base64digest
|
256
|
+
end
|
257
|
+
|
258
|
+
def self.digest_for_algorithm(algorithm)
|
259
|
+
case algorithm
|
260
|
+
when 'CRC32'
|
261
|
+
Digest32.new(Zlib.method(:crc32))
|
262
|
+
when 'CRC32C'
|
263
|
+
# this will only be used if input algorithm is CRC32C AND client supports it (crt available)
|
264
|
+
Digest32.new(Aws::Crt::Checksums.method(:crc32c))
|
265
|
+
when 'SHA1'
|
266
|
+
Digest::SHA1.new
|
267
|
+
when 'SHA256'
|
268
|
+
Digest::SHA256.new
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
# The trailer size (in bytes) is the overhead + the trailer name +
|
273
|
+
# the length of the base64 encoded checksum
|
274
|
+
def self.trailer_length(algorithm, location_name)
|
275
|
+
CHECKSUM_SIZE[algorithm] + location_name.size
|
276
|
+
end
|
277
|
+
|
278
|
+
def self.update_in_chunks(digest, io)
|
279
|
+
loop do
|
280
|
+
chunk = io.read(CHUNK_SIZE)
|
281
|
+
break unless chunk
|
282
|
+
digest.update(chunk)
|
283
|
+
end
|
284
|
+
io.rewind
|
285
|
+
end
|
286
|
+
|
287
|
+
# Wrapper for request body that implements application-layer
|
288
|
+
# chunking with Digest computed on chunks + added as a trailer
|
289
|
+
class AwsChunkedTrailerDigestIO
|
290
|
+
CHUNK_SIZE = 16384
|
291
|
+
|
292
|
+
def initialize(io, algorithm, location_name)
|
293
|
+
@io = io
|
294
|
+
@location_name = location_name
|
295
|
+
@algorithm = algorithm
|
296
|
+
@digest = ChecksumAlgorithm.digest_for_algorithm(algorithm)
|
297
|
+
@trailer_io = nil
|
298
|
+
end
|
299
|
+
|
300
|
+
# the size of the application layer aws-chunked + trailer body
|
301
|
+
def size
|
302
|
+
# compute the number of chunks
|
303
|
+
# a full chunk has 4 + 4 bytes overhead, a partial chunk is len.to_s(16).size + 4
|
304
|
+
orig_body_size = @io.size
|
305
|
+
n_full_chunks = orig_body_size / CHUNK_SIZE
|
306
|
+
partial_bytes = orig_body_size % CHUNK_SIZE
|
307
|
+
chunked_body_size = n_full_chunks * (CHUNK_SIZE + 8)
|
308
|
+
chunked_body_size += partial_bytes.to_s(16).size + partial_bytes + 4 unless partial_bytes.zero?
|
309
|
+
trailer_size = ChecksumAlgorithm.trailer_length(@algorithm, @location_name)
|
310
|
+
chunked_body_size + trailer_size
|
311
|
+
end
|
312
|
+
|
313
|
+
def rewind
|
314
|
+
@io.rewind
|
315
|
+
end
|
316
|
+
|
317
|
+
def read(length, buf)
|
318
|
+
# account for possible leftover bytes at the end, if we have trailer bytes, send them
|
319
|
+
if @trailer_io
|
320
|
+
return @trailer_io.read(length, buf)
|
321
|
+
end
|
322
|
+
|
323
|
+
chunk = @io.read(length)
|
324
|
+
if chunk
|
325
|
+
@digest.update(chunk)
|
326
|
+
application_chunked = "#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n"
|
327
|
+
return StringIO.new(application_chunked).read(application_chunked.size, buf)
|
328
|
+
else
|
329
|
+
trailers = {}
|
330
|
+
trailers[@location_name] = @digest.base64digest
|
331
|
+
trailers = trailers.map { |k,v| "#{k}:#{v}"}.join("\r\n")
|
332
|
+
@trailer_io = StringIO.new("0\r\n#{trailers}\r\n\r\n")
|
333
|
+
chunk = @trailer_io.read(length, buf)
|
334
|
+
end
|
335
|
+
chunk
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
@@ -11,7 +11,8 @@ module Aws
|
|
11
11
|
CHUNK_SIZE = 1 * 1024 * 1024 # one MB
|
12
12
|
|
13
13
|
def call(context)
|
14
|
-
if context
|
14
|
+
if checksum_required?(context) &&
|
15
|
+
!context[:checksum_algorithms] # skip in favor of flexible checksum
|
15
16
|
body = context.http_request.body
|
16
17
|
context.http_request.headers['Content-Md5'] ||= md5(body)
|
17
18
|
end
|
@@ -20,6 +21,12 @@ module Aws
|
|
20
21
|
|
21
22
|
private
|
22
23
|
|
24
|
+
def checksum_required?(context)
|
25
|
+
context.operation.http_checksum_required ||
|
26
|
+
(context.operation.http_checksum &&
|
27
|
+
context.operation.http_checksum['requestChecksumRequired'])
|
28
|
+
end
|
29
|
+
|
23
30
|
# @param [File, Tempfile, IO#read, String] value
|
24
31
|
# @return [String<MD5>]
|
25
32
|
def md5(value)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Plugins
|
5
|
+
# @api private
|
6
|
+
class RecursionDetection < Seahorse::Client::Plugin
|
7
|
+
|
8
|
+
# @api private
|
9
|
+
class Handler < Seahorse::Client::Handler
|
10
|
+
def call(context)
|
11
|
+
|
12
|
+
unless context.http_request.headers.key?('x-amz-trace-id')
|
13
|
+
if ENV['AWS_LAMBDA_FUNCTION_NAME'] &&
|
14
|
+
(trace_id = ENV['_X_AMZ_TRACE_ID'])
|
15
|
+
context.http_request.headers['x-amz-trace-id'] = trace_id
|
16
|
+
end
|
17
|
+
end
|
18
|
+
@handler.call(context)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# should be at the end of build so that
|
23
|
+
# modeled traits / service customizations apply first
|
24
|
+
handler(Handler, step: :build, order: 99)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -10,7 +10,7 @@ module Aws
|
|
10
10
|
def call(context)
|
11
11
|
context[:original_params] = context.params
|
12
12
|
resp = @handler.call(context)
|
13
|
-
|
13
|
+
PageableResponse.apply(resp)
|
14
14
|
resp.pager = context.operation[:pager] || Aws::Pager::NullPager.new
|
15
15
|
resp
|
16
16
|
end
|
@@ -98,6 +98,7 @@ module Aws
|
|
98
98
|
req.headers.delete('Authorization')
|
99
99
|
req.headers.delete('X-Amz-Security-Token')
|
100
100
|
req.headers.delete('X-Amz-Date')
|
101
|
+
req.headers.delete('x-Amz-Region-Set')
|
101
102
|
|
102
103
|
if context.config.respond_to?(:clock_skew) &&
|
103
104
|
context.config.clock_skew &&
|
@@ -134,7 +135,7 @@ module Aws
|
|
134
135
|
def apply_authtype(context)
|
135
136
|
if context.operation['authtype'].eql?('v4-unsigned-body') &&
|
136
137
|
context.http_request.endpoint.scheme.eql?('https')
|
137
|
-
context.http_request.headers['X-Amz-Content-Sha256']
|
138
|
+
context.http_request.headers['X-Amz-Content-Sha256'] ||= 'UNSIGNED-PAYLOAD'
|
138
139
|
end
|
139
140
|
context
|
140
141
|
end
|
@@ -51,7 +51,11 @@ requests are made, and retries are disabled.
|
|
51
51
|
stub = context.client.next_stub(context)
|
52
52
|
resp = Seahorse::Client::Response.new(context: context)
|
53
53
|
async_mode = context.client.is_a? Seahorse::Client::AsyncBase
|
54
|
-
|
54
|
+
if Hash === stub && stub[:mutex]
|
55
|
+
stub[:mutex].synchronize { apply_stub(stub, resp, async_mode) }
|
56
|
+
else
|
57
|
+
apply_stub(stub, resp, async_mode)
|
58
|
+
end
|
55
59
|
|
56
60
|
async_mode ? Seahorse::Client::AsyncResponse.new(
|
57
61
|
context: context, stream: context[:input_event_stream_handler].event_emitter.stream, sync_queue: Queue.new) : resp
|
@@ -27,6 +27,7 @@ module Aws
|
|
27
27
|
def initialize(process)
|
28
28
|
@process = process
|
29
29
|
@credentials = credentials_from_process(@process)
|
30
|
+
@async_refresh = false
|
30
31
|
|
31
32
|
super
|
32
33
|
end
|
@@ -73,9 +74,9 @@ module Aws
|
|
73
74
|
@credentials = credentials_from_process(@process)
|
74
75
|
end
|
75
76
|
|
76
|
-
def near_expiration?
|
77
|
+
def near_expiration?(expiration_length)
|
77
78
|
# are we within 5 minutes of expiration?
|
78
|
-
@expiration && (Time.now.to_i +
|
79
|
+
@expiration && (Time.now.to_i + expiration_length) > @expiration.to_i
|
79
80
|
end
|
80
81
|
end
|
81
82
|
end
|
@@ -17,45 +17,74 @@ module Aws
|
|
17
17
|
# @api private
|
18
18
|
module RefreshingCredentials
|
19
19
|
|
20
|
+
SYNC_EXPIRATION_LENGTH = 300 # 5 minutes
|
21
|
+
ASYNC_EXPIRATION_LENGTH = 600 # 10 minutes
|
22
|
+
|
20
23
|
def initialize(options = {})
|
21
24
|
@mutex = Mutex.new
|
25
|
+
@before_refresh = options.delete(:before_refresh) if Hash === options
|
26
|
+
|
27
|
+
@before_refresh.call(self) if @before_refresh
|
22
28
|
refresh
|
23
29
|
end
|
24
30
|
|
25
31
|
# @return [Credentials]
|
26
32
|
def credentials
|
27
|
-
refresh_if_near_expiration
|
33
|
+
refresh_if_near_expiration!
|
28
34
|
@credentials
|
29
35
|
end
|
30
36
|
|
31
37
|
# @return [Time,nil]
|
32
38
|
def expiration
|
33
|
-
refresh_if_near_expiration
|
39
|
+
refresh_if_near_expiration!
|
34
40
|
@expiration
|
35
41
|
end
|
36
42
|
|
37
43
|
# Refresh credentials.
|
38
44
|
# @return [void]
|
39
45
|
def refresh!
|
40
|
-
@mutex.synchronize
|
46
|
+
@mutex.synchronize do
|
47
|
+
@before_refresh.call(self) if @before_refresh
|
48
|
+
|
49
|
+
refresh
|
50
|
+
end
|
41
51
|
end
|
42
52
|
|
43
53
|
private
|
44
54
|
|
45
|
-
# Refreshes
|
46
|
-
#
|
47
|
-
|
48
|
-
|
55
|
+
# Refreshes credentials asynchronously and synchronously.
|
56
|
+
# If we are near to expiration, block while getting new credentials.
|
57
|
+
# Otherwise, if we're approaching expiration, use the existing credentials
|
58
|
+
# but attempt a refresh in the background.
|
59
|
+
def refresh_if_near_expiration!
|
60
|
+
# Note: This check is an optimization. Rather than acquire the mutex on every #refresh_if_near_expiration
|
61
|
+
# call, we check before doing so, and then we check within the mutex to avoid a race condition.
|
62
|
+
# See issue: https://github.com/aws/aws-sdk-ruby/issues/2641 for more info.
|
63
|
+
if near_expiration?(SYNC_EXPIRATION_LENGTH)
|
49
64
|
@mutex.synchronize do
|
50
|
-
|
65
|
+
if near_expiration?(SYNC_EXPIRATION_LENGTH)
|
66
|
+
@before_refresh.call(self) if @before_refresh
|
67
|
+
refresh
|
68
|
+
end
|
69
|
+
end
|
70
|
+
elsif @async_refresh && near_expiration?(ASYNC_EXPIRATION_LENGTH)
|
71
|
+
unless @mutex.locked?
|
72
|
+
Thread.new do
|
73
|
+
@mutex.synchronize do
|
74
|
+
if near_expiration?(ASYNC_EXPIRATION_LENGTH)
|
75
|
+
@before_refresh.call(self) if @before_refresh
|
76
|
+
refresh
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
51
80
|
end
|
52
81
|
end
|
53
82
|
end
|
54
83
|
|
55
|
-
def near_expiration?
|
84
|
+
def near_expiration?(expiration_length)
|
56
85
|
if @expiration
|
57
|
-
#
|
58
|
-
(Time.now.to_i +
|
86
|
+
# Are we within expiration?
|
87
|
+
(Time.now.to_i + expiration_length) > @expiration.to_i
|
59
88
|
else
|
60
89
|
true
|
61
90
|
end
|
@@ -100,7 +100,7 @@ module Aws
|
|
100
100
|
# or `nil` if no valid credentials were found.
|
101
101
|
def credentials(opts = {})
|
102
102
|
p = opts[:profile] || @profile_name
|
103
|
-
validate_profile_exists(p)
|
103
|
+
validate_profile_exists(p)
|
104
104
|
if (credentials = credentials_from_shared(p, opts))
|
105
105
|
credentials
|
106
106
|
elsif (credentials = credentials_from_config(p, opts))
|
@@ -195,11 +195,6 @@ module Aws
|
|
195
195
|
value
|
196
196
|
end
|
197
197
|
|
198
|
-
def credentials_present?
|
199
|
-
(@parsed_credentials && !@parsed_credentials.empty?) ||
|
200
|
-
(@parsed_config && !@parsed_config.empty?)
|
201
|
-
end
|
202
|
-
|
203
198
|
def assume_role_from_profile(cfg, profile, opts, chain_config)
|
204
199
|
if cfg && prof_cfg = cfg[profile]
|
205
200
|
opts[:source_profile] ||= prof_cfg['source_profile']
|
@@ -63,6 +63,11 @@ module Aws
|
|
63
63
|
#
|
64
64
|
# @option options [SSO::Client] :client Optional `SSO::Client`. If not
|
65
65
|
# provided, a client will be constructed.
|
66
|
+
#
|
67
|
+
# @option options [Callable] before_refresh Proc called before
|
68
|
+
# credentials are refreshed. `before_refresh` is called
|
69
|
+
# with an instance of this object when
|
70
|
+
# AWS credentials are required and need to be refreshed.
|
66
71
|
def initialize(options = {})
|
67
72
|
|
68
73
|
missing_keys = SSO_REQUIRED_OPTS.select { |k| options[k].nil? }
|
@@ -81,6 +86,7 @@ module Aws
|
|
81
86
|
options[:region] = @sso_region
|
82
87
|
options[:credentials] = nil
|
83
88
|
@client = options[:client] || Aws::SSO::Client.new(options)
|
89
|
+
@async_refresh = true
|
84
90
|
super
|
85
91
|
end
|
86
92
|
|
data/lib/aws-sdk-sso/client.rb
CHANGED
@@ -27,7 +27,9 @@ require 'aws-sdk-core/plugins/client_metrics_plugin.rb'
|
|
27
27
|
require 'aws-sdk-core/plugins/client_metrics_send_plugin.rb'
|
28
28
|
require 'aws-sdk-core/plugins/transfer_encoding.rb'
|
29
29
|
require 'aws-sdk-core/plugins/http_checksum.rb'
|
30
|
+
require 'aws-sdk-core/plugins/checksum_algorithm.rb'
|
30
31
|
require 'aws-sdk-core/plugins/defaults_mode.rb'
|
32
|
+
require 'aws-sdk-core/plugins/recursion_detection.rb'
|
31
33
|
require 'aws-sdk-core/plugins/signature_v4.rb'
|
32
34
|
require 'aws-sdk-core/plugins/protocols/rest_json.rb'
|
33
35
|
|
@@ -74,7 +76,9 @@ module Aws::SSO
|
|
74
76
|
add_plugin(Aws::Plugins::ClientMetricsSendPlugin)
|
75
77
|
add_plugin(Aws::Plugins::TransferEncoding)
|
76
78
|
add_plugin(Aws::Plugins::HttpChecksum)
|
79
|
+
add_plugin(Aws::Plugins::ChecksumAlgorithm)
|
77
80
|
add_plugin(Aws::Plugins::DefaultsMode)
|
81
|
+
add_plugin(Aws::Plugins::RecursionDetection)
|
78
82
|
add_plugin(Aws::Plugins::SignatureV4)
|
79
83
|
add_plugin(Aws::Plugins::Protocols::RestJson)
|
80
84
|
|
@@ -541,7 +545,7 @@ module Aws::SSO
|
|
541
545
|
params: params,
|
542
546
|
config: config)
|
543
547
|
context[:gem_name] = 'aws-sdk-core'
|
544
|
-
context[:gem_version] = '3.
|
548
|
+
context[:gem_version] = '3.130.0'
|
545
549
|
Seahorse::Client::Request.new(handlers, context)
|
546
550
|
end
|
547
551
|
|