aws4-nycda 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +16 -0
  4. data/Rakefile +9 -0
  5. data/aws4.gemspec +18 -0
  6. data/lib/aws4.rb +3 -0
  7. data/lib/aws4/signer.rb +108 -0
  8. data/lib/aws4/version.rb +3 -0
  9. data/readme.md +47 -0
  10. data/test/benchmark_test.rb +31 -0
  11. data/test/signer_test.rb +256 -0
  12. data/test/suite/get-header-key-duplicate.authz +1 -0
  13. data/test/suite/get-header-key-duplicate.creq +9 -0
  14. data/test/suite/get-header-key-duplicate.req +7 -0
  15. data/test/suite/get-header-key-duplicate.sreq +8 -0
  16. data/test/suite/get-header-key-duplicate.sts +4 -0
  17. data/test/suite/get-header-value-multiline.req +7 -0
  18. data/test/suite/get-header-value-order.authz +1 -0
  19. data/test/suite/get-header-value-order.creq +9 -0
  20. data/test/suite/get-header-value-order.req +8 -0
  21. data/test/suite/get-header-value-order.sreq +9 -0
  22. data/test/suite/get-header-value-order.sts +4 -0
  23. data/test/suite/get-header-value-trim.authz +1 -0
  24. data/test/suite/get-header-value-trim.creq +9 -0
  25. data/test/suite/get-header-value-trim.req +5 -0
  26. data/test/suite/get-header-value-trim.sreq +6 -0
  27. data/test/suite/get-header-value-trim.sts +4 -0
  28. data/test/suite/get-relative-relative.authz +1 -0
  29. data/test/suite/get-relative-relative.creq +8 -0
  30. data/test/suite/get-relative-relative.req +4 -0
  31. data/test/suite/get-relative-relative.sreq +5 -0
  32. data/test/suite/get-relative-relative.sts +4 -0
  33. data/test/suite/get-relative.authz +1 -0
  34. data/test/suite/get-relative.creq +8 -0
  35. data/test/suite/get-relative.req +4 -0
  36. data/test/suite/get-relative.sreq +5 -0
  37. data/test/suite/get-relative.sts +4 -0
  38. data/test/suite/get-slash-dot-slash.authz +1 -0
  39. data/test/suite/get-slash-dot-slash.creq +8 -0
  40. data/test/suite/get-slash-dot-slash.req +4 -0
  41. data/test/suite/get-slash-dot-slash.sreq +5 -0
  42. data/test/suite/get-slash-dot-slash.sts +4 -0
  43. data/test/suite/get-slash-pointless-dot.authz +1 -0
  44. data/test/suite/get-slash-pointless-dot.creq +8 -0
  45. data/test/suite/get-slash-pointless-dot.req +4 -0
  46. data/test/suite/get-slash-pointless-dot.sreq +5 -0
  47. data/test/suite/get-slash-pointless-dot.sts +4 -0
  48. data/test/suite/get-slash.authz +1 -0
  49. data/test/suite/get-slash.creq +8 -0
  50. data/test/suite/get-slash.req +4 -0
  51. data/test/suite/get-slash.sreq +5 -0
  52. data/test/suite/get-slash.sts +4 -0
  53. data/test/suite/get-slashes.authz +1 -0
  54. data/test/suite/get-slashes.creq +8 -0
  55. data/test/suite/get-slashes.req +4 -0
  56. data/test/suite/get-slashes.sreq +5 -0
  57. data/test/suite/get-slashes.sts +4 -0
  58. data/test/suite/get-space.authz +1 -0
  59. data/test/suite/get-space.creq +8 -0
  60. data/test/suite/get-space.req +4 -0
  61. data/test/suite/get-space.sreq +5 -0
  62. data/test/suite/get-space.sts +4 -0
  63. data/test/suite/get-unreserved.authz +1 -0
  64. data/test/suite/get-unreserved.creq +8 -0
  65. data/test/suite/get-unreserved.req +4 -0
  66. data/test/suite/get-unreserved.sreq +5 -0
  67. data/test/suite/get-unreserved.sts +4 -0
  68. data/test/suite/get-utf8.authz +1 -0
  69. data/test/suite/get-utf8.creq +8 -0
  70. data/test/suite/get-utf8.req +4 -0
  71. data/test/suite/get-utf8.sreq +5 -0
  72. data/test/suite/get-utf8.sts +4 -0
  73. data/test/suite/get-vanilla-empty-query-key.authz +1 -0
  74. data/test/suite/get-vanilla-empty-query-key.creq +8 -0
  75. data/test/suite/get-vanilla-empty-query-key.req +4 -0
  76. data/test/suite/get-vanilla-empty-query-key.sreq +5 -0
  77. data/test/suite/get-vanilla-empty-query-key.sts +4 -0
  78. data/test/suite/get-vanilla-query-order-key-case.authz +1 -0
  79. data/test/suite/get-vanilla-query-order-key-case.creq +8 -0
  80. data/test/suite/get-vanilla-query-order-key-case.req +4 -0
  81. data/test/suite/get-vanilla-query-order-key-case.sreq +5 -0
  82. data/test/suite/get-vanilla-query-order-key-case.sts +4 -0
  83. data/test/suite/get-vanilla-query-order-key.authz +1 -0
  84. data/test/suite/get-vanilla-query-order-key.creq +8 -0
  85. data/test/suite/get-vanilla-query-order-key.req +4 -0
  86. data/test/suite/get-vanilla-query-order-key.sreq +5 -0
  87. data/test/suite/get-vanilla-query-order-key.sts +4 -0
  88. data/test/suite/get-vanilla-query-order-value.authz +1 -0
  89. data/test/suite/get-vanilla-query-order-value.creq +8 -0
  90. data/test/suite/get-vanilla-query-order-value.req +4 -0
  91. data/test/suite/get-vanilla-query-order-value.sreq +5 -0
  92. data/test/suite/get-vanilla-query-order-value.sts +4 -0
  93. data/test/suite/get-vanilla-query-unreserved.authz +1 -0
  94. data/test/suite/get-vanilla-query-unreserved.creq +8 -0
  95. data/test/suite/get-vanilla-query-unreserved.req +4 -0
  96. data/test/suite/get-vanilla-query-unreserved.sreq +5 -0
  97. data/test/suite/get-vanilla-query-unreserved.sts +4 -0
  98. data/test/suite/get-vanilla-query.authz +1 -0
  99. data/test/suite/get-vanilla-query.creq +8 -0
  100. data/test/suite/get-vanilla-query.req +4 -0
  101. data/test/suite/get-vanilla-query.sreq +5 -0
  102. data/test/suite/get-vanilla-query.sts +4 -0
  103. data/test/suite/get-vanilla-ut8-query.authz +1 -0
  104. data/test/suite/get-vanilla-ut8-query.creq +8 -0
  105. data/test/suite/get-vanilla-ut8-query.req +4 -0
  106. data/test/suite/get-vanilla-ut8-query.sreq +5 -0
  107. data/test/suite/get-vanilla-ut8-query.sts +4 -0
  108. data/test/suite/get-vanilla.authz +1 -0
  109. data/test/suite/get-vanilla.creq +8 -0
  110. data/test/suite/get-vanilla.req +4 -0
  111. data/test/suite/get-vanilla.sreq +5 -0
  112. data/test/suite/get-vanilla.sts +4 -0
  113. data/test/suite/post-header-key-case.authz +1 -0
  114. data/test/suite/post-header-key-case.creq +8 -0
  115. data/test/suite/post-header-key-case.req +4 -0
  116. data/test/suite/post-header-key-case.sreq +5 -0
  117. data/test/suite/post-header-key-case.sts +4 -0
  118. data/test/suite/post-header-key-sort.authz +1 -0
  119. data/test/suite/post-header-key-sort.creq +9 -0
  120. data/test/suite/post-header-key-sort.req +5 -0
  121. data/test/suite/post-header-key-sort.sreq +6 -0
  122. data/test/suite/post-header-key-sort.sts +4 -0
  123. data/test/suite/post-header-value-case.authz +1 -0
  124. data/test/suite/post-header-value-case.creq +9 -0
  125. data/test/suite/post-header-value-case.req +5 -0
  126. data/test/suite/post-header-value-case.sreq +6 -0
  127. data/test/suite/post-header-value-case.sts +4 -0
  128. data/test/suite/post-vanilla-empty-query-value.authz +1 -0
  129. data/test/suite/post-vanilla-empty-query-value.creq +8 -0
  130. data/test/suite/post-vanilla-empty-query-value.req +4 -0
  131. data/test/suite/post-vanilla-empty-query-value.sreq +5 -0
  132. data/test/suite/post-vanilla-empty-query-value.sts +4 -0
  133. data/test/suite/post-vanilla-query-nonunreserved.authz +1 -0
  134. data/test/suite/post-vanilla-query-nonunreserved.creq +8 -0
  135. data/test/suite/post-vanilla-query-nonunreserved.req +4 -0
  136. data/test/suite/post-vanilla-query-nonunreserved.sreq +5 -0
  137. data/test/suite/post-vanilla-query-nonunreserved.sts +4 -0
  138. data/test/suite/post-vanilla-query-space.authz +1 -0
  139. data/test/suite/post-vanilla-query-space.creq +8 -0
  140. data/test/suite/post-vanilla-query-space.req +4 -0
  141. data/test/suite/post-vanilla-query-space.sreq +5 -0
  142. data/test/suite/post-vanilla-query-space.sts +4 -0
  143. data/test/suite/post-vanilla-query.authz +1 -0
  144. data/test/suite/post-vanilla-query.creq +8 -0
  145. data/test/suite/post-vanilla-query.req +4 -0
  146. data/test/suite/post-vanilla-query.sreq +5 -0
  147. data/test/suite/post-vanilla-query.sts +4 -0
  148. data/test/suite/post-vanilla.authz +1 -0
  149. data/test/suite/post-vanilla.creq +8 -0
  150. data/test/suite/post-vanilla.req +4 -0
  151. data/test/suite/post-vanilla.sreq +5 -0
  152. data/test/suite/post-vanilla.sts +4 -0
  153. data/test/suite/post-x-www-form-urlencoded-parameters.authz +1 -0
  154. data/test/suite/post-x-www-form-urlencoded-parameters.creq +9 -0
  155. data/test/suite/post-x-www-form-urlencoded-parameters.req +6 -0
  156. data/test/suite/post-x-www-form-urlencoded-parameters.sreq +7 -0
  157. data/test/suite/post-x-www-form-urlencoded-parameters.sts +4 -0
  158. data/test/suite/post-x-www-form-urlencoded.authz +1 -0
  159. data/test/suite/post-x-www-form-urlencoded.creq +9 -0
  160. data/test/suite/post-x-www-form-urlencoded.req +6 -0
  161. data/test/suite/post-x-www-form-urlencoded.sreq +7 -0
  162. data/test/suite/post-x-www-form-urlencoded.sts +4 -0
  163. metadata +219 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 24e12aa48af33e56a9676072857f43bde9d9aec7
4
+ data.tar.gz: 0e929a9867e68860b6dc02700b769d9b870a29c8
5
+ SHA512:
6
+ metadata.gz: 2eadc3f496102b842bf4aacd76560ac300486962a94c2fb31f172ef4a6529a195c65333a17af9fd636c4cb59fd3a08ad369b68318c1483130889f88f9517e52c
7
+ data.tar.gz: e4232d2ad6f86e4e89618f49b63ef3e26ae419c87e0029375d31d736ac9627307e3a3e2a3ec21e97d74a4fa557cdbe509cad5f39c80156ed2c561a5b8eeee685
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
@@ -0,0 +1,16 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ aws4 (0.0.2)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ rake (10.0.4)
10
+
11
+ PLATFORMS
12
+ ruby
13
+
14
+ DEPENDENCIES
15
+ aws4!
16
+ rake
@@ -0,0 +1,9 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs.push "lib"
5
+ t.test_files = FileList['test/*_test.rb']
6
+ t.verbose = true
7
+ end
8
+
9
+ task :default => :test
@@ -0,0 +1,18 @@
1
+ require "./lib/aws4/version"
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'aws4-nycda'
5
+ s.version = AWS4::VERSION
6
+ s.summary = "A ruby gem for AWS Signature version 4"
7
+ s.description = "The approach is HTTP library agnostic, so you must supply method, uri, headers, and body"
8
+ s.authors = ["Brandon Keene"]
9
+ s.email = ["bkeene@gmail.com"]
10
+ s.require_path = 'lib'
11
+ s.files = `git ls-files`.split("\n")
12
+ s.test_files = `git ls-files -- {test}/*`.split("\n")
13
+ s.executables = []
14
+ s.homepage = 'http://github.com/cmdrkeene/aws4'
15
+
16
+ s.add_development_dependency "rake"
17
+ end
18
+
@@ -0,0 +1,3 @@
1
+ # AWS4
2
+ require "aws4/version"
3
+ require "aws4/signer"
@@ -0,0 +1,108 @@
1
+ # encoding: UTF-8
2
+ require "openssl"
3
+ require "time"
4
+ require "uri"
5
+ require "pathname"
6
+
7
+ module AWS4
8
+ class Signer
9
+ RFC8601BASIC = "%Y%m%dT%H%M%SZ"
10
+ attr_reader :access_key, :secret_key, :region
11
+ attr_reader :date, :method, :uri, :headers, :body, :service
12
+
13
+ def initialize(config)
14
+ @access_key = config[:access_key] || config["access_key"]
15
+ @secret_key = config[:secret_key] || config["secret_key"]
16
+ @region = config[:region] || config["region"]
17
+ end
18
+
19
+ def sign(method, uri, headers, body, debug = false, b64 = false)
20
+ @method = method.upcase
21
+ @uri = uri
22
+ @headers = headers
23
+ @body = body
24
+ @service = @uri.host.split(".", 2)[0]
25
+ date_header = headers["Date"] || headers["DATE"] || headers["date"]
26
+ @date = (date_header ? Time.parse(date_header) : Time.now).utc.strftime(RFC8601BASIC)
27
+ dump if debug
28
+ signed = headers.dup
29
+ signed['Authorization'] = authorization(headers)
30
+ signed
31
+ end
32
+
33
+ private
34
+
35
+ # def authorization_b64(headers)
36
+ # [
37
+ # "X-Amz-Content-SHA256 Credential=#{Base64.strict_encode64(access_key)}/#{Base64.strict_encode64(credential_string)}",
38
+ # "SignedHeaders=#{headers.keys.map(&:downcase).sort.join(";")}",
39
+ # "Signature=#{Base64.strict_encode64(signature)}"
40
+ # ].join(', ')
41
+ # end
42
+
43
+ def authorization(headers)
44
+ [
45
+ "AWS4-HMAC-SHA256 Credential=#{Base64.strict_encode64(access_key.to_s + '/' + credential_string.to_s}",
46
+ "SignedHeaders=#{headers.keys.map(&:downcase).sort.join(";")}",
47
+ "Signature=#{Base64.strict_encode64(signature)}"
48
+ ].join(', ')
49
+ end
50
+
51
+ def signature
52
+ k_date = hmac("AWS4" + secret_key, date[0,8])
53
+ k_region = hmac(k_date, region)
54
+ k_service = hmac(k_region, service)
55
+ k_credentials = hmac(k_service, "aws4_request")
56
+ hexhmac(k_credentials, string_to_sign)
57
+ end
58
+
59
+ def string_to_sign
60
+ [
61
+ 'AWS4-HMAC-SHA256',
62
+ date,
63
+ credential_string,
64
+ hexdigest(canonical_request)
65
+ ].join("\n")
66
+ end
67
+
68
+ def credential_string
69
+ [
70
+ date[0,8],
71
+ region,
72
+ service,
73
+ "aws4_request"
74
+ ].join("/")
75
+ end
76
+
77
+ def canonical_request
78
+ [
79
+ method,
80
+ Pathname.new(uri.path).cleanpath.to_s,
81
+ uri.query,
82
+ headers.sort.map {|k, v| [k.downcase,v.strip].join(':')}.join("\n") + "\n",
83
+ headers.sort.map {|k, v| k.downcase}.join(";"),
84
+ hexdigest(body || '')
85
+ ].join("\n")
86
+ end
87
+
88
+ def hexdigest(value)
89
+ Digest::SHA256.new.update(value).hexdigest
90
+ end
91
+
92
+ def hmac(key, value)
93
+ OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha256'), key, value)
94
+ end
95
+
96
+ def hexhmac(key, value)
97
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('sha256'), key, value)
98
+ end
99
+
100
+ def dump
101
+ puts "string to sign"
102
+ puts string_to_sign
103
+ puts "canonical_request"
104
+ puts canonical_request
105
+ puts "authorization"
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,3 @@
1
+ module AWS4
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,47 @@
1
+ This gem signs HTTP headers with the AWS4 signature for use with Amazon’s AWS APIs.
2
+
3
+ It is designed to be library agnostic.
4
+
5
+ ## Usage
6
+
7
+ # create a signer
8
+ signer = AWS4::Signer.new(
9
+ access_key: "key",
10
+ secret_key: "secret",
11
+ region: "us-east-1"
12
+ )
13
+
14
+ # build request
15
+ uri = URI("https://dynamodb.us-east-1.amazonaws.com/")
16
+ headers = {
17
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT",
18
+ "Content-Type" => "application/json; charset=utf8"
19
+ }
20
+ body="{}"
21
+
22
+ # sign headers
23
+ headers = signer.sign("POST", uri, headers, body)
24
+
25
+ ## License
26
+
27
+ The MIT License (MIT)
28
+
29
+ Copyright (c) 2013 Brandon Keene
30
+
31
+ Permission is hereby granted, free of charge, to any person obtaining a copy
32
+ of this software and associated documentation files (the "Software"), to deal
33
+ in the Software without restriction, including without limitation the rights
34
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35
+ copies of the Software, and to permit persons to whom the Software is
36
+ furnished to do so, subject to the following conditions:
37
+
38
+ The above copyright notice and this permission notice shall be included in
39
+ all copies or substantial portions of the Software.
40
+
41
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
46
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
47
+ THE SOFTWARE.
@@ -0,0 +1,31 @@
1
+ # encoding: UTF-8
2
+ require 'minitest/spec'
3
+ require 'minitest/autorun'
4
+ require 'aws4/signer'
5
+ require "benchmark"
6
+
7
+ describe "benchmark" do
8
+ it "runs quickly" do
9
+ trials = 10_000
10
+ signer = AWS4::Signer.new(
11
+ access_key: "AKIDEXAMPLE",
12
+ secret_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
13
+ region: "us-east-1",
14
+ host: "host.foo.com"
15
+ )
16
+ uri = URI("http://host.foo.com/")
17
+ headers = {
18
+ "Host" => "host.foo.com",
19
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT",
20
+ "Content-Type" => "application/x-www-form-urlencoded; charset=utf8"
21
+ }
22
+ body = "foo=bar"
23
+
24
+ t = Benchmark.realtime do
25
+ trials.times do
26
+ signed = signer.sign("POST", uri, headers, body)
27
+ end
28
+ end
29
+ puts "#{(trials/t).round(1)} signatures/second (#{((t/trials.to_f)*1000).round(3)}ms/signature)"
30
+ end
31
+ end
@@ -0,0 +1,256 @@
1
+ # encoding: UTF-8
2
+ require 'minitest/spec'
3
+ require 'minitest/autorun'
4
+ require 'aws4/signer'
5
+
6
+ describe AWS4::Signer do
7
+ def signer
8
+ @signer ||= AWS4::Signer.new(
9
+ access_key: "AKIDEXAMPLE",
10
+ secret_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
11
+ region: "us-east-1",
12
+ host: "host.foo.com"
13
+ )
14
+ end
15
+
16
+ it "signs get-vanilla" do
17
+ uri = URI("http://host.foo.com/")
18
+ headers = {
19
+ "Host" => "host.foo.com",
20
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT"
21
+ }
22
+ body = ""
23
+ signed = signer.sign("GET", uri, headers, body)
24
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
25
+ signed["Host"].must_equal("host.foo.com")
26
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470")
27
+ end
28
+
29
+ it "signs get-relative" do
30
+ uri = URI("http://host.foo.com/foo/..")
31
+ headers = {
32
+ "Host" => "host.foo.com",
33
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT"
34
+ }
35
+ body = ""
36
+ signed = signer.sign("GET", uri, headers, body)
37
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
38
+ signed["Host"].must_equal("host.foo.com")
39
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470")
40
+ end
41
+
42
+ it "signs get-relative-relative" do
43
+ uri = URI("http://host.foo.com/foo/bar/../..")
44
+ headers = {
45
+ "Host" => "host.foo.com",
46
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT"
47
+ }
48
+ body = ""
49
+ signed = signer.sign("GET", uri, headers, body)
50
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
51
+ signed["Host"].must_equal("host.foo.com")
52
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470")
53
+ end
54
+
55
+ it "signs get-slash-pointless-dot" do
56
+ uri = URI("http://host.foo.com/./foo")
57
+ headers = {
58
+ "Host" => "host.foo.com",
59
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT"
60
+ }
61
+ body = ""
62
+ signed = signer.sign("GET", uri, headers, body)
63
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
64
+ signed["Host"].must_equal("host.foo.com")
65
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=910e4d6c9abafaf87898e1eb4c929135782ea25bb0279703146455745391e63a")
66
+ end
67
+
68
+ it "signs get-slash" do
69
+ uri = URI("http://host.foo.com//")
70
+ headers = {
71
+ "Host" => "host.foo.com",
72
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT"
73
+ }
74
+ body = ""
75
+ signed = signer.sign("GET", uri, headers, body)
76
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
77
+ signed["Host"].must_equal("host.foo.com")
78
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470")
79
+ end
80
+
81
+ it "signs get-vanilla-empty-query" do
82
+ uri = URI("http://host.foo.com/?foo=bar")
83
+ headers = {
84
+ "Host" => "host.foo.com",
85
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT"
86
+ }
87
+ body = ""
88
+ signed = signer.sign("GET", uri, headers, body)
89
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
90
+ signed["Host"].must_equal("host.foo.com")
91
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=56c054473fd260c13e4e7393eb203662195f5d4a1fada5314b8b52b23f985e9f")
92
+ end
93
+
94
+ it "signs get-unreserved" do
95
+ uri = URI("http://host.foo.com/-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
96
+ headers = {
97
+ "Host" => "host.foo.com",
98
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT"
99
+ }
100
+ body = ""
101
+ signed = signer.sign("GET", uri, headers, body)
102
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
103
+ signed["Host"].must_equal("host.foo.com")
104
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=830cc36d03f0f84e6ee4953fbe701c1c8b71a0372c63af9255aa364dd183281e")
105
+ end
106
+
107
+ it "signs get-header-value-trim" do
108
+ uri = URI("http://host.foo.com/")
109
+ headers = {
110
+ "Host" => "host.foo.com",
111
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT",
112
+ "p" => " phfft "
113
+ }
114
+ body = ""
115
+ signed = signer.sign("POST", uri, headers, body)
116
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
117
+ signed["Host"].must_equal("host.foo.com")
118
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;p, Signature=debf546796015d6f6ded8626f5ce98597c33b47b9164cf6b17b4642036fcb592")
119
+ end
120
+
121
+ it "signs get-vanilla-query-order" do
122
+ uri = URI("http://host.foo.com/?foo=Zoo&foo=aha")
123
+ headers = {
124
+ "Host" => "host.foo.com",
125
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT"
126
+ }
127
+ body = ""
128
+ signed = signer.sign("GET", uri, headers, body)
129
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
130
+ signed["Host"].must_equal("host.foo.com")
131
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=be7148d34ebccdc6423b19085378aa0bee970bdc61d144bd1a8c48c33079ab09")
132
+ end
133
+
134
+ it "signs get-vanilla-query-order-key" do
135
+ uri = URI("http://host.foo.com/?a=foo&b=foo")
136
+ headers = {
137
+ "Host" => "host.foo.com",
138
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT"
139
+ }
140
+ body = ""
141
+ signed = signer.sign("GET", uri, headers, body)
142
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
143
+ signed["Host"].must_equal("host.foo.com")
144
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=0dc122f3b28b831ab48ba65cb47300de53fbe91b577fe113edac383730254a3b")
145
+ end
146
+
147
+ it "signs get-vanilla-utf8-query" do
148
+ uri = URI(URI::encode("http://host.foo.com/?ሴ=bar"))
149
+ headers = {
150
+ "Host" => "host.foo.com",
151
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT"
152
+ }
153
+ body = ""
154
+ signed = signer.sign("GET", uri, headers, body)
155
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
156
+ signed["Host"].must_equal("host.foo.com")
157
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=6fb359e9a05394cc7074e0feb42573a2601abc0c869a953e8c5c12e4e01f1a8c")
158
+ end
159
+
160
+ it "signs post-vanilla" do
161
+ uri = URI("http://host.foo.com/")
162
+ headers = {
163
+ "Host" => "host.foo.com",
164
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT"
165
+ }
166
+ body = ""
167
+ signed = signer.sign("POST", uri, headers, body)
168
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
169
+ signed["Host"].must_equal("host.foo.com")
170
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=22902d79e148b64e7571c3565769328423fe276eae4b26f83afceda9e767f726")
171
+ end
172
+
173
+ it "signs post-vanilla-empty-query-value" do
174
+ uri = URI("http://host.foo.com/?foo=bar")
175
+ headers = {
176
+ "Host" => "host.foo.com",
177
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT"
178
+ }
179
+ body = ""
180
+ signed = signer.sign("POST", uri, headers, body)
181
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
182
+ signed["Host"].must_equal("host.foo.com")
183
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b6e3b79003ce0743a491606ba1035a804593b0efb1e20a11cba83f8c25a57a92")
184
+ end
185
+
186
+ it "signs post-header-key-sort" do
187
+ uri = URI("http://host.foo.com/")
188
+ headers = {
189
+ "Host" => "host.foo.com",
190
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT",
191
+ "ZOO" => "zoobar"
192
+ }
193
+ body = ""
194
+ signed = signer.sign("POST", uri, headers, body)
195
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
196
+ signed["Host"].must_equal("host.foo.com")
197
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;zoo, Signature=b7a95a52518abbca0964a999a880429ab734f35ebbf1235bd79a5de87756dc4a")
198
+ end
199
+
200
+ it "signs post-header-key-case" do
201
+ uri = URI("http://host.foo.com/")
202
+ headers = {
203
+ "Host" => "host.foo.com",
204
+ "DATE" => "Mon, 09 Sep 2011 23:36:00 GMT"
205
+ }
206
+ body = ""
207
+ signed = signer.sign("POST", uri, headers, body)
208
+ signed["DATE"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
209
+ signed["Host"].must_equal("host.foo.com")
210
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=22902d79e148b64e7571c3565769328423fe276eae4b26f83afceda9e767f726")
211
+ end
212
+
213
+ it "signs post-header-value-case" do
214
+ uri = URI("http://host.foo.com/")
215
+ headers = {
216
+ "Host" => "host.foo.com",
217
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT",
218
+ "zoo" => "ZOOBAR"
219
+ }
220
+ body = ""
221
+ signed = signer.sign("POST", uri, headers, body)
222
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
223
+ signed["Host"].must_equal("host.foo.com")
224
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;zoo, Signature=273313af9d0c265c531e11db70bbd653f3ba074c1009239e8559d3987039cad7")
225
+ end
226
+
227
+ it "signs post-x-www-form-urlencoded" do
228
+ uri = URI("http://host.foo.com/")
229
+ headers = {
230
+ "Host" => "host.foo.com",
231
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT",
232
+ "Content-Type" => "application/x-www-form-urlencoded"
233
+ }
234
+ body = "foo=bar"
235
+ signed = signer.sign("POST", uri, headers, body)
236
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
237
+ signed["Host"].must_equal("host.foo.com")
238
+ signed["Content-Type"].must_equal("application/x-www-form-urlencoded")
239
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=content-type;date;host, Signature=5a15b22cf462f047318703b92e6f4f38884e4a7ab7b1d6426ca46a8bd1c26cbc")
240
+ end
241
+
242
+ it "signs post-x-www-form-urlencoded-parameters" do
243
+ uri = URI("http://host.foo.com/")
244
+ headers = {
245
+ "Host" => "host.foo.com",
246
+ "Date" => "Mon, 09 Sep 2011 23:36:00 GMT",
247
+ "Content-Type" => "application/x-www-form-urlencoded; charset=utf8"
248
+ }
249
+ body = "foo=bar"
250
+ signed = signer.sign("POST", uri, headers, body)
251
+ signed["Date"].must_equal("Mon, 09 Sep 2011 23:36:00 GMT")
252
+ signed["Host"].must_equal("host.foo.com")
253
+ signed["Content-Type"].must_equal("application/x-www-form-urlencoded; charset=utf8")
254
+ signed["Authorization"].must_equal("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=content-type;date;host, Signature=b105eb10c6d318d2294de9d49dd8b031b55e3c3fe139f2e637da70511e9e7b71")
255
+ end
256
+ end