aws-sdk 1.5.2 → 1.5.3

Sign up to get free protection for your applications and to get access to all the features.
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