oauthenticator 0.1.4 → 1.0.0

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