doorkeeper 2.1.4 → 3.1.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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/.hound.yml +4 -0
  3. data/.travis.yml +5 -24
  4. data/CONTRIBUTING.md +23 -13
  5. data/Gemfile +3 -7
  6. data/{CHANGELOG.md → NEWS.md} +137 -42
  7. data/README.md +60 -46
  8. data/RELEASING.md +5 -3
  9. data/app/assets/stylesheets/doorkeeper/admin/application.css +1 -5
  10. data/app/controllers/doorkeeper/applications_controller.rb +2 -2
  11. data/app/helpers/doorkeeper/dashboard_helper.rb +1 -1
  12. data/app/validators/redirect_uri_validator.rb +1 -1
  13. data/app/views/doorkeeper/applications/_form.html.erb +13 -2
  14. data/app/views/doorkeeper/applications/show.html.erb +3 -2
  15. data/app/views/doorkeeper/authorizations/new.html.erb +1 -1
  16. data/app/views/layouts/doorkeeper/admin.html.erb +5 -2
  17. data/config/locales/en.yml +4 -32
  18. data/doorkeeper.gemspec +4 -8
  19. data/lib/doorkeeper/config.rb +20 -29
  20. data/lib/doorkeeper/engine.rb +7 -1
  21. data/lib/doorkeeper/errors.rb +12 -0
  22. data/lib/doorkeeper/grape/helpers.rb +1 -1
  23. data/lib/doorkeeper/helpers/controller.rb +6 -0
  24. data/lib/doorkeeper/models/access_grant_mixin.rb +3 -2
  25. data/lib/doorkeeper/models/access_token_mixin.rb +12 -4
  26. data/lib/doorkeeper/models/application_mixin.rb +11 -18
  27. data/lib/doorkeeper/models/concerns/revocable.rb +2 -2
  28. data/lib/doorkeeper/oauth/authorization/token.rb +15 -6
  29. data/lib/doorkeeper/oauth/authorization_code_request.rb +10 -5
  30. data/lib/doorkeeper/oauth/client.rb +9 -8
  31. data/lib/doorkeeper/oauth/client_credentials/creator.rb +3 -4
  32. data/lib/doorkeeper/oauth/error.rb +5 -1
  33. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -1
  34. data/lib/doorkeeper/oauth/refresh_token_request.rb +17 -7
  35. data/lib/doorkeeper/orm/active_record/access_grant.rb +2 -2
  36. data/lib/doorkeeper/orm/active_record/access_token.rb +2 -2
  37. data/lib/doorkeeper/orm/active_record/application.rb +2 -2
  38. data/lib/doorkeeper/orm/active_record.rb +22 -0
  39. data/lib/doorkeeper/rails/helpers.rb +19 -29
  40. data/lib/doorkeeper/request/authorization_code.rb +10 -15
  41. data/lib/doorkeeper/request/client_credentials.rb +9 -15
  42. data/lib/doorkeeper/request/code.rb +7 -13
  43. data/lib/doorkeeper/request/password.rb +10 -15
  44. data/lib/doorkeeper/request/refresh_token.rb +11 -13
  45. data/lib/doorkeeper/request/strategy.rb +17 -0
  46. data/lib/doorkeeper/request/token.rb +7 -13
  47. data/lib/doorkeeper/request.rb +18 -8
  48. data/lib/doorkeeper/server.rb +2 -2
  49. data/lib/doorkeeper/version.rb +1 -1
  50. data/lib/doorkeeper.rb +0 -4
  51. data/lib/generators/doorkeeper/templates/README +0 -20
  52. data/lib/generators/doorkeeper/templates/initializer.rb +5 -3
  53. data/lib/generators/doorkeeper/templates/migration.rb +8 -0
  54. data/spec/controllers/applications_controller_spec.rb +0 -1
  55. data/spec/controllers/protected_resources_controller_spec.rb +115 -14
  56. data/spec/controllers/token_info_controller_spec.rb +0 -4
  57. data/spec/controllers/tokens_controller_spec.rb +34 -3
  58. data/spec/dummy/app/models/user.rb +2 -24
  59. data/spec/dummy/config/application.rb +2 -1
  60. data/spec/dummy/config/initializers/doorkeeper.rb +0 -2
  61. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +24 -0
  62. data/spec/lib/config_spec.rb +20 -4
  63. data/spec/lib/models/revocable_spec.rb +2 -2
  64. data/spec/lib/oauth/authorization_code_request_spec.rb +1 -1
  65. data/spec/lib/oauth/client/credentials_spec.rb +2 -2
  66. data/spec/lib/oauth/client_credentials/creator_spec.rb +25 -1
  67. data/spec/lib/oauth/error_response_spec.rb +7 -7
  68. data/spec/lib/oauth/error_spec.rb +9 -5
  69. data/spec/lib/oauth/helpers/scope_checker_spec.rb +3 -3
  70. data/spec/lib/oauth/password_access_token_request_spec.rb +1 -1
  71. data/spec/lib/oauth/pre_authorization_spec.rb +9 -10
  72. data/spec/lib/oauth/refresh_token_request_spec.rb +26 -6
  73. data/spec/lib/oauth/scopes_spec.rb +1 -1
  74. data/spec/lib/oauth/token_request_spec.rb +6 -3
  75. data/spec/lib/request/strategy_spec.rb +53 -0
  76. data/spec/lib/server_spec.rb +4 -2
  77. data/spec/models/doorkeeper/access_grant_spec.rb +5 -5
  78. data/spec/models/doorkeeper/access_token_spec.rb +102 -5
  79. data/spec/models/doorkeeper/application_spec.rb +13 -16
  80. data/spec/requests/applications/applications_request_spec.rb +1 -1
  81. data/spec/requests/endpoints/authorization_spec.rb +2 -1
  82. data/spec/requests/endpoints/token_spec.rb +9 -9
  83. data/spec/requests/flows/authorization_code_errors_spec.rb +4 -4
  84. data/spec/requests/flows/authorization_code_spec.rb +36 -2
  85. data/spec/requests/flows/implicit_grant_spec.rb +14 -5
  86. data/spec/requests/flows/password_spec.rb +14 -20
  87. data/spec/requests/flows/refresh_token_spec.rb +15 -7
  88. data/spec/requests/flows/revoke_token_spec.rb +9 -31
  89. data/spec/requests/protected_resources/metal_spec.rb +3 -3
  90. data/spec/requests/protected_resources/private_api_spec.rb +11 -0
  91. data/spec/routing/custom_controller_routes_spec.rb +1 -2
  92. data/spec/routing/default_routes_spec.rb +1 -2
  93. data/spec/routing/scoped_routes_spec.rb +0 -1
  94. data/spec/spec_helper_integration.rb +10 -7
  95. data/spec/support/helpers/access_token_request_helper.rb +1 -1
  96. data/spec/support/helpers/authorization_request_helper.rb +1 -1
  97. data/spec/support/helpers/config_helper.rb +1 -1
  98. data/spec/support/helpers/model_helper.rb +1 -1
  99. data/spec/support/helpers/request_spec_helper.rb +1 -1
  100. data/spec/support/helpers/url_helper.rb +1 -1
  101. data/spec/support/shared/models_shared_examples.rb +1 -1
  102. data/spec/validators/redirect_uri_validator_spec.rb +5 -0
  103. metadata +127 -98
  104. data/gemfiles/Gemfile.common.rb +0 -14
  105. data/gemfiles/Gemfile.mongo_mapper.rb +0 -5
  106. data/gemfiles/Gemfile.mongoid2.rb +0 -5
  107. data/gemfiles/Gemfile.mongoid3.rb +0 -4
  108. data/gemfiles/Gemfile.mongoid4.rb +0 -5
  109. data/lib/doorkeeper/generators/doorkeeper/mongo_mapper/indexes_generator.rb +0 -12
  110. data/lib/doorkeeper/generators/doorkeeper/mongo_mapper/templates/indexes.rb +0 -3
  111. data/lib/doorkeeper/orm/mongo_mapper/access_grant.rb +0 -24
  112. data/lib/doorkeeper/orm/mongo_mapper/access_token.rb +0 -43
  113. data/lib/doorkeeper/orm/mongo_mapper/application.rb +0 -29
  114. data/lib/doorkeeper/orm/mongo_mapper.rb +0 -11
  115. data/lib/doorkeeper/orm/mongoid2/access_grant.rb +0 -22
  116. data/lib/doorkeeper/orm/mongoid2/access_token.rb +0 -37
  117. data/lib/doorkeeper/orm/mongoid2/application.rb +0 -25
  118. data/lib/doorkeeper/orm/mongoid2/concerns/scopes.rb +0 -30
  119. data/lib/doorkeeper/orm/mongoid2.rb +0 -11
  120. data/lib/doorkeeper/orm/mongoid3/access_grant.rb +0 -22
  121. data/lib/doorkeeper/orm/mongoid3/access_token.rb +0 -37
  122. data/lib/doorkeeper/orm/mongoid3/application.rb +0 -25
  123. data/lib/doorkeeper/orm/mongoid3/concerns/scopes.rb +0 -30
  124. data/lib/doorkeeper/orm/mongoid3.rb +0 -11
  125. data/lib/doorkeeper/orm/mongoid4/access_grant.rb +0 -22
  126. data/lib/doorkeeper/orm/mongoid4/access_token.rb +0 -37
  127. data/lib/doorkeeper/orm/mongoid4/application.rb +0 -25
  128. data/lib/doorkeeper/orm/mongoid4/concerns/scopes.rb +0 -17
  129. data/lib/doorkeeper/orm/mongoid4.rb +0 -11
  130. data/spec/dummy/config/mongo.yml +0 -11
  131. data/spec/dummy/config/mongoid2.yml +0 -9
  132. data/spec/dummy/config/mongoid3.yml +0 -18
  133. data/spec/dummy/config/mongoid4.yml +0 -19
  134. data/spec/support/orm/mongo_mapper.rb +0 -10
  135. data/spec/support/orm/mongoid.rb +0 -10
@@ -4,14 +4,14 @@ module Doorkeeper::OAuth
4
4
  describe PreAuthorization do
5
5
  let(:server) {
6
6
  server = Doorkeeper.configuration
7
- server.stub(:default_scopes) { Scopes.new }
8
- server.stub(:scopes) { Scopes.from_string('public profile') }
7
+ allow(server).to receive(:default_scopes).and_return(Scopes.new)
8
+ allow(server).to receive(:scopes).and_return(Scopes.from_string('public profile'))
9
9
  server
10
10
  }
11
11
 
12
12
  let(:application) do
13
13
  application = double :application
14
- application.stub(:scopes) { Scopes.from_string('') }
14
+ allow(application).to receive(:scopes).and_return(Scopes.from_string(''))
15
15
  application
16
16
  end
17
17
 
@@ -41,7 +41,7 @@ module Doorkeeper::OAuth
41
41
  end
42
42
 
43
43
  it 'accepts token as response type' do
44
- server.stub(:grant_flows) { ['implicit'] }
44
+ allow(server).to receive(:grant_flows).and_return(['implicit'])
45
45
  subject.response_type = 'token'
46
46
  expect(subject).to be_authorizable
47
47
  end
@@ -53,7 +53,7 @@ module Doorkeeper::OAuth
53
53
  end
54
54
 
55
55
  it 'accepts "token" as response type' do
56
- server.stub(:grant_flows) { ['implicit'] }
56
+ allow(server).to receive(:grant_flows).and_return(['implicit'])
57
57
  subject.response_type = 'token'
58
58
  expect(subject).to be_authorizable
59
59
  end
@@ -61,7 +61,7 @@ module Doorkeeper::OAuth
61
61
 
62
62
  context 'when authorization code grant flow is disabled' do
63
63
  before do
64
- server.stub(:grant_flows) { ['implicit'] }
64
+ allow(server).to receive(:grant_flows).and_return(['implicit'])
65
65
  end
66
66
 
67
67
  it 'does not accept "code" as response type' do
@@ -72,7 +72,7 @@ module Doorkeeper::OAuth
72
72
 
73
73
  context 'when implicit grant flow is disabled' do
74
74
  before do
75
- server.stub(:grant_flows) { ['authorization_code'] }
75
+ allow(server).to receive(:grant_flows).and_return(['authorization_code'])
76
76
  end
77
77
 
78
78
  it 'does not accept "token" as response type' do
@@ -96,7 +96,7 @@ module Doorkeeper::OAuth
96
96
  context 'client application restricts valid scopes' do
97
97
  let(:application) do
98
98
  application = double :application
99
- application.stub(:scopes) { Scopes.from_string('public nonsense') }
99
+ allow(application).to receive(:scopes).and_return(Scopes.from_string('public nonsense'))
100
100
  application
101
101
  end
102
102
 
@@ -119,7 +119,7 @@ module Doorkeeper::OAuth
119
119
  it 'uses default scopes when none is required' do
120
120
  allow(server).to receive(:default_scopes).and_return(Scopes.from_string('default'))
121
121
  subject.scope = nil
122
- expect(subject.scope).to eq('default')
122
+ expect(subject.scope).to eq('default')
123
123
  expect(subject.scopes).to eq(Scopes.from_string('default'))
124
124
  end
125
125
 
@@ -151,6 +151,5 @@ module Doorkeeper::OAuth
151
151
  subject.redirect_uri = nil
152
152
  expect(subject).not_to be_authorizable
153
153
  end
154
-
155
154
  end
156
155
  end
@@ -2,10 +2,16 @@ require 'spec_helper_integration'
2
2
 
3
3
  module Doorkeeper::OAuth
4
4
  describe RefreshTokenRequest do
5
- let(:server) { double :server, access_token_expires_in: 2.minutes }
6
- let!(:refresh_token) { FactoryGirl.create(:access_token, use_refresh_token: true) }
7
- let(:client) { refresh_token.application }
8
- let(:credentials) { Client::Credentials.new(client.uid, client.secret) }
5
+ let(:server) do
6
+ double :server,
7
+ access_token_expires_in: 2.minutes,
8
+ custom_access_token_expires_in: -> (_oauth_client) { nil }
9
+ end
10
+ let(:refresh_token) do
11
+ FactoryGirl.create(:access_token, use_refresh_token: true)
12
+ end
13
+ let(:client) { refresh_token.application }
14
+ let(:credentials) { Client::Credentials.new(client.uid, client.secret) }
9
15
 
10
16
  subject { RefreshTokenRequest.new server, refresh_token, credentials }
11
17
 
@@ -13,6 +19,17 @@ module Doorkeeper::OAuth
13
19
  expect do
14
20
  subject.authorize
15
21
  end.to change { client.access_tokens.count }.by(1)
22
+ expect(client.reload.access_tokens.last.expires_in).to eq(120)
23
+ end
24
+
25
+ it 'issues a new token for the client with custom expires_in' do
26
+ server = double :server,
27
+ access_token_expires_in: 2.minutes,
28
+ custom_access_token_expires_in: ->(_oauth_client) { 1234 }
29
+
30
+ RefreshTokenRequest.new(server, refresh_token, credentials).authorize
31
+
32
+ expect(client.reload.access_tokens.last.expires_in).to eq(1234)
16
33
  end
17
34
 
18
35
  it 'revokes the previous token' do
@@ -61,7 +78,11 @@ module Doorkeeper::OAuth
61
78
  end
62
79
 
63
80
  context 'with scopes' do
64
- let!(:refresh_token) { FactoryGirl.create(:access_token, use_refresh_token: true, scopes: 'public write') }
81
+ let(:refresh_token) do
82
+ FactoryGirl.create :access_token,
83
+ use_refresh_token: true,
84
+ scopes: 'public write'
85
+ end
65
86
  let(:parameters) { {} }
66
87
  subject { RefreshTokenRequest.new server, refresh_token, credentials, parameters }
67
88
 
@@ -98,6 +119,5 @@ module Doorkeeper::OAuth
98
119
  expect(subject.error).to eq(:invalid_scope)
99
120
  end
100
121
  end
101
-
102
122
  end
103
123
  end
@@ -47,7 +47,7 @@ module Doorkeeper::OAuth
47
47
 
48
48
  subject { Scopes.from_string(string) }
49
49
 
50
- it { should be_a(Scopes) }
50
+ it { expect(subject).to be_a(Scopes) }
51
51
 
52
52
  describe '#all' do
53
53
  it 'should be an array of the expected scopes' do
@@ -67,14 +67,14 @@ module Doorkeeper::OAuth
67
67
 
68
68
  context 'token reuse' do
69
69
  it 'creates a new token if there are no matching tokens' do
70
- Doorkeeper.configuration.stub(:reuse_access_token).and_return(true)
70
+ allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
71
71
  expect do
72
72
  subject.authorize
73
73
  end.to change { Doorkeeper::AccessToken.count }.by(1)
74
74
  end
75
75
 
76
76
  it 'creates a new token if scopes do not match' do
77
- Doorkeeper.configuration.stub(:reuse_access_token).and_return(true)
77
+ allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
78
78
  FactoryGirl.create(:access_token, application_id: pre_auth.client.id,
79
79
  resource_owner_id: owner.id, scopes: '')
80
80
  expect do
@@ -83,9 +83,12 @@ module Doorkeeper::OAuth
83
83
  end
84
84
 
85
85
  it 'skips token creation if there is a matching one' do
86
- Doorkeeper.configuration.stub(:reuse_access_token).and_return(true)
86
+ allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
87
+ allow(application.scopes).to receive(:has_scopes?).and_return(true)
88
+ allow(application.scopes).to receive(:all?).and_return(true)
87
89
  FactoryGirl.create(:access_token, application_id: pre_auth.client.id,
88
90
  resource_owner_id: owner.id, scopes: 'public')
91
+
89
92
  expect do
90
93
  subject.authorize
91
94
  end.to_not change { Doorkeeper::AccessToken.count }
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+ require 'doorkeeper/request/strategy'
3
+
4
+ module Doorkeeper
5
+ module Request
6
+ describe Strategy do
7
+ let(:server) { double }
8
+ subject(:strategy) { Strategy.new(server) }
9
+
10
+ describe :initialize do
11
+ it "sets the server attribute" do
12
+ expect(strategy.server).to eq server
13
+ end
14
+ end
15
+
16
+ describe :request do
17
+ it "requires an implementation" do
18
+ expect { strategy.request }.to raise_exception NotImplementedError
19
+ end
20
+ end
21
+
22
+ describe "a sample Strategy subclass" do
23
+ let(:fake_request) { double }
24
+
25
+ let(:strategy_class) do
26
+ subclass = Class.new(Strategy) do
27
+ class << self
28
+ attr_accessor :fake_request
29
+ end
30
+
31
+ def request
32
+ self.class.fake_request
33
+ end
34
+ end
35
+
36
+ subclass.fake_request = fake_request
37
+ subclass
38
+ end
39
+
40
+ subject(:strategy) { strategy_class.new(server) }
41
+
42
+ it "provides a request implementation" do
43
+ expect(strategy.request).to eq fake_request
44
+ end
45
+
46
+ it "authorizes the request" do
47
+ expect(fake_request).to receive :authorize
48
+ strategy.authorize
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -25,7 +25,9 @@ describe Doorkeeper::Server do
25
25
 
26
26
  context 'when only Authorization Code strategy is enabled' do
27
27
  before do
28
- Doorkeeper.configuration.stub(:grant_flows) { ['authorization_code'] }
28
+ allow(Doorkeeper.configuration).
29
+ to receive(:grant_flows).
30
+ and_return(['authorization_code'])
29
31
  end
30
32
 
31
33
  it 'raises error when using the disabled Implicit strategy' do
@@ -43,7 +45,7 @@ describe Doorkeeper::Server do
43
45
 
44
46
  it 'builds the request with selected strategy' do
45
47
  stub_const 'Doorkeeper::Request::Code', fake_class
46
- expect(fake_class).to receive(:build).with(subject)
48
+ expect(fake_class).to receive(:new).with(subject)
47
49
  subject.authorization_request :code
48
50
  end
49
51
  end
@@ -3,7 +3,7 @@ require 'spec_helper_integration'
3
3
  describe Doorkeeper::AccessGrant do
4
4
  subject { FactoryGirl.build(:access_grant) }
5
5
 
6
- it { should be_valid }
6
+ it { expect(subject).to be_valid }
7
7
 
8
8
  it_behaves_like 'an accessible token'
9
9
  it_behaves_like 'a revocable token'
@@ -14,23 +14,23 @@ describe Doorkeeper::AccessGrant do
14
14
  describe 'validations' do
15
15
  it 'is invalid without resource_owner_id' do
16
16
  subject.resource_owner_id = nil
17
- should_not be_valid
17
+ expect(subject).not_to be_valid
18
18
  end
19
19
 
20
20
  it 'is invalid without application_id' do
21
21
  subject.application_id = nil
22
- should_not be_valid
22
+ expect(subject).not_to be_valid
23
23
  end
24
24
 
25
25
  it 'is invalid without token' do
26
26
  subject.save
27
27
  subject.token = nil
28
- should_not be_valid
28
+ expect(subject).not_to be_valid
29
29
  end
30
30
 
31
31
  it 'is invalid without expires_in' do
32
32
  subject.expires_in = nil
33
- should_not be_valid
33
+ expect(subject).not_to be_valid
34
34
  end
35
35
  end
36
36
  end
@@ -4,7 +4,7 @@ module Doorkeeper
4
4
  describe AccessToken do
5
5
  subject { FactoryGirl.build(:access_token) }
6
6
 
7
- it { should be_valid }
7
+ it { expect(subject).to be_valid }
8
8
 
9
9
  it_behaves_like 'an accessible token'
10
10
  it_behaves_like 'a revocable token'
@@ -12,6 +12,103 @@ module Doorkeeper
12
12
  let(:factory_name) { :access_token }
13
13
  end
14
14
 
15
+ describe :generate_token do
16
+ it 'generates a token using the default method' do
17
+ FactoryGirl.create :access_token
18
+
19
+ token = FactoryGirl.create :access_token
20
+ expect(token.token).to be_a(String)
21
+ end
22
+
23
+ it 'generates a token using a custom object' do
24
+ module CustomGeneratorArgs
25
+ def self.generate(opts = {})
26
+ "custom_generator_token_#{opts[:resource_owner_id]}"
27
+ end
28
+ end
29
+
30
+ Doorkeeper.configure do
31
+ orm DOORKEEPER_ORM
32
+ access_token_generator "Doorkeeper::CustomGeneratorArgs"
33
+ end
34
+
35
+ token = FactoryGirl.create :access_token
36
+ expect(token.token).to match(%r{custom_generator_token_\d+})
37
+ end
38
+
39
+ it 'allows the custom generator to access the application details' do
40
+ module CustomGeneratorArgs
41
+ def self.generate(opts = {})
42
+ "custom_generator_token_#{opts[:application].name}"
43
+ end
44
+ end
45
+
46
+ Doorkeeper.configure do
47
+ orm DOORKEEPER_ORM
48
+ access_token_generator "Doorkeeper::CustomGeneratorArgs"
49
+ end
50
+
51
+ token = FactoryGirl.create :access_token
52
+ expect(token.token).to match(%r{custom_generator_token_Application \d+})
53
+ end
54
+
55
+ it 'allows the custom generator to access the scopes' do
56
+ module CustomGeneratorArgs
57
+ def self.generate(opts = {})
58
+ "custom_generator_token_#{opts[:scopes].count}_#{opts[:scopes]}"
59
+ end
60
+ end
61
+
62
+ Doorkeeper.configure do
63
+ orm DOORKEEPER_ORM
64
+ access_token_generator "Doorkeeper::CustomGeneratorArgs"
65
+ end
66
+
67
+ token = FactoryGirl.create :access_token, scopes: 'public write'
68
+
69
+ expect(token.token).to eq 'custom_generator_token_2_public write'
70
+ end
71
+
72
+ it 'allows the custom generator to access the expiry length' do
73
+ module CustomGeneratorArgs
74
+ def self.generate(opts = {})
75
+ "custom_generator_token_#{opts[:expires_in]}"
76
+ end
77
+ end
78
+
79
+ Doorkeeper.configure do
80
+ orm DOORKEEPER_ORM
81
+ access_token_generator "Doorkeeper::CustomGeneratorArgs"
82
+ end
83
+
84
+ token = FactoryGirl.create :access_token
85
+ expect(token.token).to eq 'custom_generator_token_7200'
86
+ end
87
+
88
+ it 'raises an error if the custom object does not support generate' do
89
+ module NoGenerate
90
+ end
91
+
92
+ Doorkeeper.configure do
93
+ orm DOORKEEPER_ORM
94
+ access_token_generator "Doorkeeper::NoGenerate"
95
+ end
96
+
97
+ expect { FactoryGirl.create :access_token }.to(
98
+ raise_error(Doorkeeper::Errors::UnableToGenerateToken))
99
+ end
100
+
101
+ it 'raises an error if the custom object does not exist' do
102
+ Doorkeeper.configure do
103
+ orm DOORKEEPER_ORM
104
+ access_token_generator "Doorkeeper::NotReal"
105
+ end
106
+
107
+ expect { FactoryGirl.create :access_token }.to(
108
+ raise_error(Doorkeeper::Errors::TokenGeneratorNotFound))
109
+ end
110
+ end
111
+
15
112
  describe :refresh_token do
16
113
  it 'has empty refresh token if it was not required' do
17
114
  token = FactoryGirl.create :access_token
@@ -26,7 +123,7 @@ module Doorkeeper
26
123
  it 'is not valid if token exists' do
27
124
  token1 = FactoryGirl.create :access_token, use_refresh_token: true
28
125
  token2 = FactoryGirl.create :access_token, use_refresh_token: true
29
- token2.send :write_attribute, :refresh_token, token1.refresh_token
126
+ token2.refresh_token = token1.refresh_token
30
127
  expect(token2).not_to be_valid
31
128
  end
32
129
 
@@ -34,9 +131,9 @@ module Doorkeeper
34
131
  token1 = FactoryGirl.create :access_token, use_refresh_token: true
35
132
  token2 = FactoryGirl.create :access_token, use_refresh_token: true
36
133
  expect do
37
- token2.write_attribute :refresh_token, token1.refresh_token
134
+ token2.refresh_token = token1.refresh_token
38
135
  token2.save(validate: false)
39
- end.to raise_error
136
+ end.to raise_error(ActiveRecord::RecordNotUnique)
40
137
  end
41
138
  end
42
139
 
@@ -44,7 +141,7 @@ module Doorkeeper
44
141
  it 'is valid without resource_owner_id' do
45
142
  # For client credentials flow
46
143
  subject.resource_owner_id = nil
47
- should be_valid
144
+ expect(subject).to be_valid
48
145
  end
49
146
  end
50
147
 
@@ -55,6 +55,12 @@ module Doorkeeper
55
55
  expect(new_application.uid).not_to be_nil
56
56
  end
57
57
 
58
+ it 'generates uid on create if an empty string' do
59
+ new_application.uid = ''
60
+ new_application.save
61
+ expect(new_application.uid).not_to be_blank
62
+ end
63
+
58
64
  it 'generates uid on create unless one is set' do
59
65
  new_application.uid = uid
60
66
  new_application.save
@@ -84,7 +90,7 @@ module Doorkeeper
84
90
  app1 = FactoryGirl.create(:application)
85
91
  app2 = FactoryGirl.create(:application)
86
92
  app2.uid = app1.uid
87
- expect { app2.save!(validate: false) }.to raise_error
93
+ expect { app2.save!(validate: false) }.to raise_error(ActiveRecord::RecordNotUnique)
88
94
  end
89
95
 
90
96
  it 'generate secret on create' do
@@ -93,6 +99,12 @@ module Doorkeeper
93
99
  expect(new_application.secret).not_to be_nil
94
100
  end
95
101
 
102
+ it 'generate secret on create if is blank string' do
103
+ new_application.secret = ''
104
+ new_application.save
105
+ expect(new_application.secret).not_to be_blank
106
+ end
107
+
96
108
  it 'generate secret on create unless one is set' do
97
109
  new_application.secret = secret
98
110
  new_application.save
@@ -171,20 +183,5 @@ module Doorkeeper
171
183
  expect(authenticated).to eq(app)
172
184
  end
173
185
  end
174
-
175
- if Doorkeeper.configuration.orm == :active_record
176
- describe :scopes do
177
- it 'fails on missing column with an upgrade notice' do
178
- app = FactoryGirl.build :application
179
- no_scopes_app = double(attributes: [])
180
- allow(Application).to receive(:new).and_return(no_scopes_app)
181
-
182
- expect { app.scopes }.to raise_error(
183
- NameError,
184
- /Missing column: `applications.scopes`/
185
- )
186
- end
187
- end
188
- end
189
186
  end
190
187
  end
@@ -37,7 +37,7 @@ feature 'Listing applications' do
37
37
  end
38
38
 
39
39
  feature 'Show application' do
40
- let :app do
40
+ given :app do
41
41
  FactoryGirl.create :application, name: 'Just another oauth app'
42
42
  end
43
43
 
@@ -59,7 +59,8 @@ feature 'Authorization endpoint' do
59
59
  end
60
60
 
61
61
  scenario 'raises exception on forged requests' do
62
- ActionController::Base.any_instance.should_receive(:handle_unverified_request)
62
+ skip 'TODO: need to add request helpers to this feature spec'
63
+ allow_any_instance_of(ActionController::Base).to receive(:handle_unverified_request)
63
64
  allowing_forgery_protection do
64
65
  post "/oauth/authorize",
65
66
  client_id: @client.uid,
@@ -1,19 +1,19 @@
1
1
  require 'spec_helper_integration'
2
2
 
3
- feature 'Token endpoint' do
4
- background do
3
+ describe 'Token endpoint' do
4
+ before do
5
5
  client_exists
6
6
  authorization_code_exists application: @client, scopes: 'public'
7
7
  end
8
8
 
9
- scenario 'respond with correct headers' do
9
+ it 'respond with correct headers' do
10
10
  post token_endpoint_url(code: @authorization.token, client: @client)
11
11
  should_have_header 'Pragma', 'no-cache'
12
12
  should_have_header 'Cache-Control', 'no-store'
13
13
  should_have_header 'Content-Type', 'application/json; charset=utf-8'
14
14
  end
15
15
 
16
- scenario 'accepts client credentials with basic auth header' do
16
+ it 'accepts client credentials with basic auth header' do
17
17
  post token_endpoint_url(
18
18
  code: @authorization.token,
19
19
  redirect_uri: @client.redirect_uri
@@ -22,14 +22,14 @@ feature 'Token endpoint' do
22
22
  should_have_json 'access_token', Doorkeeper::AccessToken.first.token
23
23
  end
24
24
 
25
- scenario 'returns null for expires_in when a permanent token is set' do
25
+ it 'returns null for expires_in when a permanent token is set' do
26
26
  config_is_set(:access_token_expires_in, nil)
27
27
  post token_endpoint_url(code: @authorization.token, client: @client)
28
28
  should_have_json 'access_token', Doorkeeper::AccessToken.first.token
29
29
  should_not_have_json 'expires_in'
30
30
  end
31
31
 
32
- scenario 'returns unsupported_grant_type for invalid grant_type param' do
32
+ it 'returns unsupported_grant_type for invalid grant_type param' do
33
33
  post token_endpoint_url(code: @authorization.token, client: @client, grant_type: 'nothing')
34
34
 
35
35
  should_not_have_json 'access_token'
@@ -37,7 +37,7 @@ feature 'Token endpoint' do
37
37
  should_have_json 'error_description', translated_error_message('unsupported_grant_type')
38
38
  end
39
39
 
40
- scenario 'returns unsupported_grant_type for disabled grant flows' do
40
+ it 'returns unsupported_grant_type for disabled grant flows' do
41
41
  config_is_set(:grant_flows, ['implicit'])
42
42
  post token_endpoint_url(code: @authorization.token, client: @client, grant_type: 'authorization_code')
43
43
 
@@ -46,7 +46,7 @@ feature 'Token endpoint' do
46
46
  should_have_json 'error_description', translated_error_message('unsupported_grant_type')
47
47
  end
48
48
 
49
- scenario 'returns unsupported_grant_type when refresh_token is not in use' do
49
+ it 'returns unsupported_grant_type when refresh_token is not in use' do
50
50
  post token_endpoint_url(code: @authorization.token, client: @client, grant_type: 'refresh_token')
51
51
 
52
52
  should_not_have_json 'access_token'
@@ -54,7 +54,7 @@ feature 'Token endpoint' do
54
54
  should_have_json 'error_description', translated_error_message('unsupported_grant_type')
55
55
  end
56
56
 
57
- scenario 'returns invalid_request if grant_type is missing' do
57
+ it 'returns invalid_request if grant_type is missing' do
58
58
  post token_endpoint_url(code: @authorization.token, client: @client, grant_type: '')
59
59
 
60
60
  should_not_have_json 'access_token'
@@ -34,13 +34,13 @@ feature 'Authorization Code Flow Errors' do
34
34
  end
35
35
  end
36
36
 
37
- feature 'Authorization Code Flow Errors', 'after authorization' do
38
- background do
37
+ describe 'Authorization Code Flow Errors', 'after authorization' do
38
+ before do
39
39
  client_exists
40
40
  authorization_code_exists application: @client
41
41
  end
42
42
 
43
- scenario 'returns :invalid_grant error when posting an already revoked grant code' do
43
+ it 'returns :invalid_grant error when posting an already revoked grant code' do
44
44
  # First successful request
45
45
  post token_endpoint_url(code: @authorization.token, client: @client)
46
46
 
@@ -54,7 +54,7 @@ feature 'Authorization Code Flow Errors', 'after authorization' do
54
54
  should_have_json 'error_description', translated_error_message('invalid_grant')
55
55
  end
56
56
 
57
- scenario 'returns :invalid_grant error for invalid grant code' do
57
+ it 'returns :invalid_grant error for invalid grant code' do
58
58
  post token_endpoint_url(code: 'invalid', client: @client)
59
59
 
60
60
  access_token_should_not_exist
@@ -41,6 +41,8 @@ feature 'Authorization Code Flow' do
41
41
  end
42
42
 
43
43
  scenario 'resource owner requests an access token with authorization code' do
44
+ skip 'TODO: need to add request helpers to this feature spec'
45
+
44
46
  visit authorization_endpoint_url(client: @client)
45
47
  click_on 'Authorize'
46
48
 
@@ -52,13 +54,13 @@ feature 'Authorization Code Flow' do
52
54
  should_not_have_json 'error'
53
55
 
54
56
  should_have_json 'access_token', Doorkeeper::AccessToken.first.token
55
- should_have_json 'token_type', 'bearer'
57
+ should_have_json 'token_type', 'bearer'
56
58
  should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
57
59
  end
58
60
 
59
61
  context 'with scopes' do
60
62
  background do
61
- default_scopes_exist :public
63
+ default_scopes_exist :public
62
64
  optional_scopes_exist :write
63
65
  end
64
66
 
@@ -82,6 +84,8 @@ feature 'Authorization Code Flow' do
82
84
  end
83
85
 
84
86
  scenario 'new access token matches required scopes' do
87
+ skip 'TODO: need to add request helpers to this feature spec'
88
+
85
89
  visit authorization_endpoint_url(client: @client, scope: 'public write')
86
90
  click_on 'Authorize'
87
91
 
@@ -93,6 +97,8 @@ feature 'Authorization Code Flow' do
93
97
  end
94
98
 
95
99
  scenario 'returns new token if scopes have changed' do
100
+ skip 'TODO: need to add request helpers to this feature spec'
101
+
96
102
  client_is_authorized(@client, @resource_owner, scopes: 'public write')
97
103
  visit authorization_endpoint_url(client: @client, scope: 'public')
98
104
  click_on 'Authorize'
@@ -106,6 +112,8 @@ feature 'Authorization Code Flow' do
106
112
  end
107
113
 
108
114
  scenario 'resource owner authorizes the client with extra scopes' do
115
+ skip 'TODO: need to add request helpers to this feature spec'
116
+
109
117
  client_is_authorized(@client, @resource_owner, scopes: 'public')
110
118
  visit authorization_endpoint_url(client: @client, scope: 'public write')
111
119
  click_on 'Authorize'
@@ -120,3 +128,29 @@ feature 'Authorization Code Flow' do
120
128
  end
121
129
  end
122
130
  end
131
+
132
+ describe 'Authorization Code Flow' do
133
+ before do
134
+ Doorkeeper.configure do
135
+ orm DOORKEEPER_ORM
136
+ use_refresh_token
137
+ end
138
+ client_exists
139
+ end
140
+
141
+ context 'issuing a refresh token' do
142
+ before do
143
+ authorization_code_exists application: @client
144
+ end
145
+
146
+ it 'second of simultaneous client requests get an error for revoked acccess token' do
147
+ authorization_code = Doorkeeper::AccessGrant.first.token
148
+ allow_any_instance_of(Doorkeeper::AccessGrant).to receive(:revoked?).and_return(false, true)
149
+
150
+ post token_endpoint_url(code: authorization_code, client: @client)
151
+
152
+ should_not_have_json 'access_token'
153
+ should_have_json 'error', 'invalid_grant'
154
+ end
155
+ end
156
+ end