aws-sdk 1.5.2 → 1.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. data/lib/aws/api_config/AutoScaling-2011-01-01.yml +6 -2
  2. data/lib/aws/api_config/{EC2-2012-04-01.yml → EC2-2012-06-01.yml} +12 -0
  3. data/lib/aws/api_config/STS-2011-06-15.yml +0 -4
  4. data/lib/aws/auto_scaling/client.rb +6 -2
  5. data/lib/aws/auto_scaling/launch_configuration.rb +8 -0
  6. data/lib/aws/auto_scaling/launch_configuration_collection.rb +14 -4
  7. data/lib/aws/auto_scaling/scaling_policy.rb +17 -0
  8. data/lib/aws/auto_scaling/scaling_policy_options.rb +2 -0
  9. data/lib/aws/core.rb +13 -11
  10. data/lib/aws/core/cacheable.rb +1 -1
  11. data/lib/aws/core/client.rb +40 -39
  12. data/lib/aws/core/configuration.rb +24 -15
  13. data/lib/aws/core/credential_providers.rb +395 -0
  14. data/lib/aws/core/http/net_http_handler.rb +1 -0
  15. data/lib/aws/core/http/request.rb +4 -4
  16. data/lib/aws/core/log_formatter.rb +2 -0
  17. data/lib/aws/core/signature/version_2.rb +18 -5
  18. data/lib/aws/core/signature/version_3.rb +10 -10
  19. data/lib/aws/core/signature/version_4.rb +13 -13
  20. data/lib/aws/core/signer.rb +46 -0
  21. data/lib/aws/dynamo_db/batch_write.rb +2 -1
  22. data/lib/aws/dynamo_db/client.rb +9 -24
  23. data/lib/aws/dynamo_db/table.rb +0 -23
  24. data/lib/aws/ec2/client.rb +19 -1
  25. data/lib/aws/ec2/image.rb +4 -4
  26. data/lib/aws/ec2/instance.rb +17 -5
  27. data/lib/aws/ec2/instance_collection.rb +16 -1
  28. data/lib/aws/errors.rb +40 -0
  29. data/lib/aws/s3/client.rb +2 -1
  30. data/lib/aws/s3/presigned_post.rb +10 -8
  31. data/lib/aws/s3/request.rb +7 -5
  32. data/lib/aws/s3/s3_object.rb +10 -9
  33. data/lib/aws/simple_email_service.rb +1 -1
  34. data/lib/aws/simple_email_service/identity_collection.rb +1 -1
  35. data/lib/aws/sts.rb +2 -6
  36. data/lib/aws/sts/client.rb +14 -17
  37. metadata +7 -9
  38. data/lib/aws/api_config/EC2-2011-12-15.yml +0 -3638
  39. data/lib/aws/core/default_signer.rb +0 -67
  40. data/lib/aws/core/session_signer.rb +0 -90
  41. data/lib/aws/core/signature/version_3_http.rb +0 -72
@@ -0,0 +1,395 @@
1
+ # Copyright 2011-2012 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+ require 'set'
15
+ require 'net/http'
16
+ require 'timeout'
17
+
18
+ module AWS
19
+ module Core
20
+ module CredentialProviders
21
+
22
+ # This module is mixed into the various credential provider
23
+ # classes. It provides a unified interface for getting
24
+ # credentials and refreshing them.
25
+ module Provider
26
+
27
+ # The list of possible keys in the hash returned by {#credentials}.
28
+ KEYS = Set[:access_key_id, :secret_access_key, :session_token]
29
+
30
+ # @return [Hash] Returns a hash of credentials containg at least
31
+ # the +:access_key_id+ and +:secret_access_key+. The hash may
32
+ # also contain a +:session_token+.
33
+ #
34
+ # @raise [Errors::MissingCredentialsError] Raised when the
35
+ # +:access_key_id+ or the +:secret_access_key+ can not be found.
36
+ #
37
+ def credentials
38
+ @cached_credentials ||= begin
39
+ creds = get_credentials
40
+ unless creds[:access_key_id] and creds[:secret_access_key]
41
+ raise Errors::MissingCredentialsError
42
+ end
43
+ creds
44
+ end
45
+ @cached_credentials.dup
46
+ end
47
+
48
+ # @return [String] Returns the AWS access key id.
49
+ # @raise (see #credentials)
50
+ def access_key_id
51
+ credentials[:access_key_id]
52
+ end
53
+
54
+ # @return [String] Returns the AWS secret access key.
55
+ # @raise (see #credentials)
56
+ def secret_access_key
57
+ credentials[:secret_access_key]
58
+ end
59
+
60
+ # @return [String,nil] Returns the AWS session token or nil if these
61
+ # are not session credentials.
62
+ # @raise (see #credentials)
63
+ def session_token
64
+ credentials[:session_token]
65
+ end
66
+
67
+ # Clears out cached/memoized credentials. Causes the provider
68
+ # to refetch credentials from the source.
69
+ # @return [nil]
70
+ def refresh
71
+ @cached_credentials = nil
72
+ end
73
+
74
+ protected
75
+
76
+ # This method is called on a credential provider to fetch
77
+ # credentials. The credentials hash returned from this
78
+ # method will be cashed until the client calls {#refresh}.
79
+ # @return [Hash]
80
+ def get_credentials
81
+ # should be defined in provider classes.
82
+ raise NotImplementedError
83
+ end
84
+
85
+ end
86
+
87
+ # The default credential provider makes a best effort to
88
+ # locate your AWS credentials. It checks a variety of locations
89
+ # in the following order:
90
+ #
91
+ # * Static credentials from AWS.config (e.g. AWS.config.access_key_id,
92
+ # AWS.config.secret_access_key)
93
+ #
94
+ # * The environment (e.g. ENV['AWS_ACCESS_KEY_ID'] or
95
+ # ENV['AMAZON_ACCESS_KEY_ID'])
96
+ #
97
+ # * EC2 metadata service (checks for credentials provided by
98
+ # roles for instances).
99
+ #
100
+ class DefaultProvider
101
+
102
+ include Provider
103
+
104
+ # (see StaticProvider#new)
105
+ def initialize static_credentials = {}
106
+ @providers = []
107
+ @providers << StaticProvider.new(static_credentials)
108
+ @providers << ENVProvider.new('AWS')
109
+ @providers << ENVProvider.new('AMAZON')
110
+ @providers << EC2Provider.new
111
+ end
112
+
113
+ # @return [Array<Provider>]
114
+ attr_reader :providers
115
+
116
+ def get_credentials
117
+ providers.each do |provider|
118
+ return provider.credentials rescue Errors::MissingCredentialsError
119
+ end
120
+ {}
121
+ end
122
+
123
+ end
124
+
125
+ # Static credentials are provided directly to config via
126
+ # +:access_key_id+ and +:secret_access_key+ (and optionally
127
+ # +:session_token+).
128
+ # @private
129
+ class StaticProvider
130
+
131
+ include Provider
132
+
133
+ # @param [Hash] static_credentials
134
+ # @option static_credentials [required,String] :access_key_id
135
+ # @option static_credentials [required,String] :secret_access_key
136
+ # @option static_credentials [String] :session_token
137
+ def initialize static_credentials = {}
138
+
139
+ static_credentials.keys.each do |opt_name|
140
+ unless KEYS.include?(opt_name)
141
+ raise ArgumentError, "invalid option #{opt_name.inspect}"
142
+ end
143
+ end
144
+
145
+ @static_credentials = {}
146
+ KEYS.each do |opt_name|
147
+ if opt_value = static_credentials[opt_name]
148
+ @static_credentials[opt_name] = opt_value
149
+ end
150
+ end
151
+
152
+ end
153
+
154
+ # (see Provider#get_credentials)
155
+ def get_credentials
156
+ @static_credentials
157
+ end
158
+
159
+ end
160
+
161
+ # Fetches credentials from the environment (ENV). You construct
162
+ # an ENV provider with a prefix. Given the prefix "AWS"
163
+ # ENV will be checked for the following keys:
164
+ #
165
+ # * AWS_ACCESS_KEY_ID
166
+ # * AWS_SECRET_ACCESS_KEY
167
+ # * AWS_SESSION_TOKEN (optional)
168
+ #
169
+ class ENVProvider
170
+
171
+ include Provider
172
+
173
+ # @param [String] prefix The prefix to apply to the ENV variable.
174
+ def initialize prefix
175
+ @prefix = prefix
176
+ end
177
+
178
+ # @return [String]
179
+ attr_reader :prefix
180
+
181
+ # (see Provider#get_credentials)
182
+ def get_credentials
183
+ credentials = {}
184
+ KEYS.each do |key|
185
+ if value = ENV["#{@prefix}_#{key.to_s.upcase}"]
186
+ credentials[key] = value
187
+ end
188
+ end
189
+ credentials
190
+ end
191
+
192
+ end
193
+
194
+ # This credential provider tries to get credentials from the EC2
195
+ # metadata service.
196
+ class EC2Provider
197
+
198
+ # Raised when an http response is recieved with a non 200
199
+ # http status code.
200
+ # @private
201
+ class FailedRequestError < StandardError; end
202
+
203
+ # These are the errors we trap when attempting to talk to the
204
+ # instance metadata service. Any of these imply the service
205
+ # is not present, no responding or some other non-recoverable
206
+ # error.
207
+ # @private
208
+ FAILURES = [
209
+ FailedRequestError,
210
+ Errno::EHOSTUNREACH,
211
+ Errno::ECONNREFUSED,
212
+ SocketError,
213
+ Timeout::Error,
214
+ ]
215
+
216
+ include Provider
217
+
218
+ # @param [Hash] options
219
+ # @option options [String] :ip_address ('169.254.169.254')
220
+ # @option options [Integer] :port (80)
221
+ # @option options [Float] :http_open_timeout (1)
222
+ # @option options [Float] :http_read_timeout (1)
223
+ # @option options [Object] :http_debug_output (nil) HTTP wire
224
+ # traces are sent to this object. You can specify something
225
+ # like $stdout.
226
+ def initialize options = {}
227
+ @ip_address = options[:ip_address] || '169.254.169.254'
228
+ @port = options[:port] || 80
229
+ @http_open_timeout = options[:http_open_timeout] || 1
230
+ @http_read_timeout = options[:http_read_timeout] || 1
231
+ @http_debug_output = options[:http_debug_output]
232
+ end
233
+
234
+ # @return [String] Defaults to '169.254.169.254'.
235
+ attr_accessor :ip_address
236
+
237
+ # @return [Integer] Defaults to port 80.
238
+ attr_accessor :port
239
+
240
+ # @return [Float]
241
+ attr_accessor :http_open_timeout
242
+
243
+ # @return [Float]
244
+ attr_accessor :http_read_timeout
245
+
246
+ # @return [Object,nil]
247
+ attr_accessor :http_debug_output
248
+
249
+ protected
250
+
251
+ # (see Provider#get_credentials)
252
+ def get_credentials
253
+ begin
254
+
255
+ http = Net::HTTP.new(ip_address, port)
256
+ http.open_timeout = http_open_timeout
257
+ http.read_timeout = http_read_timeout
258
+ http.set_debug_output(http_debug_output) if
259
+ http_debug_output
260
+ http.start
261
+
262
+ # get the first/default instance profile name
263
+ path = '/latest/meta-data/iam/security-credentials/'
264
+ profile_name = get(http, path).lines.map(&:strip).first
265
+
266
+ # get the session details from the instance profile name
267
+ path << profile_name
268
+ session = JSON.parse(get(http, path))
269
+
270
+ http.finish
271
+
272
+ credentials = {}
273
+ credentials[:access_key_id] = session['AccessKeyId']
274
+ credentials[:secret_access_key] = session['SecretAccessKey']
275
+ credentials[:session_token] = session['Token']
276
+ credentials
277
+
278
+ rescue *FAILURES => e
279
+ {}
280
+ end
281
+ end
282
+
283
+ # Makes an HTTP Get request with the given path. If a non-200
284
+ # response is received, then a FailedRequestError is raised.
285
+ # a {FailedRequestError} is raised.
286
+ # @param [Net::HTTPSession] session
287
+ # @param [String] path
288
+ # @raise [FailedRequestError]
289
+ # @return [String] Returns the http response body.
290
+ def get session, path
291
+ response = session.request(Net::HTTP::Get.new(path))
292
+ if response.code.to_i == 200
293
+ response.body
294
+ else
295
+ raise FailedRequestError
296
+ end
297
+ end
298
+
299
+ end
300
+
301
+ # = Session Credential Provider
302
+ #
303
+ # The session provider consumes long term credentials (+:access_key_id+
304
+ # and +:secret_access_key+) and requests a session from STS.
305
+ # It then returns the short term credential set from STS.
306
+ #
307
+ # Calling {#refresh} causes the session provider to request a new
308
+ # set of credentials.
309
+ #
310
+ # This session provider is currently only used for DynamoDB which
311
+ # requires session credentials.
312
+ class SessionProvider
313
+
314
+ include Provider
315
+
316
+ @create_mutex = Mutex.new
317
+
318
+ class << self
319
+
320
+ # @param [Hash] long_term_credentials A hash of credentials with
321
+ # +:access_key_id+ and +:secret_access_key+ (but not
322
+ # +:session_token+).
323
+ def for long_term_credentials
324
+ @create_mutex.synchronize do
325
+ @session_providers ||= {}
326
+ @session_providers[long_term_credentials[:access_key_id]] =
327
+ self.new(long_term_credentials)
328
+ end
329
+ end
330
+
331
+ # Creation of SessionProviders *must* happen behind the mutex and
332
+ # we want to reuse session providers for the same access key id.
333
+ protected :new
334
+
335
+ end
336
+
337
+ # @param [Hash] long_term_credentials A hash of credentials with
338
+ # +:access_key_id+ and +:secret_access_key+ (but not
339
+ # +:session_token+).
340
+ def initialize long_term_credentials
341
+ @static = StaticProvider.new(long_term_credentials)
342
+ if @static.session_token
343
+ raise ArgumentError, 'invalid option :session_token'
344
+ end
345
+ @session_mutex = Mutex.new
346
+ end
347
+
348
+ # Aliasing the refresh method so we can call it from the refresh
349
+ # method defined in this class.
350
+ alias_method :orig_refresh, :refresh
351
+ protected :orig_refresh
352
+
353
+ # (see Provider#refresh)
354
+ def refresh
355
+ refresh_session
356
+ orig_refresh
357
+ end
358
+
359
+ protected
360
+
361
+ # (see Provider#get_credentials)
362
+ def get_credentials
363
+ session = cached_session
364
+ if session.nil?
365
+ refresh_session
366
+ session = cached_session
367
+ end
368
+ session.credentials
369
+ end
370
+
371
+ # Replaces the cached STS session with a new one.
372
+ # @return [nil]
373
+ def refresh_session
374
+ sts = AWS::STS.new(@static.credentials.merge(:use_ssl => true))
375
+ @session_mutex.synchronize do
376
+ @session = sts.new_session
377
+ end
378
+ nil
379
+ end
380
+
381
+ # @return [nil,STS::Session] Returns nil if a session has not
382
+ # already been started.
383
+ def cached_session
384
+ local_session = nil
385
+ @session_mutex.synchronize do
386
+ local_session = @session
387
+ end
388
+ local_session
389
+ end
390
+
391
+ end
392
+
393
+ end
394
+ end
395
+ end
@@ -31,6 +31,7 @@ module AWS
31
31
  def handle request, response
32
32
 
33
33
  options = {}
34
+ options[:port] = request.port
34
35
  options[:ssl] = request.use_ssl?
35
36
  options[:proxy_uri] = request.proxy_uri
36
37
  options[:ssl_verify_peer] = request.ssl_verify_peer?
@@ -58,10 +58,6 @@ module AWS
58
58
  # @return [String] path of the request URI, defaults to /
59
59
  attr_accessor :path
60
60
 
61
- # @return [String] the AWS access key ID used to authorize the
62
- # request
63
- attr_accessor :access_key_id
64
-
65
61
  # @return [nil, URI] The URI to the proxy server requests are
66
62
  # sent through if configured. Returns nil if there is no proxy.
67
63
  attr_accessor :proxy_uri
@@ -69,6 +65,10 @@ module AWS
69
65
  # @return [String] The region name this request is for. Only needs
70
66
  # to be populated for requests against signature v4 endpoints.
71
67
  attr_accessor :region
68
+
69
+ # @return [String]
70
+ # @private
71
+ attr_accessor :access_key_id
72
72
 
73
73
  # @param [Boolean] state If the request should be sent over ssl or not.
74
74
  def use_ssl= state
@@ -11,6 +11,8 @@
11
11
  # ANY KIND, either express or implied. See the License for the specific
12
12
  # language governing permissions and limitations under the License.
13
13
 
14
+ require 'pathname'
15
+
14
16
  module AWS
15
17
  module Core
16
18
 
@@ -16,24 +16,37 @@ module AWS
16
16
  module Signature
17
17
  module Version2
18
18
 
19
- def add_authorization! signer
20
- self.access_key_id = signer.access_key_id
21
- add_param('AWSAccessKeyId', access_key_id)
22
- if signer.respond_to?(:session_token) and token = signer.session_token
19
+ def self.included base
20
+ base.send(:include, Signer)
21
+ end
22
+
23
+ def add_authorization! credentials
24
+ add_param('AWSAccessKeyId', credentials.access_key_id)
25
+ if token = credentials.session_token
23
26
  add_param("SecurityToken", token)
24
27
  end
25
28
  add_param('SignatureVersion', '2')
26
29
  add_param('SignatureMethod', 'HmacSHA256')
27
- add_param('Signature', signer.sign(string_to_sign))
30
+ add_param('Signature', sign(credentials.secret_access_key, string_to_sign))
28
31
  end
29
32
 
33
+ protected
34
+
30
35
  def string_to_sign
36
+
37
+ host =
38
+ case port
39
+ when 80, 443 then self.host
40
+ else "#{self.host}:#{port}"
41
+ end
42
+
31
43
  [
32
44
  http_method,
33
45
  host,
34
46
  path,
35
47
  params.sort.collect { |p| p.encoded }.join('&'),
36
48
  ].join("\n")
49
+
37
50
  end
38
51
 
39
52
  end