jmoses_api-auth 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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