aws-sdk-core 3.117.0 → 3.197.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +836 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-defaults/default_configuration.rb +153 -0
  5. data/lib/aws-defaults/defaults_mode_config_resolver.rb +107 -0
  6. data/lib/aws-defaults.rb +3 -0
  7. data/lib/aws-sdk-core/arn.rb +13 -0
  8. data/lib/aws-sdk-core/assume_role_credentials.rb +21 -7
  9. data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +14 -10
  10. data/lib/aws-sdk-core/binary/decode_handler.rb +0 -5
  11. data/lib/aws-sdk-core/binary/encode_handler.rb +12 -1
  12. data/lib/aws-sdk-core/binary/event_builder.rb +34 -37
  13. data/lib/aws-sdk-core/client_stubs.rb +20 -13
  14. data/lib/aws-sdk-core/credential_provider.rb +4 -1
  15. data/lib/aws-sdk-core/credential_provider_chain.rb +8 -5
  16. data/lib/aws-sdk-core/ec2_metadata.rb +4 -3
  17. data/lib/aws-sdk-core/ecs_credentials.rb +187 -52
  18. data/lib/aws-sdk-core/endpoints/condition.rb +41 -0
  19. data/lib/aws-sdk-core/endpoints/endpoint.rb +17 -0
  20. data/lib/aws-sdk-core/endpoints/endpoint_rule.rb +75 -0
  21. data/lib/aws-sdk-core/endpoints/error_rule.rb +42 -0
  22. data/lib/aws-sdk-core/endpoints/function.rb +80 -0
  23. data/lib/aws-sdk-core/endpoints/matchers.rb +135 -0
  24. data/lib/aws-sdk-core/endpoints/reference.rb +31 -0
  25. data/lib/aws-sdk-core/endpoints/rule.rb +25 -0
  26. data/lib/aws-sdk-core/endpoints/rule_set.rb +52 -0
  27. data/lib/aws-sdk-core/endpoints/rules_provider.rb +37 -0
  28. data/lib/aws-sdk-core/endpoints/templater.rb +58 -0
  29. data/lib/aws-sdk-core/endpoints/tree_rule.rb +45 -0
  30. data/lib/aws-sdk-core/endpoints/url.rb +60 -0
  31. data/lib/aws-sdk-core/endpoints.rb +78 -0
  32. data/lib/aws-sdk-core/errors.rb +17 -4
  33. data/lib/aws-sdk-core/event_emitter.rb +0 -16
  34. data/lib/aws-sdk-core/ini_parser.rb +7 -0
  35. data/lib/aws-sdk-core/instance_profile_credentials.rb +127 -33
  36. data/lib/aws-sdk-core/json/builder.rb +8 -1
  37. data/lib/aws-sdk-core/json/error_handler.rb +30 -4
  38. data/lib/aws-sdk-core/json/handler.rb +8 -1
  39. data/lib/aws-sdk-core/json/json_engine.rb +10 -8
  40. data/lib/aws-sdk-core/json/oj_engine.rb +33 -6
  41. data/lib/aws-sdk-core/json/parser.rb +38 -2
  42. data/lib/aws-sdk-core/json.rb +8 -26
  43. data/lib/aws-sdk-core/log/formatter.rb +6 -0
  44. data/lib/aws-sdk-core/log/param_filter.rb +9 -1
  45. data/lib/aws-sdk-core/lru_cache.rb +75 -0
  46. data/lib/aws-sdk-core/pageable_response.rb +81 -32
  47. data/lib/aws-sdk-core/param_validator.rb +36 -2
  48. data/lib/aws-sdk-core/plugins/bearer_authorization.rb +67 -0
  49. data/lib/aws-sdk-core/plugins/checksum_algorithm.rb +342 -0
  50. data/lib/aws-sdk-core/plugins/client_metrics_plugin.rb +1 -0
  51. data/lib/aws-sdk-core/plugins/client_metrics_send_plugin.rb +14 -2
  52. data/lib/aws-sdk-core/plugins/credentials_configuration.rb +29 -1
  53. data/lib/aws-sdk-core/plugins/defaults_mode.rb +40 -0
  54. data/lib/aws-sdk-core/plugins/endpoint_discovery.rb +6 -2
  55. data/lib/aws-sdk-core/plugins/http_checksum.rb +9 -1
  56. data/lib/aws-sdk-core/plugins/invocation_id.rb +1 -11
  57. data/lib/aws-sdk-core/plugins/jsonvalue_converter.rb +34 -6
  58. data/lib/aws-sdk-core/plugins/logging.rb +2 -0
  59. data/lib/aws-sdk-core/plugins/protocols/api_gateway.rb +17 -0
  60. data/lib/aws-sdk-core/plugins/protocols/rest_json.rb +4 -2
  61. data/lib/aws-sdk-core/plugins/protocols/rest_xml.rb +1 -2
  62. data/lib/aws-sdk-core/plugins/recursion_detection.rb +38 -0
  63. data/lib/aws-sdk-core/plugins/regional_endpoint.rb +144 -17
  64. data/lib/aws-sdk-core/plugins/request_compression.rb +226 -0
  65. data/lib/aws-sdk-core/plugins/response_paging.rb +1 -1
  66. data/lib/aws-sdk-core/plugins/retries/error_inspector.rb +7 -4
  67. data/lib/aws-sdk-core/plugins/retry_errors.rb +33 -7
  68. data/lib/aws-sdk-core/plugins/sign.rb +211 -0
  69. data/lib/aws-sdk-core/plugins/signature_v2.rb +1 -0
  70. data/lib/aws-sdk-core/plugins/signature_v4.rb +28 -31
  71. data/lib/aws-sdk-core/plugins/stub_responses.rb +6 -1
  72. data/lib/aws-sdk-core/plugins/user_agent.rb +152 -14
  73. data/lib/aws-sdk-core/process_credentials.rb +50 -34
  74. data/lib/aws-sdk-core/query/ec2_param_builder.rb +5 -7
  75. data/lib/aws-sdk-core/query/param_builder.rb +2 -2
  76. data/lib/aws-sdk-core/refreshing_credentials.rb +49 -18
  77. data/lib/aws-sdk-core/refreshing_token.rb +71 -0
  78. data/lib/aws-sdk-core/rest/handler.rb +1 -1
  79. data/lib/aws-sdk-core/rest/request/body.rb +49 -4
  80. data/lib/aws-sdk-core/rest/request/content_type.rb +60 -0
  81. data/lib/aws-sdk-core/rest/request/endpoint.rb +24 -4
  82. data/lib/aws-sdk-core/rest/request/headers.rb +23 -7
  83. data/lib/aws-sdk-core/rest/request/querystring_builder.rb +62 -36
  84. data/lib/aws-sdk-core/rest/response/body.rb +15 -1
  85. data/lib/aws-sdk-core/rest/response/header_list_parser.rb +79 -0
  86. data/lib/aws-sdk-core/rest/response/headers.rb +10 -3
  87. data/lib/aws-sdk-core/rest.rb +1 -0
  88. data/lib/aws-sdk-core/shared_config.rb +112 -12
  89. data/lib/aws-sdk-core/sso_credentials.rb +92 -51
  90. data/lib/aws-sdk-core/sso_token_provider.rb +135 -0
  91. data/lib/aws-sdk-core/static_token_provider.rb +14 -0
  92. data/lib/aws-sdk-core/structure.rb +16 -5
  93. data/lib/aws-sdk-core/stubbing/stub_data.rb +11 -0
  94. data/lib/aws-sdk-core/token.rb +31 -0
  95. data/lib/aws-sdk-core/token_provider.rb +15 -0
  96. data/lib/aws-sdk-core/token_provider_chain.rb +51 -0
  97. data/lib/aws-sdk-core/util.rb +39 -0
  98. data/lib/aws-sdk-core/waiters/poller.rb +4 -2
  99. data/lib/aws-sdk-core/xml/builder.rb +17 -9
  100. data/lib/aws-sdk-core/xml/error_handler.rb +31 -8
  101. data/lib/aws-sdk-core/xml/parser/engines/oga.rb +2 -0
  102. data/lib/aws-sdk-core/xml/parser/engines/ox.rb +1 -1
  103. data/lib/aws-sdk-core/xml/parser/engines/rexml.rb +0 -8
  104. data/lib/aws-sdk-core/xml/parser/frame.rb +27 -20
  105. data/lib/aws-sdk-core/xml/parser/stack.rb +2 -0
  106. data/lib/aws-sdk-core.rb +21 -0
  107. data/lib/aws-sdk-sso/client.rb +157 -50
  108. data/lib/aws-sdk-sso/endpoint_parameters.rb +66 -0
  109. data/lib/aws-sdk-sso/endpoint_provider.rb +57 -0
  110. data/lib/aws-sdk-sso/endpoints.rb +72 -0
  111. data/lib/aws-sdk-sso/plugins/endpoints.rb +78 -0
  112. data/lib/aws-sdk-sso/types.rb +8 -43
  113. data/lib/aws-sdk-sso.rb +5 -1
  114. data/lib/aws-sdk-ssooidc/client.rb +1008 -0
  115. data/lib/aws-sdk-ssooidc/client_api.rb +293 -0
  116. data/lib/aws-sdk-ssooidc/customizations.rb +1 -0
  117. data/lib/aws-sdk-ssooidc/endpoint_parameters.rb +66 -0
  118. data/lib/aws-sdk-ssooidc/endpoint_provider.rb +57 -0
  119. data/lib/aws-sdk-ssooidc/endpoints.rb +72 -0
  120. data/lib/aws-sdk-ssooidc/errors.rb +342 -0
  121. data/lib/aws-sdk-ssooidc/plugins/endpoints.rb +78 -0
  122. data/lib/aws-sdk-ssooidc/resource.rb +26 -0
  123. data/lib/aws-sdk-ssooidc/types.rb +823 -0
  124. data/lib/aws-sdk-ssooidc.rb +59 -0
  125. data/lib/aws-sdk-sts/client.rb +472 -398
  126. data/lib/aws-sdk-sts/client_api.rb +20 -9
  127. data/lib/aws-sdk-sts/endpoint_parameters.rb +78 -0
  128. data/lib/aws-sdk-sts/endpoint_provider.rb +112 -0
  129. data/lib/aws-sdk-sts/endpoints.rb +136 -0
  130. data/lib/aws-sdk-sts/plugins/endpoints.rb +86 -0
  131. data/lib/aws-sdk-sts/plugins/sts_regional_endpoints.rb +5 -1
  132. data/lib/aws-sdk-sts/presigner.rb +14 -10
  133. data/lib/aws-sdk-sts/types.rb +168 -227
  134. data/lib/aws-sdk-sts.rb +5 -1
  135. data/lib/seahorse/client/async_base.rb +1 -2
  136. data/lib/seahorse/client/async_response.rb +19 -0
  137. data/lib/seahorse/client/base.rb +1 -0
  138. data/lib/seahorse/client/configuration.rb +5 -5
  139. data/lib/seahorse/client/h2/connection.rb +15 -16
  140. data/lib/seahorse/client/h2/handler.rb +5 -5
  141. data/lib/seahorse/client/net_http/connection_pool.rb +10 -9
  142. data/lib/seahorse/client/net_http/handler.rb +15 -7
  143. data/lib/seahorse/client/net_http/patches.rb +12 -86
  144. data/lib/seahorse/client/plugin.rb +9 -0
  145. data/lib/seahorse/client/plugins/content_length.rb +11 -5
  146. data/lib/seahorse/client/plugins/h2.rb +3 -3
  147. data/lib/seahorse/client/plugins/net_http.rb +73 -10
  148. data/lib/seahorse/client/plugins/request_callback.rb +40 -9
  149. data/lib/seahorse/client/response.rb +6 -0
  150. data/lib/seahorse/model/operation.rb +6 -0
  151. data/lib/seahorse/model/shapes.rb +27 -2
  152. data/lib/seahorse/util.rb +4 -0
  153. data/sig/aws-sdk-core/client_stubs.rbs +10 -0
  154. data/sig/aws-sdk-core/errors.rbs +22 -0
  155. data/sig/aws-sdk-core/resources/collection.rbs +21 -0
  156. data/sig/aws-sdk-core/structure.rbs +4 -0
  157. data/sig/aws-sdk-core/waiters/errors.rbs +20 -0
  158. data/sig/aws-sdk-core.rbs +7 -0
  159. data/sig/seahorse/client/base.rbs +25 -0
  160. data/sig/seahorse/client/handler_builder.rbs +16 -0
  161. data/sig/seahorse/client/response.rbs +61 -0
  162. metadata +82 -17
  163. data/lib/aws-sdk-sso/plugins/content_type.rb +0 -25
@@ -0,0 +1,211 @@
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 sigv4-s3express 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, sigv4_region_override = nil, sigv4_credentials_override = nil)
28
+ case auth_scheme['name']
29
+ when 'sigv4', 'sigv4a', 'sigv4-s3express'
30
+ sigv4_overrides = {
31
+ region: sigv4_region_override,
32
+ credentials: sigv4_credentials_override
33
+ }
34
+ SignatureV4.new(auth_scheme, config, sigv4_overrides)
35
+ when 'bearer'
36
+ Bearer.new
37
+ else
38
+ NullSigner.new
39
+ end
40
+ end
41
+
42
+ class Handler < Seahorse::Client::Handler
43
+ def call(context)
44
+ # Skip signing if using sigv2 signing from s3_signer in S3
45
+ unless v2_signing?(context.config)
46
+ signer = Sign.signer_for(
47
+ context[:auth_scheme],
48
+ context.config,
49
+ context[:sigv4_region],
50
+ context[:sigv4_credentials]
51
+ )
52
+ signer.sign(context)
53
+ end
54
+ @handler.call(context)
55
+ end
56
+
57
+ private
58
+
59
+ def v2_signing?(config)
60
+ # 's3' is legacy signing, 'v4' is default
61
+ config.respond_to?(:signature_version) &&
62
+ config.signature_version == 's3'
63
+ end
64
+ end
65
+
66
+ # @api private
67
+ class Bearer
68
+ def initialize
69
+ end
70
+
71
+ def sign(context)
72
+ if context.http_request.endpoint.scheme != 'https'
73
+ raise ArgumentError,
74
+ 'Unable to use bearer authorization on non https endpoint.'
75
+ end
76
+
77
+ token_provider = context.config.token_provider
78
+
79
+ raise Errors::MissingBearerTokenError unless token_provider&.set?
80
+
81
+ context.http_request.headers['Authorization'] =
82
+ "Bearer #{token_provider.token.token}"
83
+ end
84
+
85
+ def presign_url(*args)
86
+ raise ArgumentError, 'Bearer auth does not support presigned urls'
87
+ end
88
+
89
+ def sign_event(*args)
90
+ raise ArgumentError, 'Bearer auth does not support event signing'
91
+ end
92
+ end
93
+
94
+ # @api private
95
+ class SignatureV4
96
+ def initialize(auth_scheme, config, sigv4_overrides = {})
97
+ scheme_name = auth_scheme['name']
98
+
99
+ unless %w[sigv4 sigv4a sigv4-s3express].include?(scheme_name)
100
+ raise ArgumentError,
101
+ "Expected sigv4, sigv4a, or sigv4-s3express auth scheme, got #{scheme_name}"
102
+ end
103
+
104
+ region = if scheme_name == 'sigv4a'
105
+ auth_scheme['signingRegionSet'].first
106
+ else
107
+ auth_scheme['signingRegion']
108
+ end
109
+ begin
110
+ @signer = Aws::Sigv4::Signer.new(
111
+ service: config.sigv4_name || auth_scheme['signingName'],
112
+ region: sigv4_overrides[:region] || config.sigv4_region || region,
113
+ credentials_provider: sigv4_overrides[:credentials] || config.credentials,
114
+ signing_algorithm: scheme_name.to_sym,
115
+ uri_escape_path: !!!auth_scheme['disableDoubleEncoding'],
116
+ normalize_path: !!!auth_scheme['disableNormalizePath'],
117
+ unsigned_headers: %w[content-length user-agent x-amzn-trace-id]
118
+ )
119
+ rescue Aws::Sigv4::Errors::MissingCredentialsError
120
+ raise Aws::Errors::MissingCredentialsError
121
+ end
122
+ end
123
+
124
+ def sign(context)
125
+ req = context.http_request
126
+
127
+ apply_authtype(context, req)
128
+ reset_signature(req)
129
+ apply_clock_skew(context, req)
130
+
131
+ # compute the signature
132
+ begin
133
+ signature = @signer.sign_request(
134
+ http_method: req.http_method,
135
+ url: req.endpoint,
136
+ headers: req.headers,
137
+ body: req.body
138
+ )
139
+ rescue Aws::Sigv4::Errors::MissingCredentialsError
140
+ # Necessary for when credentials is explicitly set to nil
141
+ raise Aws::Errors::MissingCredentialsError
142
+ end
143
+ # apply signature headers
144
+ req.headers.update(signature.headers)
145
+
146
+ # add request metadata with signature components for debugging
147
+ context[:canonical_request] = signature.canonical_request
148
+ context[:string_to_sign] = signature.string_to_sign
149
+ end
150
+
151
+ def presign_url(*args)
152
+ @signer.presign_url(*args)
153
+ end
154
+
155
+ def sign_event(*args)
156
+ @signer.sign_event(*args)
157
+ end
158
+
159
+ private
160
+
161
+ def apply_authtype(context, req)
162
+ # only used for eventstreaming at input
163
+ if context[:input_event_emitter]
164
+ req.headers['X-Amz-Content-Sha256'] = 'STREAMING-AWS4-HMAC-SHA256-EVENTS'
165
+ else
166
+ if context.operation['authtype'].eql?('v4-unsigned-body') &&
167
+ req.endpoint.scheme.eql?('https')
168
+ req.headers['X-Amz-Content-Sha256'] ||= 'UNSIGNED-PAYLOAD'
169
+ end
170
+ end
171
+ end
172
+
173
+ def reset_signature(req)
174
+ # in case this request is being re-signed
175
+ req.headers.delete('Authorization')
176
+ req.headers.delete('X-Amz-Security-Token')
177
+ req.headers.delete('X-Amz-Date')
178
+ req.headers.delete('x-Amz-Region-Set')
179
+ end
180
+
181
+ def apply_clock_skew(context, req)
182
+ if context.config.respond_to?(:clock_skew) &&
183
+ context.config.clock_skew &&
184
+ context.config.correct_clock_skew
185
+
186
+ endpoint = context.http_request.endpoint
187
+ skew = context.config.clock_skew.clock_correction(endpoint)
188
+ if skew.abs.positive?
189
+ req.headers['X-Amz-Date'] =
190
+ (Time.now.utc + skew).strftime('%Y%m%dT%H%M%SZ')
191
+ end
192
+ end
193
+ end
194
+
195
+ end
196
+
197
+ # @api private
198
+ class NullSigner
199
+
200
+ def sign(context)
201
+ end
202
+
203
+ def presign_url(*args)
204
+ end
205
+
206
+ def sign_event(*args)
207
+ end
208
+ end
209
+ end
210
+ end
211
+ 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,50 +5,46 @@ 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
13
16
 
14
17
  option(:sigv4_name) do |cfg|
15
- cfg.api.metadata['signingName'] || cfg.api.metadata['endpointPrefix']
18
+ signingName = if cfg.region
19
+ Aws::Partitions::EndpointProvider.signing_service(
20
+ cfg.region, cfg.api.metadata['endpointPrefix']
21
+ )
22
+ end
23
+ signingName || cfg.api.metadata['signingName'] || cfg.api.metadata['endpointPrefix']
16
24
  end
17
25
 
18
26
  option(:sigv4_region) do |cfg|
19
-
20
- # The signature version 4 signing region is most
21
- # commonly the configured region. There are a few
22
- # notable exceptions:
23
- #
24
- # * Some services have a global endpoint to the entire
25
- # partition. For example, when constructing a route53
26
- # client for a region like "us-west-2", we will
27
- # always use "route53.amazonaws.com". This endpoint
28
- # is actually global to the entire partition,
29
- # and must be signed as "us-east-1".
30
- #
31
- # * When the region is configured, but it is configured
32
- # to a non region, such as "aws-global". This is similar
33
- # to the previous case. We use the Aws::Partitions::EndpointProvider
34
- # to resolve to the actual signing region.
35
- #
36
- prefix = cfg.api.metadata['endpointPrefix']
37
- if prefix && cfg.endpoint.to_s.match(/#{prefix}\.amazonaws\.com/)
38
- 'us-east-1'
39
- elsif cfg.region
40
- Aws::Partitions::EndpointProvider.signing_region(cfg.region, cfg.sigv4_name)
27
+ if cfg.region
28
+ if cfg.respond_to?(:sts_regional_endpoints)
29
+ sts_regional = cfg.sts_regional_endpoints
30
+ end
31
+ Aws::Partitions::EndpointProvider.signing_region(
32
+ cfg.region, cfg.api.metadata['endpointPrefix'], sts_regional
33
+ )
41
34
  end
42
35
  end
43
36
 
44
37
  option(:unsigned_operations) do |cfg|
45
- cfg.api.operation_names.inject([]) do |unsigned, operation_name|
46
- if cfg.api.operation(operation_name)['authtype'] == 'none' ||
47
- cfg.api.operation(operation_name)['authtype'] == 'custom'
48
- # Unsign requests that has custom apigateway authorizer as well
49
- unsigned << operation_name
50
- else
51
- 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'])
52
48
  end
53
49
  end
54
50
  end
@@ -108,6 +104,7 @@ module Aws
108
104
  req.headers.delete('Authorization')
109
105
  req.headers.delete('X-Amz-Security-Token')
110
106
  req.headers.delete('X-Amz-Date')
107
+ req.headers.delete('x-Amz-Region-Set')
111
108
 
112
109
  if context.config.respond_to?(:clock_skew) &&
113
110
  context.config.clock_skew &&
@@ -144,7 +141,7 @@ module Aws
144
141
  def apply_authtype(context)
145
142
  if context.operation['authtype'].eql?('v4-unsigned-body') &&
146
143
  context.http_request.endpoint.scheme.eql?('https')
147
- context.http_request.headers['X-Amz-Content-Sha256'] = 'UNSIGNED-PAYLOAD'
144
+ context.http_request.headers['X-Amz-Content-Sha256'] ||= 'UNSIGNED-PAYLOAD'
148
145
  end
149
146
  context
150
147
  end
@@ -8,6 +8,7 @@ module Aws
8
8
  option(:stub_responses,
9
9
  default: false,
10
10
  doc_type: 'Boolean',
11
+ rbs_type: 'untyped',
11
12
  docstring: <<-DOCS)
12
13
  Causes the client to return stubbed responses. By default
13
14
  fake responses are generated and returned. You can specify
@@ -51,7 +52,11 @@ requests are made, and retries are disabled.
51
52
  stub = context.client.next_stub(context)
52
53
  resp = Seahorse::Client::Response.new(context: context)
53
54
  async_mode = context.client.is_a? Seahorse::Client::AsyncBase
54
- apply_stub(stub, resp, async_mode)
55
+ if Hash === stub && stub[:mutex]
56
+ stub[:mutex].synchronize { apply_stub(stub, resp, async_mode) }
57
+ else
58
+ apply_stub(stub, resp, async_mode)
59
+ end
55
60
 
56
61
  async_mode ? Seahorse::Client::AsyncResponse.new(
57
62
  context: context, stream: context[:input_event_stream_handler].event_emitter.stream, sync_queue: Queue.new) : resp
@@ -4,7 +4,57 @@ module Aws
4
4
  module Plugins
5
5
  # @api private
6
6
  class UserAgent < Seahorse::Client::Plugin
7
+ METRICS = Aws::Json.load(<<-METRICS)
8
+ {
9
+ "RESOURCE_MODEL": "A",
10
+ "WAITER": "B",
11
+ "PAGINATOR": "C",
12
+ "RETRY_MODE_LEGACY": "D",
13
+ "RETRY_MODE_STANDARD": "E",
14
+ "RETRY_MODE_ADAPTIVE": "F",
15
+ "S3_TRANSFER": "G",
16
+ "S3_CRYPTO_V1N": "H",
17
+ "S3_CRYPTO_V2": "I",
18
+ "S3_EXPRESS_BUCKET": "J",
19
+ "S3_ACCESS_GRANTS": "K",
20
+ "GZIP_REQUEST_COMPRESSION": "L"
21
+ }
22
+ METRICS
23
+
24
+ # @api private
7
25
  option(:user_agent_suffix)
26
+ # @api private
27
+ option(:user_agent_frameworks, default: [])
28
+
29
+ option(
30
+ :sdk_ua_app_id,
31
+ doc_type: 'String',
32
+ docstring: <<-DOCS) do |cfg|
33
+ A unique and opaque application ID that is appended to the
34
+ User-Agent header as app/sdk_ua_app_id. It should have a
35
+ maximum length of 50. This variable is sourced from environment
36
+ variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.
37
+ DOCS
38
+ app_id = ENV['AWS_SDK_UA_APP_ID']
39
+ app_id ||= Aws.shared_config.sdk_ua_app_id(profile: cfg.profile)
40
+ app_id
41
+ end
42
+
43
+ # Deprecated - must exist for old service gems
44
+ def self.feature(_feature, &block)
45
+ block.call
46
+ end
47
+
48
+ def self.metric(metric, &block)
49
+ Thread.current[:aws_sdk_core_user_agent_metric] ||= []
50
+ Thread.current[:aws_sdk_core_user_agent_metric] << METRICS[metric]
51
+ block.call
52
+ ensure
53
+ Thread.current[:aws_sdk_core_user_agent_metric].pop
54
+ if Thread.current[:aws_sdk_core_user_agent_metric].empty?
55
+ Thread.current[:aws_sdk_core_user_agent_metric] = nil
56
+ end
57
+ end
8
58
 
9
59
  # @api private
10
60
  class Handler < Seahorse::Client::Handler
@@ -14,33 +64,121 @@ module Aws
14
64
  end
15
65
 
16
66
  def set_user_agent(context)
17
- ua = "aws-sdk-ruby3/#{CORE_GEM_VERSION}"
67
+ context.http_request.headers['User-Agent'] = UserAgent.new(context).to_s
68
+ end
18
69
 
19
- begin
20
- ua += " #{RUBY_ENGINE}/#{RUBY_VERSION}"
21
- rescue
22
- ua += " RUBY_ENGINE_NA/#{RUBY_VERSION}"
70
+ class UserAgent
71
+ def initialize(context)
72
+ @context = context
23
73
  end
24
74
 
25
- ua += " #{RUBY_PLATFORM}"
75
+ def to_s
76
+ ua = "aws-sdk-ruby3/#{CORE_GEM_VERSION}"
77
+ ua += ' ua/2.1'
78
+ if (api_m = api_metadata)
79
+ ua += " #{api_m}"
80
+ end
81
+ ua += " #{os_metadata}"
82
+ ua += " #{language_metadata}"
83
+ if (env_m = env_metadata)
84
+ ua += " #{env_m}"
85
+ end
86
+ if (app_id_m = app_id_metadata)
87
+ ua += " #{app_id_m}"
88
+ end
89
+ if (framework_m = framework_metadata)
90
+ ua += " #{framework_m}"
91
+ end
92
+ if (metric_m = metric_metadata)
93
+ ua += " #{metric_m}"
94
+ end
95
+ if @context.config.user_agent_suffix
96
+ ua += " #{@context.config.user_agent_suffix}"
97
+ end
98
+ ua.strip
99
+ end
100
+
101
+ private
102
+
103
+ # Used to be gem_name/gem_version
104
+ def api_metadata
105
+ service_id = @context.config.api.metadata['serviceId']
106
+ return unless service_id
26
107
 
27
- if context[:gem_name] && context[:gem_version]
28
- ua += " #{context[:gem_name]}/#{context[:gem_version]}"
108
+ service_id = service_id.gsub(' ', '_').downcase
109
+ gem_version = @context[:gem_version]
110
+ "api/#{service_id}##{gem_version}"
29
111
  end
30
112
 
31
- if (execution_env = ENV['AWS_EXECUTION_ENV'])
32
- ua += " exec-env/#{execution_env}"
113
+ # Used to be RUBY_PLATFORM
114
+ def os_metadata
115
+ os =
116
+ case RbConfig::CONFIG['host_os']
117
+ when /mac|darwin/
118
+ 'macos'
119
+ when /linux|cygwin/
120
+ 'linux'
121
+ when /mingw|mswin/
122
+ 'windows'
123
+ else
124
+ 'other'
125
+ end
126
+ metadata = "os/#{os}"
127
+ local_version = Gem::Platform.local.version
128
+ metadata += "##{local_version}" if local_version
129
+ metadata += " md/#{RbConfig::CONFIG['host_cpu']}"
33
130
  end
34
131
 
35
- if context.config.user_agent_suffix
36
- ua += " #{context.config.user_agent_suffix}"
132
+ # Used to be RUBY_ENGINE/RUBY_VERSION
133
+ def language_metadata
134
+ "lang/#{RUBY_ENGINE}##{RUBY_ENGINE_VERSION} md/#{RUBY_VERSION}"
37
135
  end
38
136
 
39
- context.http_request.headers['User-Agent'] = ua.strip
137
+ def env_metadata
138
+ return unless (execution_env = ENV['AWS_EXECUTION_ENV'])
139
+
140
+ "exec-env/#{execution_env}"
141
+ end
142
+
143
+ def app_id_metadata
144
+ return unless (app_id = @context.config.sdk_ua_app_id)
145
+
146
+ # Sanitize and only allow these characters
147
+ app_id = app_id.gsub(/[^!#$%&'*+\-.^_`|~0-9A-Za-z]/, '-')
148
+ "app/#{app_id}"
149
+ end
150
+
151
+ def framework_metadata
152
+ if (frameworks_cfg = @context.config.user_agent_frameworks).empty?
153
+ return
154
+ end
155
+
156
+ # Frameworks may be aws-record, aws-sdk-rails, etc.
157
+ regex = /gems\/(?<name>#{frameworks_cfg.join('|')})-(?<version>\d+\.\d+\.\d+)/.freeze
158
+ frameworks = {}
159
+ Kernel.caller.each do |line|
160
+ match = line.match(regex)
161
+ next unless match
162
+
163
+ frameworks[match[:name]] = match[:version]
164
+ end
165
+ frameworks.map { |n, v| "lib/#{n}##{v}" }.join(' ')
166
+ end
167
+
168
+ def metric_metadata
169
+ return unless Thread.current[:aws_sdk_core_user_agent_metric]
170
+
171
+ metrics = Thread.current[:aws_sdk_core_user_agent_metric].join(',')
172
+ # Metric metadata is limited to 1024 bytes
173
+ return "m/#{metrics}" if metrics.bytesize <= 1024
174
+
175
+ # Removes the last unfinished metric
176
+ "m/#{metrics[0...metrics[0..1024].rindex(',')]}"
177
+ end
40
178
  end
41
179
  end
42
180
 
43
- handler(Handler)
181
+ handler(Handler, step: :sign, priority: 97)
44
182
  end
45
183
  end
46
184
  end
@@ -1,19 +1,22 @@
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
5
+ # to read its stdout to receive a JSON payload containing the credentials.
7
6
  #
8
- # Automatically handles refreshing credentials if an Expiration time is
9
- # provided in the credentials payload
7
+ # credentials = Aws::ProcessCredentials.new(['/usr/bin/credential_proc'])
8
+ # ec2 = Aws::EC2::Client.new(credentials: credentials)
10
9
  #
11
- # credentials = Aws::ProcessCredentials.new('/usr/bin/credential_proc').credentials
10
+ # Arguments should be provided as strings in the array, for example:
12
11
  #
12
+ # process = ['/usr/bin/credential_proc', 'arg1', 'arg2']
13
+ # credentials = Aws::ProcessCredentials.new(process)
13
14
  # ec2 = Aws::EC2::Client.new(credentials: credentials)
14
15
  #
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
16
+ # Automatically handles refreshing credentials if an Expiration time is
17
+ # provided in the credentials payload.
18
+ #
19
+ # @see https://docs.aws.amazon.com/cli/latest/topic/config-vars.html#sourcing-credentials-from-external-processes
17
20
  class ProcessCredentials
18
21
 
19
22
  include CredentialProvider
@@ -22,39 +25,49 @@ module Aws
22
25
  # Creates a new ProcessCredentials object, which allows an
23
26
  # external process to be used as a credential provider.
24
27
  #
25
- # @param [String] process Invocation string for process
26
- # credentials provider.
28
+ # @param [Array<String>, String] process An array of strings including
29
+ # the process name and its arguments to execute, or a single string to be
30
+ # executed by the shell (deprecated and insecure).
27
31
  def initialize(process)
32
+ if process.is_a?(String)
33
+ warn('Passing a single string to Aws::ProcessCredentials.new '\
34
+ 'is insecure, please use use an array of system arguments instead')
35
+ end
28
36
  @process = process
29
- @credentials = credentials_from_process(@process)
37
+ @credentials = credentials_from_process
38
+ @async_refresh = false
30
39
 
31
40
  super
32
41
  end
33
42
 
34
43
  private
35
- def credentials_from_process(proc_invocation)
36
- begin
37
- raw_out = `#{proc_invocation}`
38
- process_status = $?
39
- rescue Errno::ENOENT
40
- raise Errors::InvalidProcessCredentialsPayload.new("Could not find process #{proc_invocation}")
44
+
45
+ def credentials_from_process
46
+ r, w = IO.pipe
47
+ success = system(*@process, out: w)
48
+ w.close
49
+ raw_out = r.read
50
+ r.close
51
+
52
+ unless success
53
+ raise Errors::InvalidProcessCredentialsPayload.new(
54
+ 'credential_process provider failure, the credential process had '\
55
+ 'non zero exit status and failed to provide credentials'
56
+ )
41
57
  end
42
58
 
43
- if process_status.success?
44
- begin
45
- creds_json = Aws::Json.load(raw_out)
46
- rescue Aws::Json::ParseError
47
- raise Errors::InvalidProcessCredentialsPayload.new("Invalid JSON response")
48
- end
49
- payload_version = creds_json['Version']
50
- if payload_version == 1
51
- _parse_payload_format_v1(creds_json)
52
- else
53
- raise Errors::InvalidProcessCredentialsPayload.new("Invalid version #{payload_version} for credentials payload")
54
- end
55
- else
56
- raise Errors::InvalidProcessCredentialsPayload.new('credential_process provider failure, the credential process had non zero exit status and failed to provide credentials')
59
+ begin
60
+ creds_json = Aws::Json.load(raw_out)
61
+ rescue Aws::Json::ParseError
62
+ raise Errors::InvalidProcessCredentialsPayload.new('Invalid JSON response')
57
63
  end
64
+
65
+ payload_version = creds_json['Version']
66
+ return _parse_payload_format_v1(creds_json) if payload_version == 1
67
+
68
+ raise Errors::InvalidProcessCredentialsPayload.new(
69
+ "Invalid version #{payload_version} for credentials payload"
70
+ )
58
71
  end
59
72
 
60
73
  def _parse_payload_format_v1(creds_json)
@@ -66,16 +79,19 @@ module Aws
66
79
 
67
80
  @expiration = creds_json['Expiration'] ? Time.iso8601(creds_json['Expiration']) : nil
68
81
  return creds if creds.set?
69
- raise Errors::InvalidProcessCredentialsPayload.new("Invalid payload for JSON credentials version 1")
82
+
83
+ raise Errors::InvalidProcessCredentialsPayload.new(
84
+ 'Invalid payload for JSON credentials version 1'
85
+ )
70
86
  end
71
87
 
72
88
  def refresh
73
- @credentials = credentials_from_process(@process)
89
+ @credentials = credentials_from_process
74
90
  end
75
91
 
76
- def near_expiration?
92
+ def near_expiration?(expiration_length)
77
93
  # are we within 5 minutes of expiration?
78
- @expiration && (Time.now.to_i + 5 * 60) > @expiration.to_i
94
+ @expiration && (Time.now.to_i + expiration_length) > @expiration.to_i
79
95
  end
80
96
  end
81
97
  end
@@ -31,13 +31,11 @@ module Aws
31
31
  end
32
32
 
33
33
  def list(ref, values, prefix)
34
- if values.empty?
35
- set(prefix, '')
36
- else
37
- member_ref = ref.shape.member
38
- values.each.with_index do |value, n|
39
- format(member_ref, value, "#{prefix}.#{n+1}")
40
- end
34
+ return if values.empty?
35
+
36
+ member_ref = ref.shape.member
37
+ values.each.with_index do |value, n|
38
+ format(member_ref, value, "#{prefix}.#{n + 1}")
41
39
  end
42
40
  end
43
41