aws-sdk-core 3.125.6 → 3.188.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +533 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-defaults/default_configuration.rb +4 -4
  5. data/lib/aws-sdk-core/arn.rb +13 -0
  6. data/lib/aws-sdk-core/assume_role_credentials.rb +21 -7
  7. data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +14 -10
  8. data/lib/aws-sdk-core/binary/encode_handler.rb +12 -1
  9. data/lib/aws-sdk-core/client_stubs.rb +5 -1
  10. data/lib/aws-sdk-core/credential_provider.rb +3 -0
  11. data/lib/aws-sdk-core/credential_provider_chain.rb +8 -5
  12. data/lib/aws-sdk-core/ec2_metadata.rb +3 -2
  13. data/lib/aws-sdk-core/ecs_credentials.rb +186 -52
  14. data/lib/aws-sdk-core/endpoints/condition.rb +41 -0
  15. data/lib/aws-sdk-core/endpoints/endpoint.rb +17 -0
  16. data/lib/aws-sdk-core/endpoints/endpoint_rule.rb +75 -0
  17. data/lib/aws-sdk-core/endpoints/error_rule.rb +42 -0
  18. data/lib/aws-sdk-core/endpoints/function.rb +80 -0
  19. data/lib/aws-sdk-core/endpoints/matchers.rb +131 -0
  20. data/lib/aws-sdk-core/endpoints/reference.rb +31 -0
  21. data/lib/aws-sdk-core/endpoints/rule.rb +25 -0
  22. data/lib/aws-sdk-core/endpoints/rule_set.rb +52 -0
  23. data/lib/aws-sdk-core/endpoints/rules_provider.rb +37 -0
  24. data/lib/aws-sdk-core/endpoints/templater.rb +58 -0
  25. data/lib/aws-sdk-core/endpoints/tree_rule.rb +45 -0
  26. data/lib/aws-sdk-core/endpoints/url.rb +60 -0
  27. data/lib/aws-sdk-core/endpoints.rb +78 -0
  28. data/lib/aws-sdk-core/errors.rb +14 -1
  29. data/lib/aws-sdk-core/ini_parser.rb +7 -0
  30. data/lib/aws-sdk-core/instance_profile_credentials.rb +124 -31
  31. data/lib/aws-sdk-core/json/error_handler.rb +20 -1
  32. data/lib/aws-sdk-core/json/handler.rb +8 -1
  33. data/lib/aws-sdk-core/json/parser.rb +27 -2
  34. data/lib/aws-sdk-core/log/formatter.rb +6 -0
  35. data/lib/aws-sdk-core/pageable_response.rb +81 -32
  36. data/lib/aws-sdk-core/param_validator.rb +2 -2
  37. data/lib/aws-sdk-core/plugins/bearer_authorization.rb +67 -0
  38. data/lib/aws-sdk-core/plugins/checksum_algorithm.rb +340 -0
  39. data/lib/aws-sdk-core/plugins/credentials_configuration.rb +24 -0
  40. data/lib/aws-sdk-core/plugins/endpoint_discovery.rb +6 -2
  41. data/lib/aws-sdk-core/plugins/http_checksum.rb +8 -1
  42. data/lib/aws-sdk-core/plugins/jsonvalue_converter.rb +34 -6
  43. data/lib/aws-sdk-core/plugins/recursion_detection.rb +38 -0
  44. data/lib/aws-sdk-core/plugins/regional_endpoint.rb +111 -30
  45. data/lib/aws-sdk-core/plugins/request_compression.rb +217 -0
  46. data/lib/aws-sdk-core/plugins/response_paging.rb +1 -1
  47. data/lib/aws-sdk-core/plugins/retries/error_inspector.rb +3 -2
  48. data/lib/aws-sdk-core/plugins/retry_errors.rb +12 -2
  49. data/lib/aws-sdk-core/plugins/sign.rb +201 -0
  50. data/lib/aws-sdk-core/plugins/signature_v2.rb +1 -0
  51. data/lib/aws-sdk-core/plugins/signature_v4.rb +15 -8
  52. data/lib/aws-sdk-core/plugins/stub_responses.rb +5 -1
  53. data/lib/aws-sdk-core/plugins/user_agent.rb +117 -14
  54. data/lib/aws-sdk-core/process_credentials.rb +9 -11
  55. data/lib/aws-sdk-core/refreshing_credentials.rb +41 -16
  56. data/lib/aws-sdk-core/refreshing_token.rb +71 -0
  57. data/lib/aws-sdk-core/rest/handler.rb +1 -1
  58. data/lib/aws-sdk-core/rest/request/headers.rb +2 -6
  59. data/lib/aws-sdk-core/rest/request/querystring_builder.rb +43 -29
  60. data/lib/aws-sdk-core/shared_config.rb +107 -12
  61. data/lib/aws-sdk-core/sso_credentials.rb +91 -50
  62. data/lib/aws-sdk-core/sso_token_provider.rb +135 -0
  63. data/lib/aws-sdk-core/static_token_provider.rb +14 -0
  64. data/lib/aws-sdk-core/structure.rb +6 -4
  65. data/lib/aws-sdk-core/stubbing/stub_data.rb +11 -0
  66. data/lib/aws-sdk-core/token.rb +31 -0
  67. data/lib/aws-sdk-core/token_provider.rb +15 -0
  68. data/lib/aws-sdk-core/token_provider_chain.rb +51 -0
  69. data/lib/aws-sdk-core/waiters/poller.rb +3 -1
  70. data/lib/aws-sdk-core/xml/error_handler.rb +7 -0
  71. data/lib/aws-sdk-core/xml/parser/engines/oga.rb +2 -0
  72. data/lib/aws-sdk-core.rb +14 -0
  73. data/lib/aws-sdk-sso/client.rb +75 -11
  74. data/lib/aws-sdk-sso/endpoint_parameters.rb +66 -0
  75. data/lib/aws-sdk-sso/endpoint_provider.rb +57 -0
  76. data/lib/aws-sdk-sso/endpoints.rb +72 -0
  77. data/lib/aws-sdk-sso/plugins/endpoints.rb +76 -0
  78. data/lib/aws-sdk-sso/types.rb +8 -43
  79. data/lib/aws-sdk-sso.rb +5 -1
  80. data/lib/aws-sdk-ssooidc/client.rb +935 -0
  81. data/lib/aws-sdk-ssooidc/client_api.rb +271 -0
  82. data/lib/aws-sdk-ssooidc/customizations.rb +1 -0
  83. data/lib/aws-sdk-ssooidc/endpoint_parameters.rb +66 -0
  84. data/lib/aws-sdk-ssooidc/endpoint_provider.rb +57 -0
  85. data/lib/aws-sdk-ssooidc/endpoints.rb +72 -0
  86. data/lib/aws-sdk-ssooidc/errors.rb +321 -0
  87. data/lib/aws-sdk-ssooidc/plugins/endpoints.rb +76 -0
  88. data/lib/aws-sdk-ssooidc/resource.rb +26 -0
  89. data/lib/aws-sdk-ssooidc/types.rb +755 -0
  90. data/lib/aws-sdk-ssooidc.rb +59 -0
  91. data/lib/aws-sdk-sts/client.rb +330 -262
  92. data/lib/aws-sdk-sts/client_api.rb +12 -1
  93. data/lib/aws-sdk-sts/endpoint_parameters.rb +78 -0
  94. data/lib/aws-sdk-sts/endpoint_provider.rb +112 -0
  95. data/lib/aws-sdk-sts/endpoints.rb +136 -0
  96. data/lib/aws-sdk-sts/plugins/endpoints.rb +84 -0
  97. data/lib/aws-sdk-sts/presigner.rb +14 -16
  98. data/lib/aws-sdk-sts/types.rb +135 -204
  99. data/lib/aws-sdk-sts.rb +5 -1
  100. data/lib/seahorse/client/async_base.rb +0 -1
  101. data/lib/seahorse/client/configuration.rb +1 -5
  102. data/lib/seahorse/client/h2/connection.rb +12 -11
  103. data/lib/seahorse/client/net_http/patches.rb +1 -4
  104. data/lib/seahorse/client/plugins/h2.rb +3 -3
  105. data/lib/seahorse/client/plugins/request_callback.rb +40 -9
  106. data/lib/seahorse/client/response.rb +6 -0
  107. data/lib/seahorse/model/operation.rb +6 -0
  108. data/lib/seahorse/util.rb +4 -0
  109. metadata +59 -9
@@ -4,7 +4,31 @@ module Aws
4
4
  module Plugins
5
5
  # @api private
6
6
  class UserAgent < Seahorse::Client::Plugin
7
+ # @api private
7
8
  option(:user_agent_suffix)
9
+ # @api private
10
+ option(:user_agent_frameworks, default: [])
11
+
12
+ option(
13
+ :sdk_ua_app_id,
14
+ doc_type: 'String',
15
+ docstring: <<-DOCS) do |cfg|
16
+ A unique and opaque application ID that is appended to the
17
+ User-Agent header as app/<sdk_ua_app_id>. It should have a
18
+ maximum length of 50.
19
+ DOCS
20
+ app_id = ENV['AWS_SDK_UA_APP_ID']
21
+ app_id ||= Aws.shared_config.sdk_ua_app_id(profile: cfg.profile)
22
+ app_id
23
+ end
24
+
25
+ def self.feature(feature, &block)
26
+ Thread.current[:aws_sdk_core_user_agent_feature] ||= []
27
+ Thread.current[:aws_sdk_core_user_agent_feature] << "ft/#{feature}"
28
+ block.call
29
+ ensure
30
+ Thread.current[:aws_sdk_core_user_agent_feature].pop
31
+ end
8
32
 
9
33
  # @api private
10
34
  class Handler < Seahorse::Client::Handler
@@ -14,33 +38,112 @@ module Aws
14
38
  end
15
39
 
16
40
  def set_user_agent(context)
17
- ua = "aws-sdk-ruby3/#{CORE_GEM_VERSION}"
41
+ context.http_request.headers['User-Agent'] = UserAgent.new(context).to_s
42
+ end
43
+
44
+ class UserAgent
45
+ def initialize(context)
46
+ @context = context
47
+ end
48
+
49
+ def to_s
50
+ ua = "aws-sdk-ruby3/#{CORE_GEM_VERSION}"
51
+ ua += ' ua/2.0'
52
+ ua += " #{api_metadata}" if api_metadata
53
+ ua += " #{os_metadata}"
54
+ ua += " #{language_metadata}"
55
+ ua += " #{env_metadata}" if env_metadata
56
+ ua += " #{config_metadata}" if config_metadata
57
+ ua += " #{app_id}" if app_id
58
+ ua += " #{feature_metadata}" if feature_metadata
59
+ ua += " #{framework_metadata}" if framework_metadata
60
+ if @context.config.user_agent_suffix
61
+ ua += " #{@context.config.user_agent_suffix}"
62
+ end
63
+ ua.strip
64
+ end
65
+
66
+ private
18
67
 
19
- begin
20
- ua += " #{RUBY_ENGINE}/#{RUBY_VERSION}"
21
- rescue
22
- ua += " RUBY_ENGINE_NA/#{RUBY_VERSION}"
68
+ # Used to be gem_name/gem_version
69
+ def api_metadata
70
+ service_id = @context.config.api.metadata['serviceId']
71
+ return unless service_id
72
+
73
+ service_id = service_id.gsub(' ', '_').downcase
74
+ gem_version = @context[:gem_version]
75
+ "api/#{service_id}##{gem_version}"
76
+ end
77
+
78
+ # Used to be RUBY_PLATFORM
79
+ def os_metadata
80
+ os =
81
+ case RbConfig::CONFIG['host_os']
82
+ when /mac|darwin/
83
+ 'macos'
84
+ when /linux|cygwin/
85
+ 'linux'
86
+ when /mingw|mswin/
87
+ 'windows'
88
+ else
89
+ 'other'
90
+ end
91
+ metadata = "os/#{os}"
92
+ local_version = Gem::Platform.local.version
93
+ metadata += "##{local_version}" if local_version
94
+ metadata += " md/#{RbConfig::CONFIG['host_cpu']}"
95
+ metadata
23
96
  end
24
97
 
25
- ua += " #{RUBY_PLATFORM}"
98
+ # Used to be RUBY_ENGINE/RUBY_VERSION
99
+ def language_metadata
100
+ "lang/#{RUBY_ENGINE}##{RUBY_ENGINE_VERSION} md/#{RUBY_VERSION}"
101
+ end
102
+
103
+ def env_metadata
104
+ return unless (execution_env = ENV['AWS_EXECUTION_ENV'])
105
+
106
+ "exec-env/#{execution_env}"
107
+ end
26
108
 
27
- if context[:gem_name] && context[:gem_version]
28
- ua += " #{context[:gem_name]}/#{context[:gem_version]}"
109
+ def config_metadata
110
+ "cfg/retry-mode##{@context.config.retry_mode}"
29
111
  end
30
112
 
31
- if (execution_env = ENV['AWS_EXECUTION_ENV'])
32
- ua += " exec-env/#{execution_env}"
113
+ def app_id
114
+ return unless (app_id = @context.config.sdk_ua_app_id)
115
+
116
+ # Sanitize and only allow these characters
117
+ app_id = app_id.gsub(/[^!#$%&'*+\-.^_`|~0-9A-Za-z]/, '-')
118
+ "app/#{app_id}"
33
119
  end
34
120
 
35
- if context.config.user_agent_suffix
36
- ua += " #{context.config.user_agent_suffix}"
121
+ def feature_metadata
122
+ return unless Thread.current[:aws_sdk_core_user_agent_feature]
123
+
124
+ Thread.current[:aws_sdk_core_user_agent_feature].join(' ')
37
125
  end
38
126
 
39
- context.http_request.headers['User-Agent'] = ua.strip
127
+ def framework_metadata
128
+ if (frameworks_cfg = @context.config.user_agent_frameworks).empty?
129
+ return
130
+ end
131
+
132
+ # Frameworks may be aws-record, aws-sdk-rails, etc.
133
+ regex = /gems\/(?<name>#{frameworks_cfg.join('|')})-(?<version>\d+\.\d+\.\d+)/.freeze
134
+ frameworks = {}
135
+ Kernel.caller.each do |line|
136
+ match = line.match(regex)
137
+ next unless match
138
+
139
+ frameworks[match[:name]] = match[:version]
140
+ end
141
+ frameworks.map { |n, v| "lib/#{n}##{v}" }.join(' ')
142
+ end
40
143
  end
41
144
  end
42
145
 
43
- handler(Handler)
146
+ handler(Handler, priority: 1)
44
147
  end
45
148
  end
46
149
  end
@@ -1,19 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Aws
4
-
5
4
  # A credential provider that executes a given process and attempts
6
- # to read its stdout to recieve a JSON payload containing the credentials
7
- #
8
- # Automatically handles refreshing credentials if an Expiration time is
9
- # provided in the credentials payload
10
- #
11
- # credentials = Aws::ProcessCredentials.new('/usr/bin/credential_proc').credentials
5
+ # to read its stdout to recieve a JSON payload containing the credentials.
12
6
  #
7
+ # credentials = Aws::ProcessCredentials.new('/usr/bin/credential_proc')
13
8
  # ec2 = Aws::EC2::Client.new(credentials: credentials)
14
9
  #
15
- # More documentation on process based credentials can be found here:
16
- # https://docs.aws.amazon.com/cli/latest/topic/config-vars.html#sourcing-credentials-from-external-processes
10
+ # Automatically handles refreshing credentials if an Expiration time is
11
+ # provided in the credentials payload.
12
+ #
13
+ # @see https://docs.aws.amazon.com/cli/latest/topic/config-vars.html#sourcing-credentials-from-external-processes
17
14
  class ProcessCredentials
18
15
 
19
16
  include CredentialProvider
@@ -27,6 +24,7 @@ module Aws
27
24
  def initialize(process)
28
25
  @process = process
29
26
  @credentials = credentials_from_process(@process)
27
+ @async_refresh = false
30
28
 
31
29
  super
32
30
  end
@@ -73,9 +71,9 @@ module Aws
73
71
  @credentials = credentials_from_process(@process)
74
72
  end
75
73
 
76
- def near_expiration?
74
+ def near_expiration?(expiration_length)
77
75
  # are we within 5 minutes of expiration?
78
- @expiration && (Time.now.to_i + 5 * 60) > @expiration.to_i
76
+ @expiration && (Time.now.to_i + expiration_length) > @expiration.to_i
79
77
  end
80
78
  end
81
79
  end
@@ -17,45 +17,70 @@ module Aws
17
17
  # @api private
18
18
  module RefreshingCredentials
19
19
 
20
+ SYNC_EXPIRATION_LENGTH = 300 # 5 minutes
21
+ ASYNC_EXPIRATION_LENGTH = 600 # 10 minutes
22
+
23
+ CLIENT_EXCLUDE_OPTIONS = Set.new([:before_refresh]).freeze
24
+
20
25
  def initialize(options = {})
21
26
  @mutex = Mutex.new
27
+ @before_refresh = options.delete(:before_refresh) if Hash === options
28
+
29
+ @before_refresh.call(self) if @before_refresh
22
30
  refresh
23
31
  end
24
32
 
25
33
  # @return [Credentials]
26
34
  def credentials
27
- refresh_if_near_expiration
35
+ refresh_if_near_expiration!
28
36
  @credentials
29
37
  end
30
38
 
31
- # @return [Time,nil]
32
- def expiration
33
- refresh_if_near_expiration
34
- @expiration
35
- end
36
-
37
39
  # Refresh credentials.
38
40
  # @return [void]
39
41
  def refresh!
40
- @mutex.synchronize { refresh }
42
+ @mutex.synchronize do
43
+ @before_refresh.call(self) if @before_refresh
44
+
45
+ refresh
46
+ end
41
47
  end
42
48
 
43
49
  private
44
50
 
45
- # Refreshes instance metadata credentials if they are within
46
- # 5 minutes of expiration.
47
- def refresh_if_near_expiration
48
- if near_expiration?
51
+ # Refreshes credentials asynchronously and synchronously.
52
+ # If we are near to expiration, block while getting new credentials.
53
+ # Otherwise, if we're approaching expiration, use the existing credentials
54
+ # but attempt a refresh in the background.
55
+ def refresh_if_near_expiration!
56
+ # Note: This check is an optimization. Rather than acquire the mutex on every #refresh_if_near_expiration
57
+ # call, we check before doing so, and then we check within the mutex to avoid a race condition.
58
+ # See issue: https://github.com/aws/aws-sdk-ruby/issues/2641 for more info.
59
+ if near_expiration?(SYNC_EXPIRATION_LENGTH)
49
60
  @mutex.synchronize do
50
- refresh if near_expiration?
61
+ if near_expiration?(SYNC_EXPIRATION_LENGTH)
62
+ @before_refresh.call(self) if @before_refresh
63
+ refresh
64
+ end
65
+ end
66
+ elsif @async_refresh && near_expiration?(ASYNC_EXPIRATION_LENGTH)
67
+ unless @mutex.locked?
68
+ Thread.new do
69
+ @mutex.synchronize do
70
+ if near_expiration?(ASYNC_EXPIRATION_LENGTH)
71
+ @before_refresh.call(self) if @before_refresh
72
+ refresh
73
+ end
74
+ end
75
+ end
51
76
  end
52
77
  end
53
78
  end
54
79
 
55
- def near_expiration?
80
+ def near_expiration?(expiration_length)
56
81
  if @expiration
57
- # are we within 5 minutes of expiration?
58
- (Time.now.to_i + 5 * 60) > @expiration.to_i
82
+ # Are we within expiration?
83
+ (Time.now.to_i + expiration_length) > @expiration.to_i
59
84
  else
60
85
  true
61
86
  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)
@@ -4,9 +4,16 @@ module Aws
4
4
  module Rest
5
5
  module Request
6
6
  class QuerystringBuilder
7
-
8
7
  include Seahorse::Model::Shapes
9
8
 
9
+ SUPPORTED_TYPES = [
10
+ BooleanShape,
11
+ FloatShape,
12
+ IntegerShape,
13
+ StringShape,
14
+ TimestampShape
15
+ ].freeze
16
+
10
17
  # Provide shape references and param values:
11
18
  #
12
19
  # [
@@ -33,29 +40,12 @@ module Aws
33
40
  def build_part(shape_ref, param_value)
34
41
  case shape_ref.shape
35
42
  # supported scalar types
36
- when StringShape, BooleanShape, FloatShape, IntegerShape, StringShape
37
- param_name = shape_ref.location_name
38
- "#{param_name}=#{escape(param_value.to_s)}"
39
- when TimestampShape
40
- param_name = shape_ref.location_name
41
- "#{param_name}=#{escape(timestamp(shape_ref, param_value))}"
43
+ when *SUPPORTED_TYPES
44
+ "#{shape_ref.location_name}=#{query_value(shape_ref, param_value)}"
42
45
  when MapShape
43
- if StringShape === shape_ref.shape.value.shape
44
- query_map_of_string(param_value)
45
- elsif ListShape === shape_ref.shape.value.shape
46
- query_map_of_string_list(param_value)
47
- else
48
- msg = "only map of string and string list supported"
49
- raise NotImplementedError, msg
50
- end
46
+ generate_query_map(shape_ref, param_value)
51
47
  when ListShape
52
- if StringShape === shape_ref.shape.member.shape
53
- list_of_strings(shape_ref.location_name, param_value)
54
- else
55
- msg = "Only list of strings supported, got "\
56
- "#{shape_ref.shape.member.shape.class.name}"
57
- raise NotImplementedError, msg
58
- end
48
+ generate_query_list(shape_ref, param_value)
59
49
  else
60
50
  raise NotImplementedError
61
51
  end
@@ -71,6 +61,37 @@ module Aws
71
61
  end
72
62
  end
73
63
 
64
+ def query_value(ref, value)
65
+ case ref.shape
66
+ when TimestampShape
67
+ escape(timestamp(ref, value))
68
+ when *SUPPORTED_TYPES
69
+ escape(value.to_s)
70
+ else
71
+ raise NotImplementedError
72
+ end
73
+ end
74
+
75
+ def generate_query_list(ref, values)
76
+ member_ref = ref.shape.member
77
+ values.map do |value|
78
+ value = query_value(member_ref, value)
79
+ "#{ref.location_name}=#{value}"
80
+ end
81
+ end
82
+
83
+ def generate_query_map(ref, value)
84
+ case ref.shape.value.shape
85
+ when StringShape
86
+ query_map_of_string(value)
87
+ when ListShape
88
+ query_map_of_string_list(value)
89
+ else
90
+ msg = 'Only map of string and string list supported'
91
+ raise NotImplementedError, msg
92
+ end
93
+ end
94
+
74
95
  def query_map_of_string(hash)
75
96
  list = []
76
97
  hash.each_pair do |key, value|
@@ -89,16 +110,9 @@ module Aws
89
110
  list
90
111
  end
91
112
 
92
- def list_of_strings(name, values)
93
- values.map do |value|
94
- "#{name}=#{escape(value)}"
95
- end
96
- end
97
-
98
113
  def escape(string)
99
114
  Seahorse::Util.uri_escape(string)
100
115
  end
101
-
102
116
  end
103
117
  end
104
118
  end
@@ -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
@@ -100,7 +106,7 @@ module Aws
100
106
  # or `nil` if no valid credentials were found.
101
107
  def credentials(opts = {})
102
108
  p = opts[:profile] || @profile_name
103
- validate_profile_exists(p) if credentials_present?
109
+ validate_profile_exists(p)
104
110
  if (credentials = credentials_from_shared(p, opts))
105
111
  credentials
106
112
  elsif (credentials = credentials_from_config(p, opts))
@@ -149,6 +155,38 @@ 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
+
170
+ # Source a custom configured endpoint from the shared configuration file
171
+ #
172
+ # @param [Hash] opts
173
+ # @option opts [String] :profile
174
+ # @option opts [String] :service_id
175
+ def configured_endpoint(opts = {})
176
+ # services section is only allowed in the shared config file (not credentials)
177
+ profile = opts[:profile] || @profile_name
178
+ service_id = opts[:service_id]&.gsub(" ", "_")&.downcase
179
+ if @parsed_config && (prof_config = @parsed_config[profile])
180
+ services_section_name = prof_config['services']
181
+ if (services_config = @parsed_config["services #{services_section_name}"]) &&
182
+ (service_config = services_config[service_id])
183
+ return service_config['endpoint_url'] if service_config['endpoint_url']
184
+ end
185
+ return prof_config['endpoint_url']
186
+ end
187
+ nil
188
+ end
189
+
152
190
  # Add an accessor method (similar to attr_reader) to return a configuration value
153
191
  # Uses the get_config_value below to control where
154
192
  # values are loaded from
@@ -167,6 +205,7 @@ module Aws
167
205
  :use_fips_endpoint,
168
206
  :ec2_metadata_service_endpoint,
169
207
  :ec2_metadata_service_endpoint_mode,
208
+ :ec2_metadata_v1_disabled,
170
209
  :max_attempts,
171
210
  :retry_mode,
172
211
  :adaptive_retry_wait_to_fill,
@@ -179,7 +218,11 @@ module Aws
179
218
  :s3_use_arn_region,
180
219
  :s3_us_east_1_regional_endpoint,
181
220
  :s3_disable_multiregion_access_points,
182
- :defaults_mode
221
+ :defaults_mode,
222
+ :sdk_ua_app_id,
223
+ :disable_request_compression,
224
+ :request_min_compression_size_bytes,
225
+ :ignore_configured_endpoint_urls
183
226
  )
184
227
 
185
228
  private
@@ -195,11 +238,6 @@ module Aws
195
238
  value
196
239
  end
197
240
 
198
- def credentials_present?
199
- (@parsed_credentials && !@parsed_credentials.empty?) ||
200
- (@parsed_config && !@parsed_config.empty?)
201
- end
202
-
203
241
  def assume_role_from_profile(cfg, profile, opts, chain_config)
204
242
  if cfg && prof_cfg = cfg[profile]
205
243
  opts[:source_profile] ||= prof_cfg['source_profile']
@@ -319,13 +357,53 @@ module Aws
319
357
  def sso_credentials_from_profile(cfg, profile)
320
358
  if @parsed_config &&
321
359
  (prof_config = cfg[profile]) &&
322
- !(prof_config.keys & SSO_PROFILE_KEYS).empty?
360
+ !(prof_config.keys & SSO_CREDENTIAL_PROFILE_KEYS).empty?
361
+
362
+ if sso_session_name = prof_config['sso_session']
363
+ sso_session = sso_session(cfg, profile, sso_session_name)
364
+
365
+ sso_region = sso_session['sso_region']
366
+ sso_start_url = sso_session['sso_start_url']
367
+
368
+ # validate sso_region and sso_start_url don't conflict if set on profile and session
369
+ if prof_config['sso_region'] && prof_config['sso_region'] != sso_region
370
+ raise ArgumentError,
371
+ "sso-session #{sso_session_name}'s sso_region (#{sso_region}) " \
372
+ "does not match the profile #{profile}'s sso_region (#{prof_config['sso_region']}'"
373
+ end
374
+ if prof_config['sso_start_url'] && prof_config['sso_start_url'] != sso_start_url
375
+ raise ArgumentError,
376
+ "sso-session #{sso_session_name}'s sso_start_url (#{sso_start_url}) " \
377
+ "does not match the profile #{profile}'s sso_start_url (#{prof_config['sso_start_url']}'"
378
+ end
379
+ else
380
+ sso_region = prof_config['sso_region']
381
+ sso_start_url = prof_config['sso_start_url']
382
+ end
323
383
 
324
384
  SSOCredentials.new(
325
- sso_start_url: prof_config['sso_start_url'],
326
- sso_region: prof_config['sso_region'],
327
385
  sso_account_id: prof_config['sso_account_id'],
328
- sso_role_name: prof_config['sso_role_name']
386
+ sso_role_name: prof_config['sso_role_name'],
387
+ sso_session: prof_config['sso_session'],
388
+ sso_region: sso_region,
389
+ sso_start_url: sso_start_url
390
+ )
391
+ end
392
+ end
393
+
394
+ # If the required sso_ profile values are present, attempt to construct
395
+ # SSOTokenProvider
396
+ def sso_token_from_profile(cfg, profile)
397
+ if @parsed_config &&
398
+ (prof_config = cfg[profile]) &&
399
+ !(prof_config.keys & SSO_TOKEN_PROFILE_KEYS).empty?
400
+
401
+ sso_session_name = prof_config['sso_session']
402
+ sso_session = sso_session(cfg, profile, sso_session_name)
403
+
404
+ SSOTokenProvider.new(
405
+ sso_session: sso_session_name,
406
+ sso_region: sso_session['sso_region']
329
407
  )
330
408
  end
331
409
  end
@@ -379,5 +457,22 @@ module Aws
379
457
  ret ||= 'default'
380
458
  ret
381
459
  end
460
+
461
+ def sso_session(cfg, profile, sso_session_name)
462
+ # aws sso-configure may add quotes around sso session names with whitespace
463
+ sso_session = cfg["sso-session #{sso_session_name}"] || cfg["sso-session '#{sso_session_name}'"]
464
+
465
+ unless sso_session
466
+ raise ArgumentError,
467
+ "sso-session #{sso_session_name} must be defined in the config file. " \
468
+ "Referenced by profile #{profile}"
469
+ end
470
+
471
+ unless sso_session['sso_region']
472
+ raise ArgumentError, "sso-session #{sso_session_name} missing required parameter: sso_region"
473
+ end
474
+
475
+ sso_session
476
+ end
382
477
  end
383
478
  end