aws-sdk-core 3.219.0 → 3.240.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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +222 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-defaults/default_configuration.rb +2 -1
  5. data/lib/aws-sdk-core/assume_role_credentials.rb +9 -8
  6. data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +3 -2
  7. data/lib/aws-sdk-core/client_stubs.rb +28 -48
  8. data/lib/aws-sdk-core/credential_provider.rb +4 -0
  9. data/lib/aws-sdk-core/credential_provider_chain.rb +91 -22
  10. data/lib/aws-sdk-core/credentials.rb +6 -0
  11. data/lib/aws-sdk-core/ecs_credentials.rb +14 -13
  12. data/lib/aws-sdk-core/endpoints/matchers.rb +2 -1
  13. data/lib/aws-sdk-core/endpoints.rb +37 -13
  14. data/lib/aws-sdk-core/error_handler.rb +5 -0
  15. data/lib/aws-sdk-core/errors.rb +5 -2
  16. data/lib/aws-sdk-core/event_emitter.rb +1 -1
  17. data/lib/aws-sdk-core/instance_profile_credentials.rb +147 -157
  18. data/lib/aws-sdk-core/json/error_handler.rb +14 -4
  19. data/lib/aws-sdk-core/login_credentials.rb +229 -0
  20. data/lib/aws-sdk-core/plugins/checksum_algorithm.rb +28 -14
  21. data/lib/aws-sdk-core/plugins/client_metrics_plugin.rb +0 -1
  22. data/lib/aws-sdk-core/plugins/credentials_configuration.rb +75 -59
  23. data/lib/aws-sdk-core/plugins/endpoint_pattern.rb +40 -32
  24. data/lib/aws-sdk-core/plugins/sign.rb +29 -20
  25. data/lib/aws-sdk-core/plugins/stub_responses.rb +30 -8
  26. data/lib/aws-sdk-core/plugins/user_agent.rb +26 -2
  27. data/lib/aws-sdk-core/process_credentials.rb +1 -1
  28. data/lib/aws-sdk-core/refreshing_credentials.rb +8 -11
  29. data/lib/aws-sdk-core/rest/request/headers.rb +1 -1
  30. data/lib/aws-sdk-core/rpc_v2/error_handler.rb +26 -16
  31. data/lib/aws-sdk-core/rpc_v2/parser.rb +8 -0
  32. data/lib/aws-sdk-core/shared_config.rb +102 -21
  33. data/lib/aws-sdk-core/shared_credentials.rb +1 -0
  34. data/lib/aws-sdk-core/sso_credentials.rb +3 -1
  35. data/lib/aws-sdk-core/static_token_provider.rb +1 -2
  36. data/lib/aws-sdk-core/token.rb +3 -3
  37. data/lib/aws-sdk-core/token_provider.rb +4 -0
  38. data/lib/aws-sdk-core/token_provider_chain.rb +2 -6
  39. data/lib/aws-sdk-core/util.rb +2 -1
  40. data/lib/aws-sdk-core/xml/error_handler.rb +3 -1
  41. data/lib/aws-sdk-core.rb +4 -0
  42. data/lib/aws-sdk-signin/client.rb +604 -0
  43. data/lib/aws-sdk-signin/client_api.rb +119 -0
  44. data/lib/aws-sdk-signin/customizations.rb +1 -0
  45. data/lib/aws-sdk-signin/endpoint_parameters.rb +69 -0
  46. data/lib/aws-sdk-signin/endpoint_provider.rb +59 -0
  47. data/lib/aws-sdk-signin/endpoints.rb +20 -0
  48. data/lib/aws-sdk-signin/errors.rb +122 -0
  49. data/lib/aws-sdk-signin/plugins/endpoints.rb +77 -0
  50. data/lib/aws-sdk-signin/resource.rb +26 -0
  51. data/lib/aws-sdk-signin/types.rb +299 -0
  52. data/lib/aws-sdk-signin.rb +63 -0
  53. data/lib/aws-sdk-sso/client.rb +25 -19
  54. data/lib/aws-sdk-sso/endpoint_parameters.rb +4 -4
  55. data/lib/aws-sdk-sso/endpoint_provider.rb +2 -2
  56. data/lib/aws-sdk-sso.rb +1 -1
  57. data/lib/aws-sdk-ssooidc/client.rb +57 -27
  58. data/lib/aws-sdk-ssooidc/client_api.rb +11 -0
  59. data/lib/aws-sdk-ssooidc/endpoint_parameters.rb +4 -4
  60. data/lib/aws-sdk-ssooidc/errors.rb +10 -0
  61. data/lib/aws-sdk-ssooidc/types.rb +45 -6
  62. data/lib/aws-sdk-ssooidc.rb +1 -1
  63. data/lib/aws-sdk-sts/client.rb +160 -30
  64. data/lib/aws-sdk-sts/client_api.rb +82 -8
  65. data/lib/aws-sdk-sts/customizations.rb +0 -1
  66. data/lib/aws-sdk-sts/endpoint_parameters.rb +5 -5
  67. data/lib/aws-sdk-sts/endpoint_provider.rb +18 -18
  68. data/lib/aws-sdk-sts/errors.rb +79 -0
  69. data/lib/aws-sdk-sts/presigner.rb +2 -6
  70. data/lib/aws-sdk-sts/types.rb +175 -6
  71. data/lib/aws-sdk-sts.rb +1 -1
  72. data/lib/seahorse/client/async_base.rb +4 -5
  73. data/lib/seahorse/client/base.rb +0 -14
  74. data/lib/seahorse/client/h2/connection.rb +18 -28
  75. data/lib/seahorse/client/h2/handler.rb +6 -1
  76. data/lib/seahorse/client/http/response.rb +1 -1
  77. data/lib/seahorse/client/net_http/connection_pool.rb +2 -1
  78. data/lib/seahorse/client/networking_error.rb +1 -1
  79. data/lib/seahorse/client/plugins/h2.rb +4 -4
  80. data/lib/seahorse/client/request_context.rb +2 -2
  81. data/lib/seahorse/util.rb +2 -1
  82. data/sig/aws-sdk-core/async_client_stubs.rbs +21 -0
  83. data/sig/seahorse/client/async_base.rbs +18 -0
  84. metadata +46 -8
@@ -13,9 +13,6 @@ module Aws
13
13
  option(:sigv4_region)
14
14
  option(:unsigned_operations, default: [])
15
15
 
16
- supported_auth_types = %w[sigv4 bearer sigv4-s3express sigv4a none]
17
- SUPPORTED_AUTH_TYPES = supported_auth_types.freeze
18
-
19
16
  def add_handlers(handlers, cfg)
20
17
  operations = cfg.api.operation_names - cfg.unsigned_operations
21
18
  handlers.add(Handler, step: :sign, operations: operations)
@@ -32,7 +29,7 @@ module Aws
32
29
  }
33
30
  SignatureV4.new(auth_scheme, config, sigv4_overrides)
34
31
  when 'bearer'
35
- Bearer.new
32
+ Bearer.new(config)
36
33
  else
37
34
  NullSigner.new
38
35
  end
@@ -50,11 +47,22 @@ module Aws
50
47
  )
51
48
  signer.sign(context)
52
49
  end
53
- @handler.call(context)
50
+ with_metrics(signer) { @handler.call(context) }
54
51
  end
55
52
 
56
53
  private
57
54
 
55
+ def with_metrics(signer, &block)
56
+ case signer
57
+ when SignatureV4
58
+ Aws::Plugins::UserAgent.metric(*signer.credentials.metrics, &block)
59
+ when Bearer
60
+ Aws::Plugins::UserAgent.metric(*signer.token_provider.metrics, &block)
61
+ else
62
+ block.call
63
+ end
64
+ end
65
+
58
66
  def v2_signing?(config)
59
67
  # 's3' is legacy signing, 'v4' is default
60
68
  config.respond_to?(:signature_version) &&
@@ -64,21 +72,19 @@ module Aws
64
72
 
65
73
  # @api private
66
74
  class Bearer
67
- def initialize
75
+ def initialize(config)
76
+ @token_provider = config.token_provider
68
77
  end
69
78
 
79
+ attr_reader :token_provider
80
+
70
81
  def sign(context)
71
82
  if context.http_request.endpoint.scheme != 'https'
72
- raise ArgumentError,
73
- 'Unable to use bearer authorization on non https endpoint.'
83
+ raise ArgumentError, 'Unable to use bearer authorization on non https endpoint.'
74
84
  end
85
+ raise Errors::MissingBearerTokenError unless @token_provider && @token_provider.set?
75
86
 
76
- token_provider = context.config.token_provider
77
-
78
- raise Errors::MissingBearerTokenError unless token_provider&.set?
79
-
80
- context.http_request.headers['Authorization'] =
81
- "Bearer #{token_provider.token.token}"
87
+ context.http_request.headers['Authorization'] = "Bearer #{@token_provider.token.token}"
82
88
  end
83
89
 
84
90
  def presign_url(*args)
@@ -94,12 +100,9 @@ module Aws
94
100
  class SignatureV4
95
101
  def initialize(auth_scheme, config, sigv4_overrides = {})
96
102
  scheme_name = auth_scheme['name']
97
-
98
103
  unless %w[sigv4 sigv4a sigv4-s3express].include?(scheme_name)
99
- raise ArgumentError,
100
- "Expected sigv4, sigv4a, or sigv4-s3express auth scheme, got #{scheme_name}"
104
+ raise ArgumentError, "Expected sigv4, sigv4a, or sigv4-s3express auth scheme, got #{scheme_name}"
101
105
  end
102
-
103
106
  region = if scheme_name == 'sigv4a'
104
107
  auth_scheme['signingRegionSet'].join(',')
105
108
  else
@@ -111,8 +114,8 @@ module Aws
111
114
  region: sigv4_overrides[:region] || config.sigv4_region || region,
112
115
  credentials_provider: sigv4_overrides[:credentials] || config.credentials,
113
116
  signing_algorithm: scheme_name.to_sym,
114
- uri_escape_path: !!!auth_scheme['disableDoubleEncoding'],
115
- normalize_path: !!!auth_scheme['disableNormalizePath'],
117
+ uri_escape_path: !auth_scheme['disableDoubleEncoding'],
118
+ normalize_path: !auth_scheme['disableNormalizePath'],
116
119
  unsigned_headers: %w[content-length user-agent x-amzn-trace-id expect transfer-encoding connection]
117
120
  )
118
121
  rescue Aws::Sigv4::Errors::MissingCredentialsError
@@ -120,6 +123,8 @@ module Aws
120
123
  end
121
124
  end
122
125
 
126
+ attr_reader :signer
127
+
123
128
  def sign(context)
124
129
  req = context.http_request
125
130
 
@@ -155,6 +160,10 @@ module Aws
155
160
  @signer.sign_event(*args)
156
161
  end
157
162
 
163
+ def credentials
164
+ @signer.credentials_provider
165
+ end
166
+
158
167
  private
159
168
 
160
169
  def apply_authtype(context, req)
@@ -29,8 +29,22 @@ requests are made, and retries are disabled.
29
29
  end
30
30
  end
31
31
 
32
+ option(:token_provider) do |config|
33
+ if config.stub_responses
34
+ StaticTokenProvider.new('stubbed-token')
35
+ end
36
+ end
37
+
38
+ option(:stubs) { {} }
39
+ option(:stubs_mutex) { Mutex.new }
40
+ option(:api_requests) { [] }
41
+ option(:api_requests_mutex) { Mutex.new }
42
+
32
43
  def add_handlers(handlers, config)
33
- handlers.add(Handler, step: :send) if config.stub_responses
44
+ return unless config.stub_responses
45
+
46
+ handlers.add(ApiRequestsHandler)
47
+ handlers.add(StubbingHandler, step: :send)
34
48
  end
35
49
 
36
50
  def after_initialize(client)
@@ -46,8 +60,20 @@ requests are made, and retries are disabled.
46
60
  end
47
61
  end
48
62
 
49
- class Handler < Seahorse::Client::Handler
63
+ class ApiRequestsHandler < Seahorse::Client::Handler
64
+ def call(context)
65
+ context.config.api_requests_mutex.synchronize do
66
+ context.config.api_requests << {
67
+ operation_name: context.operation_name,
68
+ params: context.params,
69
+ context: context
70
+ }
71
+ end
72
+ @handler.call(context)
73
+ end
74
+ end
50
75
 
76
+ class StubbingHandler < Seahorse::Client::Handler
51
77
  def call(context)
52
78
  span_wrapper(context) do
53
79
  stub_responses(context)
@@ -57,14 +83,10 @@ requests are made, and retries are disabled.
57
83
  private
58
84
 
59
85
  def stub_responses(context)
60
- stub = context.client.next_stub(context)
61
86
  resp = Seahorse::Client::Response.new(context: context)
62
87
  async_mode = context.client.is_a? Seahorse::Client::AsyncBase
63
- if Hash === stub && stub[:mutex]
64
- stub[:mutex].synchronize { apply_stub(stub, resp, async_mode) }
65
- else
66
- apply_stub(stub, resp, async_mode)
67
- end
88
+ stub = context.client.next_stub(context)
89
+ stub[:mutex].synchronize { apply_stub(stub, resp, async_mode) }
68
90
 
69
91
  if async_mode
70
92
  Seahorse::Client::AsyncResponse.new(
@@ -34,7 +34,30 @@ module Aws
34
34
  "FLEXIBLE_CHECKSUMS_REQ_WHEN_SUPPORTED" : "Z",
35
35
  "FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED" : "a",
36
36
  "FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED" : "b",
37
- "FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED" : "c"
37
+ "FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED" : "c",
38
+ "DDB_MAPPER": "d",
39
+ "CREDENTIALS_CODE" : "e",
40
+ "CREDENTIALS_ENV_VARS" : "g",
41
+ "CREDENTIALS_ENV_VARS_STS_WEB_ID_TOKEN" : "h",
42
+ "CREDENTIALS_STS_ASSUME_ROLE" : "i",
43
+ "CREDENTIALS_STS_ASSUME_ROLE_WEB_ID" : "k",
44
+ "CREDENTIALS_PROFILE" : "n",
45
+ "CREDENTIALS_PROFILE_SOURCE_PROFILE" : "o",
46
+ "CREDENTIALS_PROFILE_NAMED_PROVIDER" : "p",
47
+ "CREDENTIALS_PROFILE_STS_WEB_ID_TOKEN" : "q",
48
+ "CREDENTIALS_PROFILE_SSO" : "r",
49
+ "CREDENTIALS_SSO" : "s",
50
+ "CREDENTIALS_PROFILE_SSO_LEGACY" : "t",
51
+ "CREDENTIALS_SSO_LEGACY" : "u",
52
+ "CREDENTIALS_PROFILE_PROCESS" : "v",
53
+ "CREDENTIALS_PROCESS" : "w",
54
+ "CREDENTIALS_HTTP" : "z",
55
+ "CREDENTIALS_IMDS" : "0",
56
+ "SSO_LOGIN_DEVICE" : "1",
57
+ "SSO_LOGIN_AUTH" : "2",
58
+ "BEARER_SERVICE_ENV_VARS": "3",
59
+ "CREDENTIALS_PROFILE_LOGIN": "AC",
60
+ "CREDENTIALS_LOGIN": "AD"
38
61
  }
39
62
  METRICS
40
63
 
@@ -196,7 +219,8 @@ variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.
196
219
  end
197
220
  end
198
221
 
199
- handler(Handler, step: :sign, priority: 97)
222
+ # Priority set to 5 in order to add user agent as late as possible after signing
223
+ handler(Handler, step: :sign, priority: 5)
200
224
  end
201
225
  end
202
226
  end
@@ -36,7 +36,7 @@ module Aws
36
36
  @process = process
37
37
  @credentials = credentials_from_process
38
38
  @async_refresh = false
39
-
39
+ @metrics = ['CREDENTIALS_PROCESS']
40
40
  super
41
41
  end
42
42
 
@@ -1,28 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Aws
4
-
5
4
  # Base class used credential classes that can be refreshed. This
6
5
  # provides basic refresh logic in a thread-safe manner. Classes mixing in
7
- # this module are expected to implement a #refresh method that populates
6
+ # this module are expected to implement a `#refresh` method that populates
8
7
  # the following instance variables:
9
8
  #
10
- # * `@access_key_id`
11
- # * `@secret_access_key`
12
- # * `@session_token`
13
- # * `@expiration`
9
+ # * `@credentials` ({Credentials})
10
+ # * `@expiration` (Time)
14
11
  #
15
- # @api private
16
12
  module RefreshingCredentials
17
-
18
13
  SYNC_EXPIRATION_LENGTH = 300 # 5 minutes
19
14
  ASYNC_EXPIRATION_LENGTH = 600 # 10 minutes
20
15
 
21
16
  CLIENT_EXCLUDE_OPTIONS = Set.new([:before_refresh]).freeze
22
17
 
18
+ # @param [Hash] options
19
+ # @option options [Proc] :before_refresh A Proc called before credentials are refreshed.
20
+ # It accepts `self` as the only argument.
23
21
  def initialize(options = {})
24
22
  @mutex = Mutex.new
25
- @before_refresh = options.delete(:before_refresh) if Hash === options
23
+ @before_refresh = options.delete(:before_refresh) if options.is_a?(Hash)
26
24
 
27
25
  @before_refresh.call(self) if @before_refresh
28
26
  refresh
@@ -59,7 +57,7 @@ module Aws
59
57
  # Otherwise, if we're approaching expiration, use the existing credentials
60
58
  # but attempt a refresh in the background.
61
59
  def refresh_if_near_expiration!
62
- # Note: This check is an optimization. Rather than acquire the mutex on every #refresh_if_near_expiration
60
+ # NOTE: This check is an optimization. Rather than acquire the mutex on every #refresh_if_near_expiration
63
61
  # call, we check before doing so, and then we check within the mutex to avoid a race condition.
64
62
  # See issue: https://github.com/aws/aws-sdk-ruby/issues/2641 for more info.
65
63
  if near_expiration?(sync_expiration_length)
@@ -91,6 +89,5 @@ module Aws
91
89
  true
92
90
  end
93
91
  end
94
-
95
92
  end
96
93
  end
@@ -68,7 +68,7 @@ module Aws
68
68
  def apply_header_map(headers, ref, values)
69
69
  prefix = ref.location_name || ''
70
70
  values.each_pair do |name, value|
71
- headers["#{prefix}#{name}"] = value.to_s
71
+ headers["#{prefix}#{name}"] ||= value.to_s
72
72
  end
73
73
  end
74
74
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Aws
4
4
  module RpcV2
5
+ # @api private
5
6
  class ErrorHandler < Aws::ErrorHandler
6
7
 
7
8
  def call(context)
@@ -37,11 +38,14 @@ module Aws
37
38
  end
38
39
 
39
40
  def error_code(data, context)
41
+ # This is not correct per protocol tests. awsQueryError is intended to populate the
42
+ # error code of the error class. The error class should come from __type. Query and
43
+ # query compatible services currently have dynamic errors raised from error codes instead
44
+ # of the modeled error class. However, changing this in this major version would break
45
+ # existing usage.
40
46
  code =
41
47
  if aws_query_error?(context)
42
- query_header = context.http_response.headers['x-amzn-query-error']
43
- error, _type = query_header.split(';') # type not supported
44
- remove_prefix(error, context)
48
+ aws_query_error_code(context)
45
49
  else
46
50
  data['__type']
47
51
  end
@@ -52,6 +56,25 @@ module Aws
52
56
  end
53
57
  end
54
58
 
59
+ def aws_query_error?(context)
60
+ context.config.api.metadata['awsQueryCompatible'] &&
61
+ context.http_response.headers['x-amzn-query-error']
62
+ end
63
+
64
+ def aws_query_error_code(context)
65
+ query_header = context.http_response.headers['x-amzn-query-error']
66
+ error, _type = query_header.split(';') # type not supported
67
+ remove_prefix(error, context)
68
+ end
69
+
70
+ def remove_prefix(error_code, context)
71
+ if (prefix = context.config.api.metadata['errorPrefix'])
72
+ error_code.sub(/^#{prefix}/, '')
73
+ else
74
+ error_code
75
+ end
76
+ end
77
+
55
78
  def parse_error_data(context, body, code)
56
79
  data = EmptyStructure.new
57
80
  if (error_rules = context.operation.errors)
@@ -67,19 +90,6 @@ module Aws
67
90
  end
68
91
  data
69
92
  end
70
-
71
- def aws_query_error?(context)
72
- context.config.api.metadata['awsQueryCompatible'] &&
73
- context.http_response.headers['x-amzn-query-error']
74
- end
75
-
76
- def remove_prefix(error_code, context)
77
- if (prefix = context.config.api.metadata['errorPrefix'])
78
- error_code.sub(/^#{prefix}/, '')
79
- else
80
- error_code
81
- end
82
- end
83
93
  end
84
94
  end
85
95
  end
@@ -85,6 +85,14 @@ module Aws
85
85
  end
86
86
  end
87
87
  end
88
+
89
+ def flattened_list?(shape)
90
+ shape.is_a?(ListShape) && shape.flattened
91
+ end
92
+
93
+ def flattened_map?(shape)
94
+ shape.is_a?(MapShape) && shape.flattened
95
+ end
88
96
  end
89
97
  end
90
98
  end
@@ -138,7 +138,11 @@ module Aws
138
138
  role_session_name: entry['role_session_name']
139
139
  }
140
140
  cfg[:region] = opts[:region] if opts[:region]
141
- AssumeRoleWebIdentityCredentials.new(cfg)
141
+ with_metrics('CREDENTIALS_PROFILE_STS_WEB_ID_TOKEN') do
142
+ creds = AssumeRoleWebIdentityCredentials.new(cfg)
143
+ creds.metrics << 'CREDENTIALS_PROFILE_STS_WEB_ID_TOKEN'
144
+ creds
145
+ end
142
146
  end
143
147
  end
144
148
  end
@@ -167,6 +171,16 @@ module Aws
167
171
  token
168
172
  end
169
173
 
174
+ # Attempts to load from shared config or shared credentials file.
175
+ # Will always attempt first to load from the shared credentials
176
+ # file, if present.
177
+ def login_credentials_from_config(opts = {})
178
+ p = opts[:profile] || @profile_name
179
+ credentials = login_credentials_from_profile(@parsed_credentials, p, opts[:region])
180
+ credentials ||= login_credentials_from_profile(@parsed_config, p, opts[:region]) if @parsed_config
181
+ credentials
182
+ end
183
+
170
184
  # Source a custom configured endpoint from the shared configuration file
171
185
  #
172
186
  # @param [Hash] opts
@@ -199,6 +213,7 @@ module Aws
199
213
  config_reader(
200
214
  :region,
201
215
  :account_id_endpoint_mode,
216
+ :auth_scheme_preference,
202
217
  :sigv4a_signing_region_set,
203
218
  :ca_bundle,
204
219
  :credential_process,
@@ -208,6 +223,7 @@ module Aws
208
223
  :ec2_metadata_service_endpoint,
209
224
  :ec2_metadata_service_endpoint_mode,
210
225
  :ec2_metadata_v1_disabled,
226
+ :disable_host_prefix_injection,
211
227
  :max_attempts,
212
228
  :retry_mode,
213
229
  :adaptive_retry_wait_to_fill,
@@ -255,8 +271,8 @@ module Aws
255
271
  'provide only source_profile or credential_source, not both.'
256
272
  elsif opts[:source_profile]
257
273
  opts[:visited_profiles] ||= Set.new
258
- opts[:credentials] = resolve_source_profile(opts[:source_profile], opts)
259
- if opts[:credentials]
274
+ provider = resolve_source_profile(opts[:source_profile], opts)
275
+ if provider && (opts[:credentials] = provider.credentials)
260
276
  opts[:role_session_name] ||= prof_cfg['role_session_name']
261
277
  opts[:role_session_name] ||= 'default_session'
262
278
  opts[:role_arn] ||= prof_cfg['role_arn']
@@ -265,17 +281,28 @@ module Aws
265
281
  opts[:serial_number] ||= prof_cfg['mfa_serial']
266
282
  opts[:profile] = opts.delete(:source_profile)
267
283
  opts.delete(:visited_profiles)
268
- AssumeRoleCredentials.new(opts)
284
+
285
+ metrics = provider.metrics
286
+ if provider.is_a?(AssumeRoleCredentials)
287
+ opts[:credentials] = provider
288
+ metrics.delete('CREDENTIALS_STS_ASSUME_ROLE')
289
+ else
290
+ metrics << 'CREDENTIALS_PROFILE_SOURCE_PROFILE'
291
+ end
292
+ # Set the original credentials metrics to [] to prevent duplicate metrics during sign plugin
293
+ opts[:credentials].metrics = []
294
+ with_metrics(metrics) do
295
+ creds = AssumeRoleCredentials.new(opts)
296
+ creds.metrics.push(*metrics)
297
+ creds
298
+ end
269
299
  else
270
300
  raise Errors::NoSourceProfileError,
271
301
  "Profile #{profile} has a role_arn, and source_profile, but the"\
272
302
  ' source_profile does not have credentials.'
273
303
  end
274
304
  elsif credential_source
275
- opts[:credentials] = credentials_from_source(
276
- credential_source,
277
- chain_config
278
- )
305
+ opts[:credentials] = credentials_from_source(credential_source, chain_config)
279
306
  if opts[:credentials]
280
307
  opts[:role_session_name] ||= prof_cfg['role_session_name']
281
308
  opts[:role_session_name] ||= 'default_session'
@@ -284,7 +311,16 @@ module Aws
284
311
  opts[:external_id] ||= prof_cfg['external_id']
285
312
  opts[:serial_number] ||= prof_cfg['mfa_serial']
286
313
  opts.delete(:source_profile) # Cleanup
287
- AssumeRoleCredentials.new(opts)
314
+
315
+ metrics = opts[:credentials].metrics
316
+ metrics << 'CREDENTIALS_PROFILE_NAMED_PROVIDER'
317
+ # Set the original credentials metrics to [] to prevent duplicate metrics during sign plugin
318
+ opts[:credentials].metrics = []
319
+ with_metrics(metrics) do
320
+ creds = AssumeRoleCredentials.new(opts)
321
+ creds.metrics.push(*metrics)
322
+ creds
323
+ end
288
324
  else
289
325
  raise Errors::NoSourceCredentials,
290
326
  "Profile #{profile} could not get source credentials from"\
@@ -312,12 +348,24 @@ module Aws
312
348
  elsif profile_config && profile_config['source_profile']
313
349
  opts.delete(:source_profile)
314
350
  assume_role_credentials_from_config(opts.merge(profile: profile))
315
- elsif (provider = assume_role_web_identity_credentials_from_config(opts.merge(profile: profile)))
316
- provider.credentials if provider.credentials.set?
351
+ elsif (provider = assume_role_web_identity_credentials_from_config_with_metrics(opts.merge(profile: profile)))
352
+ provider if provider.credentials.set?
317
353
  elsif (provider = assume_role_process_credentials_from_config(profile))
318
- provider.credentials if provider.credentials.set?
319
- elsif (provider = sso_credentials_from_config(profile: profile))
320
- provider.credentials if provider.credentials.set?
354
+ provider if provider.credentials.set?
355
+ elsif (provider = sso_credentials_from_config_with_metrics(profile))
356
+ provider if provider.credentials.set?
357
+ end
358
+ end
359
+
360
+ def assume_role_web_identity_credentials_from_config_with_metrics(opts)
361
+ with_metrics('CREDENTIALS_PROFILE_SOURCE_PROFILE') do
362
+ assume_role_web_identity_credentials_from_config(opts)
363
+ end
364
+ end
365
+
366
+ def sso_credentials_from_config_with_metrics(profile)
367
+ with_metrics('CREDENTIALS_PROFILE_SOURCE_PROFILE') do
368
+ sso_credentials_from_config(profile: profile)
321
369
  end
322
370
  end
323
371
 
@@ -331,6 +379,15 @@ module Aws
331
379
  )
332
380
  when 'EcsContainer'
333
381
  ECSCredentials.new
382
+ when 'Environment'
383
+ creds = Credentials.new(
384
+ ENV['AWS_ACCESS_KEY_ID'],
385
+ ENV['AWS_SECRET_ACCESS_KEY'],
386
+ ENV['AWS_SESSION_TOKEN'],
387
+ account_id: ENV['AWS_ACCOUNT_ID']
388
+ )
389
+ creds.metrics = ['CREDENTIALS_ENV_VARS']
390
+ creds
334
391
  else
335
392
  raise Errors::InvalidCredentialSourceError, "Unsupported credential_source: #{credential_source}"
336
393
  end
@@ -342,7 +399,11 @@ module Aws
342
399
  if @parsed_config
343
400
  credential_process ||= @parsed_config.fetch(profile, {})['credential_process']
344
401
  end
345
- ProcessCredentials.new([credential_process]) if credential_process
402
+ if credential_process
403
+ creds = ProcessCredentials.new([credential_process])
404
+ creds.metrics << 'CREDENTIALS_PROFILE_PROCESS'
405
+ creds
406
+ end
346
407
  end
347
408
 
348
409
  def credentials_from_shared(profile, _opts)
@@ -386,13 +447,18 @@ module Aws
386
447
  sso_start_url = prof_config['sso_start_url']
387
448
  end
388
449
 
389
- SSOCredentials.new(
390
- sso_account_id: prof_config['sso_account_id'],
391
- sso_role_name: prof_config['sso_role_name'],
392
- sso_session: prof_config['sso_session'],
393
- sso_region: sso_region,
394
- sso_start_url: sso_start_url
450
+ metric = prof_config['sso_session'] ? 'CREDENTIALS_PROFILE_SSO' : 'CREDENTIALS_PROFILE_SSO_LEGACY'
451
+ with_metrics(metric) do
452
+ creds = SSOCredentials.new(
453
+ sso_account_id: prof_config['sso_account_id'],
454
+ sso_role_name: prof_config['sso_role_name'],
455
+ sso_session: prof_config['sso_session'],
456
+ sso_region: sso_region,
457
+ sso_start_url: sso_start_url
395
458
  )
459
+ creds.metrics << metric
460
+ creds
461
+ end
396
462
  end
397
463
  end
398
464
 
@@ -413,6 +479,16 @@ module Aws
413
479
  end
414
480
  end
415
481
 
482
+ def login_credentials_from_profile(cfg, profile, region)
483
+ return unless @parsed_config && (prof_config = cfg[profile]) && prof_config['login_session']
484
+
485
+ cfg = { login_session: prof_config['login_session'] }
486
+ cfg[:region] = region if region
487
+ creds = LoginCredentials.new(cfg)
488
+ creds.metrics << 'CREDENTIALS_PROFILE_LOGIN'
489
+ creds
490
+ end
491
+
416
492
  def credentials_from_profile(prof_config)
417
493
  creds = Credentials.new(
418
494
  prof_config['aws_access_key_id'],
@@ -420,6 +496,7 @@ module Aws
420
496
  prof_config['aws_session_token'],
421
497
  account_id: prof_config['aws_account_id']
422
498
  )
499
+ creds.metrics = ['CREDENTIALS_PROFILE']
423
500
  creds if creds.set?
424
501
  end
425
502
 
@@ -480,5 +557,9 @@ module Aws
480
557
 
481
558
  sso_session
482
559
  end
560
+
561
+ def with_metrics(metrics, &block)
562
+ Aws::Plugins::UserAgent.metric(*metrics, &block)
563
+ end
483
564
  end
484
565
  end
@@ -40,6 +40,7 @@ module Aws
40
40
  )
41
41
  @credentials = config.credentials(profile: @profile_name)
42
42
  end
43
+ @metrics = ['CREDENTIALS_CODE']
43
44
  end
44
45
 
45
46
  # @return [String]
@@ -7,7 +7,7 @@ module Aws
7
7
  # {Aws::SSOTokenProvider} will be used to refresh the token if possible.
8
8
  # This class does NOT implement the SSO login token flow - tokens
9
9
  # must generated separately by running `aws login` from the
10
- # AWS CLI with the correct profile. The `SSOCredentials` will
10
+ # AWS CLI with the correct profile. The {SSOCredentials} will
11
11
  # auto-refresh the AWS credentials from SSO.
12
12
  #
13
13
  # # You must first run aws sso login --profile your-sso-profile
@@ -91,6 +91,7 @@ module Aws
91
91
  client_opts[:credentials] = nil
92
92
  @client = Aws::SSO::Client.new(client_opts)
93
93
  end
94
+ @metrics = ['CREDENTIALS_SSO']
94
95
  else # legacy behavior
95
96
  missing_keys = LEGACY_REQUIRED_OPTS.select { |k| options[k].nil? }
96
97
  unless missing_keys.empty?
@@ -111,6 +112,7 @@ module Aws
111
112
  client_opts[:credentials] = nil
112
113
 
113
114
  @client = options[:client] || Aws::SSO::Client.new(client_opts)
115
+ @metrics = ['CREDENTIALS_SSO_LEGACY']
114
116
  end
115
117
 
116
118
  @async_refresh = true
@@ -2,12 +2,11 @@
2
2
 
3
3
  module Aws
4
4
  class StaticTokenProvider
5
-
6
5
  include TokenProvider
7
6
 
8
7
  # @param [String] token
9
8
  # @param [Time] expiration
10
- def initialize(token, expiration=nil)
9
+ def initialize(token, expiration = nil)
11
10
  @token = Token.new(token, expiration)
12
11
  end
13
12
  end
@@ -3,9 +3,9 @@
3
3
  module Aws
4
4
  class Token
5
5
 
6
- # @param [String] token
7
- # @param [Time] expiration
8
- def initialize(token, expiration=nil)
6
+ # @param [String, nil] token
7
+ # @param [Time, nil] expiration
8
+ def initialize(token, expiration = nil)
9
9
  @token = token
10
10
  @expiration = expiration
11
11
  end
@@ -6,6 +6,10 @@ module Aws
6
6
  # @return [Token]
7
7
  attr_reader :token
8
8
 
9
+ # @api private
10
+ # Returns UserAgent metrics for tokens.
11
+ attr_accessor :metrics
12
+
9
13
  # @return [Boolean]
10
14
  def set?
11
15
  !!token && token.set?