aws-sdk-core 3.226.1 → 3.246.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +184 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-sdk-core/assume_role_credentials.rb +8 -8
  5. data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +2 -2
  6. data/lib/aws-sdk-core/client_stubs.rb +6 -0
  7. data/lib/aws-sdk-core/credential_provider_chain.rb +72 -23
  8. data/lib/aws-sdk-core/ecs_credentials.rb +25 -15
  9. data/lib/aws-sdk-core/endpoints.rb +37 -13
  10. data/lib/aws-sdk-core/error_handler.rb +5 -0
  11. data/lib/aws-sdk-core/errors.rb +3 -0
  12. data/lib/aws-sdk-core/instance_profile_credentials.rb +160 -161
  13. data/lib/aws-sdk-core/json/error_handler.rb +14 -4
  14. data/lib/aws-sdk-core/login_credentials.rb +230 -0
  15. data/lib/aws-sdk-core/plugins/checksum_algorithm.rb +147 -76
  16. data/lib/aws-sdk-core/plugins/credentials_configuration.rb +75 -59
  17. data/lib/aws-sdk-core/plugins/retries/clock_skew.rb +28 -16
  18. data/lib/aws-sdk-core/plugins/sign.rb +23 -28
  19. data/lib/aws-sdk-core/plugins/stub_responses.rb +6 -0
  20. data/lib/aws-sdk-core/plugins/user_agent.rb +6 -1
  21. data/lib/aws-sdk-core/refreshing_credentials.rb +8 -11
  22. data/lib/aws-sdk-core/rpc_v2/error_handler.rb +26 -16
  23. data/lib/aws-sdk-core/shared_config.rb +30 -0
  24. data/lib/aws-sdk-core/sso_credentials.rb +1 -1
  25. data/lib/aws-sdk-core/sso_token_provider.rb +1 -0
  26. data/lib/aws-sdk-core/static_token_provider.rb +1 -2
  27. data/lib/aws-sdk-core/token.rb +3 -3
  28. data/lib/aws-sdk-core/token_provider.rb +4 -0
  29. data/lib/aws-sdk-core/token_provider_chain.rb +2 -6
  30. data/lib/aws-sdk-core/waiters/poller.rb +2 -2
  31. data/lib/aws-sdk-core/xml/error_handler.rb +1 -0
  32. data/lib/aws-sdk-core.rb +4 -0
  33. data/lib/aws-sdk-signin/client.rb +604 -0
  34. data/lib/aws-sdk-signin/client_api.rb +119 -0
  35. data/lib/aws-sdk-signin/customizations.rb +1 -0
  36. data/lib/aws-sdk-signin/endpoint_parameters.rb +69 -0
  37. data/lib/aws-sdk-signin/endpoint_provider.rb +59 -0
  38. data/lib/aws-sdk-signin/endpoints.rb +20 -0
  39. data/lib/aws-sdk-signin/errors.rb +122 -0
  40. data/lib/aws-sdk-signin/plugins/endpoints.rb +77 -0
  41. data/lib/aws-sdk-signin/resource.rb +26 -0
  42. data/lib/aws-sdk-signin/types.rb +299 -0
  43. data/lib/aws-sdk-signin.rb +63 -0
  44. data/lib/aws-sdk-sso/client.rb +24 -17
  45. data/lib/aws-sdk-sso/endpoint_parameters.rb +4 -4
  46. data/lib/aws-sdk-sso/endpoint_provider.rb +2 -2
  47. data/lib/aws-sdk-sso.rb +1 -1
  48. data/lib/aws-sdk-ssooidc/client.rb +43 -23
  49. data/lib/aws-sdk-ssooidc/client_api.rb +5 -0
  50. data/lib/aws-sdk-ssooidc/endpoint_parameters.rb +4 -4
  51. data/lib/aws-sdk-ssooidc/errors.rb +10 -0
  52. data/lib/aws-sdk-ssooidc/types.rb +27 -15
  53. data/lib/aws-sdk-ssooidc.rb +1 -1
  54. data/lib/aws-sdk-sts/client.rb +159 -28
  55. data/lib/aws-sdk-sts/client_api.rb +73 -1
  56. data/lib/aws-sdk-sts/customizations.rb +0 -1
  57. data/lib/aws-sdk-sts/endpoint_parameters.rb +5 -5
  58. data/lib/aws-sdk-sts/errors.rb +64 -1
  59. data/lib/aws-sdk-sts/presigner.rb +2 -6
  60. data/lib/aws-sdk-sts/types.rb +175 -6
  61. data/lib/aws-sdk-sts.rb +1 -1
  62. data/lib/seahorse/client/h2/handler.rb +6 -1
  63. data/lib/seahorse/client/net_http/patches.rb +44 -11
  64. data/lib/seahorse/client/request_context.rb +2 -2
  65. metadata +27 -1
@@ -4,17 +4,39 @@ require 'time'
4
4
  require 'net/http'
5
5
 
6
6
  module Aws
7
- # An auto-refreshing credential provider that loads credentials from
8
- # EC2 instances.
7
+ # An auto-refreshing credential provider that loads credentials from EC2 instances.
9
8
  #
10
9
  # instance_credentials = Aws::InstanceProfileCredentials.new
11
10
  # ec2 = Aws::EC2::Client.new(credentials: instance_credentials)
11
+ #
12
+ # ## Retries
13
+ # When initialized from the default credential chain, this provider defaults to `0` retries.
14
+ # Breakdown of retries is as follows:
15
+ #
16
+ # * **Configurable retries** (defaults to `1`): these retries handle errors when communicating
17
+ # with the IMDS endpoint. There are two separate retry mechanisms within the provider:
18
+ # * Entire token fetch and credential retrieval process
19
+ # * Token fetching
20
+ # * **JSON parsing retries**: Fixed at 3 attempts to handle cases when IMDS returns malformed JSON
21
+ # responses. These retries are separate from configurable retries.
22
+ #
23
+ # @see https://docs.aws.amazon.com/sdkref/latest/guide/feature-imds-credentials.html IMDS Credential Provider
12
24
  class InstanceProfileCredentials
13
25
  include CredentialProvider
14
26
  include RefreshingCredentials
15
27
 
16
28
  # @api private
17
- class Non200Response < RuntimeError; end
29
+ class Non200Response < RuntimeError
30
+ attr_reader :status_code, :body
31
+
32
+ def initialize(status_code, body = nil)
33
+ @status_code = status_code
34
+ @body = body
35
+ msg = "HTTP #{status_code}"
36
+ msg += ": #{body}" if body && !body.empty?
37
+ super(msg)
38
+ end
39
+ end
18
40
 
19
41
  # @api private
20
42
  class TokenRetrivalError < RuntimeError; end
@@ -22,10 +44,8 @@ module Aws
22
44
  # @api private
23
45
  class TokenExpiredError < RuntimeError; end
24
46
 
25
- # These are the errors we trap when attempting to talk to the
26
- # instance metadata service. Any of these imply the service
27
- # is not present, no responding or some other non-recoverable
28
- # error.
47
+ # These are the errors we trap when attempting to talk to the instance metadata service.
48
+ # Any of these imply the service is not present, no responding or some other non-recoverable error.
29
49
  # @api private
30
50
  NETWORK_ERRORS = [
31
51
  Errno::EHOSTUNREACH,
@@ -46,100 +66,113 @@ module Aws
46
66
  METADATA_TOKEN_PATH = '/latest/api/token'.freeze
47
67
 
48
68
  # @param [Hash] options
49
- # @option options [Integer] :retries (1) Number of times to retry
50
- # when retrieving credentials.
51
- # @option options [String] :endpoint ('http://169.254.169.254') The IMDS
52
- # endpoint. This option has precedence over the :endpoint_mode.
53
- # @option options [String] :endpoint_mode ('IPv4') The endpoint mode for
54
- # the instance metadata service. This is either 'IPv4' ('169.254.169.254')
55
- # or 'IPv6' ('[fd00:ec2::254]').
56
- # @option options [Boolean] :disable_imds_v1 (false) Disable the use of the
57
- # legacy EC2 Metadata Service v1.
58
- # @option options [String] :ip_address ('169.254.169.254') Deprecated. Use
59
- # :endpoint instead. The IP address for the endpoint.
69
+ # @option options [Integer] :retries (1) Number of times to retry when retrieving credentials.
70
+ # @option options [Numeric, Proc] :backoff By default, failures are retried with exponential back-off, i.e.
71
+ # `lambda { |num_failures| sleep(1.2 ** num_failures) }`. You can pass a number of seconds to sleep
72
+ # between failed attempts, or a Proc that accepts the number of failures.
73
+ # @option options [String] :endpoint ('http://169.254.169.254') The IMDS endpoint. This option has precedence
74
+ # over the `:endpoint_mode`.
75
+ # @option options [String] :endpoint_mode ('IPv4') The endpoint mode for the instance metadata service. This is
76
+ # either 'IPv4' (`169.254.169.254`) or IPv6' (`[fd00:ec2::254]`).
77
+ # @option options [Boolean] :disable_imds_v1 (false) Disable the use of the legacy EC2 Metadata Service v1.
78
+ # @option options [String] :ip_address ('169.254.169.254') Deprecated. Use `:endpoint` instead.
79
+ # The IP address for the endpoint.
60
80
  # @option options [Integer] :port (80)
61
81
  # @option options [Float] :http_open_timeout (1)
62
82
  # @option options [Float] :http_read_timeout (1)
63
- # @option options [Numeric, Proc] :delay By default, failures are retried
64
- # with exponential back-off, i.e. `sleep(1.2 ** num_failures)`. You can
65
- # pass a number of seconds to sleep between failed attempts, or
66
- # a Proc that accepts the number of failures.
67
- # @option options [IO] :http_debug_output (nil) HTTP wire
68
- # traces are sent to this object. You can specify something
69
- # like $stdout.
70
- # @option options [Integer] :token_ttl Time-to-Live in seconds for EC2
71
- # Metadata Token used for fetching Metadata Profile Credentials, defaults
72
- # to 21600 seconds
73
- # @option options [Callable] before_refresh Proc called before
74
- # credentials are refreshed. `before_refresh` is called
75
- # with an instance of this object when
76
- # AWS credentials are required and need to be refreshed.
83
+ # @option options [IO] :http_debug_output (nil) HTTP wire traces are sent to this object.
84
+ # You can specify something like `$stdout`.
85
+ # @option options [Integer] :token_ttl (21600) Time-to-Live in seconds for EC2 Metadata Token used for fetching
86
+ # Metadata Profile Credentials.
87
+ # @option options [Proc] :before_refresh A Proc called before credentials are refreshed. `:before_refresh`
88
+ # is called with an instance of this object when AWS credentials are required and need to be refreshed.
77
89
  def initialize(options = {})
78
- @retries = options[:retries] || 1
79
- endpoint_mode = resolve_endpoint_mode(options)
80
- @endpoint = resolve_endpoint(options, endpoint_mode)
81
- @port = options[:port] || 80
90
+ @backoff = resolve_backoff(options[:backoff])
82
91
  @disable_imds_v1 = resolve_disable_v1(options)
83
- # Flag for if v2 flow fails, skip future attempts
84
- @imds_v1_fallback = false
92
+ @endpoint = resolve_endpoint(options)
85
93
  @http_open_timeout = options[:http_open_timeout] || 1
86
94
  @http_read_timeout = options[:http_read_timeout] || 1
87
95
  @http_debug_output = options[:http_debug_output]
88
- @backoff = backoff(options[:backoff])
96
+ @port = options[:port] || 80
97
+ @retries = options[:retries] || 1
89
98
  @token_ttl = options[:token_ttl] || 21_600
90
- @token = nil
91
- @no_refresh_until = nil
99
+
92
100
  @async_refresh = false
101
+ @imds_v1_fallback = false
102
+ @no_refresh_until = nil
103
+ @token = nil
93
104
  @metrics = ['CREDENTIALS_IMDS']
94
105
  super
95
106
  end
96
107
 
97
- # @return [Integer] Number of times to retry when retrieving credentials
98
- # from the instance metadata service. Defaults to 0 when resolving from
99
- # the default credential chain ({Aws::CredentialProviderChain}).
108
+ # @return [Boolean]
109
+ attr_reader :disable_imds_v1
110
+
111
+ # @return [Integer]
112
+ attr_reader :token_ttl
113
+
114
+ # @return [Integer]
100
115
  attr_reader :retries
101
116
 
117
+ # @return [Proc]
118
+ attr_reader :backoff
119
+
120
+ # @return [String]
121
+ attr_reader :endpoint
122
+
123
+ # @return [Integer]
124
+ attr_reader :port
125
+
126
+ # @return [Integer]
127
+ attr_reader :http_open_timeout
128
+
129
+ # @return [Integer]
130
+ attr_reader :http_read_timeout
131
+
132
+ # @return [IO, nil]
133
+ attr_reader :http_debug_output
134
+
102
135
  private
103
136
 
104
137
  def resolve_endpoint_mode(options)
105
- value = options[:endpoint_mode]
106
- value ||= ENV['AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE']
107
- value ||= Aws.shared_config.ec2_metadata_service_endpoint_mode(
108
- profile: options[:profile]
109
- )
110
- value || 'IPv4'
138
+ options[:endpoint_mode] ||
139
+ ENV['AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE'] ||
140
+ Aws.shared_config.ec2_metadata_service_endpoint_mode(profile: options[:profile]) ||
141
+ 'IPv4'
111
142
  end
112
143
 
113
- def resolve_endpoint(options, endpoint_mode)
114
- value = options[:endpoint] || options[:ip_address]
115
- value ||= ENV['AWS_EC2_METADATA_SERVICE_ENDPOINT']
116
- value ||= Aws.shared_config.ec2_metadata_service_endpoint(
117
- profile: options[:profile]
118
- )
144
+ def resolve_endpoint(options)
145
+ if (value = options[:ip_address])
146
+ warn('The `:ip_address` option is deprecated. Use `:endpoint` instead.')
147
+ return value
148
+ end
119
149
 
150
+ value =
151
+ options[:endpoint] ||
152
+ ENV['AWS_EC2_METADATA_SERVICE_ENDPOINT'] ||
153
+ Aws.shared_config.ec2_metadata_service_endpoint(profile: options[:profile]) ||
154
+ nil
120
155
  return value if value
121
156
 
157
+ endpoint_mode = resolve_endpoint_mode(options)
122
158
  case endpoint_mode.downcase
123
159
  when 'ipv4' then 'http://169.254.169.254'
124
160
  when 'ipv6' then 'http://[fd00:ec2::254]'
125
161
  else
126
- raise ArgumentError,
127
- ':endpoint_mode is not valid, expected IPv4 or IPv6, '\
128
- "got: #{endpoint_mode}"
162
+ raise ArgumentError, ":endpoint_mode is not valid, expected IPv4 or IPv6, got: #{endpoint_mode}"
129
163
  end
130
164
  end
131
165
 
132
166
  def resolve_disable_v1(options)
133
- value = options[:disable_imds_v1]
134
- value ||= ENV['AWS_EC2_METADATA_V1_DISABLED']
135
- value ||= Aws.shared_config.ec2_metadata_v1_disabled(
136
- profile: options[:profile]
137
- )
138
- value = value.to_s.downcase if value
139
- Aws::Util.str_2_bool(value) || false
167
+ value =
168
+ options[:disable_imds_v1] ||
169
+ ENV['AWS_EC2_METADATA_V1_DISABLED'] ||
170
+ Aws.shared_config.ec2_metadata_v1_disabled(profile: options[:profile]) ||
171
+ 'false'
172
+ Aws::Util.str_2_bool(value.to_s.downcase)
140
173
  end
141
174
 
142
- def backoff(backoff)
175
+ def resolve_backoff(backoff)
143
176
  case backoff
144
177
  when Proc then backoff
145
178
  when Numeric then ->(_) { sleep(backoff) }
@@ -153,114 +186,86 @@ module Aws
153
186
  return
154
187
  end
155
188
 
156
- # Retry loading credentials up to 3 times is the instance metadata
157
- # service is responding but is returning invalid JSON documents
158
- # in response to the GET profile credentials call.
159
- begin
160
- retry_errors([Aws::Json::ParseError], max_retries: 3) do
161
- c = Aws::Json.load(get_credentials.to_s)
162
- if empty_credentials?(@credentials)
163
- @credentials = Credentials.new(
164
- c['AccessKeyId'],
165
- c['SecretAccessKey'],
166
- c['Token']
167
- )
168
- @expiration = c['Expiration'] ? Time.iso8601(c['Expiration']) : nil
169
- if @expiration && @expiration < Time.now
170
- @no_refresh_until = Time.now + refresh_offset
171
- warn_expired_credentials
172
- end
173
- else
174
- # credentials are already set, update them only if the new ones are not empty
175
- if !c['AccessKeyId'] || c['AccessKeyId'].empty?
176
- # error getting new credentials
177
- @no_refresh_until = Time.now + refresh_offset
178
- warn_expired_credentials
179
- else
180
- @credentials = Credentials.new(
181
- c['AccessKeyId'],
182
- c['SecretAccessKey'],
183
- c['Token']
184
- )
185
- @expiration = c['Expiration'] ? Time.iso8601(c['Expiration']) : nil
186
- if @expiration && @expiration < Time.now
187
- @no_refresh_until = Time.now + refresh_offset
188
- warn_expired_credentials
189
- end
190
- end
189
+ new_creds =
190
+ begin
191
+ # Retry loading credentials up to 3 times is the instance metadata
192
+ # service is responding but is returning invalid JSON documents
193
+ # in response to the GET profile credentials call.
194
+ retry_errors([Aws::Json::ParseError], max_retries: 3) do
195
+ Aws::Json.load(retrieve_credentials.to_s)
191
196
  end
197
+ rescue Aws::Json::ParseError
198
+ raise Aws::Errors::MetadataParserError
192
199
  end
193
- rescue Aws::Json::ParseError
194
- raise Aws::Errors::MetadataParserError
200
+
201
+ if @credentials&.set? && empty_credentials?(new_creds)
202
+ # credentials are already set, but there was an error getting new credentials
203
+ # so don't update the credentials and use stale ones (static stability)
204
+ @no_refresh_until = Time.now + rand(300..360)
205
+ warn_expired_credentials
206
+ else
207
+ # credentials are empty or successfully retrieved, update them
208
+ update_credentials(new_creds)
195
209
  end
196
210
  end
197
211
 
198
- def get_credentials
212
+ def retrieve_credentials
199
213
  # Retry loading credentials a configurable number of times if
200
214
  # the instance metadata service is not responding.
201
- if _metadata_disabled?
202
- '{}'
203
- else
204
- begin
205
- retry_errors(NETWORK_ERRORS, max_retries: @retries) do
206
- open_connection do |conn|
207
- # attempt to fetch token to start secure flow first
208
- # and rescue to failover
209
- fetch_token(conn) unless @imds_v1_fallback
210
- token = @token.value if token_set?
211
-
212
- # disable insecure flow if we couldn't get token
213
- # and imds v1 is disabled
214
- raise TokenRetrivalError if token.nil? && @disable_imds_v1
215
-
216
- _get_credentials(conn, token)
217
- end
215
+ begin
216
+ retry_errors(NETWORK_ERRORS, max_retries: @retries) do
217
+ open_connection do |conn|
218
+ # attempt to fetch token to start secure flow first
219
+ # and rescue to failover
220
+ fetch_token(conn) unless @imds_v1_fallback || (@token && !@token.expired?)
221
+
222
+ # disable insecure flow if we couldn't get token and imds v1 is disabled
223
+ raise TokenRetrivalError if @token.nil? && @disable_imds_v1
224
+
225
+ fetch_credentials(conn)
218
226
  end
219
- rescue => e
220
- warn("Error retrieving instance profile credentials: #{e}")
221
- '{}'
222
227
  end
228
+ rescue StandardError => e
229
+ warn("Error retrieving instance profile credentials: #{e}")
230
+ '{}'
223
231
  end
224
232
  end
225
233
 
234
+ def update_credentials(creds)
235
+ @credentials = Credentials.new(creds['AccessKeyId'], creds['SecretAccessKey'], creds['Token'])
236
+ @expiration = creds['Expiration'] ? Time.iso8601(creds['Expiration']) : nil
237
+ return unless @expiration && @expiration < Time.now
238
+
239
+ @no_refresh_until = Time.now + rand(300..360)
240
+ warn_expired_credentials
241
+ end
242
+
226
243
  def fetch_token(conn)
227
- retry_errors(NETWORK_ERRORS, max_retries: @retries) do
228
- unless token_set?
229
- created_time = Time.now
230
- token_value, ttl = http_put(
231
- conn, METADATA_TOKEN_PATH, @token_ttl
232
- )
233
- @token = Token.new(token_value, ttl, created_time) if token_value && ttl
234
- end
235
- end
244
+ created_time = Time.now
245
+ token_value, ttl = http_put(conn)
246
+ @token = Token.new(token_value, ttl, created_time) if token_value && ttl
236
247
  rescue *NETWORK_ERRORS
237
248
  # token attempt failed, reset token
238
249
  # fallback to non-token mode
239
- @token = nil
240
250
  @imds_v1_fallback = true
241
251
  end
242
252
 
243
- # token is optional - if nil, uses v1 (insecure) flow
244
- def _get_credentials(conn, token)
245
- metadata = http_get(conn, METADATA_PATH_BASE, token)
253
+ def fetch_credentials(conn)
254
+ metadata = http_get(conn, METADATA_PATH_BASE)
246
255
  profile_name = metadata.lines.first.strip
247
- http_get(conn, METADATA_PATH_BASE + profile_name, token)
256
+ http_get(conn, METADATA_PATH_BASE + profile_name)
248
257
  rescue TokenExpiredError
249
258
  # Token has expired, reset it
250
259
  # The next retry should fetch it
251
260
  @token = nil
252
261
  @imds_v1_fallback = false
253
- raise Non200Response
262
+ raise Non200Response.new(401, 'Token expired')
254
263
  end
255
264
 
256
265
  def token_set?
257
266
  @token && !@token.expired?
258
267
  end
259
268
 
260
- def _metadata_disabled?
261
- ENV.fetch('AWS_EC2_METADATA_DISABLED', 'false').downcase == 'true'
262
- end
263
-
264
269
  def open_connection
265
270
  uri = URI.parse(@endpoint)
266
271
  http = Net::HTTP.new(uri.hostname || @endpoint, uri.port || @port)
@@ -272,9 +277,9 @@ module Aws
272
277
  end
273
278
 
274
279
  # GET request fetch profile and credentials
275
- def http_get(connection, path, token = nil)
280
+ def http_get(connection, path)
276
281
  headers = { 'User-Agent' => "aws-sdk-ruby3/#{CORE_GEM_VERSION}" }
277
- headers['x-aws-ec2-metadata-token'] = token if token
282
+ headers['x-aws-ec2-metadata-token'] = @token.value if @token
278
283
  response = connection.request(Net::HTTP::Get.new(path, headers))
279
284
 
280
285
  case response.code.to_i
@@ -283,17 +288,17 @@ module Aws
283
288
  when 401
284
289
  raise TokenExpiredError
285
290
  else
286
- raise Non200Response
291
+ raise Non200Response.new(response.code.to_i, response.body)
287
292
  end
288
293
  end
289
294
 
290
295
  # PUT request fetch token with ttl
291
- def http_put(connection, path, ttl)
296
+ def http_put(connection)
292
297
  headers = {
293
298
  'User-Agent' => "aws-sdk-ruby3/#{CORE_GEM_VERSION}",
294
- 'x-aws-ec2-metadata-token-ttl-seconds' => ttl.to_s
299
+ 'x-aws-ec2-metadata-token-ttl-seconds' => @token_ttl.to_s
295
300
  }
296
- response = connection.request(Net::HTTP::Put.new(path, headers))
301
+ response = connection.request(Net::HTTP::Put.new(METADATA_TOKEN_PATH, headers))
297
302
  case response.code.to_i
298
303
  when 200
299
304
  [
@@ -303,7 +308,7 @@ module Aws
303
308
  when 400
304
309
  raise TokenRetrivalError
305
310
  else
306
- raise Non200Response
311
+ raise Non200Response.new(response.code.to_i, response.body)
307
312
  end
308
313
  end
309
314
 
@@ -322,18 +327,12 @@ module Aws
322
327
  end
323
328
 
324
329
  def warn_expired_credentials
325
- warn("Attempting credential expiration extension due to a credential "\
326
- "service availability issue. A refresh of these credentials "\
327
- "will be attempted again in 5 minutes.")
328
- end
329
-
330
- def empty_credentials?(creds)
331
- !creds || !creds.access_key_id || creds.access_key_id.empty?
330
+ warn('Attempting credential expiration extension due to a credential service availability issue. '\
331
+ 'A refresh of these credentials will be attempted again in 5 minutes.')
332
332
  end
333
333
 
334
- # Compute an offset for refresh with jitter
335
- def refresh_offset
336
- 300 + rand(0..60)
334
+ def empty_credentials?(creds_hash)
335
+ !creds_hash['AccessKeyId'] || creds_hash['AccessKeyId'].empty?
337
336
  end
338
337
 
339
338
  # @api private
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Aws
4
4
  module Json
5
+ # @api private
5
6
  class ErrorHandler < Aws::ErrorHandler
6
7
 
7
8
  def call(context)
@@ -24,18 +25,21 @@ module Aws
24
25
  end
25
26
 
26
27
  def error_code(json, context)
28
+ # This is not correct per protocol tests. awsQueryError is intended to populate the
29
+ # error code of the error class. The error class should come from __type. Query and
30
+ # query compatible services currently have dynamic errors raised from error codes instead
31
+ # of the modeled error class. However, changing this in this major version would break
32
+ # existing usage.
27
33
  code =
28
34
  if aws_query_error?(context)
29
- query_header = context.http_response.headers['x-amzn-query-error']
30
- error, _type = query_header.split(';') # type not supported
31
- remove_prefix(error, context)
35
+ aws_query_error_code(context)
32
36
  else
33
37
  json['__type']
34
38
  end
35
39
  code ||= json['code']
36
40
  code ||= context.http_response.headers['x-amzn-errortype']
37
41
  if code
38
- code.split('#').last
42
+ code.split('#').last.split(':').first
39
43
  else
40
44
  http_status_error_code(context)
41
45
  end
@@ -46,6 +50,12 @@ module Aws
46
50
  context.http_response.headers['x-amzn-query-error']
47
51
  end
48
52
 
53
+ def aws_query_error_code(context)
54
+ query_header = context.http_response.headers['x-amzn-query-error']
55
+ error, _type = query_header.split(';') # type not supported
56
+ remove_prefix(error, context)
57
+ end
58
+
49
59
  def remove_prefix(error_code, context)
50
60
  if (prefix = context.config.api.metadata['errorPrefix'])
51
61
  error_code.sub(/^#{prefix}/, '')