aws-sdk-core 3.219.0 → 3.240.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +222 -0
- data/VERSION +1 -1
- data/lib/aws-defaults/default_configuration.rb +2 -1
- data/lib/aws-sdk-core/assume_role_credentials.rb +9 -8
- data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +3 -2
- data/lib/aws-sdk-core/client_stubs.rb +28 -48
- data/lib/aws-sdk-core/credential_provider.rb +4 -0
- data/lib/aws-sdk-core/credential_provider_chain.rb +91 -22
- data/lib/aws-sdk-core/credentials.rb +6 -0
- data/lib/aws-sdk-core/ecs_credentials.rb +14 -13
- data/lib/aws-sdk-core/endpoints/matchers.rb +2 -1
- data/lib/aws-sdk-core/endpoints.rb +37 -13
- data/lib/aws-sdk-core/error_handler.rb +5 -0
- data/lib/aws-sdk-core/errors.rb +5 -2
- data/lib/aws-sdk-core/event_emitter.rb +1 -1
- data/lib/aws-sdk-core/instance_profile_credentials.rb +147 -157
- data/lib/aws-sdk-core/json/error_handler.rb +14 -4
- data/lib/aws-sdk-core/login_credentials.rb +229 -0
- data/lib/aws-sdk-core/plugins/checksum_algorithm.rb +28 -14
- data/lib/aws-sdk-core/plugins/client_metrics_plugin.rb +0 -1
- data/lib/aws-sdk-core/plugins/credentials_configuration.rb +75 -59
- data/lib/aws-sdk-core/plugins/endpoint_pattern.rb +40 -32
- data/lib/aws-sdk-core/plugins/sign.rb +29 -20
- data/lib/aws-sdk-core/plugins/stub_responses.rb +30 -8
- data/lib/aws-sdk-core/plugins/user_agent.rb +26 -2
- data/lib/aws-sdk-core/process_credentials.rb +1 -1
- data/lib/aws-sdk-core/refreshing_credentials.rb +8 -11
- data/lib/aws-sdk-core/rest/request/headers.rb +1 -1
- data/lib/aws-sdk-core/rpc_v2/error_handler.rb +26 -16
- data/lib/aws-sdk-core/rpc_v2/parser.rb +8 -0
- data/lib/aws-sdk-core/shared_config.rb +102 -21
- data/lib/aws-sdk-core/shared_credentials.rb +1 -0
- data/lib/aws-sdk-core/sso_credentials.rb +3 -1
- data/lib/aws-sdk-core/static_token_provider.rb +1 -2
- data/lib/aws-sdk-core/token.rb +3 -3
- data/lib/aws-sdk-core/token_provider.rb +4 -0
- data/lib/aws-sdk-core/token_provider_chain.rb +2 -6
- data/lib/aws-sdk-core/util.rb +2 -1
- data/lib/aws-sdk-core/xml/error_handler.rb +3 -1
- data/lib/aws-sdk-core.rb +4 -0
- data/lib/aws-sdk-signin/client.rb +604 -0
- data/lib/aws-sdk-signin/client_api.rb +119 -0
- data/lib/aws-sdk-signin/customizations.rb +1 -0
- data/lib/aws-sdk-signin/endpoint_parameters.rb +69 -0
- data/lib/aws-sdk-signin/endpoint_provider.rb +59 -0
- data/lib/aws-sdk-signin/endpoints.rb +20 -0
- data/lib/aws-sdk-signin/errors.rb +122 -0
- data/lib/aws-sdk-signin/plugins/endpoints.rb +77 -0
- data/lib/aws-sdk-signin/resource.rb +26 -0
- data/lib/aws-sdk-signin/types.rb +299 -0
- data/lib/aws-sdk-signin.rb +63 -0
- data/lib/aws-sdk-sso/client.rb +25 -19
- data/lib/aws-sdk-sso/endpoint_parameters.rb +4 -4
- data/lib/aws-sdk-sso/endpoint_provider.rb +2 -2
- data/lib/aws-sdk-sso.rb +1 -1
- data/lib/aws-sdk-ssooidc/client.rb +57 -27
- data/lib/aws-sdk-ssooidc/client_api.rb +11 -0
- data/lib/aws-sdk-ssooidc/endpoint_parameters.rb +4 -4
- data/lib/aws-sdk-ssooidc/errors.rb +10 -0
- data/lib/aws-sdk-ssooidc/types.rb +45 -6
- data/lib/aws-sdk-ssooidc.rb +1 -1
- data/lib/aws-sdk-sts/client.rb +160 -30
- data/lib/aws-sdk-sts/client_api.rb +82 -8
- data/lib/aws-sdk-sts/customizations.rb +0 -1
- data/lib/aws-sdk-sts/endpoint_parameters.rb +5 -5
- data/lib/aws-sdk-sts/endpoint_provider.rb +18 -18
- data/lib/aws-sdk-sts/errors.rb +79 -0
- data/lib/aws-sdk-sts/presigner.rb +2 -6
- data/lib/aws-sdk-sts/types.rb +175 -6
- data/lib/aws-sdk-sts.rb +1 -1
- data/lib/seahorse/client/async_base.rb +4 -5
- data/lib/seahorse/client/base.rb +0 -14
- data/lib/seahorse/client/h2/connection.rb +18 -28
- data/lib/seahorse/client/h2/handler.rb +6 -1
- data/lib/seahorse/client/http/response.rb +1 -1
- data/lib/seahorse/client/net_http/connection_pool.rb +2 -1
- data/lib/seahorse/client/networking_error.rb +1 -1
- data/lib/seahorse/client/plugins/h2.rb +4 -4
- data/lib/seahorse/client/request_context.rb +2 -2
- data/lib/seahorse/util.rb +2 -1
- data/sig/aws-sdk-core/async_client_stubs.rbs +21 -0
- data/sig/seahorse/client/async_base.rbs +18 -0
- metadata +46 -8
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aws
|
|
4
|
+
# An auto-refreshing credential provider that retrieves credentials from
|
|
5
|
+
# a cached login token. This class does NOT implement the AWS Sign-In
|
|
6
|
+
# login flow - tokens must be generated separately by running `aws login`
|
|
7
|
+
# from the AWS CLI/AWS Tools for PowerShell with the correct profile.
|
|
8
|
+
# The {LoginCredentials} will auto-refresh the AWS credentials from AWS Sign-In.
|
|
9
|
+
#
|
|
10
|
+
# # You must first run aws login --profile your-login-profile
|
|
11
|
+
# login_credentials = Aws::LoginCredentials.new(login_session: 'my_login_session')
|
|
12
|
+
# ec2 = Aws::EC2::Client.new(credentials: login_credentials)
|
|
13
|
+
#
|
|
14
|
+
# If you omit the `:client` option, a new {Aws::Signin::Client} object will
|
|
15
|
+
# be constructed with additional options that were provided.
|
|
16
|
+
class LoginCredentials
|
|
17
|
+
include CredentialProvider
|
|
18
|
+
include RefreshingCredentials
|
|
19
|
+
|
|
20
|
+
# @option options [required, String] :login_session An opaque string
|
|
21
|
+
# used to determine the cache file location. This value can be found
|
|
22
|
+
# in the AWS config file which is set by the AWS CLI/AWS Tools for
|
|
23
|
+
# PowerShell automatically.
|
|
24
|
+
#
|
|
25
|
+
# @option options [Signin::Client] :client Optional `Signin::Client`.
|
|
26
|
+
# If not provided, a client will be constructed.
|
|
27
|
+
def initialize(options = {})
|
|
28
|
+
raise ArgumentError, 'Missing login_session' unless options[:login_session]
|
|
29
|
+
|
|
30
|
+
@login_session = options.delete(:login_session)
|
|
31
|
+
@client = options[:client]
|
|
32
|
+
unless @client
|
|
33
|
+
client_opts = options.reject { |key, _| CLIENT_EXCLUDE_OPTIONS.include?(key) }
|
|
34
|
+
@client = Signin::Client.new(client_opts.merge(credentials: nil))
|
|
35
|
+
end
|
|
36
|
+
@metrics = ['CREDENTIALS_LOGIN']
|
|
37
|
+
@async_refresh = true
|
|
38
|
+
super
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @return [Signin::Client]
|
|
42
|
+
attr_reader :client
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def refresh
|
|
47
|
+
# First reload the token from disk to ensure it hasn't been refreshed externally
|
|
48
|
+
token_json = read_cached_token
|
|
49
|
+
update_creds(token_json['accessToken'])
|
|
50
|
+
return if @credentials && @expiration && !near_expiration?(sync_expiration_length)
|
|
51
|
+
|
|
52
|
+
# Using OpenSSL 3.6.0 may result in errors like "certificate verify failed (unable to get certificate CRL)."
|
|
53
|
+
# A recommended workaround is to use OpenSSL version < 3.6.0 or requiring the openssl gem with a version of at
|
|
54
|
+
# least 3.2.2. GitHub issue: https://github.com/openssl/openssl/issues/28752.
|
|
55
|
+
if OpenSSL::OPENSSL_LIBRARY_VERSION.include?('3.6.') &&
|
|
56
|
+
(!Gem.loaded_specs['openssl'] || Gem.loaded_specs['openssl'].version < Gem::Version.new('3.2.2'))
|
|
57
|
+
warn 'WARNING: OpenSSL 3.6.x may cause certificate verify errors - use OpenSSL < 3.6.0 or openssl gem >= 3.2.2'
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Attempt to refresh the token
|
|
61
|
+
attempt_refresh(token_json)
|
|
62
|
+
|
|
63
|
+
# Raise if token is hard expired
|
|
64
|
+
return unless !@expiration || @expiration < Time.now
|
|
65
|
+
|
|
66
|
+
raise Errors::InvalidLoginToken,
|
|
67
|
+
'Login token is invalid and failed to refresh. Please reauthenticate.'
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def read_cached_token
|
|
71
|
+
cached_token = JSON.load_file(login_cache_file)
|
|
72
|
+
validate_cached_token(cached_token)
|
|
73
|
+
cached_token
|
|
74
|
+
rescue Errno::ENOENT, Aws::Json::ParseError
|
|
75
|
+
raise Errors::InvalidLoginToken,
|
|
76
|
+
"Failed to load a Login token for login session #{@login_session}. Please reauthenticate."
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def login_cache_file
|
|
80
|
+
directory = ENV['AWS_LOGIN_CACHE_DIRECTORY'] || File.join(Dir.home, '.aws', 'login', 'cache')
|
|
81
|
+
login_session_sha = OpenSSL::Digest::SHA256.hexdigest(@login_session.strip.encode('utf-8'))
|
|
82
|
+
File.join(directory, "#{login_session_sha}.json")
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def validate_cached_token(cached_token)
|
|
86
|
+
required_cached_token_fields = %w[accessToken clientId refreshToken dpopKey]
|
|
87
|
+
missing_fields = required_cached_token_fields.reject { |field| cached_token[field] }
|
|
88
|
+
unless missing_fields.empty?
|
|
89
|
+
raise ArgumentError, "Cached login token is missing required field(s): #{missing_fields}. " \
|
|
90
|
+
'Please reauthenticate.'
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
access_token = cached_token['accessToken']
|
|
94
|
+
required_access_token_fields = %w[accessKeyId secretAccessKey sessionToken accountId expiresAt]
|
|
95
|
+
missing_fields = required_access_token_fields.reject { |field| access_token[field] }
|
|
96
|
+
|
|
97
|
+
return if missing_fields.empty?
|
|
98
|
+
|
|
99
|
+
raise ArgumentError, "Access token in cached login token is missing required field(s): #{missing_fields}. " \
|
|
100
|
+
'Please reauthenticate.'
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def update_creds(access_token)
|
|
104
|
+
@credentials = Credentials.new(
|
|
105
|
+
access_token['accessKeyId'],
|
|
106
|
+
access_token['secretAccessKey'],
|
|
107
|
+
access_token['sessionToken'],
|
|
108
|
+
account_id: access_token['accountId']
|
|
109
|
+
)
|
|
110
|
+
@expiration = Time.parse(access_token['expiresAt'])
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def attempt_refresh(token_json)
|
|
114
|
+
resp = make_request(token_json)
|
|
115
|
+
parse_resp(resp.token_output, token_json)
|
|
116
|
+
update_creds(token_json['accessToken'])
|
|
117
|
+
update_token_cache(token_json)
|
|
118
|
+
rescue Signin::Errors::AccessDeniedException => e
|
|
119
|
+
case e.error
|
|
120
|
+
when 'TOKEN_EXPIRED'
|
|
121
|
+
warn 'Your session has expired. Please reauthenticate.'
|
|
122
|
+
when 'USER_CREDENTIALS_CHANGED'
|
|
123
|
+
warn 'Unable to refresh credentials because of a change in your password. ' \
|
|
124
|
+
'Please reauthenticate with your new password.'
|
|
125
|
+
when 'INSUFFICIENT_PERMISSIONS'
|
|
126
|
+
warn 'Unable to refresh credentials due to insufficient permissions. ' \
|
|
127
|
+
'You may be missing permission for the `CreateOAuth2Token` action.'
|
|
128
|
+
end
|
|
129
|
+
rescue StandardError => e
|
|
130
|
+
warn("Failed to refresh Login token for LoginCredentials: #{e.message}")
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def make_request(token_json)
|
|
134
|
+
options = {
|
|
135
|
+
token_input: {
|
|
136
|
+
client_id: token_json['clientId'],
|
|
137
|
+
grant_type: 'refresh_token',
|
|
138
|
+
refresh_token: token_json['refreshToken']
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
req = @client.build_request(:create_o_auth_2_token, options)
|
|
142
|
+
endpoint_params = Aws::Signin::EndpointParameters.create(req.context.config)
|
|
143
|
+
endpoint = req.context.config.endpoint_provider.resolve_endpoint(endpoint_params)
|
|
144
|
+
endpoint = URI.join(endpoint.url, @client.config.api.operation(:create_o_auth_2_token).http_request_uri).to_s
|
|
145
|
+
req.context.http_request.headers['DPoP'] = dpop_proof(token_json['dpopKey'], endpoint)
|
|
146
|
+
req.send_request
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def dpop_proof(dpop_key, endpoint)
|
|
150
|
+
# Load private key from cached token file
|
|
151
|
+
private_key = OpenSSL::PKey.read(dpop_key)
|
|
152
|
+
public_key = private_key.public_key.to_octet_string(:uncompressed)
|
|
153
|
+
|
|
154
|
+
# Construct header and payload
|
|
155
|
+
header = build_header(public_key[1, 32], public_key[33, 32])
|
|
156
|
+
payload = build_payload(endpoint)
|
|
157
|
+
|
|
158
|
+
# Base64URL encode header and payload, sign message using private key, and create header
|
|
159
|
+
message = build_message(header, payload)
|
|
160
|
+
signature = private_key.sign(OpenSSL::Digest.new('SHA256'), message)
|
|
161
|
+
jws_signature = der_to_jws(signature)
|
|
162
|
+
"#{message}.#{Base64.urlsafe_encode64(jws_signature, padding: false)}"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def build_header(x_bytes, y_bytes)
|
|
166
|
+
{
|
|
167
|
+
'alg' => 'ES256', # signing algorithm
|
|
168
|
+
'jwk' => {
|
|
169
|
+
'crv' => 'P-256', # curve name
|
|
170
|
+
'kty' => 'EC', # key type
|
|
171
|
+
'x' => Base64.urlsafe_encode64(x_bytes, padding: false), # public x coordinate
|
|
172
|
+
'y' => Base64.urlsafe_encode64(y_bytes, padding: false) # public y coordinate
|
|
173
|
+
},
|
|
174
|
+
'typ' => 'dpop+jwt' # hardcoded
|
|
175
|
+
}
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def build_payload(htu)
|
|
179
|
+
{
|
|
180
|
+
'jti' => SecureRandom.uuid, # unique identifier (UUID4)
|
|
181
|
+
'htm' => @client.config.api.operation(:create_o_auth_2_token).http_method, # POST
|
|
182
|
+
'htu' => htu, # endpoint of the CreateOAuth2Token operation, with path
|
|
183
|
+
'iat' => Time.now.utc.to_i # UTC timestamp, specified number of seconds from 1970-01-01T00:00:00Z UTC
|
|
184
|
+
}
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def build_message(header, payload)
|
|
188
|
+
encoded_header = Base64.urlsafe_encode64(JSON.dump(header), padding: false)
|
|
189
|
+
encoded_payload = Base64.urlsafe_encode64(JSON.dump(payload), padding: false)
|
|
190
|
+
"#{encoded_header}.#{encoded_payload}"
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Converts DER-encoded ASN.1 signature to JWS
|
|
194
|
+
def der_to_jws(der_signature)
|
|
195
|
+
asn1 = OpenSSL::ASN1.decode(der_signature)
|
|
196
|
+
r = asn1.value[0].value
|
|
197
|
+
s = asn1.value[1].value
|
|
198
|
+
|
|
199
|
+
r_hex = r.to_s(16).rjust(64, '0')
|
|
200
|
+
s_hex = s.to_s(16).rjust(64, '0')
|
|
201
|
+
|
|
202
|
+
[r_hex + s_hex].pack('H*')
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def parse_resp(resp, token_json)
|
|
206
|
+
access_token = token_json['accessToken']
|
|
207
|
+
access_token.merge!(
|
|
208
|
+
'accessKeyId' => resp.access_token.access_key_id,
|
|
209
|
+
'secretAccessKey' => resp.access_token.secret_access_key,
|
|
210
|
+
'sessionToken' => resp.access_token.session_token,
|
|
211
|
+
'expiresAt' => (Time.now.utc + resp.expires_in).to_datetime.rfc3339
|
|
212
|
+
)
|
|
213
|
+
token_json['refreshToken'] = resp.refresh_token
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def update_token_cache(token_json)
|
|
217
|
+
cached_token = token_json.dup
|
|
218
|
+
# File.write is not atomic so use temp file and move
|
|
219
|
+
temp_file = Tempfile.new('temp_file')
|
|
220
|
+
begin
|
|
221
|
+
temp_file.write(Json.dump(cached_token))
|
|
222
|
+
temp_file.close
|
|
223
|
+
FileUtils.mv(temp_file.path, login_cache_file)
|
|
224
|
+
ensure
|
|
225
|
+
temp_file.unlink if File.exist?(temp_file.path) # Ensure temp file is cleaned up
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
@@ -190,7 +190,6 @@ module Aws
|
|
|
190
190
|
name: "x-amz-checksum-#{algorithm.downcase}",
|
|
191
191
|
request_algorithm_header: request_algorithm_header(context)
|
|
192
192
|
}
|
|
193
|
-
|
|
194
193
|
context[:http_checksum][:request_algorithm] = request_algorithm
|
|
195
194
|
calculate_request_checksum(context, request_algorithm)
|
|
196
195
|
end
|
|
@@ -249,6 +248,7 @@ module Aws
|
|
|
249
248
|
return unless context.operation.http_checksum
|
|
250
249
|
|
|
251
250
|
input_member = context.operation.http_checksum['requestAlgorithmMember']
|
|
251
|
+
|
|
252
252
|
context.params[input_member.to_sym] ||= DEFAULT_CHECKSUM if input_member
|
|
253
253
|
end
|
|
254
254
|
|
|
@@ -271,25 +271,39 @@ module Aws
|
|
|
271
271
|
context.operation.http_checksum['responseAlgorithms']
|
|
272
272
|
end
|
|
273
273
|
|
|
274
|
-
def checksum_required?(context)
|
|
275
|
-
(http_checksum = context.operation.http_checksum) &&
|
|
276
|
-
(checksum_required = http_checksum['requestChecksumRequired']) &&
|
|
277
|
-
(checksum_required && context.config.request_checksum_calculation == 'when_required')
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
def checksum_optional?(context)
|
|
281
|
-
context.operation.http_checksum &&
|
|
282
|
-
context.config.request_checksum_calculation != 'when_required'
|
|
283
|
-
end
|
|
284
|
-
|
|
285
274
|
def checksum_provided_as_header?(headers)
|
|
286
275
|
headers.any? { |k, _| k.start_with?('x-amz-checksum-') }
|
|
287
276
|
end
|
|
288
277
|
|
|
278
|
+
# Determines whether a request checksum should be calculated.
|
|
279
|
+
# 1. **No existing checksum in header**: Skips if checksum header already present
|
|
280
|
+
# 2. **Operation support**: Considers model, client configuration and user input.
|
|
289
281
|
def should_calculate_request_checksum?(context)
|
|
290
282
|
!checksum_provided_as_header?(context.http_request.headers) &&
|
|
291
|
-
|
|
292
|
-
|
|
283
|
+
checksum_applicable?(context)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Checks if checksum calculation should proceed based on operation requirements and client settings.
|
|
287
|
+
# Returns true when any of these conditions are met:
|
|
288
|
+
# 1. http checksum's requestChecksumRequired is true
|
|
289
|
+
# 2. Config for request_checksum_calculation is "when_supported"
|
|
290
|
+
# 3. Config for request_checksum_calculation is "when_required" AND user provided checksum algorithm
|
|
291
|
+
def checksum_applicable?(context)
|
|
292
|
+
http_checksum = context.operation.http_checksum
|
|
293
|
+
return false unless http_checksum
|
|
294
|
+
|
|
295
|
+
return true if http_checksum['requestChecksumRequired']
|
|
296
|
+
|
|
297
|
+
return false unless (algorithm_member = http_checksum['requestAlgorithmMember'])
|
|
298
|
+
|
|
299
|
+
case context.config.request_checksum_calculation
|
|
300
|
+
when 'when_supported'
|
|
301
|
+
true
|
|
302
|
+
when 'when_required'
|
|
303
|
+
!context.params[algorithm_member.to_sym].nil?
|
|
304
|
+
else
|
|
305
|
+
false
|
|
306
|
+
end
|
|
293
307
|
end
|
|
294
308
|
|
|
295
309
|
def choose_request_algorithm!(context)
|
|
@@ -180,7 +180,6 @@ all generated client side metrics. Defaults to an empty string.
|
|
|
180
180
|
complete_opts = {
|
|
181
181
|
latency: end_time - start_time,
|
|
182
182
|
attempt_count: context.retries + 1,
|
|
183
|
-
user_agent: context.http_request.headers["user-agent"],
|
|
184
183
|
final_error_retryable: final_error_retryable,
|
|
185
184
|
final_http_status_code: context.http_response.status_code,
|
|
186
185
|
final_aws_exception: final_aws_exception,
|
|
@@ -14,64 +14,68 @@ module Aws
|
|
|
14
14
|
|
|
15
15
|
option(:account_id, doc_type: String, docstring: '')
|
|
16
16
|
|
|
17
|
-
option(
|
|
17
|
+
option(
|
|
18
|
+
:profile,
|
|
18
19
|
doc_default: 'default',
|
|
19
20
|
doc_type: String,
|
|
20
|
-
docstring:
|
|
21
|
-
Used when loading credentials from the shared credentials file
|
|
22
|
-
|
|
21
|
+
docstring: <<~DOCS)
|
|
22
|
+
Used when loading credentials from the shared credentials file at `HOME/.aws/credentials`.
|
|
23
|
+
When not specified, 'default' is used.
|
|
23
24
|
DOCS
|
|
24
25
|
|
|
25
|
-
option(
|
|
26
|
+
option(
|
|
27
|
+
:credentials,
|
|
26
28
|
required: true,
|
|
27
29
|
doc_type: 'Aws::CredentialProvider',
|
|
28
30
|
rbs_type: 'untyped',
|
|
29
|
-
docstring:
|
|
30
|
-
Your AWS credentials. This can be
|
|
31
|
-
following classes:
|
|
31
|
+
docstring: <<~DOCS
|
|
32
|
+
Your AWS credentials used for authentication. This can be any class that includes and implements
|
|
33
|
+
`Aws::CredentialProvider`, or instance of any one of the following classes:
|
|
32
34
|
|
|
33
|
-
* `Aws::Credentials` - Used for configuring static, non-refreshing
|
|
34
|
-
|
|
35
|
+
* `Aws::Credentials` - Used for configuring static, non-refreshing
|
|
36
|
+
credentials.
|
|
35
37
|
|
|
36
|
-
* `Aws::SharedCredentials` - Used for loading static credentials from a
|
|
37
|
-
|
|
38
|
+
* `Aws::SharedCredentials` - Used for loading static credentials from a
|
|
39
|
+
shared file, such as `~/.aws/config`.
|
|
38
40
|
|
|
39
|
-
* `Aws::AssumeRoleCredentials` - Used when you need to assume a role.
|
|
41
|
+
* `Aws::AssumeRoleCredentials` - Used when you need to assume a role.
|
|
40
42
|
|
|
41
|
-
* `Aws::AssumeRoleWebIdentityCredentials` - Used when you need to
|
|
42
|
-
|
|
43
|
+
* `Aws::AssumeRoleWebIdentityCredentials` - Used when you need to
|
|
44
|
+
assume a role after providing credentials via the web.
|
|
43
45
|
|
|
44
|
-
* `Aws::SSOCredentials` - Used for loading credentials from AWS SSO using an
|
|
45
|
-
|
|
46
|
+
* `Aws::SSOCredentials` - Used for loading credentials from AWS SSO using an
|
|
47
|
+
access token generated from `aws login`.
|
|
46
48
|
|
|
47
|
-
* `Aws::ProcessCredentials` - Used for loading credentials from a
|
|
48
|
-
|
|
49
|
+
* `Aws::ProcessCredentials` - Used for loading credentials from a
|
|
50
|
+
process that outputs to stdout.
|
|
49
51
|
|
|
50
|
-
* `Aws::InstanceProfileCredentials` - Used for loading credentials
|
|
51
|
-
|
|
52
|
+
* `Aws::InstanceProfileCredentials` - Used for loading credentials
|
|
53
|
+
from an EC2 IMDS on an EC2 instance.
|
|
52
54
|
|
|
53
|
-
* `Aws::ECSCredentials` - Used for loading credentials from
|
|
54
|
-
|
|
55
|
+
* `Aws::ECSCredentials` - Used for loading credentials from
|
|
56
|
+
instances running in ECS.
|
|
55
57
|
|
|
56
|
-
* `Aws::CognitoIdentityCredentials` - Used for loading credentials
|
|
57
|
-
|
|
58
|
+
* `Aws::CognitoIdentityCredentials` - Used for loading credentials
|
|
59
|
+
from the Cognito Identity service.
|
|
58
60
|
|
|
59
|
-
When `:credentials` are not configured directly, the following
|
|
60
|
-
locations will be searched for credentials:
|
|
61
|
+
When `:credentials` are not configured directly, the following locations will be searched for credentials:
|
|
61
62
|
|
|
62
|
-
* `Aws.config[:credentials]`
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
*
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
63
|
+
* `Aws.config[:credentials]`
|
|
64
|
+
|
|
65
|
+
* The `:access_key_id`, `:secret_access_key`, `:session_token`, and
|
|
66
|
+
`:account_id` options.
|
|
67
|
+
|
|
68
|
+
* `ENV['AWS_ACCESS_KEY_ID']`, `ENV['AWS_SECRET_ACCESS_KEY']`,
|
|
69
|
+
`ENV['AWS_SESSION_TOKEN']`, and `ENV['AWS_ACCOUNT_ID']`.
|
|
70
|
+
|
|
71
|
+
* `~/.aws/credentials`
|
|
72
|
+
|
|
73
|
+
* `~/.aws/config`
|
|
74
|
+
|
|
75
|
+
* EC2/ECS IMDS instance profile - When used by default, the timeouts are very aggressive.
|
|
76
|
+
Construct and pass an instance of `Aws::InstanceProfileCredentials` or `Aws::ECSCredentials` to
|
|
77
|
+
enable retries and extended timeouts. Instance profile credential fetching can be disabled by
|
|
78
|
+
setting `ENV['AWS_EC2_METADATA_DISABLED']` to `true`.
|
|
75
79
|
DOCS
|
|
76
80
|
) do |config|
|
|
77
81
|
CredentialProviderChain.new(config).resolve
|
|
@@ -81,31 +85,43 @@ locations will be searched for credentials:
|
|
|
81
85
|
|
|
82
86
|
option(:instance_profile_credentials_timeout, 1)
|
|
83
87
|
|
|
84
|
-
option(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
following classes:
|
|
88
|
+
option(
|
|
89
|
+
:token_provider,
|
|
90
|
+
doc_type: 'Aws::TokenProvider',
|
|
91
|
+
rbs_type: 'untyped',
|
|
92
|
+
docstring: <<~DOCS
|
|
93
|
+
Your Bearer token used for authentication. This can be any class that includes and implements
|
|
94
|
+
`Aws::TokenProvider`, or instance of any one of the following classes:
|
|
91
95
|
|
|
92
|
-
* `Aws::StaticTokenProvider` - Used for configuring static, non-refreshing
|
|
93
|
-
|
|
96
|
+
* `Aws::StaticTokenProvider` - Used for configuring static, non-refreshing
|
|
97
|
+
tokens.
|
|
94
98
|
|
|
95
|
-
* `Aws::SSOTokenProvider` - Used for loading tokens from AWS SSO using an
|
|
96
|
-
|
|
99
|
+
* `Aws::SSOTokenProvider` - Used for loading tokens from AWS SSO using an
|
|
100
|
+
access token generated from `aws login`.
|
|
97
101
|
|
|
98
|
-
When `:token_provider` is not configured directly, the `Aws::TokenProviderChain`
|
|
99
|
-
will be used to search for tokens configured for your profile in shared configuration files.
|
|
100
|
-
|
|
102
|
+
When `:token_provider` is not configured directly, the `Aws::TokenProviderChain`
|
|
103
|
+
will be used to search for tokens configured for your profile in shared configuration files.
|
|
104
|
+
DOCS
|
|
101
105
|
) do |config|
|
|
102
|
-
|
|
103
|
-
StaticTokenProvider.new('token')
|
|
104
|
-
else
|
|
105
|
-
TokenProviderChain.new(config).resolve
|
|
106
|
-
end
|
|
106
|
+
TokenProviderChain.new(config).resolve
|
|
107
107
|
end
|
|
108
108
|
|
|
109
|
+
option(
|
|
110
|
+
:auth_scheme_preference,
|
|
111
|
+
doc_type: 'Array<String>',
|
|
112
|
+
rbs_type: 'Array[String]',
|
|
113
|
+
docstring: <<~DOCS
|
|
114
|
+
A list of preferred authentication schemes to use when making a request. Supported values are:
|
|
115
|
+
`sigv4`, `sigv4a`, `httpBearerAuth`, and `noAuth`. When set using `ENV['AWS_AUTH_SCHEME_PREFERENCE']` or in
|
|
116
|
+
shared config as `auth_scheme_preference`, the value should be a comma-separated list.
|
|
117
|
+
DOCS
|
|
118
|
+
) do |config|
|
|
119
|
+
value =
|
|
120
|
+
ENV['AWS_AUTH_SCHEME_PREFERENCE'] ||
|
|
121
|
+
Aws.shared_config.auth_scheme_preference(profile: config.profile) ||
|
|
122
|
+
''
|
|
123
|
+
value.gsub(' ', '').gsub("\t", '').split(',')
|
|
124
|
+
end
|
|
109
125
|
end
|
|
110
126
|
end
|
|
111
127
|
end
|
|
@@ -4,62 +4,70 @@ module Aws
|
|
|
4
4
|
module Plugins
|
|
5
5
|
# @api private
|
|
6
6
|
class EndpointPattern < Seahorse::Client::Plugin
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
option(
|
|
8
|
+
:disable_host_prefix_injection,
|
|
9
9
|
default: false,
|
|
10
10
|
doc_type: 'Boolean',
|
|
11
|
-
docstring:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
)
|
|
11
|
+
docstring: 'When `true`, the SDK will not prepend the modeled host prefix to the endpoint.'
|
|
12
|
+
) do |cfg|
|
|
13
|
+
resolve_disable_host_prefix_injection(cfg)
|
|
14
|
+
end
|
|
16
15
|
|
|
17
|
-
def add_handlers(handlers,
|
|
16
|
+
def add_handlers(handlers, _config)
|
|
18
17
|
handlers.add(Handler, priority: 10)
|
|
19
18
|
end
|
|
20
19
|
|
|
21
|
-
class
|
|
20
|
+
class << self
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def resolve_disable_host_prefix_injection(cfg)
|
|
24
|
+
value = ENV['AWS_DISABLE_HOST_PREFIX_INJECTION'] ||
|
|
25
|
+
Aws.shared_config.disable_host_prefix_injection(profile: cfg.profile) ||
|
|
26
|
+
'false'
|
|
27
|
+
value = Aws::Util.str_2_bool(value)
|
|
28
|
+
unless [true, false].include?(value)
|
|
29
|
+
raise ArgumentError,
|
|
30
|
+
'Must provide either `true` or `false` for '\
|
|
31
|
+
'disable_host_prefix_injection profile option or for '\
|
|
32
|
+
'ENV[\'AWS_DISABLE_HOST_PREFIX_INJECTION\']'
|
|
33
|
+
end
|
|
34
|
+
value
|
|
35
|
+
end
|
|
36
|
+
end
|
|
22
37
|
|
|
38
|
+
# @api private
|
|
39
|
+
class Handler < Seahorse::Client::Handler
|
|
23
40
|
def call(context)
|
|
24
|
-
|
|
41
|
+
unless context.config.disable_host_prefix_injection
|
|
25
42
|
endpoint_trait = context.operation.endpoint_pattern
|
|
26
|
-
if endpoint_trait && !endpoint_trait.empty?
|
|
27
|
-
_apply_endpoint_trait(context, endpoint_trait)
|
|
28
|
-
end
|
|
43
|
+
apply_endpoint_trait(context, endpoint_trait) if endpoint_trait && !endpoint_trait.empty?
|
|
29
44
|
end
|
|
30
45
|
@handler.call(context)
|
|
31
46
|
end
|
|
32
47
|
|
|
33
48
|
private
|
|
34
49
|
|
|
35
|
-
def
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
ori_host, label, context.operation.input, context.params)
|
|
43
|
-
end
|
|
44
|
-
context.http_request.endpoint.host = host_prefix + context.http_request.endpoint.host
|
|
50
|
+
def apply_endpoint_trait(context, trait)
|
|
51
|
+
pattern = trait['hostPrefix']
|
|
52
|
+
return unless pattern
|
|
53
|
+
|
|
54
|
+
host_prefix = pattern.gsub(/\{.+?}/) do |label|
|
|
55
|
+
label = label.delete('{}')
|
|
56
|
+
replace_label_value(label, context.operation.input, context.params)
|
|
45
57
|
end
|
|
58
|
+
context.http_request.endpoint.host = host_prefix + context.http_request.endpoint.host
|
|
46
59
|
end
|
|
47
60
|
|
|
48
|
-
def
|
|
61
|
+
def replace_label_value(label, input_ref, params)
|
|
49
62
|
name = nil
|
|
50
63
|
input_ref.shape.members.each do |m_name, ref|
|
|
51
|
-
if ref['hostLabel'] && ref['hostLabelName'] == label
|
|
52
|
-
name = m_name
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
if name.nil? || params[name].nil?
|
|
56
|
-
raise Errors::MissingEndpointHostLabelValue.new(name)
|
|
64
|
+
name = m_name if ref['hostLabel'] && ref['hostLabelName'] == label
|
|
57
65
|
end
|
|
66
|
+
raise Errors::MissingEndpointHostLabelValue, name if name.nil? || params[name].nil?
|
|
67
|
+
|
|
58
68
|
params[name]
|
|
59
69
|
end
|
|
60
|
-
|
|
61
70
|
end
|
|
62
|
-
|
|
63
71
|
end
|
|
64
72
|
end
|
|
65
73
|
end
|