doorkeeper 0.3.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of doorkeeper might be problematic. Click here for more details.

Files changed (92) hide show
  1. data/CHANGELOG.md +13 -0
  2. data/README.md +32 -5
  3. data/app/controllers/doorkeeper/application_controller.rb +4 -11
  4. data/app/controllers/doorkeeper/authorizations_controller.rb +11 -2
  5. data/app/controllers/doorkeeper/tokens_controller.rb +19 -5
  6. data/app/models/doorkeeper/access_grant.rb +1 -8
  7. data/app/models/doorkeeper/access_token.rb +2 -10
  8. data/app/models/doorkeeper/application.rb +4 -0
  9. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  10. data/app/views/doorkeeper/authorizations/new.html.erb +1 -1
  11. data/config/locales/en.yml +3 -0
  12. data/doorkeeper.gemspec +2 -1
  13. data/lib/doorkeeper.rb +23 -3
  14. data/lib/doorkeeper/config.rb +73 -12
  15. data/lib/doorkeeper/doorkeeper_for.rb +1 -1
  16. data/lib/doorkeeper/engine.rb +28 -0
  17. data/lib/doorkeeper/models/scopes.rb +13 -0
  18. data/lib/doorkeeper/oauth/access_token_request.rb +5 -16
  19. data/lib/doorkeeper/oauth/authorization/code.rb +1 -1
  20. data/lib/doorkeeper/oauth/authorization/token.rb +1 -1
  21. data/lib/doorkeeper/oauth/authorization_request.rb +18 -23
  22. data/lib/doorkeeper/oauth/client.rb +27 -0
  23. data/lib/doorkeeper/oauth/client/credentials.rb +21 -0
  24. data/lib/doorkeeper/oauth/client/methods.rb +18 -0
  25. data/lib/doorkeeper/oauth/client_credentials/creator.rb +29 -0
  26. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +35 -0
  27. data/lib/doorkeeper/oauth/client_credentials/response.rb +42 -0
  28. data/lib/doorkeeper/oauth/client_credentials/validation.rb +33 -0
  29. data/lib/doorkeeper/oauth/client_credentials_request.rb +46 -0
  30. data/lib/doorkeeper/oauth/error.rb +9 -0
  31. data/lib/doorkeeper/oauth/error_response.rb +30 -0
  32. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +2 -2
  33. data/lib/doorkeeper/oauth/password_access_token_request.rb +130 -0
  34. data/lib/doorkeeper/oauth/scopes.rb +60 -0
  35. data/lib/doorkeeper/version.rb +1 -1
  36. data/lib/generators/doorkeeper/templates/initializer.rb +10 -5
  37. data/lib/generators/doorkeeper/templates/migration.rb +1 -1
  38. data/script/run_all +11 -0
  39. data/spec/controllers/authorizations_controller_spec.rb +3 -3
  40. data/spec/controllers/protected_resources_controller_spec.rb +7 -0
  41. data/spec/controllers/tokens_controller_spec.rb +1 -1
  42. data/spec/dummy/app/controllers/home_controller.rb +1 -1
  43. data/spec/dummy/app/models/user.rb +9 -0
  44. data/spec/dummy/config/application.rb +2 -0
  45. data/spec/dummy/config/initializers/doorkeeper.rb +12 -5
  46. data/spec/dummy/config/locales/doorkeeper.en.yml +5 -0
  47. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +5 -0
  48. data/spec/dummy/db/migrate/{20111206151426_create_doorkeeper_tables.rb → 20120524202412_create_doorkeeper_tables.rb} +10 -1
  49. data/spec/dummy/db/schema.rb +15 -6
  50. data/spec/lib/config_spec.rb +29 -13
  51. data/spec/lib/models/scopes_spec.rb +32 -0
  52. data/spec/lib/oauth/access_token_request_spec.rb +15 -29
  53. data/spec/lib/oauth/authorization_request_spec.rb +22 -72
  54. data/spec/lib/oauth/client/credentials_spec.rb +47 -0
  55. data/spec/lib/oauth/client/methods_spec.rb +54 -0
  56. data/spec/lib/oauth/client_credentials/creator_spec.rb +47 -0
  57. data/spec/lib/oauth/client_credentials/issuer_spec.rb +57 -0
  58. data/spec/lib/oauth/client_credentials/response_spec.rb +58 -0
  59. data/spec/lib/oauth/client_credentials/validation_spec.rb +29 -0
  60. data/spec/lib/oauth/client_credentials_integration_spec.rb +27 -0
  61. data/spec/lib/oauth/client_credentials_request_spec.rb +60 -0
  62. data/spec/lib/oauth/client_spec.rb +42 -0
  63. data/spec/lib/oauth/error_response_spec.rb +40 -0
  64. data/spec/lib/oauth/error_spec.rb +19 -0
  65. data/spec/lib/oauth/helpers/scope_checker_spec.rb +15 -10
  66. data/spec/lib/oauth/password_access_token_request_spec.rb +152 -0
  67. data/spec/lib/oauth/scopes_spec.rb +115 -0
  68. data/spec/models/doorkeeper/access_grant_spec.rb +0 -15
  69. data/spec/models/doorkeeper/access_token_spec.rb +11 -4
  70. data/spec/requests/applications/authorized_applications_spec.rb +2 -2
  71. data/spec/requests/endpoints/authorization_spec.rb +2 -2
  72. data/spec/requests/endpoints/token_spec.rb +7 -0
  73. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
  74. data/spec/requests/flows/authorization_code_spec.rb +8 -2
  75. data/spec/requests/flows/client_credentials_spec.rb +56 -0
  76. data/spec/requests/flows/password_spec.rb +52 -0
  77. data/spec/requests/flows/skip_authorization_spec.rb +2 -2
  78. data/spec/requests/protected_resources/private_api_spec.rb +9 -2
  79. data/spec/spec_helper_integration.rb +3 -0
  80. data/spec/support/helpers/authorization_request_helper.rb +7 -5
  81. data/spec/support/helpers/model_helper.rb +3 -3
  82. data/spec/support/helpers/request_spec_helper.rb +1 -1
  83. data/spec/support/helpers/url_helper.rb +12 -0
  84. metadata +65 -30
  85. data/lib/doorkeeper/config/scope.rb +0 -11
  86. data/lib/doorkeeper/config/scopes.rb +0 -61
  87. data/lib/doorkeeper/config/scopes_builder.rb +0 -18
  88. data/spec/dummy/config/initializers/inflections.rb +0 -10
  89. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  90. data/spec/lib/config/scope_spec.rb +0 -45
  91. data/spec/lib/config/scopes_builder_spec.rb +0 -27
  92. data/spec/lib/config/scopes_spec.rb +0 -180
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+ require 'active_support/core_ext/string'
3
+ require 'doorkeeper/oauth/client'
4
+
5
+ class Doorkeeper::OAuth::Client
6
+ describe Credentials do
7
+ it 'is blank when any of the credentials is blank' do
8
+ Credentials.new(nil, "something").should be_blank
9
+ Credentials.new("something", nil).should be_blank
10
+ end
11
+
12
+ describe :from_request do
13
+ let(:request) { stub.as_null_object }
14
+
15
+ let(:method) do
16
+ lambda { |request| return 'uid', 'secret' }
17
+ end
18
+
19
+ it 'accepts anything that responds to #call' do
20
+ method.should_receive(:call).with(request)
21
+ Credentials.from_request request, method
22
+ end
23
+
24
+ it 'delegates methods received as symbols to Credentials class' do
25
+ Credentials.should_receive(:from_params).with(request)
26
+ Credentials.from_request request, :from_params
27
+ end
28
+
29
+ it 'stops at the first credentials found' do
30
+ not_called_method = mock
31
+ not_called_method.should_not_receive(:call)
32
+ credentials = Credentials.from_request request, lambda { |r| }, method, not_called_method
33
+ end
34
+
35
+ it 'returns new Credentials' do
36
+ credentials = Credentials.from_request request, method
37
+ credentials.should be_a(Credentials)
38
+ end
39
+
40
+ it 'returns uid and secret from extractor method' do
41
+ credentials = Credentials.from_request request, method
42
+ credentials.uid.should == 'uid'
43
+ credentials.secret.should == 'secret'
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+ require 'active_support/core_ext/string'
3
+ require 'doorkeeper/oauth/client'
4
+
5
+ class Doorkeeper::OAuth::Client
6
+ describe 'Methods' do
7
+ let(:client_id) { "some-uid" }
8
+ let(:client_secret) { "some-secret" }
9
+
10
+ subject do
11
+ Class.new do
12
+ include Methods
13
+ end.new
14
+ end
15
+
16
+ describe :from_params do
17
+ it 'returns credentials from parameters when Authorization header is not available' do
18
+ request = stub :parameters => { :client_id => client_id, :client_secret => client_secret }
19
+ uid, secret = subject.from_params(request)
20
+
21
+ uid.should == "some-uid"
22
+ secret.should == "some-secret"
23
+ end
24
+
25
+ it 'is blank when there are no credentials' do
26
+ request = stub :parameters => {}
27
+ uid, secret = subject.from_params(request)
28
+
29
+ uid.should be_blank
30
+ secret.should be_blank
31
+ end
32
+ end
33
+
34
+ describe :from_basic do
35
+ let(:credentials) { Base64.encode64("#{client_id}:#{client_secret}") }
36
+
37
+ it 'decodes the credentials' do
38
+ request = stub :authorization => "Basic #{credentials}"
39
+ uid, secret = subject.from_basic(request)
40
+
41
+ uid.should == "some-uid"
42
+ secret.should == "some-secret"
43
+ end
44
+
45
+ it 'is blank if Authorization is not Basic' do
46
+ request = stub :authorization => "#{credentials}"
47
+ uid, secret = subject.from_basic(request)
48
+
49
+ uid.should be_blank
50
+ secret.should be_blank
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper_integration'
2
+
3
+ class Doorkeeper::OAuth::ClientCredentialsRequest
4
+ describe Creator do
5
+ let(:client) { FactoryGirl.create :application }
6
+ let(:scopes) { Doorkeeper::OAuth::Scopes.from_string('public') }
7
+
8
+ it 'creates a new token' do
9
+ expect do
10
+ subject.call(client, scopes)
11
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
12
+ end
13
+
14
+ it 'returns false if creation fails' do
15
+ Doorkeeper::AccessToken.should_receive(:create).and_return(false)
16
+ created = subject.call(client, scopes)
17
+ created.should be_false
18
+ end
19
+
20
+ it 'does not create a new token if there is an accessible one' do
21
+ subject.call(client, scopes, :expires_in => 10.years)
22
+ expect do
23
+ subject.call(client, scopes)
24
+ end.to_not change { Doorkeeper::AccessToken.count }
25
+ end
26
+
27
+ it 'returns the existing token if there is an accessible one' do
28
+ existing = subject.call(client, scopes, :expires_in => 10.years)
29
+ created = subject.call(client, scopes)
30
+ created.should == existing
31
+ end
32
+
33
+ it 'revokes old token if is not accessible' do
34
+ existing = subject.call(client, scopes, :expires_in => -1000)
35
+ subject.call(client, scopes)
36
+ existing.reload.should be_revoked
37
+ end
38
+
39
+ it 'returns a new token when the old one is not accessible' do
40
+ existing = subject.call(client, scopes, :expires_in => -1000)
41
+
42
+ expect do
43
+ subject.call(client, scopes)
44
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+ require 'active_support/all'
3
+ require 'doorkeeper/oauth/client_credentials/issuer'
4
+
5
+ class Doorkeeper::OAuth::ClientCredentialsRequest
6
+ describe Issuer do
7
+ let(:creator) { mock :acces_token_creator }
8
+ let(:server) { mock :server, :access_token_expires_in => 100 }
9
+ let(:validation) { mock :validation, :valid? => true }
10
+
11
+ subject { Issuer.new(server, validation) }
12
+
13
+ describe :create do
14
+ let(:client) { mock :client, :id => 'some-id' }
15
+ let(:scopes) { 'some scope' }
16
+
17
+ it 'creates and sets the token' do
18
+ creator.should_receive(:call).and_return('token')
19
+ subject.create client, scopes, creator
20
+
21
+ subject.token.should == 'token'
22
+ end
23
+
24
+ it 'creates with correct token parameters' do
25
+ creator.should_receive(:call).with(client, scopes, {
26
+ :expires_in => 100,
27
+ :use_refresh_token => false
28
+ })
29
+
30
+ subject.create client, scopes, creator
31
+ end
32
+
33
+ it 'has error set to :server_error if creator fails' do
34
+ creator.should_receive(:call).and_return(false)
35
+ subject.create client, scopes, creator
36
+
37
+ subject.error.should == :server_error
38
+ end
39
+
40
+ context 'when validation fails' do
41
+ before do
42
+ validation.stub :valid? => false, :error => :validation_error
43
+ creator.should_not_receive(:create)
44
+ end
45
+
46
+ it 'has error set from validation' do
47
+ subject.create client, scopes, creator
48
+ subject.error.should == :validation_error
49
+ end
50
+
51
+ it 'returns false' do
52
+ subject.create(client, scopes, creator).should be_false
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+ require 'doorkeeper/oauth/client_credentials/response'
3
+
4
+ class Doorkeeper::OAuth::ClientCredentialsRequest
5
+ describe Response do
6
+ subject { Response.new(stub.as_null_object) }
7
+
8
+ it 'includes access token response headers' do
9
+ headers = subject.headers
10
+ headers.fetch('Cache-Control').should == 'no-store'
11
+ headers.fetch('Pragma').should == 'no-cache'
12
+ end
13
+
14
+ it 'status is success' do
15
+ subject.status.should == :success
16
+ end
17
+
18
+ it 'token_type is bearer' do
19
+ subject.token_type.should == 'bearer'
20
+ end
21
+
22
+ it 'can be serialized to JSON' do
23
+ subject.should respond_to(:to_json)
24
+ end
25
+
26
+ context 'attributes' do
27
+ let(:access_token) do
28
+ mock :access_token, {
29
+ :token => 'some-token',
30
+ :expires_in => '3600',
31
+ :scopes_string => 'two scopes'
32
+ }
33
+ end
34
+
35
+ subject { Response.new(access_token).attributes }
36
+
37
+ it 'includes :access_token' do
38
+ subject['access_token'].should == 'some-token'
39
+ end
40
+
41
+ it 'includes :token_type' do
42
+ subject['token_type'].should == 'bearer'
43
+ end
44
+
45
+ it 'includes :expires_in' do
46
+ subject['expires_in'].should == '3600'
47
+ end
48
+
49
+ it 'includes :scope' do
50
+ subject['scope'].should == 'two scopes'
51
+ end
52
+
53
+ it 'does not include refresh_token (disabled in this flow)' do
54
+ subject.should_not have_key('refresh_token')
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+ require 'active_support/all'
3
+ require 'doorkeeper/oauth/client_credentials/validation'
4
+
5
+ class Doorkeeper::OAuth::ClientCredentialsRequest
6
+ describe Validation do
7
+ let(:server) { mock :server, :scopes => nil }
8
+ let(:request) { mock :request, :client => stub, :original_scopes => nil }
9
+
10
+ subject { Validation.new(server, request) }
11
+
12
+ it 'is valid with valid request' do
13
+ subject.should be_valid
14
+ end
15
+
16
+ it 'is invalid when client is not present' do
17
+ request.stub :client => nil
18
+ subject.should_not be_valid
19
+ end
20
+
21
+ context 'with scopes' do
22
+ it 'is invalid when scopes are not included in the server' do
23
+ server.stub :scopes => Doorkeeper::OAuth::Scopes.from_string('email')
24
+ request.stub :original_scopes => 'invalid'
25
+ subject.should_not be_valid
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper_integration'
2
+
3
+ module Doorkeeper::OAuth
4
+ describe ClientCredentialsRequest do
5
+ let(:server) { Doorkeeper.configuration }
6
+
7
+ context 'with a valid request' do
8
+ let(:client) { FactoryGirl.create :application }
9
+
10
+ it 'issues an access token' do
11
+ request = ClientCredentialsRequest.new(server, client, {})
12
+ expect do
13
+ request.authorize
14
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
15
+ end
16
+ end
17
+
18
+ describe 'with an invalid request' do
19
+ it 'does not issue an access token' do
20
+ request = ClientCredentialsRequest.new(server, nil, {})
21
+ expect do
22
+ request.authorize
23
+ end.to_not change { Doorkeeper::AccessToken.count }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+ require 'active_support/all'
3
+ require 'active_model'
4
+ require 'doorkeeper/oauth/client_credentials_request'
5
+
6
+ module Doorkeeper::OAuth
7
+ describe ClientCredentialsRequest do
8
+ let(:server) { stub :default_scopes => nil }
9
+ let(:client) { stub }
10
+ let(:token_creator) { mock :issuer, :create => true, :token => stub }
11
+
12
+ subject { ClientCredentialsRequest.new(server, client) }
13
+
14
+ before do
15
+ subject.issuer = token_creator
16
+ end
17
+
18
+ it 'issues an access token for the current client' do
19
+ token_creator.should_receive(:create).with(client, nil)
20
+ subject.authorize
21
+ end
22
+
23
+ it 'has successful response when issue was created' do
24
+ subject.authorize
25
+ subject.response.should be_a(ClientCredentialsRequest::Response)
26
+ end
27
+
28
+ it 'has an error response if issue was not created' do
29
+ subject.issuer = stub :create => false, :error => :invalid
30
+ subject.authorize
31
+ subject.response.should be_a(Doorkeeper::OAuth::ErrorResponse)
32
+ end
33
+
34
+ it 'delegates the error to issuer' do
35
+ subject.issuer = stub :create => false, :error => :invalid
36
+ subject.authorize
37
+ subject.error.should == :invalid
38
+ end
39
+
40
+ context 'with scopes' do
41
+ let(:default_scopes) { Doorkeeper::OAuth::Scopes.from_string("public email") }
42
+
43
+ before do
44
+ server.stub(:default_scopes).and_return(default_scopes)
45
+ end
46
+
47
+ it 'issues an access token with default scopes if none was requested' do
48
+ token_creator.should_receive(:create).with(client, default_scopes)
49
+ subject.authorize
50
+ end
51
+
52
+ it 'issues an access token with requested scopes' do
53
+ subject = ClientCredentialsRequest.new(server, client, :scope => "email")
54
+ subject.issuer = token_creator
55
+ token_creator.should_receive(:create).with(client, Doorkeeper::OAuth::Scopes.from_string("email"))
56
+ subject.authorize
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ require 'active_support/core_ext/module/delegation'
3
+ require 'active_support/core_ext/string'
4
+ require 'doorkeeper/oauth/client'
5
+
6
+ module Doorkeeper::OAuth
7
+ class Doorkeeper::Application
8
+ end
9
+
10
+ describe Client do
11
+ describe :find do
12
+ let(:uid) { "some-uid" }
13
+
14
+ it 'finds the client via uid' do
15
+ client = stub
16
+ Doorkeeper::Application.should_receive(:find_by_uid).with(uid).and_return(client)
17
+ Client.find(uid).should be_a(Client)
18
+ end
19
+
20
+ it 'returns nil if client was not found' do
21
+ Doorkeeper::Application.should_receive(:find_by_uid).with(uid).and_return(nil)
22
+ Client.find(uid).should be_nil
23
+ end
24
+ end
25
+
26
+ describe :authenticate do
27
+ it 'returns the authenticated client via credentials' do
28
+ credentials = Client::Credentials.new("some-uid", "some-secret")
29
+ authenticator = mock
30
+ authenticator.should_receive(:call).with("some-uid", "some-secret").and_return(stub)
31
+ Client.authenticate(credentials, authenticator).should be_a(Client)
32
+ end
33
+
34
+ it 'retunrs nil if client was not authenticated' do
35
+ credentials = Client::Credentials.new("some-uid", "some-secret")
36
+ authenticator = mock
37
+ authenticator.should_receive(:call).with("some-uid", "some-secret").and_return(nil)
38
+ Client.authenticate(credentials, authenticator).should be_nil
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ require 'active_model'
3
+ require 'doorkeeper/oauth/error'
4
+ require 'doorkeeper/oauth/error_response'
5
+
6
+ module Doorkeeper::OAuth
7
+ describe ErrorResponse do
8
+ its(:status) { should == :unauthorized }
9
+
10
+ describe :from_request do
11
+ it 'has the error from request' do
12
+ error = ErrorResponse.from_request stub(:error => :some_error)
13
+ error.name.should == :some_error
14
+ end
15
+
16
+ it 'ignores state if request does not respond to state' do
17
+ error = ErrorResponse.from_request stub(:error => :some_error)
18
+ error.state.should be_nil
19
+ end
20
+
21
+ it 'has state if request responds to state' do
22
+ error = ErrorResponse.from_request stub(:error => :some_error, :state => :hello)
23
+ error.state.should == :hello
24
+ end
25
+ end
26
+
27
+ it 'ignores empty attributes' do
28
+ subject = ErrorResponse.new(:error => :some_error, :state => nil)
29
+ subject.attributes.should_not have_key(:state)
30
+ end
31
+
32
+ context 'json response' do
33
+ subject { ErrorResponse.new(:name => :some_error, :state => :some_state).as_json }
34
+
35
+ it { should have_key('error') }
36
+ it { should have_key('error_description') }
37
+ it { should have_key('state') }
38
+ end
39
+ end
40
+ end