oauthenticator 0.1.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,653 @@
1
+ # encoding: utf-8
2
+ proc { |p| $:.unshift(p) unless $:.any? { |lp| File.expand_path(lp) == p } }.call(File.expand_path('.', File.dirname(__FILE__)))
3
+ require 'helper'
4
+
5
+ describe OAuthenticator::SignableRequest do
6
+ let :base_example_initialize_attrs do
7
+ {
8
+ :request_method => 'get',
9
+ :uri => 'http://example.com',
10
+ :media_type => 'text/plain',
11
+ :body => 'hi there',
12
+ }
13
+ end
14
+ let :example_initialize_attrs do
15
+ base_example_initialize_attrs.merge({
16
+ :consumer_key => 'a consumer key',
17
+ :consumer_secret => 'a consumer secret',
18
+ :signature_method => 'PLAINTEXT'
19
+ })
20
+ end
21
+
22
+ def example_request(attributes={})
23
+ OAuthenticator::SignableRequest.new(example_initialize_attrs.reject do |k,_|
24
+ attributes.keys.any? { |ak| ak.to_s == k.to_s }
25
+ end.merge(attributes))
26
+ end
27
+
28
+ def example_signed_request(authorization, attributes={})
29
+ attributes = attributes.merge(:authorization => authorization)
30
+ OAuthenticator::SignableRequest.new(base_example_initialize_attrs.reject do |k,_|
31
+ attributes.keys.any? { |ak| ak.to_s == k.to_s }
32
+ end.merge(attributes))
33
+ end
34
+
35
+ let :rsa_private_key do
36
+ %q(
37
+ -----BEGIN PRIVATE KEY-----
38
+ MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALRiMLAh9iimur8V
39
+ A7qVvdqxevEuUkW4K+2KdMXmnQbG9Aa7k7eBjK1S+0LYmVjPKlJGNXHDGuy5Fw/d
40
+ 7rjVJ0BLB+ubPK8iA/Tw3hLQgXMRRGRXXCn8ikfuQfjUS1uZSatdLB81mydBETlJ
41
+ hI6GH4twrbDJCR2Bwy/XWXgqgGRzAgMBAAECgYBYWVtleUzavkbrPjy0T5FMou8H
42
+ X9u2AC2ry8vD/l7cqedtwMPp9k7TubgNFo+NGvKsl2ynyprOZR1xjQ7WgrgVB+mm
43
+ uScOM/5HVceFuGRDhYTCObE+y1kxRloNYXnx3ei1zbeYLPCHdhxRYW7T0qcynNmw
44
+ rn05/KO2RLjgQNalsQJBANeA3Q4Nugqy4QBUCEC09SqylT2K9FrrItqL2QKc9v0Z
45
+ zO2uwllCbg0dwpVuYPYXYvikNHHg+aCWF+VXsb9rpPsCQQDWR9TT4ORdzoj+Nccn
46
+ qkMsDmzt0EfNaAOwHOmVJ2RVBspPcxt5iN4HI7HNeG6U5YsFBb+/GZbgfBT3kpNG
47
+ WPTpAkBI+gFhjfJvRw38n3g/+UeAkwMI2TJQS4n8+hid0uus3/zOjDySH3XHCUno
48
+ cn1xOJAyZODBo47E+67R4jV1/gzbAkEAklJaspRPXP877NssM5nAZMU0/O/NGCZ+
49
+ 3jPgDUno6WbJn5cqm8MqWhW1xGkImgRk+fkDBquiq4gPiT898jusgQJAd5Zrr6Q8
50
+ AO/0isr/3aa6O6NLQxISLKcPDk2NOccAfS/xOtfOz4sJYM3+Bs4Io9+dZGSDCA54
51
+ Lw03eHTNQghS0A==
52
+ -----END PRIVATE KEY-----
53
+ ).strip.split("\n").map(&:strip).join("\n")
54
+ end
55
+
56
+ describe 'initialize' do
57
+ describe 'default attributes' do
58
+ describe 'with any signature method' do
59
+ OAuthenticator::SignableRequest::SIGNATURE_METHODS.keys.each do |signature_method|
60
+ it("defaults to version 1.0 with #{signature_method}") do
61
+ request = example_request(:signature_method => signature_method)
62
+ assert_equal('1.0', request.protocol_params['oauth_version'])
63
+ end
64
+ it("lets you omit version if you really want to with #{signature_method}") do
65
+ request = example_request(:version => nil, :signature_method => signature_method)
66
+ assert(!request.protocol_params.key?('oauth_version'))
67
+ end
68
+ end
69
+ end
70
+ describe 'not plaintext' do
71
+ it('generates nonces') do
72
+ nonces = 2.times.map do
73
+ example_request(:signature_method => 'HMAC-SHA1').protocol_params['oauth_nonce']
74
+ end
75
+ assert_equal(2, nonces.uniq.compact.size)
76
+ end
77
+ it 'generates timestamp' do
78
+ Timecop.freeze Time.at 1391021695
79
+ request = example_request(:signature_method => 'HMAC-SHA1')
80
+ assert_equal 1391021695.to_s, request.protocol_params['oauth_timestamp']
81
+ end
82
+ end
83
+ describe 'plaintext' do
84
+ it('does not generate nonces') do
85
+ request = example_request(:signature_method => 'PLAINTEXT')
86
+ assert(!request.protocol_params.key?('oauth_nonce'))
87
+ end
88
+ it 'does not generate timestamp' do
89
+ request = example_request(:signature_method => 'PLAINTEXT')
90
+ assert(!request.protocol_params.key?('oauth_timestapm'))
91
+ end
92
+ end
93
+ end
94
+
95
+ it 'accepts string and symbol' do
96
+ initialize_attr_variants = [
97
+ # by string
98
+ example_initialize_attrs.map { |k,v| {k.to_s => v} }.inject({}, &:update),
99
+ # by symbol
100
+ example_initialize_attrs.map { |k,v| {k.to_sym => v} }.inject({}, &:update),
101
+ # random mix
102
+ example_initialize_attrs.map { |k,v| {rand(2) == 0 ? k.to_s : k.to_sym => v} }.inject({}, &:update),
103
+ ]
104
+ authorizations = initialize_attr_variants.map do |attrs|
105
+ OAuthenticator::SignableRequest.new(attrs).authorization
106
+ end
107
+ assert_equal(1, authorizations.uniq.size)
108
+ end
109
+
110
+ it 'checks type' do
111
+ assert_raises(TypeError) { OAuthenticator::SignableRequest.new("hello!") }
112
+ end
113
+
114
+ it 'checks authorization type' do
115
+ assert_raises(TypeError) { example_request(:authorization => "hello!") }
116
+ end
117
+
118
+ it 'does not allow protocol parameters to be specified when authorization is specified' do
119
+ OAuthenticator::SignableRequest::PROTOCOL_PARAM_KEYS.map do |key|
120
+ assert_raises(ArgumentError) do
121
+ example_signed_request({}, key => 'val')
122
+ end
123
+ end
124
+ end
125
+
126
+ describe 'required attributes' do
127
+ it 'complains about missing required params' do
128
+ err = assert_raises(ArgumentError) { OAuthenticator::SignableRequest.new({}) }
129
+ %w(request_method uri media_type body consumer_key signature_method).each do |required|
130
+ assert_match /#{required}/, err.message
131
+ end
132
+ end
133
+ end
134
+ end
135
+
136
+ describe 'the example in 3.1' do
137
+ # a request with attributes from the oauth spec
138
+ def spec_request(attributes={})
139
+ example_request({
140
+ :request_method => 'POST',
141
+ :uri => 'http://example.com/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b',
142
+ :media_type => 'application/x-www-form-urlencoded',
143
+ :body => 'c2&a3=2+q',
144
+ :consumer_key => '9djdj82h48djs9d2',
145
+ :token => 'kkk9d7dh3k39sjv7',
146
+ :consumer_secret => 'j49sk3j29djd',
147
+ :token_secret => 'dh893hdasih9',
148
+ :signature_method => 'HMAC-SHA1',
149
+ :timestamp => '137131201',
150
+ :nonce => '7d8f3e4a',
151
+ :version => nil,
152
+ :realm => "Example",
153
+ })
154
+ end
155
+
156
+ it 'has the same signature base string' do
157
+ spec_signature_base = (
158
+ "POST&http%3A%2F%2Fexample.com%2Frequest&a2%3Dr%2520b%26a3%3D2%2520q" +
159
+ "%26a3%3Da%26b5%3D%253D%25253D%26c%2540%3D%26c2%3D%26oauth_consumer_" +
160
+ "key%3D9djdj82h48djs9d2%26oauth_nonce%3D7d8f3e4a%26oauth_signature_m" +
161
+ "ethod%3DHMAC-SHA1%26oauth_timestamp%3D137131201%26oauth_token%3Dkkk" +
162
+ "9d7dh3k39sjv7"
163
+ )
164
+ assert_equal(spec_signature_base, spec_request.send(:signature_base))
165
+ end
166
+
167
+ it 'has the same normalized parameters' do
168
+ spec_normalized_request_params_string = (
169
+ "a2=r%20b&a3=2%20q&a3=a&b5=%3D%253D&c%40=&c2=&oauth_consumer_key=9dj" +
170
+ "dj82h48djs9d2&oauth_nonce=7d8f3e4a&oauth_signature_method=HMAC-SHA1" +
171
+ "&oauth_timestamp=137131201&oauth_token=kkk9d7dh3k39sjv7"
172
+ )
173
+ assert_equal(spec_normalized_request_params_string, spec_request.send(:normalized_request_params_string))
174
+
175
+ end
176
+
177
+ it 'calculates authorization the same' do
178
+ # a keen observer may note that the signature is different than the one in the actual spec. the spec is
179
+ # in error - see http://www.rfc-editor.org/errata_search.php?rfc=5849
180
+ spec_authorization = OAuthenticator.parse_authorization(%q(OAuth realm="Example",
181
+ oauth_consumer_key="9djdj82h48djs9d2",
182
+ oauth_token="kkk9d7dh3k39sjv7",
183
+ oauth_signature_method="HMAC-SHA1",
184
+ oauth_timestamp="137131201",
185
+ oauth_nonce="7d8f3e4a",
186
+ oauth_signature="r6%2FTJjbCOr97%2F%2BUU0NsvSne7s5g%3D"
187
+ ))
188
+ assert_equal(spec_authorization, spec_request.signed_protocol_params)
189
+ end
190
+ end
191
+
192
+ describe '#authorization' do
193
+ it 'has the parameter name followed by an = and a quoted encoded value' do
194
+ many_characters = %q( !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~Ā)
195
+ authorization = example_request(:consumer_key => many_characters).authorization
196
+ # only alphas, numerics, and -._~ remain unencoded per 3.6
197
+ # hexes are uppercase
198
+ assert authorization.include?(%q(consumer_key="%20%21%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%C4%80"))
199
+ end
200
+
201
+ it 'generally looks like: OAuth key="quoted-value", anotherkey="anothervalue"' do
202
+ assert_equal(%q(OAuth ) +
203
+ %q(oauth_consumer_key="a%20consumer%20key", ) +
204
+ %q(oauth_signature="a%2520consumer%2520secret%26", ) +
205
+ %q(oauth_signature_method="PLAINTEXT", ) +
206
+ %q(oauth_version="1.0"),
207
+ example_request.authorization
208
+ )
209
+ end
210
+ end
211
+
212
+ describe 'signature' do
213
+ describe 'PLAINTEXT' do
214
+ it 'signs with the consumer and token secrets, encoded and &-joined' do
215
+ request = example_request(:token => 'a token', :token_secret => 'a token secret', :signature_method => 'PLAINTEXT')
216
+ assert_equal('a%20consumer%20secret&a%20token%20secret', request.signed_protocol_params['oauth_signature'])
217
+ end
218
+ end
219
+
220
+ describe 'HMAC-SHA1' do
221
+ it 'signs with a HMAC-SHA1 digest of the signature base' do
222
+ request = example_request(
223
+ :token => 'a token',
224
+ :token_secret => 'a token secret',
225
+ :signature_method => 'HMAC-SHA1',
226
+ :nonce => 'a nonce',
227
+ :timestamp => 1397726597,
228
+ :hash_body? => false
229
+ )
230
+ assert_equal('rVKcy4CgAih1kv4HAMGiNnjmUJk=', request.signed_protocol_params['oauth_signature'])
231
+ end
232
+ end
233
+
234
+ describe 'RSA-SHA1' do
235
+ it 'signs with a RSA private key SHA1 signature' do
236
+ request = example_request(
237
+ :consumer_secret => rsa_private_key,
238
+ :token => 'a token',
239
+ :token_secret => 'a token secret',
240
+ :signature_method => 'RSA-SHA1',
241
+ :nonce => 'a nonce',
242
+ :timestamp => 1397726597,
243
+ :hash_body? => false
244
+ )
245
+ assert_equal(
246
+ "s3/TkrCJw54tOpsKUHkoQ9PeH1r4wB2fNb70XC2G1ef7Wb/dwwNUOhtjtpGMSDhmYQHzEPt0dAJ+PgeNs1O5NZJQB5JqdsmrhLS3ZdHx2iucxYvZSuDNi0GxaEepz5VS9rg+y5Gmep60BpAKhX0KGnkMY9HIhomTPSrYidAfDOE=",
247
+ request.signed_protocol_params['oauth_signature']
248
+ )
249
+ end
250
+
251
+ it 'ignores the token secret' do
252
+ request_attrs = {
253
+ :consumer_secret => rsa_private_key,
254
+ :token => 'a token',
255
+ :signature_method => 'RSA-SHA1',
256
+ :nonce => 'a nonce',
257
+ :timestamp => 1397726597,
258
+ }
259
+ request1 = example_request(request_attrs.merge(:token_secret => 'a token secret'))
260
+ request2 = example_request(request_attrs.merge(:token_secret => 'an entirely different token secret'))
261
+ assert_equal(request1.signature, request2.signature)
262
+ assert_equal(request1.authorization, request2.authorization)
263
+ end
264
+
265
+ describe 'with an invalid key' do
266
+ it 'errors' do
267
+ assert_raises(OpenSSL::PKey::RSAError) { example_request(:signature_method => 'RSA-SHA1').signature }
268
+ end
269
+ end
270
+ end
271
+ end
272
+
273
+ describe 'protocol_params' do
274
+ it 'includes given protocol params with an oauth_ prefix' do
275
+ OAuthenticator::SignableRequest::PROTOCOL_PARAM_KEYS.each do |param_key|
276
+ assert_equal(example_request(param_key => 'a value').protocol_params["oauth_#{param_key}"], 'a value')
277
+ end
278
+ end
279
+ it 'does not include a calculated signature' do
280
+ assert !example_request.protocol_params.key?('oauth_signature')
281
+ end
282
+ it 'does include the signature of a given authorization' do
283
+ assert_equal('a signature', example_signed_request('oauth_signature' => 'a signature').protocol_params['oauth_signature'])
284
+ end
285
+ it 'does include unknown parameters of a given authorization' do
286
+ assert_equal('bar', example_signed_request('foo' => 'bar').protocol_params['foo'])
287
+ end
288
+ end
289
+
290
+ describe 'signed_protocol_params' do
291
+ it 'includes a signature' do
292
+ assert_equal 'a%20consumer%20secret&', example_request.signed_protocol_params['oauth_signature']
293
+ end
294
+
295
+ it 'has a different signature than the given authorization if the given authorization is wrong' do
296
+ request = example_signed_request({
297
+ 'oauth_consumer_key' => 'a consumer key',
298
+ 'oauth_signature' => 'wrong%20secret&',
299
+ 'oauth_signature_method' => 'PLAINTEXT',
300
+ },
301
+ {:consumer_secret => 'a consumer secret'}
302
+ )
303
+ refute_equal(
304
+ request.protocol_params['oauth_signature'],
305
+ request.signed_protocol_params['oauth_signature']
306
+ )
307
+ end
308
+ end
309
+
310
+ describe 'uri, per section 3.4.1.2' do
311
+ it 'lowercases scheme and host' do
312
+ [
313
+ 'http://example.com/FooBar',
314
+ 'Http://Example.com/FooBar',
315
+ 'HTTP://EXAMPLE.cOM/FooBar',
316
+ ].each do |uri|
317
+ assert_equal('http://example.com/FooBar', example_request(:uri => uri).send(:base_string_uri))
318
+ end
319
+ end
320
+
321
+ it 'normalizes port' do
322
+ assert_equal('http://example.com/F', example_request(:uri => 'http://example.com/F').send(:base_string_uri))
323
+ assert_equal('http://example.com/F', example_request(:uri => 'http://example.com:80/F').send(:base_string_uri))
324
+ assert_equal('http://example.com:81/F', example_request(:uri => 'http://example.com:81/F').send(:base_string_uri))
325
+ assert_equal('https://example.com/F', example_request(:uri => 'https://example.com/F').send(:base_string_uri))
326
+ assert_equal('https://example.com/F', example_request(:uri => 'https://example.com:443/F').send(:base_string_uri))
327
+ assert_equal('https://example.com:444/F', example_request(:uri => 'https://example.com:444/F').send(:base_string_uri))
328
+ end
329
+
330
+ it 'excludes query and fragment' do
331
+ assert_equal('http://example.com/FooBar', example_request(:uri => 'http://example.com/FooBar?foo=bar#foobar').send(:base_string_uri))
332
+ end
333
+ end
334
+
335
+ it 'accepts string or symbol request methods' do
336
+ {'GET' => [:get, :Get, :GET, 'GeT', 'get'], 'OPTIONS' => [:options, 'Options']}.each do |norm, variants|
337
+ variants.each do |request_method|
338
+ assert_equal(norm, example_request(:request_method => request_method).send(:normalized_request_method))
339
+ end
340
+ end
341
+ end
342
+
343
+ describe 'body' do
344
+ it 'takes a string' do
345
+ assert_equal('abody', example_request(:body => 'abody').send(:read_body))
346
+ end
347
+ it 'takes an IO' do
348
+ assert_equal('abody', example_request(:body => StringIO.new('abody')).send(:read_body))
349
+ end
350
+ it 'takes nil' do
351
+ assert_equal('', example_request(:body => nil).send(:read_body))
352
+ end
353
+ it 'rejects something else' do
354
+ assert_raises(TypeError) { example_request(:body => Object.new).send(:read_body) }
355
+ end
356
+ it 'calculates their authorization the same' do
357
+ request_io_body = example_request(:body => StringIO.new('abody'))
358
+ request_str_body = example_request(:body => 'abody')
359
+ assert_equal(request_io_body.authorization, request_str_body.authorization)
360
+ end
361
+ end
362
+
363
+ describe 'signature_base' do
364
+ it 'includes unrecognized authorization params when calculating signature base' do
365
+ authorization = %q(OAuth realm="Example",
366
+ oauth_foo="bar",
367
+ oauth_consumer_key="9djdj82h48djs9d2",
368
+ oauth_signature_method="HMAC-SHA1",
369
+ oauth_timestamp="137131201",
370
+ oauth_nonce="7d8f3e4a"
371
+ )
372
+ assert(example_signed_request(OAuthenticator.parse_authorization(authorization)).send(:signature_base).include?("oauth_foo%3Dbar"))
373
+ end
374
+
375
+ it 'does include body in a formencoded request' do
376
+ assert(example_request(:media_type => 'application/x-www-form-urlencoded', :body => 'foo=bar').send(:signature_base).include?('foo'))
377
+ end
378
+
379
+ it 'does include body in a formencoded request with alternate capitalization' do
380
+ assert(example_request(:media_type => 'APPLICATION/X-WWW-FORM-URLENCODED', :body => 'foo=bar').send(:signature_base).include?('foo'))
381
+ end
382
+
383
+ it 'does not include body in a non-formencoded request' do
384
+ assert(!example_request(:media_type => 'text/plain', :body => 'foo=bar').send(:signature_base).include?('foo'))
385
+ end
386
+ end
387
+
388
+ describe 'normalized request params' do
389
+ describe 'normalized request params string' do
390
+ # this is effectively tested by #authorization so we won't here
391
+ end
392
+ describe 'protocol params' do
393
+ it 'does not include realm with a new request' do
394
+ request = example_request(:realm => 'everywhere')
395
+ assert(!request.send(:normalized_request_params).any? { |k,v| k.downcase == 'realm' })
396
+ end
397
+ it 'does not include realm with a previously-signed request' do
398
+ request = example_signed_request('realm' => 'somewhere')
399
+ assert(!request.send(:normalized_request_params).any? { |k,v| k.downcase == 'realm' })
400
+ end
401
+ it 'does not include signature' do
402
+ request = example_signed_request('oauth_signature' => 'totallylegit', 'foo' => 'bar')
403
+ assert(!request.send(:normalized_request_params).any? { |k,v| k.downcase == 'oauth_signature' })
404
+ end
405
+ it 'does include all other given params' do
406
+ request = example_signed_request(
407
+ 'realm' => 'somewhere',
408
+ 'foo' => 'bar',
409
+ 'oauth_signature' => 'totallylegit',
410
+ 'oauth_timestamp' => '137131201'
411
+ )
412
+ [['foo', 'bar'], ['oauth_timestamp', '137131201']].each do |pair|
413
+ assert(request.send(:normalized_request_params).include?(pair))
414
+ end
415
+ end
416
+ end
417
+ describe 'query params' do
418
+ it 'goes into normalized request params' do
419
+ request = example_request(:uri => 'http://example.com/?a=b&c=d&e=&f')
420
+ [['a', 'b'], ['c', 'd'], ['e', ''], ['f', nil]].each do |pair|
421
+ assert(request.send(:normalized_request_params).include?(pair))
422
+ end
423
+ end
424
+ it 'is empty with no query' do
425
+ request = example_request(:uri => 'http://example.com/')
426
+ assert_equal([], request.send(:query_params))
427
+ end
428
+ it 'decodes a + sign' do
429
+ request = example_request(:uri => 'http://example.com/?a+key=a+value')
430
+ assert_equal([['a key', 'a value']], request.send(:query_params))
431
+ end
432
+ it 'decodes %-encoded' do
433
+ request = example_request(:uri => 'http://example.com/?a%20key=a%20value')
434
+ assert_equal([['a key', 'a value']], request.send(:query_params))
435
+ end
436
+ it 'includes form encoded keys with an = sign and no value' do
437
+ request = example_request(:uri => 'http://example.com/?a=')
438
+ assert_equal([['a', '']], request.send(:query_params))
439
+ end
440
+ it 'includes form encoded keys with no = sign and no value' do
441
+ request = example_request(:uri => 'http://example.com/?a')
442
+ assert_equal([['a', nil]], request.send(:query_params))
443
+ end
444
+ end
445
+ describe 'entity params' do
446
+ it 'goes into normalized request params' do
447
+ request = example_request(:body => 'a=b&c=d&e=&f', :media_type => 'application/x-www-form-urlencoded')
448
+ [['a', 'b'], ['c', 'd'], ['e', ''], ['f', nil]].each do |pair|
449
+ assert(request.send(:normalized_request_params).include?(pair))
450
+ end
451
+ end
452
+ it 'includes all form encoded params' do
453
+ request = example_request(:body => 'a=b&c=d', :media_type => 'application/x-www-form-urlencoded')
454
+ assert_equal([['a', 'b'], ['c', 'd']], request.send(:entity_params))
455
+ end
456
+ it 'includes no non-form encoded params' do
457
+ request = example_request(:body => 'a=b&c=d', :media_type => 'text/plain')
458
+ assert_equal([], request.send(:entity_params))
459
+ end
460
+ it 'does not parse nested params' do
461
+ request = example_request(:body => 'a[b]=c', :media_type => 'application/x-www-form-urlencoded')
462
+ assert_equal([['a[b]', 'c']], request.send(:entity_params))
463
+ end
464
+ it 'decodes a + sign' do
465
+ request = example_request(:body => 'a+key=a+value', :media_type => 'application/x-www-form-urlencoded')
466
+ assert_equal([['a key', 'a value']], request.send(:entity_params))
467
+ end
468
+ it 'decodes %-encoded keys and values' do
469
+ request = example_request(:body => 'a%20key=a%20value', :media_type => 'application/x-www-form-urlencoded')
470
+ assert_equal([['a key', 'a value']], request.send(:entity_params))
471
+ end
472
+ it 'includes form encoded keys with an = sign and no value' do
473
+ request = example_request(:body => 'a=', :media_type => 'application/x-www-form-urlencoded')
474
+ assert_equal([['a', '']], request.send(:entity_params))
475
+ end
476
+ it 'includes form encoded keys with no = sign and no value' do
477
+ request = example_request(:body => 'a', :media_type => 'application/x-www-form-urlencoded')
478
+ assert_equal([['a', nil]], request.send(:entity_params))
479
+ end
480
+ end
481
+ end
482
+
483
+ describe 'body hash' do
484
+ describe 'default inclusion' do
485
+ it 'includes by default with non-form-encoded and HMAC-SHA1' do
486
+ request = example_request(:media_type => 'text/plain', :body => 'foo=bar', :signature_method => 'HMAC-SHA1')
487
+ assert_equal('L7j0ARXdHmlcviPU+Xzlsftpfu4=', request.protocol_params['oauth_body_hash'])
488
+ end
489
+ it 'includes by default with non-form-encoded and RSA-SHA1' do
490
+ request = example_request(:media_type => 'text/plain', :body => 'foo=bar', :signature_method => 'RSA-SHA1', :consumer_secret => rsa_private_key)
491
+ assert_equal('L7j0ARXdHmlcviPU+Xzlsftpfu4=', request.protocol_params['oauth_body_hash'])
492
+ end
493
+ it 'does not include by default with non-form-encoded and PLAINTEXT' do
494
+ request = example_request(:media_type => 'text/plain', :body => 'foo=bar', :signature_method => 'PLAINTEXT')
495
+ assert(!request.protocol_params.key?('oauth_body_hash'))
496
+ end
497
+ it 'does not include by default with form-encoded and HMAC-SHA1' do
498
+ request = example_request(:media_type => 'application/x-www-form-urlencoded', :body => 'foo=bar', :signature_method => 'HMAC-SHA1')
499
+ assert(!request.protocol_params.key?('oauth_body_hash'))
500
+ end
501
+ it 'does not include by default with form-encoded and RSA-SHA1' do
502
+ request = example_request(:media_type => 'application/x-www-form-urlencoded', :body => 'foo=bar', :signature_method => 'RSA-SHA1', :consumer_secret => rsa_private_key)
503
+ assert(!request.protocol_params.key?('oauth_body_hash'))
504
+ end
505
+ it 'does not include by default with form-encoded and PLAINTEXT' do
506
+ request = example_request(:media_type => 'application/x-www-form-urlencoded', :body => 'foo=bar', :signature_method => 'PLAINTEXT')
507
+ assert(!request.protocol_params.key?('oauth_body_hash'))
508
+ end
509
+ end
510
+ it 'respects the :hash_body? option' do
511
+ attributes = {:media_type => 'text/plain', :body => 'foo=bar', :signature_method => 'HMAC-SHA1'}
512
+ # ensure these would generate the hash by default, without :hash_body?
513
+ assert_equal('L7j0ARXdHmlcviPU+Xzlsftpfu4=', example_request(attributes).protocol_params['oauth_body_hash'])
514
+ assert(!example_request(attributes.merge(:hash_body? => false)).protocol_params.key?('oauth_body_hash'))
515
+ assert_equal('L7j0ARXdHmlcviPU+Xzlsftpfu4=', example_request(attributes.merge(:hash_body? => true)).protocol_params['oauth_body_hash'])
516
+ end
517
+ it 'does not generate a body hash when given a authorization' do
518
+ assert(!example_signed_request({}).protocol_params.key?('oauth_body_hash'))
519
+ end
520
+
521
+ describe '#body_hash' do
522
+ it 'is the same as goes in protocol params when generated' do
523
+ request = example_request(:media_type => 'text/plain', :body => 'foo=bar', :signature_method => 'HMAC-SHA1')
524
+ assert_equal(request.protocol_params['oauth_body_hash'], request.body_hash)
525
+ end
526
+ it 'matches the given protocol params for a valid request' do
527
+ request = example_signed_request(
528
+ {'oauth_body_hash' => 'Lve95gjOVATpfV8EL5X4nxwjKHE=', 'oauth_signature_method' => 'HMAC-SHA1'},
529
+ :body => 'Hello World!', :media_type => 'text/plain'
530
+ )
531
+ assert_equal(request.protocol_params['oauth_body_hash'], request.body_hash)
532
+ end
533
+ it 'is different than the given protocol params for an invalid request' do
534
+ request = example_signed_request(
535
+ {'oauth_body_hash' => 'helloooooo?=', 'oauth_signature_method' => 'HMAC-SHA1'},
536
+ :body => 'Hello World!', :media_type => 'text/plain'
537
+ )
538
+ refute_equal(request.protocol_params['oauth_body_hash'], request.body_hash)
539
+ end
540
+ it 'returns nil for an unsupported signature method' do
541
+ assert_equal(nil, example_request(:signature_method => 'PLAINTEXT').body_hash)
542
+ end
543
+ end
544
+
545
+ describe 'example appendix A1' do
546
+ let :request do
547
+ OAuthenticator::SignableRequest.new({
548
+ :request_method => 'PUT',
549
+ :uri => 'http://www.example.com/resource',
550
+ :media_type => 'text/plain',
551
+ :body => 'Hello World!',
552
+ :signature_method => 'HMAC-SHA1',
553
+ :token => "token",
554
+ :consumer_key => "consumer",
555
+ :timestamp => "1236874236",
556
+ :nonce => "10369470270925",
557
+ })
558
+ end
559
+ it 'has the same oauth body hash' do
560
+ assert_equal('Lve95gjOVATpfV8EL5X4nxwjKHE=', request.signed_protocol_params['oauth_body_hash'])
561
+ end
562
+ it 'has the same signature base' do
563
+ assert_equal(
564
+ %q(PUT&http%3A%2F%2Fwww.example.com%2Fresource&oauth_body_hash%3D) +
565
+ %q(Lve95gjOVATpfV8EL5X4nxwjKHE%253D%26oauth_consumer_key%3Dconsum) +
566
+ %q(er%26oauth_nonce%3D10369470270925%26oauth_signature_method%3DH) +
567
+ %q(MAC-SHA1%26oauth_timestamp%3D1236874236%26oauth_token%3Dtoken%) +
568
+ %q(26oauth_version%3D1.0),
569
+ request.send(:signature_base)
570
+ )
571
+ end
572
+ end
573
+ describe 'example appendix A2' do
574
+ let :request do
575
+ OAuthenticator::SignableRequest.new({
576
+ :request_method => 'GET',
577
+ :uri => 'http://www.example.com/resource',
578
+ :media_type => nil,
579
+ :body => nil,
580
+ :signature_method => 'HMAC-SHA1',
581
+ :token => "token",
582
+ :consumer_key => "consumer",
583
+ :timestamp => "1238395022",
584
+ :nonce => "8628868109991",
585
+ })
586
+ end
587
+ it 'has the same oauth body hash' do
588
+ assert_equal('2jmj7l5rSw0yVb/vlWAYkK/YBwk=', request.signed_protocol_params['oauth_body_hash'])
589
+ end
590
+ it 'has the same signature base' do
591
+ assert_equal(
592
+ %q(GET&http%3A%2F%2Fwww.example.com%2Fresource&oauth_body_hash%3D2jmj7) +
593
+ %q(l5rSw0yVb%252FvlWAYkK%252FYBwk%253D%26oauth_consumer_key%3Dconsumer) +
594
+ %q(%26oauth_nonce%3D8628868109991%26oauth_signature_method%3DHMAC-SHA1) +
595
+ %q(%26oauth_timestamp%3D1238395022%26oauth_token%3Dtoken%26oauth_versi) +
596
+ %q(on%3D1.0),
597
+ request.send(:signature_base)
598
+ )
599
+ end
600
+ end
601
+ end
602
+
603
+ it 'reproduces a successful OAuth example GET (lifted from simple oauth)' do
604
+ request = OAuthenticator::SignableRequest.new(
605
+ :request_method => :get,
606
+ :uri => 'http://photos.example.net/photos',
607
+ :media_type => 'application/x-www-form-urlencoded',
608
+ :body => 'file=vacaction.jpg&size=original',
609
+ :consumer_key => 'dpf43f3p2l4k3l03',
610
+ :consumer_secret => rsa_private_key,
611
+ :nonce => '13917289812797014437',
612
+ :signature_method => 'RSA-SHA1',
613
+ :timestamp => '1196666512'
614
+ )
615
+ expected_protocol_params = {
616
+ "oauth_consumer_key" => "dpf43f3p2l4k3l03",
617
+ "oauth_nonce" => "13917289812797014437",
618
+ "oauth_signature" => "jvTp/wX1TYtByB1m+Pbyo0lnCOLIsyGCH7wke8AUs3BpnwZJtAuEJkvQL2/9n4s5wUmUl4aCI4BwpraNx4RtEXMe5qg5T1LVTGliMRpKasKsW//e+RinhejgCuzoH26dyF8iY2ZZ/5D1ilgeijhV/vBka5twt399mXwaYdCwFYE=",
619
+ "oauth_signature_method" => "RSA-SHA1",
620
+ "oauth_timestamp" => "1196666512",
621
+ "oauth_version" => "1.0",
622
+ }
623
+
624
+ assert_equal(expected_protocol_params, request.signed_protocol_params)
625
+ end
626
+
627
+ it 'reproduces a successful OAuth example GET (lifted from simple oauth)' do
628
+ request = OAuthenticator::SignableRequest.new(
629
+ :request_method => :get,
630
+ :uri => 'http://host.net/resource?name=value',
631
+ :media_type => 'application/x-www-form-urlencoded',
632
+ :body => 'name=value',
633
+ :consumer_key => 'abcd',
634
+ :consumer_secret => 'efgh',
635
+ :token => 'ijkl',
636
+ :token_secret => 'mnop',
637
+ :nonce => 'oLKtec51GQy',
638
+ :signature_method => 'PLAINTEXT',
639
+ :timestamp => '1286977095'
640
+ )
641
+ expected_protocol_params = {
642
+ "oauth_consumer_key" => "abcd",
643
+ "oauth_nonce" => "oLKtec51GQy",
644
+ "oauth_signature" => "efgh&mnop",
645
+ "oauth_signature_method" => "PLAINTEXT",
646
+ "oauth_timestamp" => "1286977095",
647
+ "oauth_token" => "ijkl",
648
+ "oauth_version" => "1.0"
649
+ }
650
+
651
+ assert_equal(expected_protocol_params, request.signed_protocol_params)
652
+ end
653
+ end