aws-sdk 1.3.7 → 1.3.8

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.
@@ -59,7 +59,7 @@ require 'aws/core/autoloader'
59
59
  module AWS
60
60
 
61
61
  # Current version of the AWS SDK for Ruby
62
- VERSION = "1.3.7"
62
+ VERSION = "1.3.8"
63
63
 
64
64
  register_autoloads(self) do
65
65
  autoload :Errors, 'errors'
@@ -72,6 +72,7 @@ module AWS
72
72
  autoload :AsyncHandle, 'async_handle'
73
73
  autoload :AuthorizeV2, 'authorize_v2'
74
74
  autoload :AuthorizeV3, 'authorize_v3'
75
+ autoload :AuthorizeV4, 'authorize_v4'
75
76
  autoload :AuthorizeWithSessionToken, 'authorize_with_session_token'
76
77
  autoload :Cacheable, 'cacheable'
77
78
  autoload :Client, 'client'
@@ -14,7 +14,7 @@
14
14
  module AWS
15
15
  module Core
16
16
 
17
- # Mixed into clients that use v2 authorization.
17
+ # Mixed into clients that use signature v2 authorization.
18
18
  # @private
19
19
  module AuthorizeV2
20
20
 
@@ -16,7 +16,7 @@ require 'time'
16
16
  module AWS
17
17
  module Core
18
18
 
19
- # Mixed into clients that use v3 authorization.
19
+ # Mixed into clients that use signature v3 authorization.
20
20
  # @private
21
21
  module AuthorizeV3
22
22
 
@@ -0,0 +1,149 @@
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
+ # - docs don't match in task 2 between the sample and the detailed
15
+ # instructions, is the canonical request hex/hashed or just hexed?
16
+ # - the hashing method is never defined, is it a md5 hash?
17
+ # - the documentation does not discuss how to add the authorization
18
+ # to your get or post request, 2 simple examples are provided, but with
19
+ # no information about how to join the parts in the post request
20
+ # (not clear about spaces vs newlines, etc)
21
+ # - document does not displ
22
+
23
+ require 'time'
24
+ require 'openssl'
25
+ require 'digest'
26
+
27
+ # bug resigning
28
+
29
+ module AWS
30
+ module Core
31
+
32
+ # Mixed into clients that use signature v4 authorization.
33
+ module AuthorizeV4
34
+
35
+ def add_authorization! signer
36
+ self.access_key_id = signer.access_key_id
37
+ datetime = Time.now.utc.strftime("%Y%m%dT%H%M%SZ")
38
+ headers['content-type'] ||= 'application/x-www-form-urlencoded'
39
+ headers['host'] = host
40
+ headers['x-amz-date'] = datetime
41
+ headers['x-amz-security-token'] = signer.session_token if signer.session_token
42
+ headers['authorization'] = authorization(signer, datetime)
43
+ end
44
+
45
+ protected
46
+
47
+ def authorization signer, datetime
48
+ parts = []
49
+ parts << "AWS4-HMAC-SHA256 Credential=#{access_key_id}/#{credential_string(datetime)}"
50
+ parts << "SignedHeaders=#{signed_headers}"
51
+ parts << "Signature=#{hex16(signature(signer, datetime))}"
52
+ parts.join(', ')
53
+ end
54
+
55
+ def signature signer, datetime
56
+ k_secret = signer.secret_access_key
57
+ k_date = hmac("AWS4" + k_secret, datetime[0,8])
58
+ k_region = hmac(k_date, region)
59
+ k_service = hmac(k_region, service)
60
+ k_credentials = hmac(k_service, 'aws4_request')
61
+ hmac(k_credentials, string_to_sign(datetime))
62
+ end
63
+
64
+ def string_to_sign datetime
65
+ parts = []
66
+ parts << 'AWS4-HMAC-SHA256'
67
+ parts << datetime
68
+ parts << credential_string(datetime)
69
+ parts << hex16(hash(canonical_request))
70
+ parts.join("\n")
71
+ end
72
+
73
+ def credential_string datetime
74
+ parts = []
75
+ parts << datetime[0,8]
76
+ parts << region
77
+ parts << service
78
+ parts << 'aws4_request'
79
+ parts.join("/")
80
+ end
81
+
82
+ def canonical_request
83
+ parts = []
84
+ parts << action_name
85
+ parts << canonical_uri
86
+ parts << canonical_querystring
87
+ parts << canonical_headers + "\n"
88
+ parts << signed_headers
89
+ parts << hex16(hash(payload))
90
+ parts.join("\n")
91
+ end
92
+
93
+ def service
94
+ # this method is implemented in the request class for each service
95
+ raise NotImplementedError
96
+ end
97
+
98
+ def action_name
99
+ http_method.to_s.upcase
100
+ end
101
+
102
+ def canonical_uri
103
+ path
104
+ end
105
+
106
+ def payload
107
+ body || ''
108
+ end
109
+
110
+ def canonical_querystring
111
+ http_method.to_s.upcase == 'GET' ? url_encoded_params : ''
112
+ end
113
+
114
+ def signed_headers
115
+ to_sign = headers.keys.map{|k| k.to_s.downcase }
116
+ to_sign.delete('authorization')
117
+ to_sign.sort.join(";")
118
+ end
119
+
120
+ def canonical_headers
121
+ headers = []
122
+ self.headers.each_pair do |k,v|
123
+ header = [k.to_s.downcase, v]
124
+ headers << header unless header.first == 'authorization'
125
+ end
126
+ headers = headers.sort_by(&:first)
127
+ headers.map{|k,v| "#{k}:#{canonical_header_values(v)}" }.join("\n")
128
+ end
129
+
130
+ def canonical_header_values values
131
+ values = [values] unless values.is_a?(Array)
132
+ values.map(&:to_s).map(&:strip).join(',')
133
+ end
134
+
135
+ def hex16 string
136
+ string.unpack('H*').first
137
+ end
138
+
139
+ def hmac key, string
140
+ OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha256'), key, string)
141
+ end
142
+
143
+ def hash string
144
+ Digest::SHA256.digest(string)
145
+ end
146
+
147
+ end
148
+ end
149
+ end
@@ -54,20 +54,28 @@ module AWS
54
54
  # HTTP requests that this client constructs.
55
55
  #
56
56
  def initialize options = {}
57
+
58
+ options = options.dup # so we don't modify the options passed in
59
+
60
+ @service_ruby_name = self.class.service_ruby_name
57
61
 
58
- if options[:endpoint]
59
- options[:"#{self.class.service_ruby_name}_endpoint"] =
60
- options.delete(:endpoint)
62
+ # translate these into service specific configuration options,
63
+ # e.g. :endpoint into :s3_endpoint
64
+ [:endpoint, :region, :port].each do |opt|
65
+ if options[opt]
66
+ options[:"#{service_ruby_name}_#{opt}"] = options.delete(opt)
67
+ end
61
68
  end
62
69
 
63
- options_without_config = options.dup
64
- @config = options_without_config.delete(:config)
70
+ @config = options.delete(:config)
65
71
  @config ||= AWS.config
66
- @config = @config.with(options_without_config)
72
+ @config = @config.with(options)
73
+
67
74
  @signer = @config.signer
68
75
  @http_handler = @config.http_handler
69
- @stubs = {}
70
-
76
+ @endpoint = config.send(:"#{service_ruby_name}_endpoint")
77
+ @port = config.send(:"#{service_ruby_name}_port")
78
+
71
79
  end
72
80
 
73
81
  # @return [Configuration] This clients configuration.
@@ -77,11 +85,17 @@ module AWS
77
85
  # This is normally a DefaultSigner, but it can be configured to
78
86
  # an other object.
79
87
  attr_reader :signer
80
-
81
- # @return [String] the configured endpoint for this client.
82
- def endpoint
83
- config.send(:"#{self.class.service_ruby_name}_endpoint")
84
- end
88
+
89
+ # @return [String] The snake-cased ruby name for the service
90
+ # (e.g. 's3', 'iam', 'dynamo_db', etc).
91
+ attr_reader :service_ruby_name
92
+
93
+ # @return [Integer] What port this client makes requests via.
94
+ attr_reader :port
95
+
96
+ # @return [String] Returns the service endpoint (hostname) this client
97
+ # makes requests against.
98
+ attr_reader :endpoint
85
99
 
86
100
  # Returns a copy of the client with a different HTTP handler.
87
101
  # You can pass an object like BuiltinHttpHandler or you can
@@ -125,6 +139,7 @@ module AWS
125
139
  # @see new_stub_for
126
140
  # @private
127
141
  def stub_for method_name
142
+ @stubs ||= {}
128
143
  @stubs[method_name] ||= new_stub_for(method_name)
129
144
  end
130
145
 
@@ -381,7 +396,10 @@ module AWS
381
396
  http_request = new_request
382
397
 
383
398
  # configure the http request
399
+ http_request.service_ruby_name = service_ruby_name
384
400
  http_request.host = endpoint
401
+ http_request.port = port
402
+ http_request.region = config.send(:"#{service_ruby_name}_region")
385
403
  http_request.proxy_uri = config.proxy_uri
386
404
  http_request.use_ssl = config.use_ssl?
387
405
  http_request.ssl_verify_peer = config.ssl_verify_peer?
@@ -302,7 +302,7 @@ module AWS
302
302
  default_value
303
303
  end
304
304
 
305
- transform ? transform.call(value) : value
305
+ transform ? transform.call(self, value) : value
306
306
 
307
307
  end
308
308
 
@@ -346,6 +346,7 @@ module AWS
346
346
  :signer,
347
347
  :http_handler,
348
348
  :"#{ruby_name}_endpoint",
349
+ :"#{ruby_name}_port",
349
350
  :max_retries,
350
351
  :stub_requests?,
351
352
  :proxy_uri,
@@ -359,6 +360,29 @@ module AWS
359
360
 
360
361
  add_option :"#{ruby_name}_endpoint", default_endpoint
361
362
 
363
+ add_option(:"#{ruby_name}_port") do |config,value|
364
+ value || (config.use_ssl? ? 443 : 80)
365
+ end
366
+
367
+ # users only need to specify service regions when they use
368
+ # a test endpoint with a sigv4 service
369
+ add_option(:"#{ruby_name}_region") do |config,value|
370
+ value || begin
371
+ endpoint = config.send("#{ruby_name}_endpoint")
372
+ if endpoint =~ /us-gov/
373
+ if matches = enpoint.match(/(us-gov-west-\d+)/)
374
+ matches[1]
375
+ else
376
+ 'us-gov-west-1' # e.g. iam.us-gov.amazonaws.com
377
+ end
378
+ elsif matches = endpoint.match(/^.+\.(.+)\.amazonaws.com$/)
379
+ matches[1]
380
+ else
381
+ 'us-east-1'
382
+ end
383
+ end
384
+ end
385
+
362
386
  add_option_with_needs :"#{ruby_name}_client", needs, &create_block
363
387
 
364
388
  end
@@ -376,7 +400,7 @@ module AWS
376
400
 
377
401
  add_option :max_retries, 3
378
402
 
379
- add_option :proxy_uri do |uri| uri ? URI.parse(uri.to_s) : nil end
403
+ add_option :proxy_uri do |config,uri| uri ? URI.parse(uri.to_s) : nil end
380
404
 
381
405
  add_option :secret_access_key,
382
406
  ENV['AWS_SECRET_ACCESS_KEY'] || ENV['AMAZON_SECRET_ACCESS_KEY']
@@ -86,11 +86,10 @@ module AWS
86
86
 
87
87
  private
88
88
  def make_easy_handle request, response, thread = nil
89
-
90
- url = request.use_ssl? ?
91
- "https://#{request.host}:443#{request.uri}" :
92
- "http://#{request.host}#{request.uri}"
93
-
89
+
90
+ protocol = request.use_ssl? ? 'https' : 'http'
91
+ url = "#{protocol}://#{request.host}:#{request.port}#{request.uri}"
92
+
94
93
  curl = Curl::Easy.new(url)
95
94
  # curl.verbose = true
96
95
  request.headers.each {|k, v| curl.headers[k] = v}
@@ -68,12 +68,13 @@ module AWS
68
68
  end
69
69
 
70
70
  if request.use_ssl?
71
- url = "https://#{request.host}:443#{request.uri}"
72
- opts[:ssl_ca_file] = request.ssl_ca_file if
73
- request.ssl_verify_peer?
71
+ protocol = 'https'
72
+ opts[:ssl_ca_file] = request.ssl_ca_file if request.ssl_verify_peer?
74
73
  else
75
- url = "http://#{request.host}#{request.uri}"
74
+ protocol = 'http'
76
75
  end
76
+
77
+ url = "#{protocol}://#{request.host}:#{request.port}#{request.uri}"
77
78
 
78
79
  # get, post, put, delete, head
79
80
  method = request.http_method.downcase
@@ -26,6 +26,7 @@ module AWS
26
26
  @headers = CaseInsensitiveHash.new
27
27
  @params = []
28
28
  @use_ssl = true
29
+ @port = nil
29
30
  @read_timeout = 60
30
31
  end
31
32
 
@@ -33,6 +34,10 @@ module AWS
33
34
  # before a timeout error is raised on the request. Defaults to
34
35
  # 60 seconds.
35
36
  attr_accessor :read_timeout
37
+
38
+ # @return [String] The snake-cased ruby name for the service
39
+ # (e.g. 's3', 'iam', 'dynamo_db', etc).
40
+ attr_accessor :service_ruby_name
36
41
 
37
42
  # @return [String] hostname of the request
38
43
  attr_accessor :host
@@ -57,6 +62,10 @@ module AWS
57
62
  # @return [nil, URI] The URI to the proxy server requests are
58
63
  # sent through if configured. Returns nil if there is no proxy.
59
64
  attr_accessor :proxy_uri
65
+
66
+ # @return [String] The region name this request is for. Only needs
67
+ # to be populated for requests against signature v4 endpoints.
68
+ attr_accessor :region
60
69
 
61
70
  # @param [Boolean] ssl If the request should be sent over ssl or not.
62
71
  def use_ssl= use_ssl
@@ -67,6 +76,19 @@ module AWS
67
76
  def use_ssl?
68
77
  @use_ssl
69
78
  end
79
+
80
+ # Override the default port (443 or 80). If you pass nil then
81
+ # the default port will take precedence.
82
+ # @param [Integer,nil] port_number
83
+ def port= port_number
84
+ @port = port_number
85
+ end
86
+
87
+ # @return [Integer] Returns the port the request will be made over.
88
+ # Defaults to 443 for SSL requests and 80 for non-SSL requests.
89
+ def port
90
+ @port || (use_ssl? ? 443 : 80)
91
+ end
70
92
 
71
93
  # @param [Boolean] verify_peer If the client should verify the
72
94
  # peer certificate or not.
@@ -16,7 +16,13 @@ module AWS
16
16
 
17
17
  # @private
18
18
  class Request < Core::Http::Request
19
- include Core::AuthorizeV2
19
+
20
+ include Core::AuthorizeV4
21
+
22
+ def service
23
+ 'iam'
24
+ end
25
+
20
26
  end
21
27
 
22
28
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws-sdk
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 11
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 3
9
- - 7
10
- version: 1.3.7
9
+ - 8
10
+ version: 1.3.8
11
11
  platform: ruby
12
12
  authors:
13
13
  - Amazon Web Services
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-03-09 00:00:00 Z
18
+ date: 2012-03-16 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  prerelease: false
@@ -93,6 +93,7 @@ files:
93
93
  - lib/aws/core/async_handle.rb
94
94
  - lib/aws/core/authorize_v2.rb
95
95
  - lib/aws/core/authorize_v3.rb
96
+ - lib/aws/core/authorize_v4.rb
96
97
  - lib/aws/core/authorize_with_session_token.rb
97
98
  - lib/aws/core/autoloader.rb
98
99
  - lib/aws/core/cacheable.rb