aws-sdk-core 3.131.1 → 3.170.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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +275 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-sdk-core/arn.rb +13 -0
  5. data/lib/aws-sdk-core/binary/encode_handler.rb +12 -1
  6. data/lib/aws-sdk-core/credential_provider_chain.rb +6 -4
  7. data/lib/aws-sdk-core/endpoints/condition.rb +41 -0
  8. data/lib/aws-sdk-core/endpoints/endpoint.rb +17 -0
  9. data/lib/aws-sdk-core/endpoints/endpoint_rule.rb +75 -0
  10. data/lib/aws-sdk-core/endpoints/error_rule.rb +42 -0
  11. data/lib/aws-sdk-core/endpoints/function.rb +80 -0
  12. data/lib/aws-sdk-core/endpoints/matchers.rb +127 -0
  13. data/lib/aws-sdk-core/endpoints/reference.rb +31 -0
  14. data/lib/aws-sdk-core/endpoints/rule.rb +25 -0
  15. data/lib/aws-sdk-core/endpoints/rule_set.rb +52 -0
  16. data/lib/aws-sdk-core/endpoints/rules_provider.rb +37 -0
  17. data/lib/aws-sdk-core/endpoints/templater.rb +58 -0
  18. data/lib/aws-sdk-core/endpoints/tree_rule.rb +45 -0
  19. data/lib/aws-sdk-core/endpoints/url.rb +60 -0
  20. data/lib/aws-sdk-core/endpoints.rb +74 -0
  21. data/lib/aws-sdk-core/errors.rb +13 -0
  22. data/lib/aws-sdk-core/json/error_handler.rb +10 -1
  23. data/lib/aws-sdk-core/pageable_response.rb +7 -0
  24. data/lib/aws-sdk-core/plugins/bearer_authorization.rb +67 -0
  25. data/lib/aws-sdk-core/plugins/credentials_configuration.rb +24 -0
  26. data/lib/aws-sdk-core/plugins/endpoint_discovery.rb +6 -2
  27. data/lib/aws-sdk-core/plugins/jsonvalue_converter.rb +34 -6
  28. data/lib/aws-sdk-core/plugins/recursion_detection.rb +14 -3
  29. data/lib/aws-sdk-core/plugins/regional_endpoint.rb +5 -0
  30. data/lib/aws-sdk-core/plugins/retries/error_inspector.rb +2 -1
  31. data/lib/aws-sdk-core/plugins/sign.rb +200 -0
  32. data/lib/aws-sdk-core/plugins/signature_v2.rb +1 -0
  33. data/lib/aws-sdk-core/plugins/signature_v4.rb +13 -7
  34. data/lib/aws-sdk-core/refreshing_token.rb +71 -0
  35. data/lib/aws-sdk-core/rest/handler.rb +1 -1
  36. data/lib/aws-sdk-core/rest/request/headers.rb +2 -6
  37. data/lib/aws-sdk-core/shared_config.rb +76 -5
  38. data/lib/aws-sdk-core/sso_credentials.rb +79 -44
  39. data/lib/aws-sdk-core/sso_token_provider.rb +135 -0
  40. data/lib/aws-sdk-core/static_token_provider.rb +14 -0
  41. data/lib/aws-sdk-core/structure.rb +6 -4
  42. data/lib/aws-sdk-core/token.rb +31 -0
  43. data/lib/aws-sdk-core/token_provider.rb +15 -0
  44. data/lib/aws-sdk-core/token_provider_chain.rb +51 -0
  45. data/lib/aws-sdk-core/xml/error_handler.rb +7 -0
  46. data/lib/aws-sdk-core/xml/parser/engines/oga.rb +2 -0
  47. data/lib/aws-sdk-core.rb +14 -0
  48. data/lib/aws-sdk-sso/client.rb +51 -11
  49. data/lib/aws-sdk-sso/endpoint_parameters.rb +66 -0
  50. data/lib/aws-sdk-sso/endpoint_provider.rb +51 -0
  51. data/lib/aws-sdk-sso/endpoints.rb +71 -0
  52. data/lib/aws-sdk-sso/plugins/endpoints.rb +76 -0
  53. data/lib/aws-sdk-sso/types.rb +8 -43
  54. data/lib/aws-sdk-sso.rb +5 -1
  55. data/lib/aws-sdk-ssooidc/client.rb +606 -0
  56. data/lib/aws-sdk-ssooidc/client_api.rb +216 -0
  57. data/lib/aws-sdk-ssooidc/customizations.rb +1 -0
  58. data/lib/aws-sdk-ssooidc/endpoint_parameters.rb +66 -0
  59. data/lib/aws-sdk-ssooidc/endpoint_provider.rb +51 -0
  60. data/lib/aws-sdk-ssooidc/endpoints.rb +57 -0
  61. data/lib/aws-sdk-ssooidc/errors.rb +290 -0
  62. data/lib/aws-sdk-ssooidc/plugins/endpoints.rb +74 -0
  63. data/lib/aws-sdk-ssooidc/resource.rb +26 -0
  64. data/lib/aws-sdk-ssooidc/types.rb +502 -0
  65. data/lib/aws-sdk-ssooidc.rb +59 -0
  66. data/lib/aws-sdk-sts/client.rb +153 -134
  67. data/lib/aws-sdk-sts/endpoint_parameters.rb +78 -0
  68. data/lib/aws-sdk-sts/endpoint_provider.rb +109 -0
  69. data/lib/aws-sdk-sts/endpoints.rb +135 -0
  70. data/lib/aws-sdk-sts/plugins/endpoints.rb +84 -0
  71. data/lib/aws-sdk-sts/presigner.rb +13 -15
  72. data/lib/aws-sdk-sts/types.rb +79 -186
  73. data/lib/aws-sdk-sts.rb +5 -1
  74. data/lib/seahorse/client/async_base.rb +0 -1
  75. data/lib/seahorse/client/configuration.rb +2 -2
  76. data/lib/seahorse/client/h2/connection.rb +2 -5
  77. data/lib/seahorse/client/plugins/request_callback.rb +9 -9
  78. data/lib/seahorse/util.rb +4 -0
  79. metadata +47 -6
@@ -72,7 +72,11 @@ the background every 60 secs (default). Defaults to `false`.
72
72
  context,
73
73
  Aws::Util.str_2_bool(discovery_cfg["required"])
74
74
  )
75
- context.http_request.endpoint = _valid_uri(endpoint.address) if endpoint
75
+ if endpoint
76
+ context.http_request.endpoint = _valid_uri(endpoint.address)
77
+ # Skips dynamic endpoint usage, use this endpoint instead
78
+ context[:discovered_endpoint] = true
79
+ end
76
80
  if endpoint || context.config.endpoint_discovery
77
81
  _apply_endpoint_discovery_user_agent(context)
78
82
  end
@@ -100,7 +104,7 @@ the background every 60 secs (default). Defaults to `false`.
100
104
  end
101
105
 
102
106
  def _discover_endpoint(ctx, required)
103
- cache = ctx.config.endpoint_cache
107
+ cache = ctx.config.endpoint_cache
104
108
  key = cache.extract_key(ctx)
105
109
 
106
110
  if required
@@ -11,15 +11,43 @@ module Aws
11
11
 
12
12
  def call(context)
13
13
  context.operation.input.shape.members.each do |m, ref|
14
- if ref['jsonvalue']
15
- param_value = context.params[m]
16
- unless param_value.respond_to?(:to_json)
17
- raise ArgumentError, "The value of params[#{m}] is not JSON serializable."
14
+ convert_jsonvalue(m, ref, context.params, 'params')
15
+ end
16
+ @handler.call(context)
17
+ end
18
+
19
+ def convert_jsonvalue(m, ref, params, context)
20
+ return if params.nil? || !params.key?(m)
21
+
22
+ if ref['jsonvalue']
23
+ params[m] = serialize_jsonvalue(params[m], "#{context}[#{m}]")
24
+ else
25
+ case ref.shape
26
+ when Seahorse::Model::Shapes::StructureShape
27
+ ref.shape.members.each do |member_m, ref|
28
+ convert_jsonvalue(member_m, ref, params[m], "#{context}[#{m}]")
29
+ end
30
+ when Seahorse::Model::Shapes::ListShape
31
+ if ref.shape.member['jsonvalue']
32
+ params[m] = params[m].each_with_index.map do |v, i|
33
+ serialize_jsonvalue(v, "#{context}[#{m}][#{i}]")
34
+ end
35
+ end
36
+ when Seahorse::Model::Shapes::MapShape
37
+ if ref.shape.value['jsonvalue']
38
+ params[m].each do |k, v|
39
+ params[m][k] = serialize_jsonvalue(v, "#{context}[#{m}][#{k}]")
40
+ end
18
41
  end
19
- context.params[m] = param_value.to_json
20
42
  end
21
43
  end
22
- @handler.call(context)
44
+ end
45
+
46
+ def serialize_jsonvalue(v, context)
47
+ unless v.respond_to?(:to_json)
48
+ raise ArgumentError, "The value of #{context} is not JSON serializable."
49
+ end
50
+ v.to_json
23
51
  end
24
52
 
25
53
  end
@@ -9,14 +9,25 @@ module Aws
9
9
  class Handler < Seahorse::Client::Handler
10
10
  def call(context)
11
11
 
12
- unless context.http_request.headers.key?('x-amz-trace-id')
12
+ unless context.http_request.headers.key?('x-amzn-trace-id')
13
13
  if ENV['AWS_LAMBDA_FUNCTION_NAME'] &&
14
- (trace_id = ENV['_X_AMZ_TRACE_ID'])
15
- context.http_request.headers['x-amz-trace-id'] = trace_id
14
+ (trace_id = validate_header(ENV['_X_AMZN_TRACE_ID']))
15
+ context.http_request.headers['x-amzn-trace-id'] = trace_id
16
16
  end
17
17
  end
18
18
  @handler.call(context)
19
19
  end
20
+
21
+ private
22
+ def validate_header(header_value)
23
+ return unless header_value
24
+
25
+ if (header_value.chars & (0..31).map(&:chr)).any?
26
+ raise ArgumentError, 'Invalid _X_AMZN_TRACE_ID value: '\
27
+ 'contains ASCII control characters'
28
+ end
29
+ header_value
30
+ end
20
31
  end
21
32
 
22
33
  # should be at the end of build so that
@@ -43,8 +43,13 @@ is set to `true`.
43
43
  resolve_use_fips_endpoint(cfg)
44
44
  end
45
45
 
46
+ # This option signals whether :endpoint was provided or not.
47
+ # Legacy endpoints must continue to be generated at client time.
46
48
  option(:regional_endpoint, false)
47
49
 
50
+ # NOTE: All of the defaults block code is effectively deprecated.
51
+ # Because old services can depend on this new core version, we must
52
+ # retain it.
48
53
  option(:endpoint, doc_type: String, docstring: <<-DOCS) do |cfg|
49
54
  The client endpoint is normally constructed from the `:region`
50
55
  option. You should only configure an `:endpoint` when connecting
@@ -39,7 +39,8 @@ module Aws
39
39
 
40
40
  CHECKSUM_ERRORS = Set.new(
41
41
  [
42
- 'CRC32CheckFailed' # dynamodb
42
+ 'CRC32CheckFailed', # dynamodb
43
+ 'BadDigest' # s3
43
44
  ]
44
45
  )
45
46
 
@@ -0,0 +1,200 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aws-sigv4'
4
+
5
+ module Aws
6
+ module Plugins
7
+ # @api private
8
+ class Sign < Seahorse::Client::Plugin
9
+ # These once had defaults. But now they are used as overrides to
10
+ # new endpoint and auth resolution.
11
+ option(:sigv4_signer)
12
+ option(:sigv4_name)
13
+ option(:sigv4_region)
14
+ option(:unsigned_operations, default: [])
15
+
16
+ supported_auth_types = %w[sigv4 bearer none]
17
+ supported_auth_types += ['sigv4a'] if Aws::Sigv4::Signer.use_crt?
18
+ SUPPORTED_AUTH_TYPES = supported_auth_types.freeze
19
+
20
+ def add_handlers(handlers, cfg)
21
+ operations = cfg.api.operation_names - cfg.unsigned_operations
22
+ handlers.add(Handler, step: :sign, operations: operations)
23
+ end
24
+
25
+ # @api private
26
+ # Return a signer with the `sign(context)` method
27
+ def self.signer_for(auth_scheme, config, region_override = nil)
28
+ case auth_scheme['name']
29
+ when 'sigv4', 'sigv4a'
30
+ SignatureV4.new(auth_scheme, config, region_override)
31
+ when 'bearer'
32
+ Bearer.new
33
+ else
34
+ NullSigner.new
35
+ end
36
+ end
37
+
38
+ class Handler < Seahorse::Client::Handler
39
+ def call(context)
40
+ # Skip signing if using sigv2 signing from s3_signer in S3
41
+ unless v2_signing?(context.config)
42
+ signer = Sign.signer_for(
43
+ context[:auth_scheme],
44
+ context.config,
45
+ context[:sigv4_region]
46
+ )
47
+ signer.sign(context)
48
+ end
49
+ @handler.call(context)
50
+ end
51
+
52
+ private
53
+
54
+ def v2_signing?(config)
55
+ # 's3' is legacy signing, 'v4' is default
56
+ config.respond_to?(:signature_version) &&
57
+ config.signature_version == 's3'
58
+ end
59
+ end
60
+
61
+ # @api private
62
+ class Bearer
63
+ def initialize
64
+ end
65
+
66
+ def sign(context)
67
+ if context.http_request.endpoint.scheme != 'https'
68
+ raise ArgumentError,
69
+ 'Unable to use bearer authorization on non https endpoint.'
70
+ end
71
+
72
+ token_provider = context.config.token_provider
73
+
74
+ raise Errors::MissingBearerTokenError unless token_provider&.set?
75
+
76
+ context.http_request.headers['Authorization'] =
77
+ "Bearer #{token_provider.token.token}"
78
+ end
79
+
80
+ def presign_url(*args)
81
+ raise ArgumentError, 'Bearer auth does not support presigned urls'
82
+ end
83
+
84
+ def sign_event(*args)
85
+ raise ArgumentError, 'Bearer auth does not support event signing'
86
+ end
87
+ end
88
+
89
+ # @api private
90
+ class SignatureV4
91
+ def initialize(auth_scheme, config, region_override = nil)
92
+ scheme_name = auth_scheme['name']
93
+
94
+ unless %w[sigv4 sigv4a].include?(scheme_name)
95
+ raise ArgumentError,
96
+ "Expected sigv4 or sigv4a auth scheme, got #{scheme_name}"
97
+ end
98
+
99
+ region = if scheme_name == 'sigv4a'
100
+ auth_scheme['signingRegionSet'].first
101
+ else
102
+ auth_scheme['signingRegion']
103
+ end
104
+ begin
105
+ @signer = Aws::Sigv4::Signer.new(
106
+ service: config.sigv4_name || auth_scheme['signingName'],
107
+ region: region_override || config.sigv4_region || region,
108
+ credentials_provider: config.credentials,
109
+ signing_algorithm: scheme_name.to_sym,
110
+ uri_escape_path: !!!auth_scheme['disableDoubleEncoding'],
111
+ unsigned_headers: %w[content-length user-agent x-amzn-trace-id]
112
+ )
113
+ rescue Aws::Sigv4::Errors::MissingCredentialsError
114
+ raise Aws::Errors::MissingCredentialsError
115
+ end
116
+ end
117
+
118
+ def sign(context)
119
+ req = context.http_request
120
+
121
+ apply_authtype(context, req)
122
+ reset_signature(req)
123
+ apply_clock_skew(context, req)
124
+
125
+ # compute the signature
126
+ begin
127
+ signature = @signer.sign_request(
128
+ http_method: req.http_method,
129
+ url: req.endpoint,
130
+ headers: req.headers,
131
+ body: req.body
132
+ )
133
+ rescue Aws::Sigv4::Errors::MissingCredentialsError
134
+ # Necessary for when credentials is explicitly set to nil
135
+ raise Aws::Errors::MissingCredentialsError
136
+ end
137
+ # apply signature headers
138
+ req.headers.update(signature.headers)
139
+
140
+ # add request metadata with signature components for debugging
141
+ context[:canonical_request] = signature.canonical_request
142
+ context[:string_to_sign] = signature.string_to_sign
143
+ end
144
+
145
+ def presign_url(*args)
146
+ @signer.presign_url(*args)
147
+ end
148
+
149
+ def sign_event(*args)
150
+ @signer.sign_event(*args)
151
+ end
152
+
153
+ private
154
+
155
+ def apply_authtype(context, req)
156
+ if context.operation['authtype'].eql?('v4-unsigned-body') &&
157
+ req.endpoint.scheme.eql?('https')
158
+ req.headers['X-Amz-Content-Sha256'] ||= 'UNSIGNED-PAYLOAD'
159
+ end
160
+ end
161
+
162
+ def reset_signature(req)
163
+ # in case this request is being re-signed
164
+ req.headers.delete('Authorization')
165
+ req.headers.delete('X-Amz-Security-Token')
166
+ req.headers.delete('X-Amz-Date')
167
+ req.headers.delete('x-Amz-Region-Set')
168
+ end
169
+
170
+ def apply_clock_skew(context, req)
171
+ if context.config.respond_to?(:clock_skew) &&
172
+ context.config.clock_skew &&
173
+ context.config.correct_clock_skew
174
+
175
+ endpoint = context.http_request.endpoint
176
+ skew = context.config.clock_skew.clock_correction(endpoint)
177
+ if skew.abs.positive?
178
+ req.headers['X-Amz-Date'] =
179
+ (Time.now.utc + skew).strftime('%Y%m%dT%H%M%SZ')
180
+ end
181
+ end
182
+ end
183
+
184
+ end
185
+
186
+ # @api private
187
+ class NullSigner
188
+
189
+ def sign(context)
190
+ end
191
+
192
+ def presign_url(*args)
193
+ end
194
+
195
+ def sign_event(*args)
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
@@ -3,6 +3,7 @@
3
3
  module Aws
4
4
  module Plugins
5
5
  # @api private
6
+ # Necessary to keep after Endpoints 2.0
6
7
  class SignatureV2 < Seahorse::Client::Plugin
7
8
 
8
9
  option(:v2_signer) do |cfg|
@@ -5,8 +5,11 @@ require 'aws-sigv4'
5
5
  module Aws
6
6
  module Plugins
7
7
  # @api private
8
+ # Necessary to exist after endpoints 2.0
8
9
  class SignatureV4 < Seahorse::Client::Plugin
9
10
 
11
+ V4_AUTH = %w[v4 v4-unsigned-payload v4-unsigned-body]
12
+
10
13
  option(:sigv4_signer) do |cfg|
11
14
  SignatureV4.build_signer(cfg)
12
15
  end
@@ -32,13 +35,16 @@ module Aws
32
35
  end
33
36
 
34
37
  option(:unsigned_operations) do |cfg|
35
- cfg.api.operation_names.inject([]) do |unsigned, operation_name|
36
- if cfg.api.operation(operation_name)['authtype'] == 'none' ||
37
- cfg.api.operation(operation_name)['authtype'] == 'custom'
38
- # Unsign requests that has custom apigateway authorizer as well
39
- unsigned << operation_name
40
- else
41
- unsigned
38
+ if cfg.api.metadata['signatureVersion'] == 'v4'
39
+ # select operations where authtype is set and is not v4
40
+ cfg.api.operation_names.select do |o|
41
+ cfg.api.operation(o)['authtype'] && !V4_AUTH.include?(cfg.api.operation(o)['authtype'])
42
+ end
43
+ else # service is not v4 auth
44
+ # select all operations where authtype is not v4
45
+ # (includes operations with no explicit authtype)
46
+ cfg.api.operation_names.select do |o|
47
+ !V4_AUTH.include?(cfg.api.operation(o)['authtype'])
42
48
  end
43
49
  end
44
50
  end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thread'
4
+
5
+ module Aws
6
+
7
+ # Module/mixin used by token provider classes that can be refreshed. This
8
+ # provides basic refresh logic in a thread-safe manner. Classes mixing in
9
+ # this module are expected to implement a #refresh method that populates
10
+ # the following instance variable:
11
+ #
12
+ # * `@token` [Token] - {Aws::Token} object with the `expiration` and `token`
13
+ # fields set.
14
+ #
15
+ # @api private
16
+ module RefreshingToken
17
+
18
+ def initialize(options = {})
19
+ @mutex = Mutex.new
20
+ @before_refresh = options.delete(:before_refresh) if Hash === options
21
+
22
+ @before_refresh.call(self) if @before_refresh
23
+ refresh
24
+ end
25
+
26
+ # @return [Token]
27
+ def token
28
+ refresh_if_near_expiration
29
+ @token
30
+ end
31
+
32
+ # @return [Time,nil]
33
+ def expiration
34
+ refresh_if_near_expiration
35
+ @expiration
36
+ end
37
+
38
+ # Refresh token.
39
+ # @return [void]
40
+ def refresh!
41
+ @mutex.synchronize do
42
+ @before_refresh.call(self) if @before_refresh
43
+ refresh
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ # Refreshes token if it is within
50
+ # 5 minutes of expiration.
51
+ def refresh_if_near_expiration
52
+ if near_expiration?
53
+ @mutex.synchronize do
54
+ if near_expiration?
55
+ @before_refresh.call(self) if @before_refresh
56
+ refresh
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ def near_expiration?
63
+ if @token && @token.expiration
64
+ # are we within 5 minutes of expiration?
65
+ (Time.now.to_i + 5 * 60) > @token.expiration.to_i
66
+ else
67
+ true
68
+ end
69
+ end
70
+ end
71
+ end
@@ -17,7 +17,7 @@ module Aws
17
17
 
18
18
  def apply_request_id(context)
19
19
  h = context.http_response.headers
20
- context[:request_id] = h['x-amz-request-id'] || h['x-amzn-requestid']
20
+ context[:request_id] ||= h['x-amz-request-id'] || h['x-amzn-requestid']
21
21
  end
22
22
 
23
23
  end
@@ -53,12 +53,8 @@ module Aws
53
53
  return if !value || value.empty?
54
54
  headers[ref.location_name] = value
55
55
  .compact
56
- .map { |s| escape_header_list_string(s.to_s) }
57
- .join(",")
58
- end
59
-
60
- def escape_header_list_string(s)
61
- (s.include?('"') || s.include?(",")) ? "\"#{s.gsub('"', '\"')}\"" : s
56
+ .map { |s| Seahorse::Util.escape_header_list_string(s.to_s) }
57
+ .join(',')
62
58
  end
63
59
 
64
60
  def apply_header_map(headers, ref, values)
@@ -3,7 +3,11 @@
3
3
  module Aws
4
4
  # @api private
5
5
  class SharedConfig
6
- SSO_PROFILE_KEYS = %w[sso_start_url sso_region sso_account_id sso_role_name].freeze
6
+ SSO_CREDENTIAL_PROFILE_KEYS = %w[sso_account_id sso_role_name].freeze
7
+ SSO_PROFILE_KEYS = %w[sso_session sso_start_url sso_region sso_account_id sso_role_name].freeze
8
+ SSO_TOKEN_PROFILE_KEYS = %w[sso_session].freeze
9
+ SSO_SESSION_KEYS = %w[sso_region sso_start_url].freeze
10
+
7
11
 
8
12
  # @return [String]
9
13
  attr_reader :credentials_path
@@ -51,10 +55,12 @@ module Aws
51
55
  @config_enabled = options[:config_enabled]
52
56
  @credentials_path = options[:credentials_path] ||
53
57
  determine_credentials_path
58
+ @credentials_path = File.expand_path(@credentials_path) if @credentials_path
54
59
  @parsed_credentials = {}
55
60
  load_credentials_file if loadable?(@credentials_path)
56
61
  if @config_enabled
57
62
  @config_path = options[:config_path] || determine_config_path
63
+ @config_path = File.expand_path(@config_path) if @config_path
58
64
  load_config_file if loadable?(@config_path)
59
65
  end
60
66
  end
@@ -149,6 +155,18 @@ module Aws
149
155
  credentials
150
156
  end
151
157
 
158
+ # Attempts to load from shared config or shared credentials file.
159
+ # Will always attempt first to load from the shared credentials
160
+ # file, if present.
161
+ def sso_token_from_config(opts = {})
162
+ p = opts[:profile] || @profile_name
163
+ token = sso_token_from_profile(@parsed_credentials, p)
164
+ if @parsed_config
165
+ token ||= sso_token_from_profile(@parsed_config, p)
166
+ end
167
+ token
168
+ end
169
+
152
170
  # Add an accessor method (similar to attr_reader) to return a configuration value
153
171
  # Uses the get_config_value below to control where
154
172
  # values are loaded from
@@ -314,13 +332,66 @@ module Aws
314
332
  def sso_credentials_from_profile(cfg, profile)
315
333
  if @parsed_config &&
316
334
  (prof_config = cfg[profile]) &&
317
- !(prof_config.keys & SSO_PROFILE_KEYS).empty?
335
+ !(prof_config.keys & SSO_CREDENTIAL_PROFILE_KEYS).empty?
336
+
337
+ if sso_session_name = prof_config['sso_session']
338
+ sso_session = cfg["sso-session #{sso_session_name}"]
339
+ unless sso_session
340
+ raise ArgumentError,
341
+ "sso-session #{sso_session_name} must be defined in the config file. " \
342
+ "Referenced by profile #{profile}"
343
+ end
344
+ sso_region = sso_session['sso_region']
345
+ sso_start_url = sso_session['sso_start_url']
346
+
347
+ # validate sso_region and sso_start_url don't conflict if set on profile and session
348
+ if prof_config['sso_region'] && prof_config['sso_region'] != sso_region
349
+ raise ArgumentError,
350
+ "sso-session #{sso_session_name}'s sso_region (#{sso_region}) " \
351
+ "does not match the profile #{profile}'s sso_region (#{prof_config['sso_region']}'"
352
+ end
353
+ if prof_config['sso_start_url'] && prof_config['sso_start_url'] != sso_start_url
354
+ raise ArgumentError,
355
+ "sso-session #{sso_session_name}'s sso_start_url (#{sso_start_url}) " \
356
+ "does not match the profile #{profile}'s sso_start_url (#{prof_config['sso_start_url']}'"
357
+ end
358
+ else
359
+ sso_region = prof_config['sso_region']
360
+ sso_start_url = prof_config['sso_start_url']
361
+ end
318
362
 
319
363
  SSOCredentials.new(
320
- sso_start_url: prof_config['sso_start_url'],
321
- sso_region: prof_config['sso_region'],
322
364
  sso_account_id: prof_config['sso_account_id'],
323
- sso_role_name: prof_config['sso_role_name']
365
+ sso_role_name: prof_config['sso_role_name'],
366
+ sso_session: prof_config['sso_session'],
367
+ sso_region: sso_region,
368
+ sso_start_url: prof_config['sso_start_url']
369
+ )
370
+ end
371
+ end
372
+
373
+ # If the required sso_ profile values are present, attempt to construct
374
+ # SSOTokenProvider
375
+ def sso_token_from_profile(cfg, profile)
376
+ if @parsed_config &&
377
+ (prof_config = cfg[profile]) &&
378
+ !(prof_config.keys & SSO_TOKEN_PROFILE_KEYS).empty?
379
+
380
+ sso_session_name = prof_config['sso_session']
381
+ sso_session = cfg["sso-session #{sso_session_name}"]
382
+ unless sso_session
383
+ raise ArgumentError,
384
+ "sso-session #{sso_session_name} must be defined in the config file." \
385
+ "Referenced by profile #{profile}"
386
+ end
387
+
388
+ unless sso_session['sso_region']
389
+ raise ArgumentError, "sso-session #{sso_session_name} missing required parameter: sso_region"
390
+ end
391
+
392
+ SSOTokenProvider.new(
393
+ sso_session: sso_session_name,
394
+ sso_region: sso_session['sso_region']
324
395
  )
325
396
  end
326
397
  end