jmoses_api-auth 1.0.4

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.
@@ -0,0 +1,407 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "ApiAuth" do
4
+
5
+ describe "generating secret keys" do
6
+
7
+ it "should generate secret keys" do
8
+ ApiAuth.generate_secret_key
9
+ end
10
+
11
+ it "should generate secret keys that are 88 characters" do
12
+ ApiAuth.generate_secret_key.size.should be(88)
13
+ end
14
+
15
+ it "should generate keys that have a Hamming Distance of at least 65" do
16
+ key1 = ApiAuth.generate_secret_key
17
+ key2 = ApiAuth.generate_secret_key
18
+ Amatch::Hamming.new(key1).match(key2).should be > 65
19
+ end
20
+
21
+ end
22
+
23
+ describe "signing requests" do
24
+
25
+ def hmac(secret_key, request)
26
+ canonical_string = ApiAuth::Headers.new(request).canonical_string
27
+ digest = OpenSSL::Digest::Digest.new('sha1')
28
+ ApiAuth.b64_encode(OpenSSL::HMAC.digest(digest, secret_key, canonical_string))
29
+ end
30
+
31
+ before(:all) do
32
+ @access_id = "1044"
33
+ @secret_key = ApiAuth.generate_secret_key
34
+ end
35
+
36
+ describe "with Net::HTTP" do
37
+
38
+ before(:each) do
39
+ @request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
40
+ 'content-type' => 'text/plain',
41
+ 'content-md5' => '1B2M2Y8AsgTpgAmY7PhCfg==',
42
+ 'date' => Time.now.utc.httpdate)
43
+ @signed_request = ApiAuth.sign!(@request, @access_id, @secret_key)
44
+ end
45
+
46
+ it "should return a Net::HTTP object after signing it" do
47
+ ApiAuth.sign!(@request, @access_id, @secret_key).class.to_s.should match("Net::HTTP")
48
+ end
49
+
50
+ describe "md5 header" do
51
+ context "not already provided" do
52
+ it "should calculate for empty string" do
53
+ request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
54
+ 'content-type' => 'text/plain',
55
+ 'date' => "Mon, 23 Jan 1984 03:29:56 GMT")
56
+ signed_request = ApiAuth.sign!(request, @access_id, @secret_key)
57
+ signed_request['Content-MD5'].should == Digest::MD5.base64digest('')
58
+ end
59
+
60
+ it "should calculate for real content" do
61
+ request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
62
+ 'content-type' => 'text/plain',
63
+ 'date' => "Mon, 23 Jan 1984 03:29:56 GMT")
64
+ request.body = "hello\nworld"
65
+ signed_request = ApiAuth.sign!(request, @access_id, @secret_key)
66
+ signed_request['Content-MD5'].should == Digest::MD5.base64digest("hello\nworld")
67
+ end
68
+ end
69
+
70
+ it "should leave the content-md5 alone if provided" do
71
+ @signed_request['Content-MD5'].should == '1B2M2Y8AsgTpgAmY7PhCfg=='
72
+ end
73
+ end
74
+
75
+ it "should sign the request" do
76
+ @signed_request['Authorization'].should == "APIAuth 1044:#{hmac(@secret_key, @request)}"
77
+ end
78
+
79
+ it "should authenticate a valid request" do
80
+ ApiAuth.authentic?(@signed_request, @secret_key).should be_true
81
+ end
82
+
83
+ it "should NOT authenticate a non-valid request" do
84
+ ApiAuth.authentic?(@signed_request, @secret_key+'j').should be_false
85
+ end
86
+
87
+ it "should NOT authenticate a mismatched content-md5 when body has changed" do
88
+ request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
89
+ 'content-type' => 'text/plain',
90
+ 'date' => "Mon, 23 Jan 1984 03:29:56 GMT")
91
+ request.body = "hello\nworld"
92
+ signed_request = ApiAuth.sign!(request, @access_id, @secret_key)
93
+ signed_request.body = "goodbye"
94
+ ApiAuth.authentic?(signed_request, @secret_key).should be_false
95
+ end
96
+
97
+ it "should NOT authenticate an expired request" do
98
+ @request['Date'] = 16.minutes.ago.utc.httpdate
99
+ signed_request = ApiAuth.sign!(@request, @access_id, @secret_key)
100
+ ApiAuth.authentic?(signed_request, @secret_key).should be_false
101
+ end
102
+
103
+ it "should retrieve the access_id" do
104
+ ApiAuth.access_id(@signed_request).should == "1044"
105
+ end
106
+
107
+ end
108
+
109
+ describe "with RestClient" do
110
+
111
+ before(:each) do
112
+ headers = { 'Content-MD5' => "1B2M2Y8AsgTpgAmY7PhCfg==",
113
+ 'Content-Type' => "text/plain",
114
+ 'Date' => Time.now.utc.httpdate }
115
+ @request = RestClient::Request.new(:url => "/resource.xml?foo=bar&bar=foo",
116
+ :headers => headers,
117
+ :method => :put)
118
+ @signed_request = ApiAuth.sign!(@request, @access_id, @secret_key)
119
+ end
120
+
121
+ it "should return a RestClient object after signing it" do
122
+ ApiAuth.sign!(@request, @access_id, @secret_key).class.to_s.should match("RestClient")
123
+ end
124
+
125
+ describe "md5 header" do
126
+ context "not already provided" do
127
+ it "should calculate for empty string" do
128
+ headers = { 'Content-Type' => "text/plain",
129
+ 'Date' => "Mon, 23 Jan 1984 03:29:56 GMT" }
130
+ request = RestClient::Request.new(:url => "/resource.xml?foo=bar&bar=foo",
131
+ :headers => headers,
132
+ :method => :put)
133
+ signed_request = ApiAuth.sign!(request, @access_id, @secret_key)
134
+ signed_request.headers['Content-MD5'].should == Digest::MD5.base64digest('')
135
+ end
136
+
137
+ it "should calculate for real content" do
138
+ headers = { 'Content-Type' => "text/plain",
139
+ 'Date' => "Mon, 23 Jan 1984 03:29:56 GMT" }
140
+ request = RestClient::Request.new(:url => "/resource.xml?foo=bar&bar=foo",
141
+ :headers => headers,
142
+ :method => :put,
143
+ :payload => "hellow\nworld")
144
+ signed_request = ApiAuth.sign!(request, @access_id, @secret_key)
145
+ signed_request.headers['Content-MD5'].should == Digest::MD5.base64digest("hellow\nworld")
146
+ end
147
+ end
148
+
149
+ it "should leave the content-md5 alone if provided" do
150
+ @signed_request.headers['Content-MD5'].should == "1B2M2Y8AsgTpgAmY7PhCfg=="
151
+ end
152
+ end
153
+
154
+ it "should sign the request" do
155
+ @signed_request.headers['Authorization'].should == "APIAuth 1044:#{hmac(@secret_key, @request)}"
156
+ end
157
+
158
+ it "should authenticate a valid request" do
159
+ ApiAuth.authentic?(@signed_request, @secret_key).should be_true
160
+ end
161
+
162
+ it "should NOT authenticate a non-valid request" do
163
+ ApiAuth.authentic?(@signed_request, @secret_key+'j').should be_false
164
+ end
165
+
166
+ it "should NOT authenticate a mismatched content-md5 when body has changed" do
167
+ headers = { 'Content-Type' => "text/plain",
168
+ 'Date' => "Mon, 23 Jan 1984 03:29:56 GMT" }
169
+ request = RestClient::Request.new(:url => "/resource.xml?foo=bar&bar=foo",
170
+ :headers => headers,
171
+ :method => :put,
172
+ :payload => "hello\nworld")
173
+ signed_request = ApiAuth.sign!(request, @access_id, @secret_key)
174
+ signed_request.instance_variable_set("@payload", RestClient::Payload.generate('goodbye'))
175
+ ApiAuth.authentic?(signed_request, @secret_key).should be_false
176
+ end
177
+
178
+ it "should NOT authenticate an expired request" do
179
+ @request.headers['Date'] = 16.minutes.ago.utc.httpdate
180
+ signed_request = ApiAuth.sign!(@request, @access_id, @secret_key)
181
+ ApiAuth.authentic?(signed_request, @secret_key).should be_false
182
+ end
183
+
184
+ it "should retrieve the access_id" do
185
+ ApiAuth.access_id(@signed_request).should == "1044"
186
+ end
187
+
188
+ end
189
+
190
+ describe "with Curb" do
191
+
192
+ before(:each) do
193
+ headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
194
+ 'Content-Type' => "text/plain",
195
+ 'Date' => Time.now.utc.httpdate }
196
+ @request = Curl::Easy.new("/resource.xml?foo=bar&bar=foo") do |curl|
197
+ curl.headers = headers
198
+ end
199
+ @signed_request = ApiAuth.sign!(@request, @access_id, @secret_key)
200
+ end
201
+
202
+ it "should return a Curl::Easy object after signing it" do
203
+ ApiAuth.sign!(@request, @access_id, @secret_key).class.to_s.should match("Curl::Easy")
204
+ end
205
+
206
+ describe "md5 header" do
207
+ it "should not calculate and add the content-md5 header if not provided" do
208
+ headers = { 'Content-Type' => "text/plain",
209
+ 'Date' => "Mon, 23 Jan 1984 03:29:56 GMT" }
210
+ request = Curl::Easy.new("/resource.xml?foo=bar&bar=foo") do |curl|
211
+ curl.headers = headers
212
+ end
213
+ signed_request = ApiAuth.sign!(request, @access_id, @secret_key)
214
+ signed_request.headers['Content-MD5'].should == nil
215
+ end
216
+
217
+ it "should leave the content-md5 alone if provided" do
218
+ @signed_request.headers['Content-MD5'].should == "e59ff97941044f85df5297e1c302d260"
219
+ end
220
+ end
221
+
222
+ it "should sign the request" do
223
+ @signed_request.headers['Authorization'].should == "APIAuth 1044:#{hmac(@secret_key, @request)}"
224
+ end
225
+
226
+ it "should authenticate a valid request" do
227
+ ApiAuth.authentic?(@signed_request, @secret_key).should be_true
228
+ end
229
+
230
+ it "should NOT authenticate a non-valid request" do
231
+ ApiAuth.authentic?(@signed_request, @secret_key+'j').should be_false
232
+ end
233
+
234
+ it "should NOT authenticate an expired request" do
235
+ @request.headers['Date'] = 16.minutes.ago.utc.httpdate
236
+ signed_request = ApiAuth.sign!(@request, @access_id, @secret_key)
237
+ ApiAuth.authentic?(signed_request, @secret_key).should be_false
238
+ end
239
+
240
+ it "should retrieve the access_id" do
241
+ ApiAuth.access_id(@signed_request).should == "1044"
242
+ end
243
+
244
+ end
245
+
246
+ describe "with ActionController" do
247
+
248
+ before(:each) do
249
+ @request = ActionController::Request.new(
250
+ 'PATH_INFO' => '/resource.xml',
251
+ 'QUERY_STRING' => 'foo=bar&bar=foo',
252
+ 'REQUEST_METHOD' => 'PUT',
253
+ 'CONTENT_MD5' => '1B2M2Y8AsgTpgAmY7PhCfg==',
254
+ 'CONTENT_TYPE' => 'text/plain',
255
+ 'HTTP_DATE' => Time.now.utc.httpdate)
256
+ @signed_request = ApiAuth.sign!(@request, @access_id, @secret_key)
257
+ end
258
+
259
+ it "should return a ActionController::Request object after signing it" do
260
+ ApiAuth.sign!(@request, @access_id, @secret_key).class.to_s.should match("ActionController::Request")
261
+ end
262
+
263
+ describe "md5 header" do
264
+ context "not already provided" do
265
+ it "should calculate for empty string" do
266
+ request = ActionController::Request.new(
267
+ 'PATH_INFO' => '/resource.xml',
268
+ 'QUERY_STRING' => 'foo=bar&bar=foo',
269
+ 'REQUEST_METHOD' => 'PUT',
270
+ 'CONTENT_TYPE' => 'text/plain',
271
+ 'HTTP_DATE' => 'Mon, 23 Jan 1984 03:29:56 GMT')
272
+ signed_request = ApiAuth.sign!(request, @access_id, @secret_key)
273
+ signed_request.env['Content-MD5'].should == Digest::MD5.base64digest('')
274
+ end
275
+
276
+ it "should calculate for real content" do
277
+ request = ActionController::Request.new(
278
+ 'PATH_INFO' => '/resource.xml',
279
+ 'QUERY_STRING' => 'foo=bar&bar=foo',
280
+ 'REQUEST_METHOD' => 'PUT',
281
+ 'CONTENT_TYPE' => 'text/plain',
282
+ 'HTTP_DATE' => 'Mon, 23 Jan 1984 03:29:56 GMT',
283
+ 'RAW_POST_DATA' => "hello\nworld")
284
+ signed_request = ApiAuth.sign!(request, @access_id, @secret_key)
285
+ signed_request.env['Content-MD5'].should == Digest::MD5.base64digest("hello\nworld")
286
+ end
287
+
288
+ end
289
+
290
+ it "should leave the content-md5 alone if provided" do
291
+ @signed_request.env['CONTENT_MD5'].should == '1B2M2Y8AsgTpgAmY7PhCfg=='
292
+ end
293
+ end
294
+
295
+ it "should sign the request" do
296
+ @signed_request.env['Authorization'].should == "APIAuth 1044:#{hmac(@secret_key, @request)}"
297
+ end
298
+
299
+ it "should authenticate a valid request" do
300
+ ApiAuth.authentic?(@signed_request, @secret_key).should be_true
301
+ end
302
+
303
+ it "should NOT authenticate a non-valid request" do
304
+ ApiAuth.authentic?(@signed_request, @secret_key+'j').should be_false
305
+ end
306
+
307
+ it "should NOT authenticate a mismatched content-md5 when body has changed" do
308
+ request = ActionController::Request.new(
309
+ 'PATH_INFO' => '/resource.xml',
310
+ 'QUERY_STRING' => 'foo=bar&bar=foo',
311
+ 'REQUEST_METHOD' => 'PUT',
312
+ 'CONTENT_TYPE' => 'text/plain',
313
+ 'HTTP_DATE' => 'Mon, 23 Jan 1984 03:29:56 GMT',
314
+ 'rack.input' => StringIO.new("hello\nworld"))
315
+ signed_request = ApiAuth.sign!(request, @access_id, @secret_key)
316
+ signed_request.instance_variable_get("@env")["rack.input"] = StringIO.new("goodbye")
317
+ ApiAuth.authentic?(signed_request, @secret_key).should be_false
318
+ end
319
+
320
+ it "should NOT authenticate an expired request" do
321
+ @request.env['HTTP_DATE'] = 16.minutes.ago.utc.httpdate
322
+ signed_request = ApiAuth.sign!(@request, @access_id, @secret_key)
323
+ ApiAuth.authentic?(signed_request, @secret_key).should be_false
324
+ end
325
+
326
+ it "should retrieve the access_id" do
327
+ ApiAuth.access_id(@signed_request).should == "1044"
328
+ end
329
+
330
+ end
331
+
332
+ describe "with Rack::Request" do
333
+
334
+ before(:each) do
335
+ headers = { 'Content-MD5' => "1B2M2Y8AsgTpgAmY7PhCfg==",
336
+ 'Content-Type' => "text/plain",
337
+ 'Date' => Time.now.utc.httpdate }
338
+ @request = Rack::Request.new(Rack::MockRequest.env_for("/resource.xml?foo=bar&bar=foo", :method => :put).merge!(headers))
339
+ @signed_request = ApiAuth.sign!(@request, @access_id, @secret_key)
340
+ end
341
+
342
+ it "should return a Rack::Request object after signing it" do
343
+ ApiAuth.sign!(@request, @access_id, @secret_key).class.to_s.should match("Rack::Request")
344
+ end
345
+
346
+ describe "md5 header" do
347
+ context "not already provided" do
348
+ it "should calculate for empty string" do
349
+ headers = { 'Content-Type' => "text/plain",
350
+ 'Date' => "Mon, 23 Jan 1984 03:29:56 GMT" }
351
+ request = Rack::Request.new(Rack::MockRequest.env_for("/resource.xml?foo=bar&bar=foo", :method => :put).merge!(headers))
352
+ signed_request = ApiAuth.sign!(request, @access_id, @secret_key)
353
+ signed_request.env['Content-MD5'].should == Digest::MD5.base64digest('')
354
+ end
355
+
356
+ it "should calculate for real content" do
357
+ headers = { 'Content-Type' => "text/plain",
358
+ 'Date' => "Mon, 23 Jan 1984 03:29:56 GMT" }
359
+ request = Rack::Request.new(Rack::MockRequest.env_for("/resource.xml?foo=bar&bar=foo", :method => :put, :input => "hellow\nworld").merge!(headers))
360
+ signed_request = ApiAuth.sign!(request, @access_id, @secret_key)
361
+ signed_request.env['Content-MD5'].should == Digest::MD5.base64digest("hellow\nworld")
362
+ end
363
+ end
364
+
365
+ it "should leave the content-md5 alone if provided" do
366
+ @signed_request.env['Content-MD5'].should == "1B2M2Y8AsgTpgAmY7PhCfg=="
367
+ end
368
+ end
369
+
370
+ it "should sign the request" do
371
+ @signed_request.env['Authorization'].should == "APIAuth 1044:#{hmac(@secret_key, @request)}"
372
+ end
373
+
374
+ it "should authenticate a valid request" do
375
+ ApiAuth.authentic?(@signed_request, @secret_key).should be_true
376
+ end
377
+
378
+ it "should NOT authenticate a non-valid request" do
379
+ ApiAuth.authentic?(@signed_request, @secret_key+'j').should be_false
380
+ end
381
+
382
+ it "should NOT authenticate a mismatched content-md5 when body has changed" do
383
+ headers = { 'Content-Type' => "text/plain",
384
+ 'Date' => "Mon, 23 Jan 1984 03:29:56 GMT" }
385
+ request = Rack::Request.new(Rack::MockRequest.env_for("/resource.xml?foo=bar&bar=foo", :method => :put, :input => "hellow\nworld").merge!(headers))
386
+ signed_request = ApiAuth.sign!(request, @access_id, @secret_key)
387
+ changed_request = Rack::Request.new(Rack::MockRequest.env_for("/resource.xml?foo=bar&bar=foo", :method => :put, :input => "goodbye").merge!(headers))
388
+ signed_request.env['rack.input'] = changed_request.env['rack.input']
389
+ signed_request.env['CONTENT_LENGTH'] = changed_request.env['CONTENT_LENGTH']
390
+ ApiAuth.authentic?(signed_request, @secret_key).should be_false
391
+ end
392
+
393
+ it "should NOT authenticate an expired request" do
394
+ @request.env['Date'] = 16.minutes.ago.utc.httpdate
395
+ signed_request = ApiAuth.sign!(@request, @access_id, @secret_key)
396
+ ApiAuth.authentic?(signed_request, @secret_key).should be_false
397
+ end
398
+
399
+ it "should retrieve the access_id" do
400
+ ApiAuth.access_id(@signed_request).should == "1044"
401
+ end
402
+
403
+ end
404
+
405
+ end
406
+
407
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,223 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "ApiAuth::Headers" do
4
+
5
+ CANONICAL_STRING = "text/plain,e59ff97941044f85df5297e1c302d260,/resource.xml?foo=bar&bar=foo,Mon, 23 Jan 1984 03:29:56 GMT"
6
+
7
+ describe "with Net::HTTP" do
8
+
9
+ before(:each) do
10
+ @request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
11
+ 'content-type' => 'text/plain',
12
+ 'content-md5' => 'e59ff97941044f85df5297e1c302d260',
13
+ 'date' => "Mon, 23 Jan 1984 03:29:56 GMT")
14
+ @headers = ApiAuth::Headers.new(@request)
15
+ end
16
+
17
+ it "should generate the proper canonical string" do
18
+ @headers.canonical_string.should == CANONICAL_STRING
19
+ end
20
+
21
+ it "should set the authorization header" do
22
+ @headers.sign_header("alpha")
23
+ @headers.authorization_header.should == "alpha"
24
+ end
25
+
26
+ it "should set the DATE header if one is not already present" do
27
+ @request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
28
+ 'content-type' => 'text/plain',
29
+ 'content-md5' => 'e59ff97941044f85df5297e1c302d260')
30
+ ApiAuth.sign!(@request, "some access id", "some secret key")
31
+ @request['DATE'].should_not be_nil
32
+ end
33
+
34
+ it "should not set the DATE header just by asking for the canonical_string" do
35
+ request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
36
+ 'content-type' => 'text/plain',
37
+ 'content-md5' => 'e59ff97941044f85df5297e1c302d260')
38
+ headers = ApiAuth::Headers.new(request)
39
+ headers.canonical_string
40
+ request['DATE'].should be_nil
41
+ end
42
+
43
+ context "md5_mismatch?" do
44
+ it "is false if no md5 header is present" do
45
+ request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
46
+ 'content-type' => 'text/plain')
47
+ headers = ApiAuth::Headers.new(request)
48
+ headers.md5_mismatch?.should be_false
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "with RestClient" do
54
+
55
+ before(:each) do
56
+ headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
57
+ 'Content-Type' => "text/plain",
58
+ 'Date' => "Mon, 23 Jan 1984 03:29:56 GMT" }
59
+ @request = RestClient::Request.new(:url => "/resource.xml?foo=bar&bar=foo",
60
+ :headers => headers,
61
+ :method => :put)
62
+ @headers = ApiAuth::Headers.new(@request)
63
+ end
64
+
65
+ it "should generate the proper canonical string" do
66
+ @headers.canonical_string.should == CANONICAL_STRING
67
+ end
68
+
69
+ it "should set the authorization header" do
70
+ @headers.sign_header("alpha")
71
+ @headers.authorization_header.should == "alpha"
72
+ end
73
+
74
+ it "should set the DATE header if one is not already present" do
75
+ headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
76
+ 'Content-Type' => "text/plain" }
77
+ @request = RestClient::Request.new(:url => "/resource.xml?foo=bar&bar=foo",
78
+ :headers => headers,
79
+ :method => :put)
80
+ ApiAuth.sign!(@request, "some access id", "some secret key")
81
+ @request.headers['DATE'].should_not be_nil
82
+ end
83
+
84
+ it "should not set the DATE header just by asking for the canonical_string" do
85
+ headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
86
+ 'Content-Type' => "text/plain" }
87
+ request = RestClient::Request.new(:url => "/resource.xml?foo=bar&bar=foo",
88
+ :headers => headers,
89
+ :method => :put)
90
+ headers = ApiAuth::Headers.new(request)
91
+ headers.canonical_string
92
+ request.headers['DATE'].should be_nil
93
+ end
94
+ end
95
+
96
+ describe "with Curb" do
97
+
98
+ before(:each) do
99
+ headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
100
+ 'Content-Type' => "text/plain",
101
+ 'Date' => "Mon, 23 Jan 1984 03:29:56 GMT" }
102
+ @request = Curl::Easy.new("/resource.xml?foo=bar&bar=foo") do |curl|
103
+ curl.headers = headers
104
+ end
105
+ @headers = ApiAuth::Headers.new(@request)
106
+ end
107
+
108
+ it "should generate the proper canonical string" do
109
+ @headers.canonical_string.should == CANONICAL_STRING
110
+ end
111
+
112
+ it "should set the authorization header" do
113
+ @headers.sign_header("alpha")
114
+ @headers.authorization_header.should == "alpha"
115
+ end
116
+
117
+ it "should set the DATE header if one is not already present" do
118
+ headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
119
+ 'Content-Type' => "text/plain" }
120
+ @request = Curl::Easy.new("/resource.xml?foo=bar&bar=foo") do |curl|
121
+ curl.headers = headers
122
+ end
123
+ ApiAuth.sign!(@request, "some access id", "some secret key")
124
+ @request.headers['DATE'].should_not be_nil
125
+ end
126
+
127
+ it "should not set the DATE header just by asking for the canonical_string" do
128
+ headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
129
+ 'Content-Type' => "text/plain" }
130
+ request = Curl::Easy.new("/resource.xml?foo=bar&bar=foo") do |curl|
131
+ curl.headers = headers
132
+ end
133
+ headers = ApiAuth::Headers.new(request)
134
+ headers.canonical_string
135
+ request.headers['DATE'].should be_nil
136
+ end
137
+ end
138
+
139
+ describe "with ActionController" do
140
+
141
+ before(:each) do
142
+ @request = ActionController::Request.new(
143
+ 'PATH_INFO' => '/resource.xml',
144
+ 'QUERY_STRING' => 'foo=bar&bar=foo',
145
+ 'REQUEST_METHOD' => 'PUT',
146
+ 'CONTENT_MD5' => 'e59ff97941044f85df5297e1c302d260',
147
+ 'CONTENT_TYPE' => 'text/plain',
148
+ 'HTTP_DATE' => 'Mon, 23 Jan 1984 03:29:56 GMT')
149
+ @headers = ApiAuth::Headers.new(@request)
150
+ end
151
+
152
+ it "should generate the proper canonical string" do
153
+ @headers.canonical_string.should == CANONICAL_STRING
154
+ end
155
+
156
+ it "should set the authorization header" do
157
+ @headers.sign_header("alpha")
158
+ @headers.authorization_header.should == "alpha"
159
+ end
160
+
161
+ it "should set the DATE header if one is not already present" do
162
+ @request = ActionController::Request.new(
163
+ 'PATH_INFO' => '/resource.xml',
164
+ 'QUERY_STRING' => 'foo=bar&bar=foo',
165
+ 'REQUEST_METHOD' => 'PUT',
166
+ 'CONTENT_MD5' => 'e59ff97941044f85df5297e1c302d260',
167
+ 'CONTENT_TYPE' => 'text/plain')
168
+ ApiAuth.sign!(@request, "some access id", "some secret key")
169
+ @request.headers['DATE'].should_not be_nil
170
+ end
171
+
172
+ it "should not set the DATE header just by asking for the canonical_string" do
173
+ request = ActionController::Request.new(
174
+ 'PATH_INFO' => '/resource.xml',
175
+ 'QUERY_STRING' => 'foo=bar&bar=foo',
176
+ 'REQUEST_METHOD' => 'PUT',
177
+ 'CONTENT_MD5' => 'e59ff97941044f85df5297e1c302d260',
178
+ 'CONTENT_TYPE' => 'text/plain')
179
+ headers = ApiAuth::Headers.new(request)
180
+ headers.canonical_string
181
+ request.headers['DATE'].should be_nil
182
+ end
183
+ end
184
+
185
+ describe "with Rack::Request" do
186
+
187
+ before(:each) do
188
+ headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
189
+ 'Content-Type' => "text/plain",
190
+ 'Date' => "Mon, 23 Jan 1984 03:29:56 GMT"
191
+ }
192
+ @request = Rack::Request.new(Rack::MockRequest.env_for("/resource.xml?foo=bar&bar=foo", :method => :put).merge!(headers))
193
+ @headers = ApiAuth::Headers.new(@request)
194
+ end
195
+
196
+ it "should generate the proper canonical string" do
197
+ @headers.canonical_string.should == CANONICAL_STRING
198
+ end
199
+
200
+ it "should set the authorization header" do
201
+ @headers.sign_header("alpha")
202
+ @headers.authorization_header.should == "alpha"
203
+ end
204
+
205
+ it "should set the DATE header if one is not already present" do
206
+ headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
207
+ 'Content-Type' => "text/plain" }
208
+ @request = Rack::Request.new(Rack::MockRequest.env_for("/resource.xml?foo=bar&bar=foo", :method => :put).merge!(headers))
209
+ ApiAuth.sign!(@request, "some access id", "some secret key")
210
+ @request.env['DATE'].should_not be_nil
211
+ end
212
+
213
+ it "should not set the DATE header just by asking for the canonical_string" do
214
+ headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
215
+ 'Content-Type' => "text/plain" }
216
+ request = Rack::Request.new(Rack::MockRequest.env_for("/resource.xml?foo=bar&bar=foo", :method => :put).merge!(headers))
217
+ headers = ApiAuth::Headers.new(request)
218
+ headers.canonical_string
219
+ request.env['DATE'].should be_nil
220
+ end
221
+ end
222
+
223
+ end
@@ -0,0 +1,14 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "ApiAuth::Helpers" do
4
+
5
+ it "should strip the new line character on a Base64 encoding" do
6
+ ApiAuth.b64_encode("some string").should_not match(/\n/)
7
+ end
8
+
9
+ it "should properly upcase a hash's keys" do
10
+ hsh = { "JoE" => "rOOLz" }
11
+ ApiAuth.capitalize_keys(hsh)["JOE"].should == "rOOLz"
12
+ end
13
+
14
+ end