aws-sdk-core 3.132.0 → 3.147.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 834ced1c0e2ea4d743b2fc0cbe70ed75d6bcf57385521cd3c6ecded7e2eba288
4
- data.tar.gz: cb7e8f63bc55a0ac685f0c1545fe95433e1b9a6397f4a41d264e3e01364772c0
3
+ metadata.gz: 7a89bc0a08601c30848156cba150df190803855fb14070f91811141a220e6131
4
+ data.tar.gz: 037f1ddbddc86ce7c2d434cac153ae9250503d3b7dc766c77653c090c753ed5d
5
5
  SHA512:
6
- metadata.gz: 4363ba1ee176a0656ca650ece2c0f816ccdb2e1dedc95db49c67d1277b90a6f797f5fbe3c7096de2a7b0335b47d02bfe127ea94d07f00961ce6e5b8a6380b120
7
- data.tar.gz: 42518b3ea0ba92f776c1422f1c87b300c6bcd916e220184378b139987c5e00ad41d801231b1ce0c7c77ff88fa202de0bc22bb451887e00fbe6598f01cac5163d
6
+ metadata.gz: 118641c4ff5934370f547bb9665d97208227d8fa6ad14c4a0e60401a5e1d620930f7d52a66ba23ec16a217bb9277f28467ff37fe9b66425733194e1331845bbc
7
+ data.tar.gz: ceb838b58bdd07abdba12e18ce52281671f5a62c73f278a6d4e3000066ed8a87bb63e745ea42069574f4439517fb4b33bb5fe1c0e36f0adc754cc4a075010b1b
data/CHANGELOG.md CHANGED
@@ -1,6 +1,86 @@
1
1
  Unreleased Changes
2
2
  ------------------
3
3
 
4
+ 3.147.0 (2022-09-14)
5
+ ------------------
6
+
7
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
8
+
9
+ 3.146.0 (2022-09-13)
10
+ ------------------
11
+
12
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
13
+
14
+ 3.145.0 (2022-09-12)
15
+ ------------------
16
+
17
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
18
+
19
+ 3.144.0 (2022-09-09)
20
+ ------------------
21
+
22
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
23
+
24
+ 3.143.0 (2022-09-08)
25
+ ------------------
26
+
27
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
28
+
29
+ 3.142.0 (2022-09-07)
30
+ ------------------
31
+
32
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
33
+
34
+ 3.141.0 (2022-09-06)
35
+ ------------------
36
+
37
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
38
+
39
+ 3.140.0 (2022-09-02)
40
+ ------------------
41
+
42
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
43
+
44
+ 3.139.0 (2022-09-01)
45
+ ------------------
46
+
47
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
48
+
49
+ 3.138.0 (2022-08-31)
50
+ ------------------
51
+
52
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
53
+
54
+ 3.137.0 (2022-08-30)
55
+ ------------------
56
+
57
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
58
+
59
+ * Issue - Fix errors in recursion detection when `_X_AMZN_TRACE_ID` is unset (#2748).
60
+
61
+ 3.136.0 (2022-08-25)
62
+ ------------------
63
+
64
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
65
+
66
+ 3.135.0 (2022-08-24)
67
+ ------------------
68
+
69
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
70
+
71
+ 3.134.0 (2022-08-23)
72
+ ------------------
73
+
74
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
75
+
76
+ * Feature - Add support for Bearer Token Authentication and TokenProviders.
77
+ * Issue - Validate that `_X_AMZN_TRACE_ID` ENV value contains only valid, non-control characters.
78
+
79
+ 3.133.0 (2022-08-22)
80
+ ------------------
81
+
82
+ * Feature - Moved functionality from `aws-sdk-ssoidc` into core.
83
+
4
84
  3.132.0 (2022-08-08)
5
85
  ------------------
6
86
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.132.0
1
+ 3.147.0
@@ -210,6 +210,19 @@ module Aws
210
210
  # Raised when SSO Credentials are invalid
211
211
  class InvalidSSOCredentials < RuntimeError; end
212
212
 
213
+ # Raised when SSO Token is invalid
214
+ class InvalidSSOToken < RuntimeError; end
215
+
216
+ # Raised when a client is unable to sign a request because
217
+ # the bearer token is not configured or available
218
+ class MissingBearerTokenError < RuntimeError
219
+ def initialize(*args)
220
+ msg = 'unable to sign request without token set'
221
+ super(msg)
222
+ end
223
+ end
224
+
225
+
213
226
  # Raised when there is a circular reference in chained
214
227
  # source_profiles
215
228
  class SourceProfileCircularReferenceError < RuntimeError; end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ # @api private
5
+ module Plugins
6
+ # @api private
7
+ class BearerAuthorization < Seahorse::Client::Plugin
8
+
9
+ option(:token_provider,
10
+ required: false,
11
+ doc_type: 'Aws::TokenProvider',
12
+ docstring: <<-DOCS
13
+ A Bearer Token Provider. This can be an instance of any one of the
14
+ following classes:
15
+
16
+ * `Aws::StaticTokenProvider` - Used for configuring static, non-refreshing
17
+ tokens.
18
+
19
+ * `Aws::SSOTokenProvider` - Used for loading tokens from AWS SSO using an
20
+ access token generated from `aws login`.
21
+
22
+ When `:token_provider` is not configured directly, the `Aws::TokenProviderChain`
23
+ will be used to search for tokens configured for your profile in shared configuration files.
24
+ DOCS
25
+ ) do |config|
26
+ if config.stub_responses
27
+ StaticTokenProvider.new('token')
28
+ else
29
+ TokenProviderChain.new(config).resolve
30
+ end
31
+ end
32
+
33
+
34
+ def add_handlers(handlers, cfg)
35
+ bearer_operations =
36
+ if cfg.api.metadata['signatureVersion'] == 'bearer'
37
+ # select operations where authtype is either not set or is bearer
38
+ cfg.api.operation_names.select do |o|
39
+ !cfg.api.operation(o)['authtype'] || cfg.api.operation(o)['authtype'] == 'bearer'
40
+ end
41
+ else # service is not bearer auth
42
+ # select only operations where authtype is explicitly bearer
43
+ cfg.api.operation_names.select do |o|
44
+ cfg.api.operation(o)['authtype'] == 'bearer'
45
+ end
46
+ end
47
+ handlers.add(Handler, step: :sign, operations: bearer_operations)
48
+ end
49
+
50
+ class Handler < Seahorse::Client::Handler
51
+ def call(context)
52
+ if context.http_request.endpoint.scheme != 'https'
53
+ raise ArgumentError, 'Unable to use bearer authorization on non https endpoint.'
54
+ end
55
+
56
+ token_provider = context.config.token_provider
57
+ if token_provider && token_provider.set?
58
+ context.http_request.headers['Authorization'] = "Bearer #{token_provider.token.token}"
59
+ else
60
+ raise Errors::MissingBearerTokenError
61
+ end
62
+ @handler.call(context)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -11,12 +11,23 @@ module Aws
11
11
 
12
12
  unless context.http_request.headers.key?('x-amzn-trace-id')
13
13
  if ENV['AWS_LAMBDA_FUNCTION_NAME'] &&
14
- (trace_id = ENV['_X_AMZN_TRACE_ID'])
14
+ (trace_id = validate_header(ENV['_X_AMZN_TRACE_ID']))
15
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
@@ -7,6 +7,8 @@ module Aws
7
7
  # @api private
8
8
  class SignatureV4 < Seahorse::Client::Plugin
9
9
 
10
+ V4_AUTH = %w[v4 v4-unsigned-payload v4-unsigned-body]
11
+
10
12
  option(:sigv4_signer) do |cfg|
11
13
  SignatureV4.build_signer(cfg)
12
14
  end
@@ -32,13 +34,16 @@ module Aws
32
34
  end
33
35
 
34
36
  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
37
+ if cfg.api.metadata['signatureVersion'] == 'v4'
38
+ # select operations where authtype is set and is not v4
39
+ cfg.api.operation_names.select do |o|
40
+ cfg.api.operation(o)['authtype'] && !V4_AUTH.include?(cfg.api.operation(o)['authtype'])
41
+ end
42
+ else # service is not v4 auth
43
+ # select all operations where authtype is not v4
44
+ # (includes operations with no explicit authtype)
45
+ cfg.api.operation_names.select do |o|
46
+ !V4_AUTH.include?(cfg.api.operation(o)['authtype'])
42
47
  end
43
48
  end
44
49
  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
@@ -4,6 +4,9 @@ module Aws
4
4
  # @api private
5
5
  class SharedConfig
6
6
  SSO_PROFILE_KEYS = %w[sso_start_url sso_region sso_account_id sso_role_name].freeze
7
+ SSO_TOKEN_PROFILE_KEYS = %w[sso_session].freeze
8
+ SSO_SESSION_KEYS = %w[sso_region]
9
+
7
10
 
8
11
  # @return [String]
9
12
  attr_reader :credentials_path
@@ -151,6 +154,18 @@ module Aws
151
154
  credentials
152
155
  end
153
156
 
157
+ # Attempts to load from shared config or shared credentials file.
158
+ # Will always attempt first to load from the shared credentials
159
+ # file, if present.
160
+ def sso_token_from_config(opts = {})
161
+ p = opts[:profile] || @profile_name
162
+ token = sso_token_from_profile(@parsed_credentials, p)
163
+ if @parsed_config
164
+ token ||= sso_token_from_profile(@parsed_config, p)
165
+ end
166
+ token
167
+ end
168
+
154
169
  # Add an accessor method (similar to attr_reader) to return a configuration value
155
170
  # Uses the get_config_value below to control where
156
171
  # values are loaded from
@@ -327,6 +342,32 @@ module Aws
327
342
  end
328
343
  end
329
344
 
345
+ # If the required sso_ profile values are present, attempt to construct
346
+ # SSOTokenProvider
347
+ def sso_token_from_profile(cfg, profile)
348
+ if @parsed_config &&
349
+ (prof_config = cfg[profile]) &&
350
+ !(prof_config.keys & SSO_TOKEN_PROFILE_KEYS).empty?
351
+
352
+ sso_session_name = prof_config['sso_session']
353
+ sso_session = cfg["sso-session #{sso_session_name}"]
354
+ unless sso_session
355
+ raise ArgumentError,
356
+ "sso-session #{sso_session_name} must be defined in the config file." /
357
+ "Referenced by profile #{profile}"
358
+ end
359
+
360
+ unless sso_session['sso_region']
361
+ raise ArgumentError, "sso-session #{sso_session_name} missing required parameter: sso_region"
362
+ end
363
+
364
+ SSOTokenProvider.new(
365
+ sso_session: sso_session_name,
366
+ sso_region: sso_session['sso_region']
367
+ )
368
+ end
369
+ end
370
+
330
371
  def credentials_from_profile(prof_config)
331
372
  creds = Credentials.new(
332
373
  prof_config['aws_access_key_id'],
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ class SSOTokenProvider
5
+
6
+ include TokenProvider
7
+ include RefreshingToken
8
+
9
+ # @api private
10
+ SSO_REQUIRED_OPTS = [:sso_region, :sso_session].freeze
11
+
12
+ # @api private
13
+ SSO_LOGIN_GUIDANCE = 'The SSO session associated with this profile has '\
14
+ 'expired or is otherwise invalid. To refresh this SSO session run '\
15
+ 'aws sso login with the corresponding profile.'.freeze
16
+
17
+ # @option options [required, String] :sso_region The AWS region where the
18
+ # SSO directory for the given sso_start_url is hosted.
19
+ #
20
+ # @option options [required, String] :sso_session The SSO Session used to
21
+ # for fetching this token.
22
+ #
23
+ # @option options [SSOOIDC::Client] :client Optional `SSOOIDC::Client`. If not
24
+ # provided, a client will be constructed.
25
+ #
26
+ # @option options [Callable] before_refresh Proc called before
27
+ # credentials are refreshed. `before_refresh` is called
28
+ # with an instance of this object when
29
+ # AWS credentials are required and need to be refreshed.
30
+ def initialize(options = {})
31
+
32
+ missing_keys = SSO_REQUIRED_OPTS.select { |k| options[k].nil? }
33
+ unless missing_keys.empty?
34
+ raise ArgumentError, "Missing required keys: #{missing_keys}"
35
+ end
36
+
37
+ @sso_session = options.delete(:sso_session)
38
+ @sso_region = options.delete(:sso_region)
39
+
40
+ options[:region] = @sso_region
41
+ options[:credentials] = nil
42
+ @client = options[:client] || Aws::SSOOIDC::Client.new(options)
43
+
44
+ super
45
+ end
46
+
47
+ # @return [SSO::Client]
48
+ attr_reader :client
49
+
50
+ private
51
+
52
+ def refresh
53
+ # token is valid and not in refresh window - do not refresh it.
54
+ return if @token && @token.expiration && !near_expiration?
55
+
56
+ # token may not exist or is out of the expiration window
57
+ # attempt to refresh from disk first (another process/application may have refreshed already)
58
+ token_json = read_cached_token
59
+ @token = Token.new(token_json['accessToken'], token_json['expiresAt'])
60
+ return if @token && @token.expiration && !near_expiration?
61
+
62
+ # The token is expired and needs to be refreshed
63
+ if can_refresh_token?(token_json)
64
+ begin
65
+ current_time = Time.now
66
+ resp = @client.create_token(
67
+ grant_type: 'refresh_token',
68
+ client_id: token_json['clientId'],
69
+ client_secret: token_json['client_secret'],
70
+ refresh_token: token_json['refreshToken']
71
+ )
72
+ token_json['accessToken'] = resp.access_token
73
+ token_json['expiresAt'] = current_time + resp.expires_in
74
+ @token = Token.new(token_json['accessToken'], token_json['expiresAt'])
75
+
76
+ if resp.refresh_token
77
+ token_json['refreshToken'] = resp.refresh_token
78
+ else
79
+ token_json.delete('refreshToken')
80
+ end
81
+
82
+ update_token_cache(token_json)
83
+ rescue
84
+ # refresh has failed, continue attempting to use the token if its not hard expired
85
+ end
86
+ end
87
+
88
+ if !@token.expiration || @token.expiration < Time.now
89
+ # Token is hard expired, raise an exception
90
+ raise Errors::InvalidSSOToken, 'Token is invalid and failed to refresh.'
91
+ end
92
+ end
93
+
94
+ def read_cached_token
95
+ cached_token = Json.load(File.read(sso_cache_file))
96
+ # validation
97
+ unless cached_token['accessToken'] && cached_token['expiresAt']
98
+ raise ArgumentError, 'Missing required field(s)'
99
+ end
100
+ cached_token['expiresAt'] = Time.parse(cached_token['expiresAt'])
101
+ cached_token
102
+ rescue Errno::ENOENT, Aws::Json::ParseError, ArgumentError
103
+ raise Errors::InvalidSSOToken, SSO_LOGIN_GUIDANCE
104
+ end
105
+
106
+ def update_token_cache(token_json)
107
+ cached_token = token_json.dup
108
+ cached_token['expiresAt'] = cached_token['expiresAt'].iso8601
109
+ File.write(sso_cache_file, Json.dump(cached_token))
110
+ end
111
+
112
+ def sso_cache_file
113
+ sso_session_sha1 = OpenSSL::Digest::SHA1.hexdigest(@sso_session.encode('utf-8'))
114
+ File.join(Dir.home, '.aws', 'sso', 'cache', "#{sso_session_sha1}.json")
115
+ rescue ArgumentError
116
+ # Dir.home raises ArgumentError when ENV['home'] is not set
117
+ raise ArgumentError, "Unable to load sso_cache_file: ENV['HOME'] is not set."
118
+ end
119
+
120
+ # return true if all required fields are present
121
+ # return false if registrationExpiresAt exists and is later than now
122
+ def can_refresh_token?(token_json)
123
+ if token_json['clientId'] &&
124
+ token_json['clientSecret'] &&
125
+ token_json['refreshToken']
126
+
127
+ return !token_json['registrationExpiresAt'] ||
128
+ Time.parse(token_json['registrationExpiresAt']) > Time.now
129
+ else
130
+ false
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ class StaticTokenProvider
5
+
6
+ include TokenProvider
7
+
8
+ # @param [String] token
9
+ # @param [Time] expiration
10
+ def initialize(token, expiration=nil)
11
+ @token = Token.new(token, expiration)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ class Token
5
+
6
+ # @param [String] token
7
+ # @param [Time] expiration
8
+ def initialize(token, expiration=nil)
9
+ @token = token
10
+ @expiration = expiration
11
+ end
12
+
13
+ # @return [String, nil]
14
+ attr_reader :token
15
+
16
+ # @return [Time, nil]
17
+ attr_reader :expiration
18
+
19
+ # @return [Boolean] Returns `true` if token is set
20
+ def set?
21
+ !token.nil? && !token.empty?
22
+ end
23
+
24
+ # Removing the token from the default inspect string.
25
+ # @api private
26
+ def inspect
27
+ "#<#{self.class.name} token=[FILTERED]> expiration=#{expiration}>"
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module TokenProvider
5
+
6
+ # @return [Token]
7
+ attr_reader :token
8
+
9
+ # @return [Boolean]
10
+ def set?
11
+ !!token && token.set?
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ # @api private
5
+ class TokenProviderChain
6
+ def initialize(config = nil)
7
+ @config = config
8
+ end
9
+
10
+ # @return [TokenProvider, nil]
11
+ def resolve
12
+ providers.each do |method_name, options|
13
+ provider = send(method_name, options.merge(config: @config))
14
+ return provider if provider && provider.set?
15
+ end
16
+ nil
17
+ end
18
+
19
+ private
20
+
21
+ def providers
22
+ [
23
+ [:static_profile_sso_token, {}],
24
+ [:sso_token, {}]
25
+ ]
26
+ end
27
+
28
+ def static_profile_sso_token(options)
29
+ if Aws.shared_config.config_enabled? && options[:config] && options[:config].profile
30
+ Aws.shared_config.sso_token_from_config(
31
+ profile: options[:config].profile
32
+ )
33
+ end
34
+ end
35
+
36
+
37
+ def sso_token(options)
38
+ profile_name = determine_profile_name(options)
39
+ if Aws.shared_config.config_enabled?
40
+ Aws.shared_config.sso_token_from_config(profile: profile_name)
41
+ end
42
+ rescue Errors::NoSuchProfileError
43
+ nil
44
+ end
45
+
46
+ def determine_profile_name(options)
47
+ (options[:config] && options[:config].profile) || ENV['AWS_PROFILE'] || ENV['AWS_DEFAULT_PROFILE'] || 'default'
48
+ end
49
+
50
+ end
51
+ end
data/lib/aws-sdk-core.rb CHANGED
@@ -20,6 +20,15 @@ require_relative 'aws-sdk-core/shared_credentials'
20
20
  require_relative 'aws-sdk-core/process_credentials'
21
21
  require_relative 'aws-sdk-core/sso_credentials'
22
22
 
23
+ # tokens and token providers
24
+ require_relative 'aws-sdk-core/token'
25
+ require_relative 'aws-sdk-core/token_provider'
26
+ require_relative 'aws-sdk-core/static_token_provider'
27
+ require_relative 'aws-sdk-core/refreshing_token'
28
+ require_relative 'aws-sdk-core/sso_token_provider'
29
+ require_relative 'aws-sdk-core/token_provider_chain'
30
+ require_relative 'aws-sdk-core/plugins/bearer_authorization'
31
+
23
32
  # client modules
24
33
 
25
34
  require_relative 'aws-sdk-core/client_stubs'
@@ -99,6 +108,7 @@ require_relative 'aws-sdk-sts'
99
108
 
100
109
  # aws-sdk-sso is included to support Aws::SSOCredentials
101
110
  require_relative 'aws-sdk-sso'
111
+ require_relative 'aws-sdk-ssooidc'
102
112
 
103
113
  module Aws
104
114