aws-sdk-core 3.46.2 → 3.126.2

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 (206) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1258 -0
  3. data/LICENSE.txt +202 -0
  4. data/VERSION +1 -1
  5. data/lib/aws-defaults/default_configuration.rb +153 -0
  6. data/lib/aws-defaults/defaults_mode_config_resolver.rb +107 -0
  7. data/lib/aws-defaults.rb +3 -0
  8. data/lib/aws-sdk-core/arn.rb +92 -0
  9. data/lib/aws-sdk-core/arn_parser.rb +40 -0
  10. data/lib/aws-sdk-core/assume_role_credentials.rb +20 -0
  11. data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +109 -0
  12. data/lib/aws-sdk-core/async_client_stubs.rb +82 -0
  13. data/lib/aws-sdk-core/binary/decode_handler.rb +11 -1
  14. data/lib/aws-sdk-core/binary/encode_handler.rb +34 -0
  15. data/lib/aws-sdk-core/binary/event_builder.rb +124 -0
  16. data/lib/aws-sdk-core/binary/event_parser.rb +50 -18
  17. data/lib/aws-sdk-core/binary/event_stream_decoder.rb +7 -2
  18. data/lib/aws-sdk-core/binary/event_stream_encoder.rb +55 -0
  19. data/lib/aws-sdk-core/binary.rb +5 -0
  20. data/lib/aws-sdk-core/client_side_monitoring/publisher.rb +11 -1
  21. data/lib/aws-sdk-core/client_side_monitoring/request_metrics.rb +2 -0
  22. data/lib/aws-sdk-core/client_stubs.rb +16 -13
  23. data/lib/aws-sdk-core/credential_provider.rb +1 -30
  24. data/lib/aws-sdk-core/credential_provider_chain.rb +102 -40
  25. data/lib/aws-sdk-core/credentials.rb +2 -0
  26. data/lib/aws-sdk-core/deprecations.rb +17 -11
  27. data/lib/aws-sdk-core/eager_loader.rb +2 -0
  28. data/lib/aws-sdk-core/ec2_metadata.rb +238 -0
  29. data/lib/aws-sdk-core/ecs_credentials.rb +18 -9
  30. data/lib/aws-sdk-core/endpoint_cache.rb +16 -11
  31. data/lib/aws-sdk-core/errors.rb +138 -15
  32. data/lib/aws-sdk-core/event_emitter.rb +44 -0
  33. data/lib/aws-sdk-core/ini_parser.rb +2 -0
  34. data/lib/aws-sdk-core/instance_profile_credentials.rb +179 -42
  35. data/lib/aws-sdk-core/json/builder.rb +2 -0
  36. data/lib/aws-sdk-core/json/error_handler.rb +21 -2
  37. data/lib/aws-sdk-core/json/handler.rb +21 -1
  38. data/lib/aws-sdk-core/json/json_engine.rb +12 -8
  39. data/lib/aws-sdk-core/json/oj_engine.rb +35 -6
  40. data/lib/aws-sdk-core/json/parser.rb +10 -0
  41. data/lib/aws-sdk-core/json.rb +11 -28
  42. data/lib/aws-sdk-core/log/formatter.rb +16 -4
  43. data/lib/aws-sdk-core/log/handler.rb +2 -0
  44. data/lib/aws-sdk-core/log/param_filter.rb +38 -13
  45. data/lib/aws-sdk-core/log/param_formatter.rb +2 -0
  46. data/lib/aws-sdk-core/pageable_response.rb +48 -24
  47. data/lib/aws-sdk-core/pager.rb +5 -0
  48. data/lib/aws-sdk-core/param_converter.rb +2 -0
  49. data/lib/aws-sdk-core/param_validator.rb +63 -7
  50. data/lib/aws-sdk-core/plugins/api_key.rb +5 -1
  51. data/lib/aws-sdk-core/plugins/apig_authorizer_token.rb +2 -0
  52. data/lib/aws-sdk-core/plugins/apig_credentials_configuration.rb +2 -0
  53. data/lib/aws-sdk-core/plugins/apig_user_agent.rb +2 -0
  54. data/lib/aws-sdk-core/plugins/client_metrics_plugin.rb +28 -1
  55. data/lib/aws-sdk-core/plugins/client_metrics_send_plugin.rb +2 -0
  56. data/lib/aws-sdk-core/plugins/credentials_configuration.rb +26 -7
  57. data/lib/aws-sdk-core/plugins/defaults_mode.rb +40 -0
  58. data/lib/aws-sdk-core/plugins/endpoint_discovery.rb +12 -4
  59. data/lib/aws-sdk-core/plugins/endpoint_pattern.rb +8 -6
  60. data/lib/aws-sdk-core/plugins/event_stream_configuration.rb +16 -0
  61. data/lib/aws-sdk-core/plugins/global_configuration.rb +2 -0
  62. data/lib/aws-sdk-core/plugins/helpful_socket_errors.rb +2 -0
  63. data/lib/aws-sdk-core/plugins/http_checksum.rb +57 -0
  64. data/lib/aws-sdk-core/plugins/idempotency_token.rb +2 -0
  65. data/lib/aws-sdk-core/plugins/invocation_id.rb +35 -0
  66. data/lib/aws-sdk-core/plugins/jsonvalue_converter.rb +2 -0
  67. data/lib/aws-sdk-core/plugins/logging.rb +2 -0
  68. data/lib/aws-sdk-core/plugins/param_converter.rb +2 -0
  69. data/lib/aws-sdk-core/plugins/param_validator.rb +2 -0
  70. data/lib/aws-sdk-core/plugins/protocols/api_gateway.rb +19 -0
  71. data/lib/aws-sdk-core/plugins/protocols/ec2.rb +2 -0
  72. data/lib/aws-sdk-core/plugins/protocols/json_rpc.rb +2 -0
  73. data/lib/aws-sdk-core/plugins/protocols/query.rb +2 -0
  74. data/lib/aws-sdk-core/plugins/protocols/rest_json.rb +18 -1
  75. data/lib/aws-sdk-core/plugins/protocols/rest_xml.rb +2 -0
  76. data/lib/aws-sdk-core/plugins/recursion_detection.rb +27 -0
  77. data/lib/aws-sdk-core/plugins/regional_endpoint.rb +74 -16
  78. data/lib/aws-sdk-core/plugins/response_paging.rb +2 -0
  79. data/lib/aws-sdk-core/plugins/retries/client_rate_limiter.rb +139 -0
  80. data/lib/aws-sdk-core/plugins/retries/clock_skew.rb +100 -0
  81. data/lib/aws-sdk-core/plugins/retries/error_inspector.rb +146 -0
  82. data/lib/aws-sdk-core/plugins/retries/retry_quota.rb +59 -0
  83. data/lib/aws-sdk-core/plugins/retry_errors.rb +295 -107
  84. data/lib/aws-sdk-core/plugins/signature_v2.rb +2 -0
  85. data/lib/aws-sdk-core/plugins/signature_v4.rb +28 -25
  86. data/lib/aws-sdk-core/plugins/stub_responses.rb +24 -7
  87. data/lib/aws-sdk-core/plugins/transfer_encoding.rb +53 -0
  88. data/lib/aws-sdk-core/plugins/user_agent.rb +6 -8
  89. data/lib/aws-sdk-core/process_credentials.rb +12 -5
  90. data/lib/aws-sdk-core/query/ec2_param_builder.rb +2 -0
  91. data/lib/aws-sdk-core/query/handler.rb +2 -0
  92. data/lib/aws-sdk-core/query/param.rb +2 -0
  93. data/lib/aws-sdk-core/query/param_builder.rb +2 -0
  94. data/lib/aws-sdk-core/query/param_list.rb +2 -0
  95. data/lib/aws-sdk-core/query.rb +2 -0
  96. data/lib/aws-sdk-core/refreshing_credentials.rb +15 -2
  97. data/lib/aws-sdk-core/resources/collection.rb +2 -0
  98. data/lib/aws-sdk-core/rest/handler.rb +2 -0
  99. data/lib/aws-sdk-core/rest/request/body.rb +21 -1
  100. data/lib/aws-sdk-core/rest/request/builder.rb +2 -0
  101. data/lib/aws-sdk-core/rest/request/endpoint.rb +10 -3
  102. data/lib/aws-sdk-core/rest/request/headers.rb +20 -6
  103. data/lib/aws-sdk-core/rest/request/querystring_builder.rb +4 -2
  104. data/lib/aws-sdk-core/rest/response/body.rb +2 -0
  105. data/lib/aws-sdk-core/rest/response/headers.rb +6 -3
  106. data/lib/aws-sdk-core/rest/response/parser.rb +2 -0
  107. data/lib/aws-sdk-core/rest/response/status_code.rb +2 -0
  108. data/lib/aws-sdk-core/rest.rb +2 -0
  109. data/lib/aws-sdk-core/shared_config.rb +153 -127
  110. data/lib/aws-sdk-core/shared_credentials.rb +9 -1
  111. data/lib/aws-sdk-core/sso_credentials.rb +136 -0
  112. data/lib/aws-sdk-core/structure.rb +14 -4
  113. data/lib/aws-sdk-core/stubbing/data_applicator.rb +2 -0
  114. data/lib/aws-sdk-core/stubbing/empty_stub.rb +2 -0
  115. data/lib/aws-sdk-core/stubbing/protocols/api_gateway.rb +2 -0
  116. data/lib/aws-sdk-core/stubbing/protocols/ec2.rb +2 -0
  117. data/lib/aws-sdk-core/stubbing/protocols/json.rb +3 -1
  118. data/lib/aws-sdk-core/stubbing/protocols/query.rb +4 -2
  119. data/lib/aws-sdk-core/stubbing/protocols/rest.rb +52 -7
  120. data/lib/aws-sdk-core/stubbing/protocols/rest_json.rb +3 -1
  121. data/lib/aws-sdk-core/stubbing/protocols/rest_xml.rb +2 -2
  122. data/lib/aws-sdk-core/stubbing/stub_data.rb +15 -4
  123. data/lib/aws-sdk-core/stubbing/xml_error.rb +2 -0
  124. data/lib/aws-sdk-core/type_builder.rb +2 -0
  125. data/lib/aws-sdk-core/util.rb +6 -0
  126. data/lib/aws-sdk-core/waiters/errors.rb +2 -0
  127. data/lib/aws-sdk-core/waiters/poller.rb +2 -0
  128. data/lib/aws-sdk-core/waiters/waiter.rb +4 -2
  129. data/lib/aws-sdk-core/waiters.rb +2 -0
  130. data/lib/aws-sdk-core/xml/builder.rb +5 -3
  131. data/lib/aws-sdk-core/xml/default_list.rb +2 -0
  132. data/lib/aws-sdk-core/xml/default_map.rb +2 -0
  133. data/lib/aws-sdk-core/xml/doc_builder.rb +15 -4
  134. data/lib/aws-sdk-core/xml/error_handler.rb +29 -4
  135. data/lib/aws-sdk-core/xml/parser/engines/libxml.rb +2 -0
  136. data/lib/aws-sdk-core/xml/parser/engines/nokogiri.rb +2 -0
  137. data/lib/aws-sdk-core/xml/parser/engines/oga.rb +2 -0
  138. data/lib/aws-sdk-core/xml/parser/engines/ox.rb +3 -1
  139. data/lib/aws-sdk-core/xml/parser/engines/rexml.rb +4 -1
  140. data/lib/aws-sdk-core/xml/parser/frame.rb +25 -0
  141. data/lib/aws-sdk-core/xml/parser/parsing_error.rb +2 -0
  142. data/lib/aws-sdk-core/xml/parser/stack.rb +2 -0
  143. data/lib/aws-sdk-core/xml/parser.rb +7 -0
  144. data/lib/aws-sdk-core/xml.rb +2 -0
  145. data/lib/aws-sdk-core.rb +23 -4
  146. data/lib/aws-sdk-sso/client.rb +568 -0
  147. data/lib/aws-sdk-sso/client_api.rb +190 -0
  148. data/lib/aws-sdk-sso/customizations.rb +1 -0
  149. data/lib/aws-sdk-sso/errors.rb +102 -0
  150. data/lib/aws-sdk-sso/resource.rb +26 -0
  151. data/lib/aws-sdk-sso/types.rb +352 -0
  152. data/lib/aws-sdk-sso.rb +55 -0
  153. data/lib/aws-sdk-sts/client.rb +1282 -531
  154. data/lib/aws-sdk-sts/client_api.rb +76 -1
  155. data/lib/aws-sdk-sts/customizations.rb +4 -0
  156. data/lib/aws-sdk-sts/errors.rb +153 -1
  157. data/lib/aws-sdk-sts/plugins/sts_regional_endpoints.rb +38 -0
  158. data/lib/aws-sdk-sts/presigner.rb +75 -0
  159. data/lib/aws-sdk-sts/resource.rb +4 -1
  160. data/lib/aws-sdk-sts/types.rb +958 -229
  161. data/lib/aws-sdk-sts.rb +16 -6
  162. data/lib/seahorse/client/async_base.rb +52 -0
  163. data/lib/seahorse/client/async_response.rb +64 -0
  164. data/lib/seahorse/client/base.rb +7 -2
  165. data/lib/seahorse/client/block_io.rb +6 -2
  166. data/lib/seahorse/client/configuration.rb +7 -1
  167. data/lib/seahorse/client/events.rb +3 -1
  168. data/lib/seahorse/client/h2/connection.rb +250 -0
  169. data/lib/seahorse/client/h2/handler.rb +152 -0
  170. data/lib/seahorse/client/handler.rb +2 -0
  171. data/lib/seahorse/client/handler_builder.rb +2 -0
  172. data/lib/seahorse/client/handler_list.rb +2 -0
  173. data/lib/seahorse/client/handler_list_entry.rb +6 -4
  174. data/lib/seahorse/client/http/async_response.rb +44 -0
  175. data/lib/seahorse/client/http/headers.rb +2 -0
  176. data/lib/seahorse/client/http/request.rb +5 -3
  177. data/lib/seahorse/client/http/response.rb +18 -11
  178. data/lib/seahorse/client/logging/formatter.rb +6 -2
  179. data/lib/seahorse/client/logging/handler.rb +2 -0
  180. data/lib/seahorse/client/managed_file.rb +2 -0
  181. data/lib/seahorse/client/net_http/connection_pool.rb +30 -23
  182. data/lib/seahorse/client/net_http/handler.rb +24 -7
  183. data/lib/seahorse/client/net_http/patches.rb +15 -84
  184. data/lib/seahorse/client/networking_error.rb +30 -0
  185. data/lib/seahorse/client/plugin.rb +10 -7
  186. data/lib/seahorse/client/plugin_list.rb +2 -0
  187. data/lib/seahorse/client/plugins/content_length.rb +14 -3
  188. data/lib/seahorse/client/plugins/endpoint.rb +4 -2
  189. data/lib/seahorse/client/plugins/h2.rb +69 -0
  190. data/lib/seahorse/client/plugins/logging.rb +2 -0
  191. data/lib/seahorse/client/plugins/net_http.rb +39 -3
  192. data/lib/seahorse/client/plugins/operation_methods.rb +2 -0
  193. data/lib/seahorse/client/plugins/raise_response_errors.rb +2 -0
  194. data/lib/seahorse/client/plugins/request_callback.rb +110 -0
  195. data/lib/seahorse/client/plugins/response_target.rb +23 -14
  196. data/lib/seahorse/client/request.rb +2 -0
  197. data/lib/seahorse/client/request_context.rb +2 -0
  198. data/lib/seahorse/client/response.rb +5 -5
  199. data/lib/seahorse/model/api.rb +10 -0
  200. data/lib/seahorse/model/authorizer.rb +2 -0
  201. data/lib/seahorse/model/operation.rb +9 -0
  202. data/lib/seahorse/model/shapes.rb +29 -2
  203. data/lib/seahorse/util.rb +8 -1
  204. data/lib/seahorse/version.rb +2 -0
  205. data/lib/seahorse.rb +12 -0
  206. metadata +64 -14
@@ -1,7 +1,9 @@
1
- module Aws
1
+ # frozen_string_literal: true
2
2
 
3
+ module Aws
3
4
  # @api private
4
5
  class SharedConfig
6
+ SSO_PROFILE_KEYS = %w[sso_start_url sso_region sso_account_id sso_role_name].freeze
5
7
 
6
8
  # @return [String]
7
9
  attr_reader :credentials_path
@@ -48,7 +50,7 @@ module Aws
48
50
  @profile_name = determine_profile(options)
49
51
  @config_enabled = options[:config_enabled]
50
52
  @credentials_path = options[:credentials_path] ||
51
- determine_credentials_path
53
+ determine_credentials_path
52
54
  @parsed_credentials = {}
53
55
  load_credentials_file if loadable?(@credentials_path)
54
56
  if @config_enabled
@@ -67,7 +69,7 @@ module Aws
67
69
  @config_enabled = options[:config_enabled] ? true : false
68
70
  @profile_name = determine_profile(options)
69
71
  @credentials_path = options[:credentials_path] ||
70
- determine_credentials_path
72
+ determine_credentials_path
71
73
  load_credentials_file if loadable?(@credentials_path)
72
74
  if @config_enabled
73
75
  @config_path = options[:config_path] || determine_config_path
@@ -98,13 +100,11 @@ module Aws
98
100
  # or `nil` if no valid credentials were found.
99
101
  def credentials(opts = {})
100
102
  p = opts[:profile] || @profile_name
101
- validate_profile_exists(p) if credentials_present?
102
- if credentials = credentials_from_shared(p, opts)
103
+ validate_profile_exists(p)
104
+ if (credentials = credentials_from_shared(p, opts))
103
105
  credentials
104
- elsif credentials = credentials_from_config(p, opts)
106
+ elsif (credentials = credentials_from_config(p, opts))
105
107
  credentials
106
- else
107
- nil
108
108
  end
109
109
  end
110
110
 
@@ -121,110 +121,107 @@ module Aws
121
121
  credentials
122
122
  end
123
123
 
124
- def region(opts = {})
124
+ def assume_role_web_identity_credentials_from_config(opts = {})
125
125
  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"]
126
+ if @config_enabled && @parsed_config
127
+ entry = @parsed_config.fetch(p, {})
128
+ if entry['web_identity_token_file'] && entry['role_arn']
129
+ cfg = {
130
+ role_arn: entry['role_arn'],
131
+ web_identity_token_file: entry['web_identity_token_file'],
132
+ role_session_name: entry['role_session_name']
133
+ }
134
+ cfg[:region] = opts[:region] if opts[:region]
135
+ AssumeRoleWebIdentityCredentials.new(cfg)
132
136
  end
133
- region
134
- else
135
- nil
136
137
  end
137
138
  end
138
139
 
139
- def endpoint_discovery(opts = {})
140
+ # Attempts to load from shared config or shared credentials file.
141
+ # Will always attempt first to load from the shared credentials
142
+ # file, if present.
143
+ def sso_credentials_from_config(opts = {})
140
144
  p = opts[:profile] || @profile_name
141
- if @config_enabled && @parsed_config
142
- @parsed_config.fetch(p, {})["endpoint_discovery_enabled"]
145
+ credentials = sso_credentials_from_profile(@parsed_credentials, p)
146
+ if @parsed_config
147
+ credentials ||= sso_credentials_from_profile(@parsed_config, p)
143
148
  end
149
+ credentials
144
150
  end
145
151
 
146
- def credentials_process(profile)
147
- validate_profile_exists(profile)
148
- @parsed_config[profile]['credential_process']
149
- end
150
-
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
152
+ # Add an accessor method (similar to attr_reader) to return a configuration value
153
+ # Uses the get_config_value below to control where
154
+ # values are loaded from
155
+ def self.config_reader(*attrs)
156
+ attrs.each do |attr|
157
+ define_method(attr) { |opts = {}| get_config_value(attr.to_s, opts) }
163
158
  end
164
159
  end
165
160
 
166
- def csm_client_id(opts = {})
167
- 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
161
+ config_reader(
162
+ :region,
163
+ :ca_bundle,
164
+ :credential_process,
165
+ :endpoint_discovery_enabled,
166
+ :use_dualstack_endpoint,
167
+ :use_fips_endpoint,
168
+ :ec2_metadata_service_endpoint,
169
+ :ec2_metadata_service_endpoint_mode,
170
+ :max_attempts,
171
+ :retry_mode,
172
+ :adaptive_retry_wait_to_fill,
173
+ :correct_clock_skew,
174
+ :csm_client_id,
175
+ :csm_enabled,
176
+ :csm_host,
177
+ :csm_port,
178
+ :sts_regional_endpoints,
179
+ :s3_use_arn_region,
180
+ :s3_us_east_1_regional_endpoint,
181
+ :s3_disable_multiregion_access_points,
182
+ :defaults_mode
183
+ )
184
+
185
+ private
180
186
 
181
- def csm_port(opts = {})
187
+ # Get a config value from from shared credential/config files.
188
+ # Only loads a value when config_enabled is true
189
+ # Return a value from credentials preferentially over config
190
+ def get_config_value(key, opts)
182
191
  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
194
- end
195
192
 
196
- private
197
- def credentials_present?
198
- (@parsed_credentials && !@parsed_credentials.empty?) ||
199
- (@parsed_config && !@parsed_config.empty?)
193
+ value = @parsed_credentials.fetch(p, {})[key] if @parsed_credentials
194
+ value ||= @parsed_config.fetch(p, {})[key] if @config_enabled && @parsed_config
195
+ value
200
196
  end
201
197
 
202
198
  def assume_role_from_profile(cfg, profile, opts, chain_config)
203
199
  if cfg && prof_cfg = cfg[profile]
204
- opts[:source_profile] ||= prof_cfg["source_profile"]
200
+ opts[:source_profile] ||= prof_cfg['source_profile']
205
201
  credential_source = opts.delete(:credential_source)
206
- credential_source ||= prof_cfg["credential_source"]
202
+ credential_source ||= prof_cfg['credential_source']
207
203
  if opts[:source_profile] && credential_source
208
- raise Errors::CredentialSourceConflictError.new(
204
+ raise Errors::CredentialSourceConflictError,
209
205
  "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
- )
206
+ 'a credential_source. For assume role credentials, must '\
207
+ 'provide only source_profile or credential_source, not both.'
213
208
  elsif opts[:source_profile]
214
- opts[:credentials] = credentials(profile: opts[:source_profile])
209
+ opts[:visited_profiles] ||= Set.new
210
+ opts[:credentials] = resolve_source_profile(opts[:source_profile], opts)
215
211
  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"]
212
+ opts[:role_session_name] ||= prof_cfg['role_session_name']
213
+ opts[:role_session_name] ||= 'default_session'
214
+ opts[:role_arn] ||= prof_cfg['role_arn']
215
+ opts[:duration_seconds] ||= prof_cfg['duration_seconds']
216
+ opts[:external_id] ||= prof_cfg['external_id']
217
+ opts[:serial_number] ||= prof_cfg['mfa_serial']
221
218
  opts[:profile] = opts.delete(:source_profile)
219
+ opts.delete(:visited_profiles)
222
220
  AssumeRoleCredentials.new(opts)
223
221
  else
224
- raise Errors::NoSourceProfileError.new(
222
+ raise Errors::NoSourceProfileError,
225
223
  "Profile #{profile} has a role_arn, and source_profile, but the"\
226
- " source_profile does not have credentials."
227
- )
224
+ ' source_profile does not have credentials.'
228
225
  end
229
226
  elsif credential_source
230
227
  opts[:credentials] = credentials_from_source(
@@ -232,61 +229,99 @@ module Aws
232
229
  chain_config
233
230
  )
234
231
  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"]
232
+ opts[:role_session_name] ||= prof_cfg['role_session_name']
233
+ opts[:role_session_name] ||= 'default_session'
234
+ opts[:role_arn] ||= prof_cfg['role_arn']
235
+ opts[:duration_seconds] ||= prof_cfg['duration_seconds']
236
+ opts[:external_id] ||= prof_cfg['external_id']
237
+ opts[:serial_number] ||= prof_cfg['mfa_serial']
240
238
  opts.delete(:source_profile) # Cleanup
241
239
  AssumeRoleCredentials.new(opts)
242
240
  else
243
- raise Errors::NoSourceCredentials.new(
241
+ raise Errors::NoSourceCredentials,
244
242
  "Profile #{profile} could not get source credentials from"\
245
- " provider #{credential_source}"
246
- )
243
+ " provider #{credential_source}"
247
244
  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
245
+ elsif prof_cfg['role_arn']
246
+ raise Errors::NoSourceProfileError, "Profile #{profile} has a role_arn, but no source_profile."
254
247
  end
255
- else
256
- nil
248
+ end
249
+ end
250
+
251
+ def resolve_source_profile(profile, opts = {})
252
+ if opts[:visited_profiles] && opts[:visited_profiles].include?(profile)
253
+ raise Errors::SourceProfileCircularReferenceError
254
+ end
255
+ opts[:visited_profiles].add(profile) if opts[:visited_profiles]
256
+
257
+ profile_config = @parsed_credentials[profile]
258
+ if @config_enabled
259
+ profile_config ||= @parsed_config[profile]
260
+ end
261
+
262
+ if (creds = credentials(profile: profile))
263
+ creds # static credentials
264
+ elsif profile_config && profile_config['source_profile']
265
+ opts.delete(:source_profile)
266
+ assume_role_credentials_from_config(opts.merge(profile: profile))
267
+ elsif (provider = assume_role_web_identity_credentials_from_config(opts.merge(profile: profile)))
268
+ provider.credentials if provider.credentials.set?
269
+ elsif (provider = assume_role_process_credentials_from_config(profile))
270
+ provider.credentials if provider.credentials.set?
271
+ elsif (provider = sso_credentials_from_config(profile: profile))
272
+ provider.credentials if provider.credentials.set?
257
273
  end
258
274
  end
259
275
 
260
276
  def credentials_from_source(credential_source, config)
261
277
  case credential_source
262
- when "Ec2InstanceMetadata"
278
+ when 'Ec2InstanceMetadata'
263
279
  InstanceProfileCredentials.new(
264
280
  retries: config ? config.instance_profile_credentials_retries : 0,
265
281
  http_open_timeout: config ? config.instance_profile_credentials_timeout : 1,
266
282
  http_read_timeout: config ? config.instance_profile_credentials_timeout : 1
267
283
  )
268
- when "EcsContainer"
284
+ when 'EcsContainer'
269
285
  ECSCredentials.new
270
286
  else
271
- raise Errors::InvalidCredentialSourceError.new(
272
- "Unsupported credential_source: #{credential_source}"
273
- )
287
+ raise Errors::InvalidCredentialSourceError, "Unsupported credential_source: #{credential_source}"
288
+ end
289
+ end
290
+
291
+ def assume_role_process_credentials_from_config(profile)
292
+ validate_profile_exists(profile)
293
+ credential_process = @parsed_credentials.fetch(profile, {})['credential_process']
294
+ if @parsed_config
295
+ credential_process ||= @parsed_config.fetch(profile, {})['credential_process']
274
296
  end
297
+ ProcessCredentials.new(credential_process) if credential_process
275
298
  end
276
299
 
277
- def credentials_from_shared(profile, opts)
300
+ def credentials_from_shared(profile, _opts)
278
301
  if @parsed_credentials && prof_config = @parsed_credentials[profile]
279
302
  credentials_from_profile(prof_config)
280
- else
281
- nil
282
303
  end
283
304
  end
284
305
 
285
- def credentials_from_config(profile, opts)
306
+ def credentials_from_config(profile, _opts)
286
307
  if @parsed_config && prof_config = @parsed_config[profile]
287
308
  credentials_from_profile(prof_config)
288
- else
289
- nil
309
+ end
310
+ end
311
+
312
+ # If any of the sso_ profile values are present, attempt to construct
313
+ # SSOCredentials
314
+ def sso_credentials_from_profile(cfg, profile)
315
+ if @parsed_config &&
316
+ (prof_config = cfg[profile]) &&
317
+ !(prof_config.keys & SSO_PROFILE_KEYS).empty?
318
+
319
+ SSOCredentials.new(
320
+ sso_start_url: prof_config['sso_start_url'],
321
+ sso_region: prof_config['sso_region'],
322
+ sso_account_id: prof_config['sso_account_id'],
323
+ sso_role_name: prof_config['sso_role_name']
324
+ )
290
325
  end
291
326
  end
292
327
 
@@ -296,15 +331,7 @@ module Aws
296
331
  prof_config['aws_secret_access_key'],
297
332
  prof_config['aws_session_token']
298
333
  )
299
- if credentials_complete(creds)
300
- creds
301
- else
302
- nil
303
- end
304
- end
305
-
306
- def credentials_complete(creds)
307
- creds.set?
334
+ creds if creds.set?
308
335
  end
309
336
 
310
337
  def load_credentials_file
@@ -334,19 +361,18 @@ module Aws
334
361
 
335
362
  def validate_profile_exists(profile)
336
363
  unless (@parsed_credentials && @parsed_credentials[profile]) ||
337
- (@parsed_config && @parsed_config[profile])
338
- msg = "Profile `#{profile}' not found in #{@credentials_path}"
339
- msg << " or #{@config_path}" if @config_path
340
- raise Errors::NoSuchProfileError.new(msg)
364
+ (@parsed_config && @parsed_config[profile])
365
+ msg = "Profile `#{profile}' not found in #{@credentials_path}"\
366
+ "#{" or #{@config_path}" if @config_path}"
367
+ raise Errors::NoSuchProfileError, msg
341
368
  end
342
369
  end
343
370
 
344
371
  def determine_profile(options)
345
372
  ret = options[:profile_name]
346
- ret ||= ENV["AWS_PROFILE"]
347
- ret ||= "default"
373
+ ret ||= ENV['AWS_PROFILE']
374
+ ret ||= 'default'
348
375
  ret
349
376
  end
350
-
351
377
  end
352
378
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'ini_parser'
2
4
 
3
5
  module Aws
@@ -12,11 +14,17 @@ module Aws
12
14
  'aws_session_token' => 'session_token',
13
15
  }
14
16
 
15
- # Constructs a new SharedCredentials object. This will load AWS access
17
+ # Constructs a new SharedCredentials object. This will load static
18
+ # (access_key_id, secret_access_key and session_token) AWS access
16
19
  # credentials from an ini file, which supports profiles. The default
17
20
  # profile name is 'default'. You can specify the profile name with the
18
21
  # `ENV['AWS_PROFILE']` or with the `:profile_name` option.
19
22
  #
23
+ # To use credentials from the default credential resolution chain
24
+ # create a client without the credential option specified.
25
+ # You may access the resolved credentials through
26
+ # `client.config.credentials`.
27
+ #
20
28
  # @option [String] :path Path to the shared file. Defaults
21
29
  # to "#{Dir.home}/.aws/credentials".
22
30
  #
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ # An auto-refreshing credential provider that works by assuming a
5
+ # role via {Aws::SSO::Client#get_role_credentials} using a cached access
6
+ # token. This class does NOT implement the SSO login token flow - tokens
7
+ # must generated and refreshed separately by running `aws login` from the
8
+ # AWS CLI with the correct profile.
9
+ #
10
+ # For more background on AWS SSO see the official
11
+ # {https://docs.aws.amazon.com/singlesignon/latest/userguide/what-is.html what is SSO Userguide}
12
+ #
13
+ # ## Refreshing Credentials from SSO
14
+ #
15
+ # The `SSOCredentials` will auto-refresh the AWS credentials from SSO. In
16
+ # addition to AWS credentials expiring after a given amount of time, the
17
+ # access token generated and cached from `aws login` will also expire.
18
+ # Once this token expires, it will not be usable to refresh AWS credentials,
19
+ # and another token will be needed. The SDK does not manage refreshing of
20
+ # the token value, but this can be done by running `aws login` with the
21
+ # correct profile.
22
+ #
23
+ #
24
+ # # You must first run aws sso login --profile your-sso-profile
25
+ # sso_credentials = Aws::SSOCredentials.new(
26
+ # sso_account_id: '123456789',
27
+ # sso_role_name: "role_name",
28
+ # sso_region: "us-east-1",
29
+ # sso_start_url: 'https://your-start-url.awsapps.com/start'
30
+ # )
31
+ #
32
+ # ec2 = Aws::EC2::Client.new(credentials: sso_credentials)
33
+ #
34
+ # If you omit `:client` option, a new {SSO::Client} object will be
35
+ # constructed.
36
+ class SSOCredentials
37
+
38
+ include CredentialProvider
39
+ include RefreshingCredentials
40
+
41
+ # @api private
42
+ SSO_REQUIRED_OPTS = [:sso_account_id, :sso_region, :sso_role_name, :sso_start_url].freeze
43
+
44
+ # @api private
45
+ SSO_LOGIN_GUIDANCE = 'The SSO session associated with this profile has '\
46
+ 'expired or is otherwise invalid. To refresh this SSO session run '\
47
+ 'aws sso login with the corresponding profile.'.freeze
48
+
49
+ # @option options [required, String] :sso_account_id The AWS account ID
50
+ # that temporary AWS credentials will be resolved for
51
+ #
52
+ # @option options [required, String] :sso_region The AWS region where the
53
+ # SSO directory for the given sso_start_url is hosted.
54
+ #
55
+ # @option options [required, String] :sso_role_name The corresponding
56
+ # IAM role in the AWS account that temporary AWS credentials
57
+ # will be resolved for.
58
+ #
59
+ # @option options [required, String] :sso_start_url The start URL is
60
+ # provided by the SSO service via the console and is the URL used to
61
+ # login to the SSO directory. This is also sometimes referred to as
62
+ # the "User Portal URL"
63
+ #
64
+ # @option options [SSO::Client] :client Optional `SSO::Client`. If not
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.
71
+ def initialize(options = {})
72
+
73
+ missing_keys = SSO_REQUIRED_OPTS.select { |k| options[k].nil? }
74
+ unless missing_keys.empty?
75
+ raise ArgumentError, "Missing required keys: #{missing_keys}"
76
+ end
77
+
78
+ @sso_start_url = options.delete(:sso_start_url)
79
+ @sso_region = options.delete(:sso_region)
80
+ @sso_role_name = options.delete(:sso_role_name)
81
+ @sso_account_id = options.delete(:sso_account_id)
82
+
83
+ # validate we can read the token file
84
+ read_cached_token
85
+
86
+ options[:region] = @sso_region
87
+ options[:credentials] = nil
88
+ @client = options[:client] || Aws::SSO::Client.new(options)
89
+ super
90
+ end
91
+
92
+ # @return [SSO::Client]
93
+ attr_reader :client
94
+
95
+ private
96
+
97
+ def read_cached_token
98
+ cached_token = Json.load(File.read(sso_cache_file))
99
+ # validation
100
+ unless cached_token['accessToken'] && cached_token['expiresAt']
101
+ raise ArgumentError, 'Missing required field(s)'
102
+ end
103
+ expires_at = DateTime.parse(cached_token['expiresAt'])
104
+ if expires_at < DateTime.now
105
+ raise ArgumentError, 'Cached SSO Token is expired.'
106
+ end
107
+ cached_token
108
+ rescue Errno::ENOENT, Aws::Json::ParseError, ArgumentError
109
+ raise Errors::InvalidSSOCredentials, SSO_LOGIN_GUIDANCE
110
+ end
111
+
112
+ def refresh
113
+ cached_token = read_cached_token
114
+ c = @client.get_role_credentials(
115
+ account_id: @sso_account_id,
116
+ role_name: @sso_role_name,
117
+ access_token: cached_token['accessToken']
118
+ ).role_credentials
119
+
120
+ @credentials = Credentials.new(
121
+ c.access_key_id,
122
+ c.secret_access_key,
123
+ c.session_token
124
+ )
125
+ @expiration = c.expiration
126
+ end
127
+
128
+ def sso_cache_file
129
+ start_url_sha1 = OpenSSL::Digest::SHA1.hexdigest(@sso_start_url.encode('utf-8'))
130
+ File.join(Dir.home, '.aws', 'sso', 'cache', "#{start_url_sha1}.json")
131
+ rescue ArgumentError
132
+ # Dir.home raises ArgumentError when ENV['home'] is not set
133
+ raise ArgumentError, "Unable to load sso_cache_file: ENV['HOME'] is not set."
134
+ end
135
+ end
136
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  # @api private
3
5
  module Structure
@@ -29,8 +31,7 @@ module Aws
29
31
  def to_h(obj = self)
30
32
  case obj
31
33
  when Struct
32
- obj.members.each.with_object({}) do |member, hash|
33
- value = obj[member]
34
+ obj.each_pair.with_object({}) do |(member, value), hash|
34
35
  hash[member] = to_hash(value) unless value.nil?
35
36
  end
36
37
  when Hash
@@ -47,7 +48,7 @@ module Aws
47
48
 
48
49
  # Wraps the default #to_s logic with filtering of sensitive parameters.
49
50
  def to_s(obj = self)
50
- Aws::Log::ParamFilter.new.filter(obj).to_s
51
+ Aws::Log::ParamFilter.new.filter(obj, obj.class).to_s
51
52
  end
52
53
 
53
54
  class << self
@@ -69,11 +70,20 @@ module Aws
69
70
  end
70
71
 
71
72
  end
73
+
74
+ module Union
75
+ def member
76
+ self.members.select { |k| self[k] != nil }.first
77
+ end
78
+
79
+ def value
80
+ self[member] if member
81
+ end
82
+ end
72
83
  end
73
84
 
74
85
  # @api private
75
86
  class EmptyStructure < Struct.new('AwsEmptyStructure')
76
87
  include(Aws::Structure)
77
88
  end
78
-
79
89
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module Stubbing
3
5
  class DataApplicator
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module Stubbing
3
5
  class EmptyStub
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module Stubbing
3
5
  module Protocols
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module Stubbing
3
5
  module Protocols
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module Stubbing
3
5
  module Protocols
@@ -27,7 +29,7 @@ module Aws
27
29
  private
28
30
 
29
31
  def content_type(api)
30
- "application/x-amz-json-#{api.metadata['jsonVerison']}"
32
+ "application/x-amz-json-#{api.metadata['jsonVersion']}"
31
33
  end
32
34
 
33
35
  def build_body(operation, data)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module Stubbing
3
5
  module Protocols
@@ -23,9 +25,9 @@ module Aws
23
25
  xml = []
24
26
  builder = Aws::Xml::DocBuilder.new(target: xml, indent: ' ')
25
27
  builder.node(operation.name + 'Response', xmlns: xmlns(api)) do
26
- if rules = operation.output
28
+ if (rules = operation.output)
27
29
  rules.location_name = operation.name + 'Result'
28
- Xml::Builder.new(rules, target:xml, pad:' ').to_xml(data)
30
+ Xml::Builder.new(rules, target: xml, pad:' ').to_xml(data)
29
31
  end
30
32
  builder.node('ResponseMetadata') do
31
33
  builder.node('RequestId', 'stubbed-request-id')