rockoauth 0.1.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.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/History.txt +5 -0
  3. data/README.rdoc +422 -0
  4. data/example/README.rdoc +11 -0
  5. data/example/application.rb +158 -0
  6. data/example/config.ru +3 -0
  7. data/example/environment.rb +11 -0
  8. data/example/models/connection.rb +9 -0
  9. data/example/models/note.rb +4 -0
  10. data/example/models/user.rb +5 -0
  11. data/example/public/style.css +78 -0
  12. data/example/schema.rb +22 -0
  13. data/example/views/authorize.erb +28 -0
  14. data/example/views/create_user.erb +3 -0
  15. data/example/views/error.erb +6 -0
  16. data/example/views/home.erb +24 -0
  17. data/example/views/layout.erb +24 -0
  18. data/example/views/login.erb +20 -0
  19. data/example/views/new_client.erb +25 -0
  20. data/example/views/new_user.erb +22 -0
  21. data/example/views/show_client.erb +15 -0
  22. data/lib/rockoauth/model/authorization.rb +132 -0
  23. data/lib/rockoauth/model/client.rb +54 -0
  24. data/lib/rockoauth/model/client_owner.rb +13 -0
  25. data/lib/rockoauth/model/hashing.rb +26 -0
  26. data/lib/rockoauth/model/helpers.rb +14 -0
  27. data/lib/rockoauth/model/resource_owner.rb +22 -0
  28. data/lib/rockoauth/model.rb +38 -0
  29. data/lib/rockoauth/provider/access_token.rb +70 -0
  30. data/lib/rockoauth/provider/authorization.rb +185 -0
  31. data/lib/rockoauth/provider/error.rb +19 -0
  32. data/lib/rockoauth/provider/exchange.rb +225 -0
  33. data/lib/rockoauth/provider.rb +133 -0
  34. data/lib/rockoauth/router.rb +75 -0
  35. data/lib/rockoauth/schema/20120828112156_rockoauth_schema_original_schema.rb +35 -0
  36. data/lib/rockoauth/schema/20121024180930_rockoauth_schema_add_authorization_index.rb +13 -0
  37. data/lib/rockoauth/schema/20121025180447_rockoauth_schema_add_unique_indexes.rb +31 -0
  38. data/lib/rockoauth/schema.rb +25 -0
  39. data/lib/rockoauth.rb +1 -0
  40. data/spec/factories.rb +20 -0
  41. data/spec/request_helpers.rb +62 -0
  42. data/spec/rockoauth/model/authorization_spec.rb +237 -0
  43. data/spec/rockoauth/model/client_spec.rb +44 -0
  44. data/spec/rockoauth/model/helpers_spec.rb +25 -0
  45. data/spec/rockoauth/model/resource_owner_spec.rb +87 -0
  46. data/spec/rockoauth/provider/access_token_spec.rb +138 -0
  47. data/spec/rockoauth/provider/authorization_spec.rb +356 -0
  48. data/spec/rockoauth/provider/exchange_spec.rb +361 -0
  49. data/spec/rockoauth/provider_spec.rb +560 -0
  50. data/spec/spec_helper.rb +80 -0
  51. data/spec/test_app/helper.rb +36 -0
  52. data/spec/test_app/provider/application.rb +67 -0
  53. data/spec/test_app/provider/views/authorize.erb +19 -0
  54. metadata +238 -0
@@ -0,0 +1,560 @@
1
+ require 'spec_helper'
2
+
3
+ describe RockOAuth::Provider do
4
+ include RequestHelpers
5
+
6
+ before(:all) { TestApp::Provider.start(RequestHelpers::SERVER_PORT) }
7
+ after(:all) { TestApp::Provider.stop }
8
+
9
+ let(:params) { { 'response_type' => 'code',
10
+ 'client_id' => @client.client_id,
11
+ 'redirect_uri' => @client.redirect_uri }
12
+ }
13
+
14
+ before do
15
+ @client = Factory(:client, :name => 'Test client')
16
+ @owner = TestApp::User['Bob']
17
+ end
18
+
19
+ describe "access grant request" do
20
+ shared_examples_for "asks for user permission" do
21
+ it "creates an authorization" do
22
+ auth = mock_request(RockOAuth::Provider::Authorization, :client => @client, :params => {}, :scopes => [], :valid? => true)
23
+ expect(RockOAuth::Provider::Authorization).to receive(:new).with(@owner, params, nil).and_return(auth)
24
+ get(params)
25
+ end
26
+
27
+ it "displays an authorization page" do
28
+ response = get(params)
29
+ expect(response.code.to_i).to eq(200)
30
+ expect(response.body).to match(/Do you want to allow Test client/)
31
+ expect(response['Content-Type']).to match(/text\/html/)
32
+ end
33
+ end
34
+
35
+ describe "with valid parameters" do
36
+ it_should_behave_like "asks for user permission"
37
+ end
38
+
39
+ describe "for token requests" do
40
+ before { params['response_type'] = 'token' }
41
+ it_should_behave_like "asks for user permission"
42
+ end
43
+
44
+ describe "for code_and_token requests" do
45
+ before { params['response_type'] = 'code_and_token' }
46
+ it_should_behave_like "asks for user permission"
47
+ end
48
+
49
+ describe "enforcing SSL" do
50
+ before { RockOAuth::Provider.enforce_ssl = true }
51
+
52
+ it "does not allow non-SSL requests" do
53
+ response = get(params)
54
+ validate_response(response, 400, 'WAT')
55
+ end
56
+ end
57
+
58
+ describe "when there is already a pending authorization from the user" do
59
+ before do
60
+ @authorization = create_authorization(
61
+ :owner => @owner,
62
+ :client => @client,
63
+ :code => 'pending_code',
64
+ :scope => 'offline_access')
65
+ end
66
+
67
+ it "immediately redirects with the code" do
68
+ response = get(params)
69
+ expect(response.code.to_i).to eq(302)
70
+ expect(response['location']).to eq('https://client.example.com/cb?code=pending_code')
71
+ end
72
+
73
+ describe "when the client is requesting scopes it already has access to" do
74
+ before { params['scope'] = 'offline_access' }
75
+
76
+ it "immediately redirects with the code" do
77
+ response = get(params)
78
+ expect(response.code.to_i).to eq(302)
79
+ expect(response['location']).to eq('https://client.example.com/cb?code=pending_code&scope=offline_access')
80
+ end
81
+ end
82
+
83
+ describe "when the client is requesting scopes it doesn't have yet" do
84
+ before { params['scope'] = 'wall_publish' }
85
+ it_should_behave_like "asks for user permission"
86
+ end
87
+
88
+ describe "and the authorization does not have a code" do
89
+ before { @authorization.update_attribute(:code, nil) }
90
+
91
+ it "generates a new code and redirects" do
92
+ expect(RockOAuth::Model::Authorization).not_to receive(:create)
93
+ expect(RockOAuth::Model::Authorization).not_to receive(:new)
94
+ expect(RockOAuth).to receive(:random_string).and_return('new_code')
95
+ response = get(params)
96
+ expect(response.code.to_i).to eq(302)
97
+ expect(response['location']).to eq('https://client.example.com/cb?code=new_code')
98
+ end
99
+ end
100
+
101
+ describe "and the authorization is expired" do
102
+ before { @authorization.update_attribute(:expires_at, 2.hours.ago) }
103
+ it_should_behave_like "asks for user permission"
104
+ end
105
+ end
106
+
107
+ describe "when there is already a completed authorization from the user" do
108
+ before do
109
+ @authorization = create_authorization(
110
+ :owner => @owner,
111
+ :client => @client,
112
+ :code => nil,
113
+ :access_token => RockOAuth.hashify('complete_token'))
114
+ end
115
+
116
+ it "immediately redirects with a new code" do
117
+ expect(RockOAuth).to receive(:random_string).and_return('new_code')
118
+ response = get(params)
119
+ expect(response.code.to_i).to eq(302)
120
+ expect(response['location']).to eq('https://client.example.com/cb?code=new_code')
121
+ end
122
+
123
+ describe "for token requests" do
124
+ before { params['response_type'] = 'token' }
125
+
126
+ it "immediately redirects with a new token" do
127
+ expect(RockOAuth).to receive(:random_string).and_return('new_access_token')
128
+ response = get(params)
129
+ expect(response.code.to_i).to eq(302)
130
+ expect(response['location']).to eq('https://client.example.com/cb#access_token=new_access_token')
131
+ end
132
+
133
+ describe "with an invalid client_id" do
134
+ before { params['client_id'] = 'unknown_id' }
135
+
136
+ it "does not generate any new tokens" do
137
+ expect(RockOAuth).not_to receive(:random_string)
138
+ get(params)
139
+ end
140
+ end
141
+ end
142
+
143
+ it "does not create a new Authorization" do
144
+ get(params)
145
+ expect(RockOAuth::Model::Authorization.count).to eq(1)
146
+ end
147
+
148
+ it "keeps the code and access token on the Authorization" do
149
+ get(params)
150
+ authorization = RockOAuth::Model::Authorization.first
151
+ expect(authorization.code).not_to be_nil
152
+ expect(authorization.access_token_hash).not_to be_nil
153
+ end
154
+ end
155
+
156
+ describe "with no parameters" do
157
+ let(:params) { {} }
158
+
159
+ it "renders an error page" do
160
+ response = get(params)
161
+ validate_response(response, 400, 'WAT')
162
+ end
163
+ end
164
+
165
+ describe "with a redirect_uri and no client_id" do
166
+ let(:params) { {'redirect_uri' => 'http://evilsite.com/callback'} }
167
+
168
+ it "renders an error page" do
169
+ response = get(params)
170
+ validate_response(response, 400, 'WAT')
171
+ end
172
+ end
173
+
174
+ describe "with a client_id and a bad redirect_uri" do
175
+ let(:params) { {'redirect_uri' => 'http://evilsite.com/callback',
176
+ 'client_id' => @client.client_id} }
177
+
178
+ it "redirects to the client's registered redirect_uri" do
179
+ response = get(params)
180
+ expect(response.code.to_i).to eq(302)
181
+ expect(response['location']).to eq('https://client.example.com/cb?error=invalid_request&error_description=Missing+required+parameter+response_type')
182
+ end
183
+ end
184
+
185
+ describe "with an invalid request" do
186
+ before { params.delete('response_type') }
187
+
188
+ it "redirects to the client's redirect_uri on error" do
189
+ response = get(params)
190
+ expect(response.code.to_i).to eq(302)
191
+ expect(response['location']).to eq('https://client.example.com/cb?error=invalid_request&error_description=Missing+required+parameter+response_type')
192
+ end
193
+
194
+ describe "with a state parameter" do
195
+ before { params['state'] = "Facebook\nmesses this\nup" }
196
+
197
+ it "redirects to the client, including the state param" do
198
+ response = get(params)
199
+ expect(response.code.to_i).to eq(302)
200
+ expect(response['location']).to eq("https://client.example.com/cb?error=invalid_request&error_description=Missing+required+parameter+response_type&state=Facebook%0Amesses+this%0Aup")
201
+ end
202
+ end
203
+ end
204
+ end
205
+
206
+ describe "authorization confirmation from the user" do
207
+ let(:mock_auth) do
208
+ mock = double RockOAuth::Provider::Authorization,
209
+ :redirect_uri => 'http://example.com/',
210
+ :response_status => 302
211
+
212
+ allow(RockOAuth::Provider::Authorization).to receive(:new).and_return(mock)
213
+ mock
214
+ end
215
+
216
+ describe "without the user's permission" do
217
+ before { params['allow'] = '' }
218
+
219
+ it "does not grant access" do
220
+ expect(mock_auth).to receive(:deny_access!)
221
+ allow_or_deny(params)
222
+ end
223
+
224
+ it "redirects to the client with an error" do
225
+ response = allow_or_deny(params)
226
+ expect(response.code.to_i).to eq(302)
227
+ expect(response['location']).to eq('https://client.example.com/cb?error=access_denied&error_description=The+user+denied+you+access')
228
+ end
229
+ end
230
+
231
+ describe "with valid parameters and user permission" do
232
+ before { allow(RockOAuth).to receive(:random_string).and_return('foo') }
233
+ before { params['allow'] = '1' }
234
+
235
+ describe "for code requests" do
236
+ it "grants access" do
237
+ expect(mock_auth).to receive(:grant_access!)
238
+ allow_or_deny(params)
239
+ end
240
+
241
+ it "redirects to the client with an authorization code" do
242
+ response = allow_or_deny(params)
243
+ expect(response.code.to_i).to eq(302)
244
+ expect(response['location']).to eq('https://client.example.com/cb?code=foo')
245
+ end
246
+
247
+ it "passes the state parameter through" do
248
+ params['state'] = 'illinois'
249
+ response = allow_or_deny(params)
250
+ expect(response.code.to_i).to eq(302)
251
+ expect(response['location']).to eq('https://client.example.com/cb?code=foo&state=illinois')
252
+ end
253
+
254
+ it "passes the scope parameter through" do
255
+ params['scope'] = 'foo bar'
256
+ response = allow_or_deny(params)
257
+ expect(response.code.to_i).to eq(302)
258
+ expect(response['location']).to eq('https://client.example.com/cb?code=foo&scope=foo+bar')
259
+ end
260
+ end
261
+
262
+ describe "for token requests" do
263
+ before { params['response_type'] = 'token' }
264
+
265
+ it "grants access" do
266
+ expect(mock_auth).to receive(:grant_access!)
267
+ allow_or_deny(params)
268
+ end
269
+
270
+ it "redirects to the client with an access token" do
271
+ response = allow_or_deny(params)
272
+ expect(response.code.to_i).to eq(302)
273
+ expect(response['location']).to eq('https://client.example.com/cb#access_token=foo&expires_in=10800')
274
+ end
275
+
276
+ it "passes the state parameter through" do
277
+ params['state'] = 'illinois'
278
+ response = allow_or_deny(params)
279
+ expect(response.code.to_i).to eq(302)
280
+ expect(response['location']).to eq('https://client.example.com/cb#access_token=foo&expires_in=10800&state=illinois')
281
+ end
282
+
283
+ it "passes the scope parameter through" do
284
+ params['scope'] = 'foo bar'
285
+ response = allow_or_deny(params)
286
+ expect(response.code.to_i).to eq(302)
287
+ expect(response['location']).to eq('https://client.example.com/cb#access_token=foo&expires_in=10800&scope=foo+bar')
288
+ end
289
+ end
290
+
291
+ describe "for code_and_token requests" do
292
+ before { params['response_type'] = 'code_and_token' }
293
+
294
+ it "grants access" do
295
+ expect(mock_auth).to receive(:grant_access!)
296
+ allow_or_deny(params)
297
+ end
298
+
299
+ it "redirects to the client with an access token" do
300
+ response = allow_or_deny(params)
301
+ expect(response.code.to_i).to eq(302)
302
+ expect(response['location']).to eq('https://client.example.com/cb?code=foo#access_token=foo&expires_in=10800')
303
+ end
304
+
305
+ it "passes the state parameter through" do
306
+ params['state'] = 'illinois'
307
+ response = allow_or_deny(params)
308
+ expect(response.code.to_i).to eq(302)
309
+ expect(response['location']).to eq('https://client.example.com/cb?code=foo&state=illinois#access_token=foo&expires_in=10800')
310
+ end
311
+
312
+ it "passes the scope parameter through" do
313
+ params['scope'] = 'foo bar'
314
+ response = allow_or_deny(params)
315
+ expect(response.code.to_i).to eq(302)
316
+ expect(response['location']).to eq('https://client.example.com/cb?code=foo#access_token=foo&expires_in=10800&scope=foo+bar')
317
+ end
318
+ end
319
+ end
320
+ end
321
+
322
+ describe "access token request" do
323
+ before do
324
+ @client = Factory(:client)
325
+ @authorization = create_authorization(
326
+ :owner => @owner,
327
+ :client => @client,
328
+ :code => 'a_fake_code',
329
+ :expires_at => 3.hours.from_now)
330
+ end
331
+
332
+ let(:auth_params) { { 'client_id' => @client.client_id,
333
+ 'client_secret' => @client.client_secret }
334
+ }
335
+
336
+ describe "using authorization_code request" do
337
+ let(:query_params) { { 'client_id' => @client.client_id,
338
+ 'grant_type' => 'authorization_code',
339
+ 'code' => @authorization.code,
340
+ 'redirect_uri' => @client.redirect_uri }
341
+ }
342
+
343
+ let(:params) { auth_params.merge(query_params) }
344
+
345
+ describe "with valid parameters" do
346
+ it "does not respond to GET" do
347
+ expect(RockOAuth::Provider::Authorization).not_to receive(:new)
348
+ params.delete('client_secret')
349
+ response = get(params)
350
+ validate_json_response(response, 400,
351
+ 'error' => 'invalid_request',
352
+ 'error_description' => 'Bad request: must be a POST request'
353
+ )
354
+ end
355
+
356
+ it "does not allow client credentials to be passed in the query string" do
357
+ expect(RockOAuth::Provider::Authorization).not_to receive(:new)
358
+ query_string = {'client_id' => params.delete('client_id'), 'client_secret' => params.delete('client_secret')}
359
+ response = post(params, query_string)
360
+ validate_json_response(response, 400,
361
+ 'error' => 'invalid_request',
362
+ 'error_description' => 'Bad request: must not send client credentials in the URI'
363
+ )
364
+ end
365
+
366
+ describe "enforcing SSL" do
367
+ before { RockOAuth::Provider.enforce_ssl = true }
368
+
369
+ it "does not allow non-SSL requests" do
370
+ response = get(params)
371
+ validate_json_response(response, 400,
372
+ 'error' => 'invalid_request',
373
+ 'error_description' => 'Bad request: must make requests using HTTPS'
374
+ )
375
+ end
376
+ end
377
+
378
+ it "creates a Token when using Basic Auth" do
379
+ token = mock_request(RockOAuth::Provider::Exchange, :response_body => 'Hello')
380
+ expect(RockOAuth::Provider::Exchange).to receive(:new).with(@owner, params, nil).and_return(token)
381
+ post_basic_auth(auth_params, query_params)
382
+ end
383
+
384
+ it "creates a Token when passing params in the POST body" do
385
+ token = mock_request(RockOAuth::Provider::Exchange, :response_body => 'Hello')
386
+ expect(RockOAuth::Provider::Exchange).to receive(:new).with(@owner, params, nil).and_return(token)
387
+ post(params)
388
+ end
389
+
390
+ it "returns a successful response" do
391
+ allow(RockOAuth).to receive(:random_string).and_return('random_access_token')
392
+ response = post_basic_auth(auth_params, query_params)
393
+ validate_json_response(response, 200, 'access_token' => 'random_access_token', 'expires_in' => 10800)
394
+ end
395
+
396
+ describe "with a scope parameter" do
397
+ before do
398
+ @authorization.update_attribute(:scope, 'foo bar')
399
+ end
400
+
401
+ it "passes the scope back in the success response" do
402
+ allow(RockOAuth).to receive(:random_string).and_return('random_access_token')
403
+ response = post_basic_auth(auth_params, query_params)
404
+ validate_json_response(response, 200,
405
+ 'access_token' => 'random_access_token',
406
+ 'scope' => 'foo bar',
407
+ 'expires_in' => 10800
408
+ )
409
+ end
410
+ end
411
+ end
412
+
413
+ describe "with invalid parameters" do
414
+ before { query_params.delete('code') }
415
+
416
+ it "returns an error response" do
417
+ response = post_basic_auth(auth_params, query_params)
418
+ validate_json_response(response, 400,
419
+ 'error' => 'invalid_request',
420
+ 'error_description' => 'Missing required parameter code'
421
+ )
422
+ end
423
+ end
424
+
425
+ describe "with mismatched client_id in POST params and Basic Auth params" do
426
+ before { query_params['client_id'] = 'foo' }
427
+
428
+ it "returns an error response" do
429
+ response = post_basic_auth(auth_params, query_params)
430
+ validate_json_response(response, 400,
431
+ 'error' => 'invalid_request',
432
+ 'error_description' => 'Bad request: client_id from Basic Auth and request body do not match'
433
+ )
434
+ end
435
+ end
436
+
437
+ describe "when there is an Authorization with code and token" do
438
+ before do
439
+ @authorization.update_attributes(:code => 'pending_code', :access_token => 'working_token')
440
+ allow(RockOAuth).to receive(:random_string).and_return('random_access_token')
441
+ end
442
+
443
+ it "returns a new access token" do
444
+ response = post(params)
445
+ validate_json_response(response, 200,
446
+ 'access_token' => 'random_access_token',
447
+ 'expires_in' => 10800
448
+ )
449
+ end
450
+
451
+ it "exchanges the code for the new token on the existing Authorization" do
452
+ post(params)
453
+ @authorization.reload
454
+ expect(@authorization.code).to be_nil
455
+ expect(@authorization.access_token_hash).to eq(RockOAuth.hashify('random_access_token'))
456
+ end
457
+ end
458
+ end
459
+ end
460
+
461
+ describe "protected resource request" do
462
+ before do
463
+ @authorization = create_authorization(
464
+ :owner => @owner,
465
+ :client => @client,
466
+ :access_token => 'magic-key',
467
+ :scope => 'profile')
468
+ end
469
+
470
+ shared_examples_for "protected resource" do
471
+ it "creates an AccessToken response" do
472
+ mock_token = double(RockOAuth::Provider::AccessToken)
473
+ expect(mock_token).to receive(:response_headers).and_return({})
474
+ expect(mock_token).to receive(:response_status).and_return(200)
475
+ expect(mock_token).to receive(:valid?).and_return(true)
476
+ expect(RockOAuth::Provider::AccessToken).to receive(:new).with(TestApp::User['Bob'], ['profile'], 'magic-key', nil).and_return(mock_token)
477
+ request('/user_profile', 'oauth_token' => 'magic-key')
478
+ end
479
+
480
+ it "allows access when the key is passed" do
481
+ response = request('/user_profile', 'oauth_token' => 'magic-key')
482
+ expect(JSON.parse(response.body)['data']).to eq('Top secret')
483
+ expect(response.code.to_i).to eq(200)
484
+ end
485
+
486
+ it "blocks access when the wrong key is passed" do
487
+ response = request('/user_profile', 'oauth_token' => 'is-the-password-books')
488
+ expect(JSON.parse(response.body)['data']).to eq('No soup for you')
489
+ expect(response.code.to_i).to eq(401)
490
+ expect(response['WWW-Authenticate']).to eq("OAuth realm='Demo App', error='invalid_token'")
491
+ end
492
+
493
+ it "blocks access when the no key is passed" do
494
+ response = request('/user_profile')
495
+ expect(JSON.parse(response.body)['data']).to eq('No soup for you')
496
+ expect(response.code.to_i).to eq(401)
497
+ expect(response['WWW-Authenticate']).to eq("OAuth realm='Demo App'")
498
+ end
499
+
500
+ describe "enforcing SSL" do
501
+ before { RockOAuth::Provider.enforce_ssl = true }
502
+
503
+ let(:authorization) do
504
+ RockOAuth::Model::Authorization.find_by_access_token_hash(RockOAuth.hashify('magic-key'))
505
+ end
506
+
507
+ it "blocks access when not using HTTPS" do
508
+ response = request('/user_profile', 'oauth_token' => 'magic-key')
509
+ expect(JSON.parse(response.body)['data']).to eq('No soup for you')
510
+ expect(response.code.to_i).to eq(401)
511
+ expect(response['WWW-Authenticate']).to eq("OAuth realm='Demo App', error='invalid_request'")
512
+ end
513
+
514
+ it "destroys the access token since it's been leaked" do
515
+ expect(authorization.access_token_hash).to eq(RockOAuth.hashify('magic-key'))
516
+ request('/user_profile', 'oauth_token' => 'magic-key')
517
+ authorization.reload
518
+ expect(authorization.access_token_hash).to be_nil
519
+ end
520
+
521
+ it "keeps the access token if the wrong key is passed" do
522
+ expect(authorization.access_token_hash).to eq(RockOAuth.hashify('magic-key'))
523
+ request('/user_profile', 'oauth_token' => 'is-the-password-books')
524
+ authorization.reload
525
+ expect(authorization.access_token_hash).to eq(RockOAuth.hashify('magic-key'))
526
+ end
527
+ end
528
+ end
529
+
530
+ describe "for header-based requests" do
531
+ def request(path, params = {})
532
+ access_token = params.delete('oauth_token')
533
+ http = Net::HTTP.new('localhost', RequestHelpers::SERVER_PORT)
534
+ qs = params.map { |k,v| "#{ CGI.escape k.to_s }=#{ CGI.escape v.to_s }" }.join('&')
535
+ header = {'Authorization' => "OAuth #{access_token}"}
536
+ http.request_get(path + '?' + qs, header)
537
+ end
538
+
539
+ it_should_behave_like "protected resource"
540
+ end
541
+
542
+ describe "for GET requests" do
543
+ def request(path, params = {})
544
+ qs = params.map { |k,v| "#{ CGI.escape k.to_s }=#{ CGI.escape v.to_s }" }.join('&')
545
+ uri = URI.parse("http://localhost:#{RequestHelpers::SERVER_PORT}" + path + '?' + qs)
546
+ Net::HTTP.get_response(uri)
547
+ end
548
+
549
+ it_should_behave_like "protected resource"
550
+ end
551
+
552
+ describe "for POST requests" do
553
+ def request(path, params = {})
554
+ Net::HTTP.post_form(URI.parse("http://localhost:#{RequestHelpers::SERVER_PORT}" + path), params)
555
+ end
556
+
557
+ it_should_behave_like "protected resource"
558
+ end
559
+ end
560
+ end
@@ -0,0 +1,80 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'active_record'
5
+
6
+ require 'rockoauth/provider'
7
+
8
+ case ENV['DB']
9
+ when 'mysql'
10
+ ActiveRecord::Base.establish_connection(
11
+ :adapter => 'mysql',
12
+ :host => '127.0.0.1',
13
+ :username => 'root',
14
+ :database => 'oauth2_test')
15
+ when 'postgres'
16
+ ActiveRecord::Base.establish_connection(
17
+ :adapter => 'postgresql',
18
+ :host => '127.0.0.1',
19
+ :username => 'postgres',
20
+ :database => 'oauth2_test')
21
+ else
22
+ dbfile = File.expand_path('../test.sqlite3', __FILE__)
23
+ File.unlink(dbfile) if File.file?(dbfile)
24
+
25
+ ActiveRecord::Base.establish_connection(
26
+ :adapter => 'sqlite3',
27
+ :database => dbfile)
28
+ end
29
+
30
+ require 'logger'
31
+ ActiveRecord::Base.logger = Logger.new(STDERR)
32
+ ActiveRecord::Base.logger.level = Logger::INFO
33
+
34
+ RockOAuth::Model::Schema.up
35
+
36
+ ActiveRecord::Schema.define do |version|
37
+ create_table :users, :force => true do |t|
38
+ t.string :name
39
+ end
40
+ end
41
+
42
+ require 'test_app/provider/application'
43
+ require 'request_helpers'
44
+ require 'factories'
45
+
46
+ require 'thin'
47
+ Thin::Logging.silent = true
48
+ $VERBOSE = nil
49
+
50
+ RSpec.configure do |config|
51
+ # to run only specific specs, add :focus to the spec
52
+ # describe "foo", :focus do
53
+ # OR
54
+ # it "should foo", :focus do
55
+
56
+ config.filter_run :focus => true
57
+ config.run_all_when_everything_filtered = true
58
+
59
+ config.before do
60
+ RockOAuth::Provider.enforce_ssl = false
61
+ time = Time.now
62
+ allow(Time).to receive(:now).and_return time
63
+ end
64
+
65
+ config.after do
66
+ [ RockOAuth::Model::Client,
67
+ RockOAuth::Model::Authorization,
68
+ TestApp::User
69
+
70
+ ].each { |k| k.delete_all }
71
+ end
72
+ end
73
+
74
+ def create_authorization(params)
75
+ RockOAuth::Model::Authorization.__send__(:create) do |authorization|
76
+ params.each do |key, value|
77
+ authorization.__send__ "#{key}=", value
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,36 @@
1
+ module TestApp
2
+
3
+ class User < ActiveRecord::Base
4
+ self.table_name = :users
5
+
6
+ include RockOAuth::Model::ResourceOwner
7
+ include RockOAuth::Model::ClientOwner
8
+
9
+ def self.[](name)
10
+ if respond_to?(:find_or_create_by)
11
+ find_or_create_by(:name => name)
12
+ else
13
+ find_or_create_by_name(name)
14
+ end
15
+ end
16
+ end
17
+
18
+ module Helper
19
+ module RackRunner
20
+ def start(port)
21
+ handler = Rack::Handler.get('thin')
22
+ Thread.new do
23
+ handler.run(new, :Port => port) { |server| @server = server }
24
+ end
25
+ sleep 0.1 until @server
26
+ end
27
+
28
+ def stop
29
+ @server.stop if @server
30
+ @server = nil
31
+ sleep 0.1 while EM.reactor_running?
32
+ end
33
+ end
34
+ end
35
+
36
+ end