aws4-nycda 0.0.1

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 (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