simple_aws 0.0.1c → 0.0.1d

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -122,10 +122,6 @@ These are the following Amazon APIs that SimpleAWS currently handles:
122
122
  * Mechanical Turk
123
123
  * SQS (Simple Queue Service)
124
124
  * SES (Simple Email Service)
125
-
126
- Yet to be Implemented
127
- ---------------------
128
-
129
125
  * CloudFront
130
126
 
131
127
  Currently Out-Of-Scope
@@ -0,0 +1,117 @@
1
+ require 'aws/api'
2
+ require 'aws/core/util'
3
+
4
+ module AWS
5
+
6
+ ##
7
+ # Amazon's CloudFront
8
+ #
9
+ # http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/Welcome.html
10
+ #
11
+ # As CloudFront is much closer to a RESTful service than the other AWS APIs, all
12
+ # calls through this API are done through these four HTTP METHODS:
13
+ # GET, PUT, DELETE, and POST.
14
+ #
15
+ # The paths for all request get the version prepended on to them, you do not
16
+ # have to worry about that part of the path. Outside of this, in keeping with
17
+ # the goals of SimpleAWS, everything else should be exactly as you read it in
18
+ # the AWS API docs in the link above.
19
+ #
20
+ # So "GET Distribution List" is
21
+ #
22
+ # cloud_front.get "/distribution"
23
+ #
24
+ # For requests that need extra parameters, use the :params option
25
+ #
26
+ # cloud_front.get "/distribution", :params => {
27
+ # "MaxItems" => 10
28
+ # }
29
+ #
30
+ # Like :params, use :headers to add headers to the request
31
+ #
32
+ # cloud_front.get "/distribution", :headers => {
33
+ # "x-amz-security-token" => "security string"
34
+ # }
35
+ #
36
+ # The details of CloudFront requests are all passed through XML bodies.
37
+ # To make this as simple and painless as possible, this API supports the
38
+ # :xml option to turn a Hash into an XML string
39
+ #
40
+ # cloud_front.post "/distribution", :xml => {
41
+ # :DistributionConfig => {
42
+ # ...
43
+ # }
44
+ # }
45
+ #
46
+ # Do note that this XML building is very simple, does not support attributes,
47
+ # and will only work on Hashes, Arrays, and objects that can be easily #to_s-ed.
48
+ # Anything else will error out or might result in invalid request bodies.
49
+ #
50
+ # If you already have the XML string and just need to give it to the
51
+ # request, you can use :body to set the raw value of the request body:
52
+ #
53
+ # cloud_front.post "/distribution", :body => raw_body_xml
54
+ #
55
+ # All responses are wrapped in an AWS::Response object.
56
+ ##
57
+ class CloudFront < API
58
+ endpoint "cloudfront"
59
+ use_https true
60
+ version "2010-11-01"
61
+
62
+ def initialize(key, secret)
63
+ super(key, secret)
64
+ end
65
+
66
+ [:get, :post, :put, :delete].each do |method|
67
+ define_method(method) do |*args|
68
+ self.call method, *args
69
+ end
70
+ end
71
+
72
+ def call(method, path, options = {})
73
+ request = AWS::Request.new method, self.uri, "/#{self.version}#{path}"
74
+
75
+ (options[:params] || {}).each do |k, v|
76
+ request.params[k] = v
77
+ end
78
+
79
+ (options[:headers] || {}).each do |k, v|
80
+ request.headers[k] = v
81
+ end
82
+
83
+ if xml = options[:xml]
84
+ raise ":xml must be a Hash" unless xml.is_a?(Hash)
85
+
86
+ namespace = "http://cloudfront.amazonaws.com/doc/#{self.version}"
87
+ request.body = AWS::Util.build_xml_from xml, namespace
88
+ request.headers["Content-Type"] = "text/xml"
89
+ else
90
+ request.body = options[:body]
91
+ end
92
+
93
+ connection = AWS::Connection.new
94
+ connection.call finish_and_sign_request(request)
95
+ end
96
+
97
+ protected
98
+
99
+ ##
100
+ # Build and sign the final request, as per the rules here:
101
+ # http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/RESTAuthentication.html
102
+ ##
103
+ def finish_and_sign_request(request)
104
+ request.headers["Date"] = Time.now.utc.httpdate
105
+ request.headers["Authorization"] =
106
+ "AWS #{self.access_key}:#{Base64.encode64(build_signature_for(request)).chomp}"
107
+
108
+ request
109
+ end
110
+
111
+ def build_signature_for(request)
112
+ date = request.headers["x-amz-date"] || request.headers["Date"]
113
+
114
+ OpenSSL::HMAC.digest("sha1", self.secret_key, date)
115
+ end
116
+ end
117
+ end
data/lib/aws/core/util.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'ox'
2
+
1
3
  module AWS
2
4
  ##
3
5
  # Collection of helper methods used in the library
@@ -7,7 +9,7 @@ module AWS
7
9
  ##
8
10
  # Simpler version of ActiveSupport's camelize
9
11
  ##
10
- def self.camelcase(string, lower_first_char = false)
12
+ def camelcase(string, lower_first_char = false)
11
13
  return string if string =~ /[A-Z]/
12
14
 
13
15
  if lower_first_char
@@ -19,7 +21,7 @@ module AWS
19
21
 
20
22
 
21
23
  # AWS URI escaping, as implemented by Fog
22
- def self.uri_escape(string)
24
+ def uri_escape(string)
23
25
  # Quick hack for already escaped string, don't escape again
24
26
  # I don't think any requests require a % in a parameter, but if
25
27
  # there is one I'll need to rethink this
@@ -30,5 +32,52 @@ module AWS
30
32
  }
31
33
  end
32
34
 
35
+ ##
36
+ # Take a hash and build a simple XML string from
37
+ # that Hash. This does not support properties on elements,
38
+ # and is meant for request bodies like what CloudFront expects.
39
+ #
40
+ # The hash body can contain symbols, strings, arrays and hashes
41
+ ##
42
+ def build_xml_from(hash, namespace = nil)
43
+ doc = Ox::Document.new(:version => 1.0, :standalone => true)
44
+
45
+ root_key = hash.keys.first
46
+ root = Ox::Element.new root_key
47
+ root[:xmlns] = namespace if namespace
48
+
49
+ doc << root
50
+
51
+ build_body root, hash[root_key]
52
+
53
+ %|<?xml version="1.0" encoding="UTF-8"?>#{Ox.dump doc}|
54
+ end
55
+
56
+ extend self
57
+
58
+ protected
59
+
60
+ def build_body(parent, hash)
61
+ hash.each do |key, value|
62
+ case value
63
+ when Hash
64
+ node = build_node(key)
65
+ build_body node, value
66
+ parent << node
67
+ when Array
68
+ value.each do |entry|
69
+ build_body parent, {key => entry}
70
+ end
71
+ else
72
+ parent << build_node(key, value)
73
+ end
74
+ end
75
+ end
76
+
77
+ def build_node(key, value = nil)
78
+ child = Ox::Element.new key
79
+ child << value.to_s unless value.nil?
80
+ child
81
+ end
33
82
  end
34
83
  end
data/lib/aws/s3.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'aws/api'
2
- require 'aws/signing/authorization_header'
3
2
 
4
3
  module AWS
5
4
 
@@ -9,7 +8,7 @@ module AWS
9
8
  # http://docs.amazonwebservices.com/AmazonS3/latest/API/Welcome.html
10
9
  #
11
10
  # As S3 is much closer to a RESTful service than the other AWS APIs, all
12
- # calls through this API are done through the four handled HTTP METHODS:
11
+ # calls through this API are done through these five handled HTTP METHODS:
13
12
  # GET, PUT, DELETE, POST and HEAD. When sending a request, follow exactly what
14
13
  # is described in the AWS API docs in the link above.
15
14
  #
@@ -107,8 +106,6 @@ module AWS
107
106
  connection.call finish_and_sign_request(request)
108
107
  end
109
108
 
110
- include Signing::AuthorizationHeader
111
-
112
109
  ##
113
110
  # S3 handles region endpoints a little differently
114
111
  ##
@@ -122,6 +119,39 @@ module AWS
122
119
  @uri
123
120
  end
124
121
 
122
+ protected
123
+
124
+ ##
125
+ # Build and sign the final request, as per the rules here:
126
+ # http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html
127
+ ##
128
+ def finish_and_sign_request(request)
129
+ request.headers["Date"] = Time.now.utc.httpdate
130
+ request.headers["Authorization"] =
131
+ "AWS #{self.access_key}:#{Base64.encode64(build_signature_for(request)).chomp}"
132
+
133
+ request
134
+ end
135
+
136
+ def build_signature_for(request)
137
+ amazon_headers = request.headers.select {|k, v|
138
+ k =~ /^x-amz/i
139
+ }.map {|k, v|
140
+ "#{k.downcase}:#{v}".chomp
141
+ }
142
+
143
+ to_sign = [
144
+ request.method.to_s.upcase,
145
+ request.headers["Content-Md5"] || "",
146
+ request.headers["Content-Type"] || "",
147
+ request.headers["Date"],
148
+ amazon_headers,
149
+ request.path
150
+ ].flatten.join("\n")
151
+
152
+ OpenSSL::HMAC.digest("sha1", self.secret_key, to_sign)
153
+ end
154
+
125
155
  end
126
156
 
127
157
  end
@@ -0,0 +1,52 @@
1
+ $: << File.expand_path("../../lib", __FILE__)
2
+
3
+ require 'aws/cloud_front'
4
+
5
+ ##
6
+ # Expects your Amazon keys to be in the environment, something like
7
+ #
8
+ # export AWS_KEY="KEY"
9
+ # export AWS_SECRET="SECRET"
10
+ ##
11
+
12
+ cloud_front = AWS::CloudFront.new ENV["AWS_KEY"], ENV["AWS_SECRET"]
13
+
14
+ puts "First ten distribution items:", ""
15
+
16
+ cloud_front.get("/distribution", :params => {"MaxItems" => 10}).distribution_summary.each do |d|
17
+ puts "ID: #{d.id}"
18
+ puts "Domain: #{d.domain_name}"
19
+ if d["CustomOrigin"]
20
+ puts "Custom Origin: #{d.custom_origin.inspect}"
21
+ elsif d["S3Origin"]
22
+ puts "S3 Origin: #{d.s3_origin.inspect}"
23
+ end
24
+ puts "Status: #{d.status}"
25
+ puts ""
26
+ end
27
+
28
+ # Leaving this commented out. It works, but you can't quickly
29
+ # delete the new distribution so you'll have to clean up manually
30
+ #
31
+ #puts "", "Creating new test distribution", ""
32
+ #
33
+ #response = cloud_front.post "/distribution", :xml => {
34
+ # "DistributionConfig" => {
35
+ # "CustomOrigin" => {
36
+ # "DNSName" => "cnd.example.com",
37
+ # "HTTPPort" => 80,
38
+ # "OriginProtocolPolicy" => "http-only"
39
+ # },
40
+ # "CallerReference" => "simple_aws_testing_#{rand(100_000)}",
41
+ # "Enabled" => false
42
+ # }
43
+ #}
44
+ #
45
+ #p response
46
+ #
47
+ #id = response.id
48
+ #etag = response.headers["etag"]
49
+ #
50
+ #puts ""
51
+ #puts "Created distribution with id #{id} and etag #{etag}."
52
+ #puts "It's at domain #{response.domain_name}"
data/simple_aws.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "simple_aws"
3
- s.version = "0.0.1c"
3
+ s.version = "0.0.1d"
4
4
  s.platform = Gem::Platform::RUBY
5
5
  s.authors = ["Jason Roelofs"]
6
6
  s.email = ["jameskilton@gmail.com"]
@@ -0,0 +1,109 @@
1
+ require 'test_helper'
2
+ require 'aws/cloud_front'
3
+
4
+ describe AWS::CloudFront do
5
+
6
+ before do
7
+ @api = AWS::CloudFront.new "key", "secret"
8
+ end
9
+
10
+ it "points to the endpoint" do
11
+ @api.uri.must_equal "https://cloudfront.amazonaws.com"
12
+ end
13
+
14
+ it "does not support region selection" do
15
+ lambda {
16
+ AWS::CloudFront.new "key", "secret", "us-east-1"
17
+ }.must_raise ArgumentError
18
+ end
19
+
20
+ it "works with the current version" do
21
+ @api.version.must_equal "2010-11-01"
22
+ end
23
+
24
+ describe "API calls" do
25
+
26
+ [:get, :post, :put, :delete].each do |method|
27
+ it "supports the #{method} HTTP method" do
28
+ AWS::Connection.any_instance.expects(:call).with do |request|
29
+ request.method.must_equal method
30
+ true
31
+ end
32
+
33
+ @api.send method, "/"
34
+ end
35
+ end
36
+
37
+ it "pre-pends the version to the path for every request" do
38
+ AWS::Connection.any_instance.expects(:call).with do |request|
39
+ request.path.must_equal "/2010-11-01/"
40
+ true
41
+ end
42
+
43
+ @api.get "/"
44
+ end
45
+
46
+ it "takes parameters" do
47
+ AWS::Connection.any_instance.expects(:call).with do |request|
48
+ request.params["Parameter1"].must_equal "Value2"
49
+ true
50
+ end
51
+
52
+ @api.get "/", :params => { "Parameter1" => "Value2" }
53
+ end
54
+
55
+ it "takes a raw body" do
56
+ AWS::Connection.any_instance.expects(:call).with do |request|
57
+ request.body.must_equal "This is a body of text"
58
+ true
59
+ end
60
+
61
+ @api.get "/", :body => "This is a body of text"
62
+ end
63
+
64
+ it "uses :xml to take a hash and build XML from it" do
65
+ AWS::Connection.any_instance.expects(:call).with do |request|
66
+ request.headers["Content-Type"].must_equal "text/xml"
67
+ request.body.must_match(/amazonaws\.com\/doc\//)
68
+ request.body.must_match(/<InnerNode>/)
69
+ true
70
+ end
71
+
72
+ @api.get "/", :xml => {:RootNode => { :InnerNode => "Value" } }
73
+ end
74
+
75
+ it "complains if :xml doesn't contain a Hash" do
76
+ error = lambda {
77
+ @api.get "/", :xml => "not a hash"
78
+ }.must_raise RuntimeError
79
+
80
+ error.message.must_match /must be a Hash/
81
+ end
82
+
83
+ it "takes extra headers" do
84
+ AWS::Connection.any_instance.expects(:call).with do |request|
85
+ request.headers["Header14"].must_equal "Out to Lunch"
86
+ true
87
+ end
88
+
89
+ @api.get "/", :headers => { "Header14" => "Out to Lunch" }
90
+ end
91
+
92
+ it "signs the given request according to Version 3 rules" do
93
+ AWS::Connection.any_instance.expects(:call).with do |request|
94
+ request.headers["Authorization"].wont_be_nil
95
+ header = request.headers["Authorization"]
96
+ parts = header.split(":")
97
+
98
+ parts[0].must_equal "AWS key"
99
+ parts[1].wont_be_nil
100
+
101
+ Time.parse(request.headers["Date"]).wont_be_nil
102
+ true
103
+ end.returns
104
+
105
+ @api.get "/"
106
+ end
107
+ end
108
+
109
+ end
@@ -0,0 +1,86 @@
1
+ require 'test_helper'
2
+ require 'aws/core/util'
3
+
4
+ describe AWS::Util do
5
+
6
+ describe "#build_xml_from" do
7
+ it "takes a hash and builds XML" do
8
+ response = AWS::Util.build_xml_from :RootNode => { :InnerNode => "Value" }
9
+
10
+ response.must_equal <<END
11
+ <?xml version="1.0" encoding="UTF-8"?>
12
+ <RootNode>
13
+ <InnerNode>Value</InnerNode>
14
+ </RootNode>
15
+ END
16
+ end
17
+
18
+ it "will add namespace to the root node" do
19
+ response = AWS::Util.build_xml_from(
20
+ {:RootNode => { :InnerNode => "Value" }},
21
+ "http://cloudfront.amazonaws.com/doc/2010-11-01/"
22
+ )
23
+
24
+ response.must_equal <<END
25
+ <?xml version="1.0" encoding="UTF-8"?>
26
+ <RootNode xmlns="http://cloudfront.amazonaws.com/doc/2010-11-01/">
27
+ <InnerNode>Value</InnerNode>
28
+ </RootNode>
29
+ END
30
+ end
31
+
32
+ it "works with arrays of items" do
33
+ response = AWS::Util.build_xml_from(
34
+ {:RootNode => { :InnerNode => ["Value1", "Value2", "Value3"] }}
35
+ )
36
+
37
+ response.must_equal <<END
38
+ <?xml version="1.0" encoding="UTF-8"?>
39
+ <RootNode>
40
+ <InnerNode>Value1</InnerNode>
41
+ <InnerNode>Value2</InnerNode>
42
+ <InnerNode>Value3</InnerNode>
43
+ </RootNode>
44
+ END
45
+ end
46
+
47
+ it "works at any nestedness of hashes" do
48
+ response = AWS::Util.build_xml_from(
49
+ :RootNode => {
50
+ :InnerNode => [
51
+ {:Child => "Value1"},
52
+ {:Child => "Value2"}
53
+ ]
54
+ }
55
+ )
56
+
57
+ response.must_equal <<END
58
+ <?xml version="1.0" encoding="UTF-8"?>
59
+ <RootNode>
60
+ <InnerNode>
61
+ <Child>Value1</Child>
62
+ </InnerNode>
63
+ <InnerNode>
64
+ <Child>Value2</Child>
65
+ </InnerNode>
66
+ </RootNode>
67
+ END
68
+ end
69
+
70
+ it "auto-strings all leaf nodes" do
71
+ response = AWS::Util.build_xml_from(
72
+ :RootNode => { :BoolVal => true, :Number => 12, :BadBool => false }
73
+ )
74
+
75
+ response.must_equal <<END
76
+ <?xml version="1.0" encoding="UTF-8"?>
77
+ <RootNode>
78
+ <BoolVal>true</BoolVal>
79
+ <Number>12</Number>
80
+ <BadBool>false</BadBool>
81
+ </RootNode>
82
+ END
83
+ end
84
+ end
85
+
86
+ end
data/test/aws/s3_test.rb CHANGED
@@ -96,13 +96,20 @@ describe AWS::S3 do
96
96
  @api.get "/", :file => "This is a body of text"
97
97
  end
98
98
 
99
- it "signs the request using the Authorization header" do
99
+ it "signs the given request according to Version 3 rules" do
100
100
  AWS::Connection.any_instance.expects(:call).with do |request|
101
- request.headers["Authorization"].wont_be_nil
101
+ header = request.headers["Authorization"]
102
+ parts = header.split(":")
103
+
104
+ parts[0].must_equal "AWS key"
105
+ parts[1].wont_be_nil
106
+
107
+ Time.parse(request.headers["Date"]).wont_be_nil
102
108
  true
103
- end
109
+ end.returns
104
110
 
105
111
  @api.get "/"
106
112
  end
113
+
107
114
  end
108
115
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_aws
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1c
4
+ version: 0.0.1d
5
5
  prerelease: 5
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-01-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ox
16
- requirement: &70146086124160 !ruby/object:Gem::Requirement
16
+ requirement: &70172190923080 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70146086124160
24
+ version_requirements: *70172190923080
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: httparty
27
- requirement: &70146086123740 !ruby/object:Gem::Requirement
27
+ requirement: &70172190922660 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70146086123740
35
+ version_requirements: *70172190922660
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: httmultiparty
38
- requirement: &70146086123280 !ruby/object:Gem::Requirement
38
+ requirement: &70172190922220 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70146086123280
46
+ version_requirements: *70172190922220
47
47
  description: The simplest and easiest to use and maintain AWS communication library
48
48
  email:
49
49
  - jameskilton@gmail.com
@@ -60,6 +60,7 @@ files:
60
60
  - lib/aws/auto_scaling.rb
61
61
  - lib/aws/call_types/action_param.rb
62
62
  - lib/aws/cloud_formation.rb
63
+ - lib/aws/cloud_front.rb
63
64
  - lib/aws/cloud_watch.rb
64
65
  - lib/aws/core/connection.rb
65
66
  - lib/aws/core/request.rb
@@ -76,11 +77,11 @@ files:
76
77
  - lib/aws/rds.rb
77
78
  - lib/aws/s3.rb
78
79
  - lib/aws/ses.rb
79
- - lib/aws/signing/authorization_header.rb
80
80
  - lib/aws/signing/version2.rb
81
81
  - lib/aws/signing/version3.rb
82
82
  - lib/aws/sns.rb
83
83
  - lib/aws/sqs.rb
84
+ - samples/cloud_front.rb
84
85
  - samples/ec2.rb
85
86
  - samples/elb.rb
86
87
  - samples/iam.rb
@@ -92,10 +93,12 @@ files:
92
93
  - test/aws/auto_scaling_test.rb
93
94
  - test/aws/call_types/action_param_test.rb
94
95
  - test/aws/cloud_formation_test.rb
96
+ - test/aws/cloud_front_test.rb
95
97
  - test/aws/cloud_watch_test.rb
96
98
  - test/aws/core/connection_test.rb
97
99
  - test/aws/core/request_test.rb
98
100
  - test/aws/core/response_test.rb
101
+ - test/aws/core/util_test.rb
99
102
  - test/aws/ec2_test.rb
100
103
  - test/aws/elasti_cache_test.rb
101
104
  - test/aws/elastic_beanstalk_test.rb
@@ -107,7 +110,6 @@ files:
107
110
  - test/aws/rds_test.rb
108
111
  - test/aws/s3_test.rb
109
112
  - test/aws/ses.rb
110
- - test/aws/signing/authorization_header_test.rb
111
113
  - test/aws/signing/version2_test.rb
112
114
  - test/aws/signing/version3.rb
113
115
  - test/aws/sns_test.rb
@@ -142,10 +144,12 @@ test_files:
142
144
  - test/aws/auto_scaling_test.rb
143
145
  - test/aws/call_types/action_param_test.rb
144
146
  - test/aws/cloud_formation_test.rb
147
+ - test/aws/cloud_front_test.rb
145
148
  - test/aws/cloud_watch_test.rb
146
149
  - test/aws/core/connection_test.rb
147
150
  - test/aws/core/request_test.rb
148
151
  - test/aws/core/response_test.rb
152
+ - test/aws/core/util_test.rb
149
153
  - test/aws/ec2_test.rb
150
154
  - test/aws/elasti_cache_test.rb
151
155
  - test/aws/elastic_beanstalk_test.rb
@@ -157,7 +161,6 @@ test_files:
157
161
  - test/aws/rds_test.rb
158
162
  - test/aws/s3_test.rb
159
163
  - test/aws/ses.rb
160
- - test/aws/signing/authorization_header_test.rb
161
164
  - test/aws/signing/version2_test.rb
162
165
  - test/aws/signing/version3.rb
163
166
  - test/aws/sns_test.rb
@@ -1,43 +0,0 @@
1
- require 'openssl'
2
-
3
- module AWS
4
- module Signing
5
- ##
6
- # Implementation of signing using the Authorization header, as used by S3 and CloudFront
7
- ##
8
- module AuthorizationHeader
9
-
10
- ##
11
- # Build and sign the final request, as per the rules here:
12
- # http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html
13
- ##
14
- def finish_and_sign_request(request)
15
- request.headers["Date"] = Time.now.utc.httpdate
16
- request.headers["Authorization"] =
17
- "AWS #{self.access_key}:#{Base64.encode64(build_signature_for(request)).chomp}"
18
-
19
- request
20
- end
21
-
22
- def build_signature_for(request)
23
- amazon_headers = request.headers.select {|k, v|
24
- k =~ /^x-amz/i
25
- }.map {|k, v|
26
- "#{k.downcase}:#{v}".chomp
27
- }
28
-
29
- to_sign = [
30
- request.method.to_s.upcase,
31
- request.headers["Content-Md5"] || "",
32
- request.headers["Content-Type"] || "",
33
- request.headers["Date"],
34
- amazon_headers,
35
- request.path
36
- ].flatten.join("\n")
37
-
38
- OpenSSL::HMAC.digest("sha1", self.secret_key, to_sign)
39
- end
40
-
41
- end
42
- end
43
- end
@@ -1,33 +0,0 @@
1
- require 'test_helper'
2
- require 'aws/api'
3
- require 'aws/call_types/action_param'
4
- require 'aws/signing/authorization_header'
5
-
6
- describe AWS::Signing::AuthorizationHeader do
7
-
8
- class SigningAuthHeaderTestAPI < AWS::API
9
- endpoint "aptest"
10
- version "2011-01-01"
11
- use_https true
12
-
13
- include AWS::CallTypes::ActionParam
14
- include AWS::Signing::AuthorizationHeader
15
- end
16
-
17
- it "signs the given request according to Version 3 rules" do
18
- AWS::Connection.any_instance.expects(:call).with do |request|
19
- header = request.headers["Authorization"]
20
- parts = header.split(":")
21
-
22
- parts[0].must_equal "AWS key"
23
- parts[1].wont_be_nil
24
-
25
- Time.parse(request.headers["Date"]).wont_be_nil
26
- true
27
- end.returns
28
-
29
- obj = SigningAuthHeaderTestAPI.new "key", "secret"
30
- obj.describe_instances
31
- end
32
-
33
- end