aws-sdk-core 3.46.0 → 3.94.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +5 -5
  2. data/VERSION +1 -1
  3. data/lib/aws-sdk-core.rb +7 -0
  4. data/lib/aws-sdk-core/arn.rb +77 -0
  5. data/lib/aws-sdk-core/arn_parser.rb +38 -0
  6. data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +102 -0
  7. data/lib/aws-sdk-core/async_client_stubs.rb +80 -0
  8. data/lib/aws-sdk-core/binary.rb +3 -0
  9. data/lib/aws-sdk-core/binary/decode_handler.rb +9 -1
  10. data/lib/aws-sdk-core/binary/encode_handler.rb +32 -0
  11. data/lib/aws-sdk-core/binary/event_builder.rb +122 -0
  12. data/lib/aws-sdk-core/binary/event_parser.rb +48 -18
  13. data/lib/aws-sdk-core/binary/event_stream_decoder.rb +5 -2
  14. data/lib/aws-sdk-core/binary/event_stream_encoder.rb +53 -0
  15. data/lib/aws-sdk-core/client_side_monitoring/publisher.rb +9 -1
  16. data/lib/aws-sdk-core/client_stubs.rb +10 -9
  17. data/lib/aws-sdk-core/credential_provider.rb +0 -31
  18. data/lib/aws-sdk-core/credential_provider_chain.rb +79 -39
  19. data/lib/aws-sdk-core/deprecations.rb +16 -10
  20. data/lib/aws-sdk-core/ecs_credentials.rb +12 -8
  21. data/lib/aws-sdk-core/endpoint_cache.rb +14 -11
  22. data/lib/aws-sdk-core/errors.rb +94 -6
  23. data/lib/aws-sdk-core/event_emitter.rb +42 -0
  24. data/lib/aws-sdk-core/instance_profile_credentials.rb +120 -38
  25. data/lib/aws-sdk-core/json.rb +13 -14
  26. data/lib/aws-sdk-core/json/error_handler.rb +19 -2
  27. data/lib/aws-sdk-core/json/handler.rb +19 -1
  28. data/lib/aws-sdk-core/log/formatter.rb +7 -1
  29. data/lib/aws-sdk-core/log/param_filter.rb +3 -3
  30. data/lib/aws-sdk-core/pageable_response.rb +34 -20
  31. data/lib/aws-sdk-core/param_validator.rb +11 -5
  32. data/lib/aws-sdk-core/plugins/client_metrics_plugin.rb +26 -1
  33. data/lib/aws-sdk-core/plugins/endpoint_discovery.rb +1 -1
  34. data/lib/aws-sdk-core/plugins/event_stream_configuration.rb +14 -0
  35. data/lib/aws-sdk-core/plugins/invocation_id.rb +33 -0
  36. data/lib/aws-sdk-core/plugins/regional_endpoint.rb +8 -1
  37. data/lib/aws-sdk-core/plugins/retries/client_rate_limiter.rb +137 -0
  38. data/lib/aws-sdk-core/plugins/retries/clock_skew.rb +98 -0
  39. data/lib/aws-sdk-core/plugins/retries/error_inspector.rb +142 -0
  40. data/lib/aws-sdk-core/plugins/retries/retry_quota.rb +57 -0
  41. data/lib/aws-sdk-core/plugins/retry_errors.rb +290 -106
  42. data/lib/aws-sdk-core/plugins/signature_v4.rb +13 -2
  43. data/lib/aws-sdk-core/plugins/stub_responses.rb +20 -7
  44. data/lib/aws-sdk-core/plugins/transfer_encoding.rb +51 -0
  45. data/lib/aws-sdk-core/plugins/user_agent.rb +4 -8
  46. data/lib/aws-sdk-core/process_credentials.rb +9 -3
  47. data/lib/aws-sdk-core/shared_config.rb +95 -125
  48. data/lib/aws-sdk-core/structure.rb +1 -2
  49. data/lib/aws-sdk-core/stubbing/protocols/rest.rb +19 -0
  50. data/lib/aws-sdk-core/stubbing/stub_data.rb +13 -4
  51. data/lib/aws-sdk-core/util.rb +4 -0
  52. data/lib/aws-sdk-core/waiters/waiter.rb +2 -2
  53. data/lib/aws-sdk-core/xml/error_handler.rb +26 -3
  54. data/lib/aws-sdk-sts.rb +7 -4
  55. data/lib/aws-sdk-sts/client.rb +1109 -459
  56. data/lib/aws-sdk-sts/client_api.rb +67 -0
  57. data/lib/aws-sdk-sts/customizations.rb +2 -0
  58. data/lib/aws-sdk-sts/errors.rb +150 -0
  59. data/lib/aws-sdk-sts/plugins/sts_regional_endpoints.rb +32 -0
  60. data/lib/aws-sdk-sts/presigner.rb +67 -0
  61. data/lib/aws-sdk-sts/resource.rb +1 -0
  62. data/lib/aws-sdk-sts/types.rb +736 -176
  63. data/lib/seahorse.rb +9 -0
  64. data/lib/seahorse/client/async_base.rb +50 -0
  65. data/lib/seahorse/client/async_response.rb +62 -0
  66. data/lib/seahorse/client/base.rb +4 -2
  67. data/lib/seahorse/client/configuration.rb +4 -2
  68. data/lib/seahorse/client/events.rb +1 -1
  69. data/lib/seahorse/client/h2/connection.rb +246 -0
  70. data/lib/seahorse/client/h2/handler.rb +151 -0
  71. data/lib/seahorse/client/handler_list_entry.rb +2 -2
  72. data/lib/seahorse/client/http/async_response.rb +42 -0
  73. data/lib/seahorse/client/http/response.rb +13 -8
  74. data/lib/seahorse/client/logging/formatter.rb +4 -2
  75. data/lib/seahorse/client/net_http/connection_pool.rb +19 -20
  76. data/lib/seahorse/client/net_http/handler.rb +7 -1
  77. data/lib/seahorse/client/net_http/patches.rb +7 -1
  78. data/lib/seahorse/client/networking_error.rb +28 -0
  79. data/lib/seahorse/client/plugin.rb +5 -4
  80. data/lib/seahorse/client/plugins/content_length.rb +5 -2
  81. data/lib/seahorse/client/plugins/h2.rb +64 -0
  82. data/lib/seahorse/client/response.rb +3 -5
  83. data/lib/seahorse/model/api.rb +4 -0
  84. data/lib/seahorse/model/operation.rb +4 -0
  85. data/lib/seahorse/model/shapes.rb +2 -2
  86. metadata +43 -10
@@ -42,7 +42,7 @@ module Aws
42
42
  option(:unsigned_operations) do |cfg|
43
43
  cfg.api.operation_names.inject([]) do |unsigned, operation_name|
44
44
  if cfg.api.operation(operation_name)['authtype'] == 'none' ||
45
- cfg.api.operation(operation_name)['authtype'] == 'custom'
45
+ cfg.api.operation(operation_name)['authtype'] == 'custom'
46
46
  # Unsign requests that has custom apigateway authorizer as well
47
47
  unsigned << operation_name
48
48
  else
@@ -107,6 +107,17 @@ module Aws
107
107
  req.headers.delete('X-Amz-Security-Token')
108
108
  req.headers.delete('X-Amz-Date')
109
109
 
110
+ if context.config.respond_to?(:clock_skew) &&
111
+ context.config.clock_skew &&
112
+ context.config.correct_clock_skew
113
+
114
+ endpoint = context.http_request.endpoint
115
+ skew = context.config.clock_skew.clock_correction(endpoint)
116
+ if skew.abs > 0
117
+ req.headers['X-Amz-Date'] = (Time.now.utc + skew).strftime("%Y%m%dT%H%M%SZ")
118
+ end
119
+ end
120
+
110
121
  # compute the signature
111
122
  begin
112
123
  signature = signer.sign_request(
@@ -130,7 +141,7 @@ module Aws
130
141
  # @api private
131
142
  def apply_authtype(context)
132
143
  if context.operation['authtype'].eql?('v4-unsigned-body') &&
133
- context.http_request.endpoint.scheme.eql?('https')
144
+ context.http_request.endpoint.scheme.eql?('https')
134
145
  context.http_request.headers['X-Amz-Content-Sha256'] = 'UNSIGNED-PAYLOAD'
135
146
  end
136
147
  context
@@ -34,6 +34,7 @@ requests are made, and retries are disabled.
34
34
  if client.config.stub_responses
35
35
  client.setup_stubbing
36
36
  client.handlers.remove(RetryErrors::Handler)
37
+ client.handlers.remove(RetryErrors::LegacyHandler)
37
38
  client.handlers.remove(ClientMetricsPlugin::Handler)
38
39
  client.handlers.remove(ClientMetricsSendPlugin::LatencyHandler)
39
40
  client.handlers.remove(ClientMetricsSendPlugin::AttemptHandler)
@@ -45,15 +46,18 @@ requests are made, and retries are disabled.
45
46
  def call(context)
46
47
  stub = context.client.next_stub(context)
47
48
  resp = Seahorse::Client::Response.new(context: context)
48
- apply_stub(stub, resp)
49
- resp
49
+ async_mode = context.client.is_a? Seahorse::Client::AsyncBase
50
+ apply_stub(stub, resp, async_mode)
51
+
52
+ async_mode ? Seahorse::Client::AsyncResponse.new(
53
+ context: context, stream: context[:input_event_stream_handler].event_emitter.stream, sync_queue: Queue.new) : resp
50
54
  end
51
55
 
52
- def apply_stub(stub, response)
56
+ def apply_stub(stub, response, async_mode = false)
53
57
  http_resp = response.context.http_response
54
58
  case
55
59
  when stub[:error] then signal_error(stub[:error], http_resp)
56
- when stub[:http] then signal_http(stub[:http], http_resp)
60
+ when stub[:http] then signal_http(stub[:http], http_resp, async_mode)
57
61
  when stub[:data] then response.data = stub[:data]
58
62
  end
59
63
  end
@@ -67,9 +71,18 @@ requests are made, and retries are disabled.
67
71
  end
68
72
 
69
73
  # @param [Seahorse::Client::Http::Response] stub
70
- # @param [Seahorse::Client::Http::Response] http_resp
71
- def signal_http(stub, http_resp)
72
- http_resp.signal_headers(stub.status_code, stub.headers.to_h)
74
+ # @param [Seahorse::Client::Http::Response | Seahorse::Client::Http::AsyncResponse] http_resp
75
+ # @param [Boolean] async_mode
76
+ def signal_http(stub, http_resp, async_mode = false)
77
+ if async_mode
78
+ h2_headers = stub.headers.to_h.inject([]) do |arr, (k, v)|
79
+ arr << [k, v]
80
+ end
81
+ h2_headers << [":status", stub.status_code]
82
+ http_resp.signal_headers(h2_headers)
83
+ else
84
+ http_resp.signal_headers(stub.status_code, stub.headers.to_h)
85
+ end
73
86
  while chunk = stub.body.read(1024 * 1024)
74
87
  http_resp.signal_data(chunk)
75
88
  end
@@ -0,0 +1,51 @@
1
+ module Aws
2
+ module Plugins
3
+
4
+ # For Streaming Input Operations, when `requiresLength` is enabled
5
+ # checking whether `Content-Length` header can be set,
6
+ # for `v4-unsigned-body` operations, set `Transfer-Encoding` header
7
+ class TransferEncoding < Seahorse::Client::Plugin
8
+
9
+ # @api private
10
+ class Handler < Seahorse::Client::Handler
11
+ def call(context)
12
+ if streaming?(context.operation.input)
13
+ # If it's an IO object and not a File / String / String IO
14
+ unless context.http_request.body.respond_to?(:size)
15
+ if requires_length?(context.operation.input)
16
+ # if size of the IO is not available but required
17
+ raise Aws::Errors::MissingContentLength.new
18
+ elsif context.operation['authtype'] == "v4-unsigned-body"
19
+ context.http_request.headers['Transfer-Encoding'] = 'chunked'
20
+ end
21
+ end
22
+ end
23
+
24
+ @handler.call(context)
25
+ end
26
+
27
+ private
28
+
29
+ def streaming?(ref)
30
+ if payload = ref[:payload_member]
31
+ payload["streaming"] || # checking ref and shape
32
+ payload.shape["streaming"]
33
+ else
34
+ false
35
+ end
36
+ end
37
+
38
+ def requires_length?(ref)
39
+ payload = ref[:payload_member]
40
+ payload["requiresLength"] || # checking ref and shape
41
+ payload.shape["requiresLength"]
42
+ end
43
+
44
+ end
45
+
46
+ handler(Handler, step: :sign)
47
+
48
+ end
49
+
50
+ end
51
+ end
@@ -2,20 +2,16 @@ module Aws
2
2
  module Plugins
3
3
  # @api private
4
4
  class UserAgent < Seahorse::Client::Plugin
5
-
6
5
  option(:user_agent_suffix)
7
6
 
8
7
  # @api private
9
8
  class Handler < Seahorse::Client::Handler
10
-
11
9
  def call(context)
12
10
  set_user_agent(context)
13
11
  @handler.call(context)
14
12
  end
15
13
 
16
14
  def set_user_agent(context)
17
- execution_env = ENV["AWS_EXECUTION_ENV"]
18
-
19
15
  ua = "aws-sdk-ruby3/#{CORE_GEM_VERSION}"
20
16
 
21
17
  begin
@@ -30,19 +26,19 @@ module Aws
30
26
  ua += " #{context[:gem_name]}/#{context[:gem_version]}"
31
27
  end
32
28
 
33
- if execution_env
29
+ if (execution_env = ENV['AWS_EXECUTION_ENV'])
34
30
  ua += " exec-env/#{execution_env}"
35
31
  end
36
32
 
37
- ua += " #{context.config.user_agent_suffix}" if context.config.user_agent_suffix
33
+ if context.config.user_agent_suffix
34
+ ua += " #{context.config.user_agent_suffix}"
35
+ end
38
36
 
39
37
  context.http_request.headers['User-Agent'] = ua.strip
40
38
  end
41
-
42
39
  end
43
40
 
44
41
  handler(Handler)
45
-
46
42
  end
47
43
  end
48
44
  end
@@ -5,7 +5,7 @@ module Aws
5
5
  # A credential provider that executes a given process and attempts
6
6
  # to read its stdout to recieve a JSON payload containing the credentials
7
7
  #
8
- # Automatically handles refreshing credentials if an Expiration time is
8
+ # Automatically handles refreshing credentials if an Expiration time is
9
9
  # provided in the credentials payload
10
10
  #
11
11
  # credentials = Aws::ProcessCredentials.new('/usr/bin/credential_proc').credentials
@@ -23,10 +23,12 @@ module Aws
23
23
  # external process to be used as a credential provider.
24
24
  #
25
25
  # @param [String] process Invocation string for process
26
- # credentials provider.
26
+ # credentials provider.
27
27
  def initialize(process)
28
28
  @process = process
29
29
  @credentials = credentials_from_process(@process)
30
+
31
+ super
30
32
  end
31
33
 
32
34
  private
@@ -38,7 +40,11 @@ module Aws
38
40
  end
39
41
 
40
42
  if process_status.success?
41
- creds_json = JSON.parse(raw_out)
43
+ begin
44
+ creds_json = JSON.parse(raw_out)
45
+ rescue JSON::ParserError
46
+ raise Errors::InvalidProcessCredentialsPayload.new("Invalid JSON response")
47
+ end
42
48
  payload_version = creds_json['Version']
43
49
  if payload_version == 1
44
50
  _parse_payload_format_v1(creds_json)
@@ -1,8 +1,6 @@
1
1
  module Aws
2
-
3
2
  # @api private
4
3
  class SharedConfig
5
-
6
4
  # @return [String]
7
5
  attr_reader :credentials_path
8
6
 
@@ -48,7 +46,7 @@ module Aws
48
46
  @profile_name = determine_profile(options)
49
47
  @config_enabled = options[:config_enabled]
50
48
  @credentials_path = options[:credentials_path] ||
51
- determine_credentials_path
49
+ determine_credentials_path
52
50
  @parsed_credentials = {}
53
51
  load_credentials_file if loadable?(@credentials_path)
54
52
  if @config_enabled
@@ -67,7 +65,7 @@ module Aws
67
65
  @config_enabled = options[:config_enabled] ? true : false
68
66
  @profile_name = determine_profile(options)
69
67
  @credentials_path = options[:credentials_path] ||
70
- determine_credentials_path
68
+ determine_credentials_path
71
69
  load_credentials_file if loadable?(@credentials_path)
72
70
  if @config_enabled
73
71
  @config_path = options[:config_path] || determine_config_path
@@ -99,12 +97,10 @@ module Aws
99
97
  def credentials(opts = {})
100
98
  p = opts[:profile] || @profile_name
101
99
  validate_profile_exists(p) if credentials_present?
102
- if credentials = credentials_from_shared(p, opts)
100
+ if (credentials = credentials_from_shared(p, opts))
103
101
  credentials
104
- elsif credentials = credentials_from_config(p, opts)
102
+ elsif (credentials = credentials_from_config(p, opts))
105
103
  credentials
106
- else
107
- nil
108
104
  end
109
105
  end
110
106
 
@@ -121,79 +117,61 @@ module Aws
121
117
  credentials
122
118
  end
123
119
 
124
- def region(opts = {})
120
+ def assume_role_web_identity_credentials_from_config(opts = {})
125
121
  p = opts[:profile] || @profile_name
126
- if @config_enabled
127
- if @parsed_credentials
128
- region = @parsed_credentials.fetch(p, {})["region"]
129
- end
130
- if @parsed_config
131
- region ||= @parsed_config.fetch(p, {})["region"]
122
+ if @config_enabled && @parsed_config
123
+ entry = @parsed_config.fetch(p, {})
124
+ if entry['web_identity_token_file'] && entry['role_arn']
125
+ cfg = {
126
+ role_arn: entry['role_arn'],
127
+ web_identity_token_file: entry['web_identity_token_file'],
128
+ role_session_name: entry['role_session_name']
129
+ }
130
+ cfg[:region] = opts[:region] if opts[:region]
131
+ AssumeRoleWebIdentityCredentials.new(cfg)
132
132
  end
133
- region
134
- else
135
- nil
136
133
  end
137
134
  end
138
135
 
139
- def endpoint_discovery(opts = {})
140
- p = opts[:profile] || @profile_name
141
- if @config_enabled && @parsed_config
142
- @parsed_config.fetch(p, {})["endpoint_discovery_enabled"]
136
+ # Add an accessor method (similar to attr_reader) to return a configuration value
137
+ # Uses the get_config_value below to control where
138
+ # values are loaded from
139
+ def self.config_reader(*attrs)
140
+ attrs.each do |attr|
141
+ define_method(attr) { |opts = {}| get_config_value(attr.to_s, opts) }
143
142
  end
144
143
  end
145
144
 
146
- def credentials_process(profile)
147
- validate_profile_exists(profile)
148
- @parsed_config[profile]['credential_process']
149
- end
145
+ config_reader(
146
+ :region,
147
+ :credential_process,
148
+ :endpoint_discovery_enabled,
149
+ :max_attempts,
150
+ :retry_mode,
151
+ :adaptive_retry_wait_to_fill,
152
+ :correct_clock_skew,
153
+ :csm_client_id,
154
+ :csm_enabled,
155
+ :csm_host,
156
+ :csm_port,
157
+ :sts_regional_endpoints,
158
+ :s3_use_arn_region,
159
+ :s3_us_east_1_regional_endpoint
160
+ )
150
161
 
151
- def csm_enabled(opts = {})
152
- p = opts[:profile] || @profile_name
153
- if @config_enabled
154
- if @parsed_credentials
155
- value = @parsed_credentials.fetch(p, {})["csm_enabled"]
156
- end
157
- if @parsed_config
158
- value ||= @parsed_config.fetch(p, {})["csm_enabled"]
159
- end
160
- value
161
- else
162
- nil
163
- end
164
- end
162
+ private
165
163
 
166
- def csm_client_id(opts = {})
164
+ # Get a config value from from shared credential/config files.
165
+ # Only loads a value when config_enabled is true
166
+ # Return a value from credentials preferentially over config
167
+ def get_config_value(key, opts)
167
168
  p = opts[:profile] || @profile_name
168
- if @config_enabled
169
- if @parsed_credentials
170
- value = @parsed_credentials.fetch(p, {})["csm_client_id"]
171
- end
172
- if @parsed_config
173
- value ||= @parsed_config.fetch(p, {})["csm_client_id"]
174
- end
175
- value
176
- else
177
- nil
178
- end
179
- end
180
169
 
181
- def csm_port(opts = {})
182
- p = opts[:profile] || @profile_name
183
- if @config_enabled
184
- if @parsed_credentials
185
- value = @parsed_credentials.fetch(p, {})["csm_port"]
186
- end
187
- if @parsed_config
188
- value ||= @parsed_config.fetch(p, {})["csm_port"]
189
- end
190
- value
191
- else
192
- nil
193
- end
170
+ value = @parsed_credentials.fetch(p, {})[key] if @parsed_credentials
171
+ value ||= @parsed_config.fetch(p, {})[key] if @config_enabled && @parsed_config
172
+ value
194
173
  end
195
174
 
196
- private
197
175
  def credentials_present?
198
176
  (@parsed_credentials && !@parsed_credentials.empty?) ||
199
177
  (@parsed_config && !@parsed_config.empty?)
@@ -201,30 +179,28 @@ module Aws
201
179
 
202
180
  def assume_role_from_profile(cfg, profile, opts, chain_config)
203
181
  if cfg && prof_cfg = cfg[profile]
204
- opts[:source_profile] ||= prof_cfg["source_profile"]
182
+ opts[:source_profile] ||= prof_cfg['source_profile']
205
183
  credential_source = opts.delete(:credential_source)
206
- credential_source ||= prof_cfg["credential_source"]
184
+ credential_source ||= prof_cfg['credential_source']
207
185
  if opts[:source_profile] && credential_source
208
- raise Errors::CredentialSourceConflictError.new(
209
- "Profile #{profile} has a source_profile, and "\
210
- "a credential_source. For assume role credentials, must "\
211
- "provide only source_profile or credential_source, not both."
212
- )
186
+ raise Errors::CredentialSourceConflictError,
187
+ "Profile #{profile} has a source_profile, and "\
188
+ 'a credential_source. For assume role credentials, must '\
189
+ 'provide only source_profile or credential_source, not both.'
213
190
  elsif opts[:source_profile]
214
- opts[:credentials] = credentials(profile: opts[:source_profile])
191
+ opts[:credentials] = resolve_source_profile(opts[:source_profile], opts)
215
192
  if opts[:credentials]
216
- opts[:role_session_name] ||= prof_cfg["role_session_name"]
217
- opts[:role_session_name] ||= "default_session"
218
- opts[:role_arn] ||= prof_cfg["role_arn"]
219
- opts[:external_id] ||= prof_cfg["external_id"]
220
- opts[:serial_number] ||= prof_cfg["mfa_serial"]
193
+ opts[:role_session_name] ||= prof_cfg['role_session_name']
194
+ opts[:role_session_name] ||= 'default_session'
195
+ opts[:role_arn] ||= prof_cfg['role_arn']
196
+ opts[:duration_seconds] ||= prof_cfg['duration_seconds']
197
+ opts[:external_id] ||= prof_cfg['external_id']
198
+ opts[:serial_number] ||= prof_cfg['mfa_serial']
221
199
  opts[:profile] = opts.delete(:source_profile)
222
200
  AssumeRoleCredentials.new(opts)
223
201
  else
224
- raise Errors::NoSourceProfileError.new(
225
- "Profile #{profile} has a role_arn, and source_profile, but the"\
226
- " source_profile does not have credentials."
227
- )
202
+ raise Errors::NoSourceProfileError, "Profile #{profile} has a role_arn, and source_profile, but the"\
203
+ ' source_profile does not have credentials.'
228
204
  end
229
205
  elsif credential_source
230
206
  opts[:credentials] = credentials_from_source(
@@ -232,61 +208,64 @@ module Aws
232
208
  chain_config
233
209
  )
234
210
  if opts[:credentials]
235
- opts[:role_session_name] ||= prof_cfg["role_session_name"]
236
- opts[:role_session_name] ||= "default_session"
237
- opts[:role_arn] ||= prof_cfg["role_arn"]
238
- opts[:external_id] ||= prof_cfg["external_id"]
239
- opts[:serial_number] ||= prof_cfg["mfa_serial"]
211
+ opts[:role_session_name] ||= prof_cfg['role_session_name']
212
+ opts[:role_session_name] ||= 'default_session'
213
+ opts[:role_arn] ||= prof_cfg['role_arn']
214
+ opts[:duration_seconds] ||= prof_cfg['duration_seconds']
215
+ opts[:external_id] ||= prof_cfg['external_id']
216
+ opts[:serial_number] ||= prof_cfg['mfa_serial']
240
217
  opts.delete(:source_profile) # Cleanup
241
218
  AssumeRoleCredentials.new(opts)
242
219
  else
243
- raise Errors::NoSourceCredentials.new(
244
- "Profile #{profile} could not get source credentials from"\
220
+ raise Errors::NoSourceCredentials, "Profile #{profile} could not get source credentials from"\
245
221
  " provider #{credential_source}"
246
- )
247
222
  end
248
- elsif prof_cfg["role_arn"]
249
- raise Errors::NoSourceProfileError.new(
250
- "Profile #{profile} has a role_arn, but no source_profile."
251
- )
252
- else
253
- nil
223
+ elsif prof_cfg['role_arn']
224
+ raise Errors::NoSourceProfileError, "Profile #{profile} has a role_arn, but no source_profile."
254
225
  end
255
- else
256
- nil
226
+ end
227
+ end
228
+
229
+ def resolve_source_profile(profile, opts = {})
230
+ if (creds = credentials(profile: profile))
231
+ creds # static credentials
232
+ elsif (provider = assume_role_web_identity_credentials_from_config(opts.merge(profile: profile)))
233
+ provider.credentials if provider.credentials.set?
234
+ elsif (provider = assume_role_process_credentials_from_config(profile))
235
+ provider.credentials if provider.credentials.set?
257
236
  end
258
237
  end
259
238
 
260
239
  def credentials_from_source(credential_source, config)
261
240
  case credential_source
262
- when "Ec2InstanceMetadata"
241
+ when 'Ec2InstanceMetadata'
263
242
  InstanceProfileCredentials.new(
264
243
  retries: config ? config.instance_profile_credentials_retries : 0,
265
244
  http_open_timeout: config ? config.instance_profile_credentials_timeout : 1,
266
245
  http_read_timeout: config ? config.instance_profile_credentials_timeout : 1
267
246
  )
268
- when "EcsContainer"
247
+ when 'EcsContainer'
269
248
  ECSCredentials.new
270
249
  else
271
- raise Errors::InvalidCredentialSourceError.new(
272
- "Unsupported credential_source: #{credential_source}"
273
- )
250
+ raise Errors::InvalidCredentialSourceError, "Unsupported credential_source: #{credential_source}"
274
251
  end
275
252
  end
276
253
 
277
- def credentials_from_shared(profile, opts)
254
+ def assume_role_process_credentials_from_config(profile)
255
+ validate_profile_exists(profile)
256
+ credential_process = @parsed_config[profile]['credential_process']
257
+ ProcessCredentials.new(credential_process) if credential_process
258
+ end
259
+
260
+ def credentials_from_shared(profile, _opts)
278
261
  if @parsed_credentials && prof_config = @parsed_credentials[profile]
279
262
  credentials_from_profile(prof_config)
280
- else
281
- nil
282
263
  end
283
264
  end
284
265
 
285
- def credentials_from_config(profile, opts)
266
+ def credentials_from_config(profile, _opts)
286
267
  if @parsed_config && prof_config = @parsed_config[profile]
287
268
  credentials_from_profile(prof_config)
288
- else
289
- nil
290
269
  end
291
270
  end
292
271
 
@@ -296,15 +275,7 @@ module Aws
296
275
  prof_config['aws_secret_access_key'],
297
276
  prof_config['aws_session_token']
298
277
  )
299
- if credentials_complete(creds)
300
- creds
301
- else
302
- nil
303
- end
304
- end
305
-
306
- def credentials_complete(creds)
307
- creds.set?
278
+ creds if creds.set?
308
279
  end
309
280
 
310
281
  def load_credentials_file
@@ -334,19 +305,18 @@ module Aws
334
305
 
335
306
  def validate_profile_exists(profile)
336
307
  unless (@parsed_credentials && @parsed_credentials[profile]) ||
337
- (@parsed_config && @parsed_config[profile])
308
+ (@parsed_config && @parsed_config[profile])
338
309
  msg = "Profile `#{profile}' not found in #{@credentials_path}"
339
310
  msg << " or #{@config_path}" if @config_path
340
- raise Errors::NoSuchProfileError.new(msg)
311
+ raise Errors::NoSuchProfileError, msg
341
312
  end
342
313
  end
343
314
 
344
315
  def determine_profile(options)
345
316
  ret = options[:profile_name]
346
- ret ||= ENV["AWS_PROFILE"]
347
- ret ||= "default"
317
+ ret ||= ENV['AWS_PROFILE']
318
+ ret ||= 'default'
348
319
  ret
349
320
  end
350
-
351
321
  end
352
322
  end