doorkeeper 4.4.3 → 5.0.0.rc1

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 (169) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +2 -0
  4. data/Appraisals +2 -2
  5. data/Gemfile +1 -1
  6. data/NEWS.md +36 -17
  7. data/README.md +85 -3
  8. data/Rakefile +6 -0
  9. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  10. data/app/controllers/doorkeeper/application_controller.rb +4 -3
  11. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
  12. data/app/controllers/doorkeeper/applications_controller.rb +42 -22
  13. data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
  14. data/app/controllers/doorkeeper/authorized_applications_controller.rb +15 -1
  15. data/app/controllers/doorkeeper/tokens_controller.rb +12 -15
  16. data/app/helpers/doorkeeper/dashboard_helper.rb +7 -7
  17. data/app/validators/redirect_uri_validator.rb +3 -2
  18. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  19. data/app/views/doorkeeper/applications/_form.html.erb +25 -24
  20. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  21. data/app/views/doorkeeper/applications/index.html.erb +17 -7
  22. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  23. data/app/views/doorkeeper/applications/show.html.erb +6 -6
  24. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  25. data/app/views/doorkeeper/authorizations/new.html.erb +4 -0
  26. data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
  27. data/config/locales/en.yml +9 -1
  28. data/doorkeeper.gemspec +0 -2
  29. data/gemfiles/rails_5_2.gemfile +1 -1
  30. data/lib/doorkeeper/config.rb +58 -35
  31. data/lib/doorkeeper/engine.rb +4 -0
  32. data/lib/doorkeeper/errors.rb +2 -5
  33. data/lib/doorkeeper/grape/helpers.rb +1 -1
  34. data/lib/doorkeeper/helpers/controller.rb +7 -2
  35. data/lib/doorkeeper/models/access_grant_mixin.rb +56 -0
  36. data/lib/doorkeeper/models/access_token_mixin.rb +38 -21
  37. data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
  38. data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
  39. data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
  40. data/lib/doorkeeper/oauth/authorization/token.rb +23 -6
  41. data/lib/doorkeeper/oauth/authorization_code_request.rb +27 -2
  42. data/lib/doorkeeper/oauth/base_request.rb +18 -8
  43. data/lib/doorkeeper/oauth/client/credentials.rb +1 -1
  44. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -1
  45. data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -2
  46. data/lib/doorkeeper/oauth/error_response.rb +11 -3
  47. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
  48. data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -4
  49. data/lib/doorkeeper/oauth/pre_authorization.rb +41 -11
  50. data/lib/doorkeeper/oauth/refresh_token_request.rb +6 -1
  51. data/lib/doorkeeper/oauth/scopes.rb +1 -1
  52. data/lib/doorkeeper/oauth/token.rb +5 -2
  53. data/lib/doorkeeper/oauth/token_introspection.rb +2 -2
  54. data/lib/doorkeeper/oauth/token_response.rb +4 -2
  55. data/lib/doorkeeper/oauth.rb +13 -0
  56. data/lib/doorkeeper/orm/active_record/application.rb +13 -16
  57. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  58. data/lib/doorkeeper/orm/active_record.rb +2 -0
  59. data/lib/doorkeeper/rails/helpers.rb +2 -4
  60. data/lib/doorkeeper/rails/routes.rb +14 -6
  61. data/lib/doorkeeper/rake/db.rake +40 -0
  62. data/lib/doorkeeper/rake/setup.rake +6 -0
  63. data/lib/doorkeeper/rake.rb +14 -0
  64. data/lib/doorkeeper/request.rb +28 -28
  65. data/lib/doorkeeper/version.rb +5 -25
  66. data/lib/doorkeeper.rb +4 -17
  67. data/lib/generators/doorkeeper/application_owner_generator.rb +23 -18
  68. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  69. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  70. data/lib/generators/doorkeeper/migration_generator.rb +23 -18
  71. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  72. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -24
  73. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  74. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  75. data/lib/generators/doorkeeper/templates/initializer.rb +60 -9
  76. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  77. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  78. data/spec/controllers/applications_controller_spec.rb +126 -13
  79. data/spec/controllers/authorizations_controller_spec.rb +252 -49
  80. data/spec/controllers/protected_resources_controller_spec.rb +16 -16
  81. data/spec/controllers/token_info_controller_spec.rb +4 -12
  82. data/spec/controllers/tokens_controller_spec.rb +19 -73
  83. data/spec/dummy/app/assets/config/manifest.js +2 -0
  84. data/spec/dummy/config/environments/test.rb +4 -5
  85. data/spec/dummy/config/initializers/doorkeeper.rb +5 -4
  86. data/spec/dummy/config/initializers/new_framework_defaults.rb +4 -0
  87. data/spec/dummy/config/routes.rb +3 -42
  88. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  89. data/spec/dummy/db/migrate/{20180210183654_add_confidential_to_application.rb → 20180210183654_add_confidential_to_applications.rb} +1 -1
  90. data/spec/dummy/db/schema.rb +36 -36
  91. data/spec/generators/application_owner_generator_spec.rb +1 -1
  92. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  93. data/spec/generators/install_generator_spec.rb +1 -1
  94. data/spec/generators/migration_generator_spec.rb +1 -1
  95. data/spec/generators/pkce_generator_spec.rb +43 -0
  96. data/spec/generators/previous_refresh_token_generator_spec.rb +1 -1
  97. data/spec/generators/views_generator_spec.rb +1 -1
  98. data/spec/grape/grape_integration_spec.rb +1 -1
  99. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
  100. data/spec/lib/config_spec.rb +51 -31
  101. data/spec/lib/doorkeeper_spec.rb +1 -126
  102. data/spec/lib/models/expirable_spec.rb +0 -3
  103. data/spec/lib/models/revocable_spec.rb +0 -2
  104. data/spec/lib/models/scopes_spec.rb +0 -4
  105. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  106. data/spec/lib/oauth/authorization_code_request_spec.rb +9 -2
  107. data/spec/lib/oauth/base_request_spec.rb +16 -2
  108. data/spec/lib/oauth/base_response_spec.rb +1 -1
  109. data/spec/lib/oauth/client/credentials_spec.rb +1 -3
  110. data/spec/lib/oauth/client_credentials/creator_spec.rb +5 -1
  111. data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
  112. data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
  113. data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
  114. data/spec/lib/oauth/client_credentials_request_spec.rb +3 -5
  115. data/spec/lib/oauth/client_spec.rb +0 -3
  116. data/spec/lib/oauth/code_request_spec.rb +4 -2
  117. data/spec/lib/oauth/error_response_spec.rb +0 -3
  118. data/spec/lib/oauth/error_spec.rb +0 -2
  119. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  120. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
  121. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  122. data/spec/lib/oauth/helpers/uri_checker_spec.rb +5 -7
  123. data/spec/lib/oauth/invalid_token_response_spec.rb +1 -4
  124. data/spec/lib/oauth/password_access_token_request_spec.rb +37 -2
  125. data/spec/lib/oauth/pre_authorization_spec.rb +33 -4
  126. data/spec/lib/oauth/refresh_token_request_spec.rb +11 -7
  127. data/spec/lib/oauth/scopes_spec.rb +0 -3
  128. data/spec/lib/oauth/token_request_spec.rb +4 -5
  129. data/spec/lib/oauth/token_response_spec.rb +0 -1
  130. data/spec/lib/oauth/token_spec.rb +37 -14
  131. data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
  132. data/spec/lib/request/strategy_spec.rb +0 -1
  133. data/spec/lib/server_spec.rb +1 -1
  134. data/spec/models/doorkeeper/access_grant_spec.rb +1 -1
  135. data/spec/models/doorkeeper/access_token_spec.rb +50 -16
  136. data/spec/models/doorkeeper/application_spec.rb +1 -47
  137. data/spec/requests/applications/applications_request_spec.rb +89 -1
  138. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  139. data/spec/requests/endpoints/authorization_spec.rb +1 -1
  140. data/spec/requests/endpoints/token_spec.rb +7 -5
  141. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
  142. data/spec/requests/flows/authorization_code_spec.rb +198 -2
  143. data/spec/requests/flows/client_credentials_spec.rb +46 -6
  144. data/spec/requests/flows/implicit_grant_errors_spec.rb +1 -1
  145. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  146. data/spec/requests/flows/password_spec.rb +56 -2
  147. data/spec/requests/flows/refresh_token_spec.rb +2 -2
  148. data/spec/requests/flows/revoke_token_spec.rb +11 -11
  149. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  150. data/spec/requests/protected_resources/metal_spec.rb +1 -1
  151. data/spec/requests/protected_resources/private_api_spec.rb +1 -1
  152. data/spec/routing/custom_controller_routes_spec.rb +59 -7
  153. data/spec/routing/default_routes_spec.rb +2 -2
  154. data/spec/routing/scoped_routes_spec.rb +16 -2
  155. data/spec/spec_helper.rb +54 -3
  156. data/spec/spec_helper_integration.rb +2 -74
  157. data/spec/support/dependencies/{factory_girl.rb → factory_bot.rb} +0 -0
  158. data/spec/support/doorkeeper_rspec.rb +19 -0
  159. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  160. data/spec/support/helpers/request_spec_helper.rb +2 -2
  161. data/spec/support/helpers/url_helper.rb +7 -3
  162. data/spec/support/http_method_shim.rb +12 -16
  163. data/spec/validators/redirect_uri_validator_spec.rb +7 -1
  164. data/spec/version/version_spec.rb +3 -3
  165. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  166. metadata +33 -31
  167. data/lib/generators/doorkeeper/add_client_confidentiality_generator.rb +0 -31
  168. data/lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb +0 -11
  169. data/spec/controllers/application_metal_controller.rb +0 -10
@@ -1,15 +1,8 @@
1
1
  require 'spec_helper'
2
- require 'uri'
3
- require 'doorkeeper/oauth/helpers/uri_checker'
4
2
 
5
3
  module Doorkeeper::OAuth::Helpers
6
4
  describe URIChecker do
7
5
  describe '.valid?' do
8
- it 'is valid for native uris' do
9
- uri = 'urn:ietf:wg:oauth:2.0:oob'
10
- expect(URIChecker.valid?(uri)).to be_truthy
11
- end
12
-
13
6
  it 'is valid for valid uris' do
14
7
  uri = 'http://app.co'
15
8
  expect(URIChecker.valid?(uri)).to be_truthy
@@ -49,6 +42,11 @@ module Doorkeeper::OAuth::Helpers
49
42
  uri = ' '
50
43
  expect(URIChecker.valid?(uri)).to be_falsey
51
44
  end
45
+
46
+ it 'is valid for native uris' do
47
+ uri = 'urn:ietf:wg:oauth:2.0:oob'
48
+ expect(URIChecker.valid?(uri)).to be_truthy
49
+ end
52
50
  end
53
51
 
54
52
  describe '.matches?' do
@@ -1,12 +1,9 @@
1
1
  require 'spec_helper'
2
- require 'active_model'
3
- require 'doorkeeper'
4
- require 'doorkeeper/oauth/invalid_token_response'
5
2
 
6
3
  module Doorkeeper::OAuth
7
4
  describe InvalidTokenResponse do
8
5
  describe "#name" do
9
- it { expect(subject.name).to eq(:invalid_token) }
6
+ it { expect(subject.name).to eq(:invalid_token) }
10
7
  end
11
8
 
12
9
  describe "#status" do
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper::OAuth
4
4
  describe PasswordAccessTokenRequest do
@@ -8,7 +8,9 @@ module Doorkeeper::OAuth
8
8
  default_scopes: Doorkeeper::OAuth::Scopes.new,
9
9
  access_token_expires_in: 2.hours,
10
10
  refresh_token_enabled?: false,
11
- custom_access_token_expires_in: ->(_app) { nil }
11
+ custom_access_token_expires_in: lambda { |context|
12
+ context.grant_type == Doorkeeper::OAuth::PASSWORD ? 1234 : nil
13
+ }
12
14
  )
13
15
  end
14
16
  let(:client) { FactoryBot.create(:application) }
@@ -22,6 +24,7 @@ module Doorkeeper::OAuth
22
24
  expect do
23
25
  subject.authorize
24
26
  end.to change { client.reload.access_tokens.count }.by(1)
27
+ expect(client.reload.access_tokens.sort_by(&:created_at).last.expires_in).to eq(1234)
25
28
  end
26
29
 
27
30
  it 'issues a new token without a client' do
@@ -92,5 +95,37 @@ module Doorkeeper::OAuth
92
95
  expect(Doorkeeper::AccessToken.last.scopes).to include('public')
93
96
  end
94
97
  end
98
+
99
+ describe 'with custom expiry' do
100
+ let(:server) do
101
+ double(
102
+ :server,
103
+ default_scopes: Doorkeeper::OAuth::Scopes.new,
104
+ access_token_expires_in: 2.hours,
105
+ refresh_token_enabled?: false,
106
+ custom_access_token_expires_in: lambda { |context|
107
+ context.scopes.exists?('public') ? 222 : nil
108
+ }
109
+ )
110
+ end
111
+
112
+ it 'checks scopes' do
113
+ subject = PasswordAccessTokenRequest.new(server, client, owner, scope: 'public')
114
+ allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string('public'))
115
+ expect do
116
+ subject.authorize
117
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
118
+ expect(Doorkeeper::AccessToken.last.expires_in).to eq(222)
119
+ end
120
+
121
+ it 'falls back to the default otherwise' do
122
+ subject = PasswordAccessTokenRequest.new(server, client, owner, scope: 'private')
123
+ allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string('private'))
124
+ expect do
125
+ subject.authorize
126
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
127
+ expect(Doorkeeper::AccessToken.last.expires_in).to eq(2.hours)
128
+ end
129
+ end
95
130
  end
96
131
  end
@@ -1,13 +1,13 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper::OAuth
4
4
  describe PreAuthorization do
5
- let(:server) {
5
+ let(:server) do
6
6
  server = Doorkeeper.configuration
7
7
  allow(server).to receive(:default_scopes).and_return(Scopes.new)
8
8
  allow(server).to receive(:scopes).and_return(Scopes.from_string('public profile'))
9
9
  server
10
- }
10
+ end
11
11
 
12
12
  let(:application) do
13
13
  application = double :application
@@ -133,11 +133,16 @@ module Doorkeeper::OAuth
133
133
  end
134
134
 
135
135
  it 'invalidates redirect_uri when it does\'n match with the client' do
136
- subject.redirect_uri = native_redirect_uri
136
+ subject.redirect_uri = 'urn:ietf:wg:oauth:2.0:oob'
137
137
  expect(subject).not_to be_authorizable
138
138
  end
139
139
  end
140
140
 
141
+ it 'matches the redirect uri against client\'s one' do
142
+ subject.redirect_uri = 'http://nothesame.com'
143
+ expect(subject).not_to be_authorizable
144
+ end
145
+
141
146
  it 'stores the state' do
142
147
  expect(subject.state).to eq('save-this')
143
148
  end
@@ -156,5 +161,29 @@ module Doorkeeper::OAuth
156
161
  subject.redirect_uri = nil
157
162
  expect(subject).not_to be_authorizable
158
163
  end
164
+
165
+ describe "as_json" do
166
+ let(:client_id) { "client_uid_123" }
167
+ let(:client_name) { "Acme Co." }
168
+
169
+ before do
170
+ allow(client).to receive(:uid).and_return client_id
171
+ allow(client).to receive(:name).and_return client_name
172
+ end
173
+
174
+ let(:json) { subject.as_json({}) }
175
+
176
+ it { is_expected.to respond_to :as_json }
177
+
178
+ it "returns correct values" do
179
+ expect(json[:client_id]).to eq client_id
180
+ expect(json[:redirect_uri]).to eq subject.redirect_uri
181
+ expect(json[:state]).to eq subject.state
182
+ expect(json[:response_type]).to eq subject.response_type
183
+ expect(json[:scope]).to eq subject.scope
184
+ expect(json[:client_name]).to eq client_name
185
+ expect(json[:status]).to eq I18n.t('doorkeeper.pre_authorization.status')
186
+ end
187
+ end
159
188
  end
160
189
  end
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper::OAuth
4
4
  describe RefreshTokenRequest do
@@ -9,7 +9,7 @@ module Doorkeeper::OAuth
9
9
  let(:server) do
10
10
  double :server,
11
11
  access_token_expires_in: 2.minutes,
12
- custom_access_token_expires_in: -> (_oauth_client) { nil }
12
+ custom_access_token_expires_in: ->(_context) { nil }
13
13
  end
14
14
 
15
15
  let(:refresh_token) do
@@ -30,7 +30,9 @@ module Doorkeeper::OAuth
30
30
  it 'issues a new token for the client with custom expires_in' do
31
31
  server = double :server,
32
32
  access_token_expires_in: 2.minutes,
33
- custom_access_token_expires_in: ->(_oauth_client) { 1234 }
33
+ custom_access_token_expires_in: lambda { |context|
34
+ context.grant_type == Doorkeeper::OAuth::REFRESH_TOKEN ? 1234 : nil
35
+ }
34
36
 
35
37
  allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
36
38
 
@@ -85,7 +87,9 @@ module Doorkeeper::OAuth
85
87
  let(:server) do
86
88
  double :server,
87
89
  access_token_expires_in: 2.minutes,
88
- custom_access_token_expires_in: ->(_oauth_client) { 1234 }
90
+ custom_access_token_expires_in: lambda { |context|
91
+ context.grant_type == Doorkeeper::OAuth::REFRESH_TOKEN ? 1234 : nil
92
+ }
89
93
  end
90
94
 
91
95
  before do
@@ -131,13 +135,13 @@ module Doorkeeper::OAuth
131
135
 
132
136
  it 'transfers scopes from the old token to the new token' do
133
137
  subject.authorize
134
- expect(Doorkeeper::AccessToken.last.scopes).to eq([:public, :write])
138
+ expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public write])
135
139
  end
136
140
 
137
141
  it 'reduces scopes to the provided scopes' do
138
142
  parameters[:scopes] = 'public'
139
143
  subject.authorize
140
- expect(Doorkeeper::AccessToken.last.scopes).to eq([:public])
144
+ expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public])
141
145
  end
142
146
 
143
147
  it 'validates that scopes are included in the original access token' do
@@ -151,7 +155,7 @@ module Doorkeeper::OAuth
151
155
  parameters[:scopes] = 'public update'
152
156
  parameters[:scope] = 'public'
153
157
  subject.authorize
154
- expect(Doorkeeper::AccessToken.last.scopes).to eq([:public])
158
+ expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public])
155
159
  end
156
160
 
157
161
  it 'uses params[:scope] in favor of scopes if present (invalid)' do
@@ -1,7 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'active_support/core_ext/module/delegation'
3
- require 'active_support/core_ext/string'
4
- require 'doorkeeper/oauth/scopes'
5
2
 
6
3
  module Doorkeeper::OAuth
7
4
  describe Scopes do
@@ -1,10 +1,9 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper::OAuth
4
4
  describe TokenRequest do
5
5
  let :application do
6
- scopes = double(all: ['public'])
7
- double(:application, id: 9990, scopes: scopes)
6
+ FactoryBot.create(:application, scopes: "public")
8
7
  end
9
8
 
10
9
  let :pre_auth do
@@ -51,8 +50,8 @@ module Doorkeeper::OAuth
51
50
  before do
52
51
  Doorkeeper.configure do
53
52
  orm DOORKEEPER_ORM
54
- custom_access_token_expires_in do |_oauth_client|
55
- 1234
53
+ custom_access_token_expires_in do |context|
54
+ context.grant_type == Doorkeeper::OAuth::IMPLICIT ? 1234 : nil
56
55
  end
57
56
  end
58
57
  end
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'doorkeeper/oauth/token_response'
3
2
 
4
3
  module Doorkeeper::OAuth
5
4
  describe TokenResponse do
@@ -1,6 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'active_support/core_ext/string'
3
- require 'doorkeeper/oauth/token'
4
2
 
5
3
  module Doorkeeper
6
4
  unless defined?(AccessToken)
@@ -14,7 +12,7 @@ module Doorkeeper
14
12
  let(:request) { double.as_null_object }
15
13
 
16
14
  let(:method) do
17
- ->(request) { return 'token-value' }
15
+ ->(*) { 'token-value' }
18
16
  end
19
17
 
20
18
  it 'accepts anything that responds to #call' do
@@ -96,19 +94,44 @@ module Doorkeeper
96
94
  end
97
95
 
98
96
  describe :authenticate do
99
- it 'calls the finder if token was returned' do
100
- token = ->(_r) { 'token' }
101
- expect(AccessToken).to receive(:by_token).with('token')
102
- Token.authenticate double, token
97
+ context 'refresh tokens are disabled (default)' do
98
+ context 'refresh tokens are enabled' do
99
+ it 'does not revoke previous refresh_token if token was found' do
100
+ token = ->(_r) { 'token' }
101
+ expect(
102
+ AccessToken
103
+ ).to receive(:by_token).with('token').and_return(token)
104
+ expect(token).not_to receive(:revoke_previous_refresh_token!)
105
+ Token.authenticate double, token
106
+ end
107
+ end
108
+
109
+ it 'calls the finder if token was returned' do
110
+ token = ->(_r) { 'token' }
111
+ expect(AccessToken).to receive(:by_token).with('token')
112
+ Token.authenticate double, token
113
+ end
103
114
  end
104
115
 
105
- it 'revokes previous refresh_token if token was found' do
106
- token = ->(_r) { 'token' }
107
- expect(
108
- AccessToken
109
- ).to receive(:by_token).with('token').and_return(token)
110
- expect(token).to receive(:revoke_previous_refresh_token!)
111
- Token.authenticate double, token
116
+ context 'refresh tokens are enabled' do
117
+ before do
118
+ Doorkeeper.configure { use_refresh_token }
119
+ end
120
+
121
+ it 'revokes previous refresh_token if token was found' do
122
+ token = ->(_r) { 'token' }
123
+ expect(
124
+ AccessToken
125
+ ).to receive(:by_token).with('token').and_return(token)
126
+ expect(token).to receive(:revoke_previous_refresh_token!)
127
+ Token.authenticate double, token
128
+ end
129
+
130
+ it 'calls the finder if token was returned' do
131
+ token = ->(_r) { 'token' }
132
+ expect(AccessToken).to receive(:by_token).with('token')
133
+ Token.authenticate double, token
134
+ end
112
135
  end
113
136
  end
114
137
  end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Doorkeeper::Orm::ActiveRecord::StaleRecordsCleaner do
6
+ let(:cleaner) { described_class.new(model) }
7
+ let(:models_by_name) do
8
+ {
9
+ access_token: Doorkeeper::AccessToken,
10
+ access_grant: Doorkeeper::AccessGrant
11
+ }
12
+ end
13
+
14
+ %i[access_token access_grant].each do |model_name|
15
+ context "(#{model_name})" do
16
+ let(:model) { models_by_name.fetch(model_name) }
17
+
18
+ describe '#clean_revoked' do
19
+ subject { cleaner.clean_revoked }
20
+
21
+ context 'with revoked record' do
22
+ before do
23
+ FactoryBot.create model_name, revoked_at: Time.current - 1.minute
24
+ end
25
+
26
+ it 'removes the record' do
27
+ expect { subject }.to change { model.count }.to(0)
28
+ end
29
+ end
30
+
31
+ context 'with record revoked in the future' do
32
+ before do
33
+ FactoryBot.create model_name, revoked_at: Time.current + 1.minute
34
+ end
35
+
36
+ it 'keeps the record' do
37
+ expect { subject }.not_to change { model.count }
38
+ end
39
+ end
40
+
41
+ context 'with unrevoked record' do
42
+ before do
43
+ FactoryBot.create model_name, revoked_at: nil
44
+ end
45
+
46
+ it 'keeps the record' do
47
+ expect { subject }.not_to change { model.count }
48
+ end
49
+ end
50
+ end
51
+
52
+ describe '#clean_expired' do
53
+ subject { cleaner.clean_expired(ttl) }
54
+ let(:ttl) { 500 }
55
+ let(:expiry_border) { ttl.seconds.ago }
56
+
57
+ context 'with record that is expired' do
58
+ before do
59
+ FactoryBot.create model_name, created_at: expiry_border - 1.minute
60
+ end
61
+
62
+ it 'removes the record' do
63
+ expect { subject }.to change { model.count }.to(0)
64
+ end
65
+ end
66
+
67
+ context 'with record that is not expired' do
68
+ before do
69
+ FactoryBot.create model_name, created_at: expiry_border + 1.minute
70
+ end
71
+
72
+ it 'keeps the record' do
73
+ expect { subject }.not_to change { model.count }
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'doorkeeper/request/strategy'
3
2
 
4
3
  module Doorkeeper
5
4
  module Request
@@ -46,7 +46,7 @@ describe Doorkeeper::Server do
46
46
  subject.authorization_request :code
47
47
  end
48
48
 
49
- it 'builds the request with composit strategy name' do
49
+ it 'builds the request with composite strategy name' do
50
50
  allow(Doorkeeper.configuration).
51
51
  to receive(:authorization_response_types).
52
52
  and_return(['id_token token'])
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  describe Doorkeeper::AccessGrant do
4
4
  subject { FactoryBot.build(:access_grant) }
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper
4
4
  describe AccessToken do
@@ -144,7 +144,7 @@ module Doorkeeper
144
144
  end
145
145
 
146
146
  module CustomGeneratorArgs
147
- def self.generate(opts = {})
147
+ def self.generate(_opts = {})
148
148
  raise LoadError, 'custom behaviour'
149
149
  end
150
150
  end
@@ -218,7 +218,7 @@ module Doorkeeper
218
218
  context 'with default parameters' do
219
219
 
220
220
  let(:resource_owner_id) { 100 }
221
- let(:application) { FactoryBot.create :application }
221
+ let(:application) { FactoryBot.create :application }
222
222
  let(:default_attributes) do
223
223
  { application: application, resource_owner_id: resource_owner_id }
224
224
  end
@@ -330,6 +330,10 @@ module Doorkeeper
330
330
  }
331
331
  end
332
332
 
333
+ before do
334
+ default_scopes_exist(*scopes.all)
335
+ end
336
+
333
337
  it 'returns only one token' do
334
338
  token = FactoryBot.create :access_token, default_attributes
335
339
  last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
@@ -355,37 +359,45 @@ module Doorkeeper
355
359
  expect(last_token).to be_nil
356
360
  end
357
361
 
358
- it 'matches the application' do
362
+ it "excludes tokens with a different application" do
359
363
  FactoryBot.create :access_token, default_attributes.merge(application: FactoryBot.create(:application))
360
364
  last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
361
365
  expect(last_token).to be_nil
362
366
  end
363
367
 
364
- it 'matches the resource owner' do
368
+ it "excludes tokens with a different resource owner" do
365
369
  FactoryBot.create :access_token, default_attributes.merge(resource_owner_id: 2)
366
370
  last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
367
371
  expect(last_token).to be_nil
368
372
  end
369
373
 
370
- it 'matches token with fewer scopes' do
374
+ it "excludes tokens with fewer scopes" do
371
375
  FactoryBot.create :access_token, default_attributes.merge(scopes: 'public')
372
376
  last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
373
377
  expect(last_token).to be_nil
374
378
  end
375
379
 
376
- it 'matches token with different scopes' do
380
+ it 'excludes tokens with different scopes' do
377
381
  FactoryBot.create :access_token, default_attributes.merge(scopes: 'public email')
378
382
  last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
379
383
  expect(last_token).to be_nil
380
384
  end
381
385
 
382
- it 'matches token with more scopes' do
386
+ it 'excludes tokens with additional scopes' do
383
387
  FactoryBot.create :access_token, default_attributes.merge(scopes: 'public write email')
384
388
  last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
385
389
  expect(last_token).to be_nil
386
390
  end
387
391
 
388
- it 'matches application scopes' do
392
+ it 'excludes tokens with scopes that are not present in server scopes' do
393
+ FactoryBot.create :access_token, default_attributes.merge(
394
+ application: application, scopes: 'public read'
395
+ )
396
+ last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
397
+ expect(last_token).to be_nil
398
+ end
399
+
400
+ it 'excludes tokens with scopes that are not present in application scopes' do
389
401
  application = FactoryBot.create :application, scopes: "private read"
390
402
  FactoryBot.create :access_token, default_attributes.merge(
391
403
  application: application
@@ -394,25 +406,47 @@ module Doorkeeper
394
406
  expect(last_token).to be_nil
395
407
  end
396
408
 
397
- it 'returns the last created token' do
409
+ it 'does not match token if empty scope requested and token/app scopes present' do
410
+ application = FactoryBot.create :application, scopes: "sample:scope"
411
+ app_params = {
412
+ application_id: application.id, scopes: "sample:scope",
413
+ resource_owner_id: 100
414
+ }
415
+ FactoryBot.create :access_token, app_params
416
+ empty_scopes = Doorkeeper::OAuth::Scopes.from_string("")
417
+ last_token = AccessToken.matching_token_for(application, 100, empty_scopes)
418
+ expect(last_token).to be_nil
419
+ end
420
+
421
+ it 'matches token if empty scope requested and no token scopes present' do
422
+ empty_scopes = Doorkeeper::OAuth::Scopes.from_string("")
423
+ token = FactoryBot.create :access_token, default_attributes.merge(scopes: empty_scopes)
424
+ last_token = AccessToken.matching_token_for(application, 100, empty_scopes)
425
+ expect(last_token).to eq(token)
426
+ end
427
+
428
+ it 'returns the last matching token' do
398
429
  FactoryBot.create :access_token, default_attributes.merge(created_at: 1.day.ago)
399
- token = FactoryBot.create :access_token, default_attributes
430
+ matching_token = FactoryBot.create :access_token, default_attributes
431
+ FactoryBot.create :access_token, default_attributes.merge(scopes: 'public')
432
+
400
433
  last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
401
- expect(last_token).to eq(token)
434
+ expect(last_token).to eq(matching_token)
402
435
  end
436
+ end
403
437
 
404
- it 'returns as_json hash' do
405
- token = FactoryBot.create :access_token, default_attributes
438
+ describe "#as_json" do
439
+ it "returns as_json hash" do
440
+ token = FactoryBot.create :access_token
406
441
  token_hash = {
407
442
  resource_owner_id: token.resource_owner_id,
408
443
  scopes: token.scopes,
409
444
  expires_in_seconds: token.expires_in_seconds,
410
445
  application: { uid: token.application.uid },
411
- created_at: token.created_at.to_i,
446
+ created_at: token.created_at.to_i
412
447
  }
413
448
  expect(token.as_json).to eq token_hash
414
449
  end
415
450
  end
416
-
417
451
  end
418
452
  end
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper
4
4
  describe Application do
@@ -253,51 +253,5 @@ module Doorkeeper
253
253
  it { expect(subject).to eq(false) }
254
254
  end
255
255
  end
256
-
257
- describe :confidential do
258
- subject { FactoryBot.create(:application, confidential: confidential).confidential }
259
-
260
- context 'when application is private/confidential' do
261
- let(:confidential) { true }
262
- it { expect(subject).to eq(true) }
263
- end
264
-
265
- context 'when application is public/non-confidential' do
266
- let(:confidential) { false }
267
- it { expect(subject).to eq(false) }
268
- end
269
-
270
- context 'when the application does not support confidentiality' do
271
- let(:confidential) { false }
272
-
273
- before { allow(Application).to receive(:supports_confidentiality?).and_return(false) }
274
-
275
- it 'warns of the CVE' do
276
- expect(ActiveSupport::Deprecation).to receive(:warn).with(
277
- 'You are susceptible to security bug ' \
278
- 'CVE-2018-1000211. Please follow instructions outlined in ' \
279
- 'Doorkeeper::CVE_2018_1000211_WARNING'
280
- )
281
- Application.new.confidential
282
- end
283
-
284
- it { expect(subject).to eq(true) }
285
- end
286
- end
287
-
288
- describe :supports_confidentiality? do
289
- context 'when no column' do
290
- it 'returns false' do
291
- expect(Application).to receive(:column_names).and_return(%w[foo bar])
292
- expect(Application.supports_confidentiality?).to eq(false)
293
- end
294
- end
295
- context 'when column' do
296
- it 'returns true' do
297
- expect(Application).to receive(:column_names).and_return(%w[foo bar confidential])
298
- expect(Application.supports_confidentiality?).to eq(true)
299
- end
300
- end
301
- end
302
256
  end
303
257
  end