doorkeeper 5.0.2 → 5.1.0.rc2

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 (94) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +17 -4
  3. data/Appraisals +29 -3
  4. data/Dangerfile +5 -2
  5. data/Gemfile +14 -4
  6. data/NEWS.md +64 -19
  7. data/README.md +68 -487
  8. data/app/controllers/doorkeeper/token_info_controller.rb +1 -1
  9. data/app/controllers/doorkeeper/tokens_controller.rb +7 -7
  10. data/app/views/doorkeeper/applications/show.html.erb +1 -1
  11. data/app/views/layouts/doorkeeper/admin.html.erb +5 -3
  12. data/bin/console +15 -0
  13. data/doorkeeper.gemspec +3 -2
  14. data/gemfiles/rails_4_2.gemfile +8 -4
  15. data/gemfiles/rails_5_0.gemfile +9 -5
  16. data/gemfiles/rails_5_1.gemfile +9 -5
  17. data/gemfiles/rails_5_2.gemfile +9 -5
  18. data/gemfiles/rails_6_0.gemfile +16 -0
  19. data/gemfiles/rails_master.gemfile +8 -9
  20. data/lib/doorkeeper/config.rb +164 -11
  21. data/lib/doorkeeper/helpers/controller.rb +3 -2
  22. data/lib/doorkeeper/models/access_grant_mixin.rb +16 -1
  23. data/lib/doorkeeper/models/access_token_mixin.rb +54 -10
  24. data/lib/doorkeeper/models/application_mixin.rb +42 -1
  25. data/lib/doorkeeper/models/concerns/expirable.rb +3 -2
  26. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  27. data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
  28. data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
  29. data/lib/doorkeeper/oauth/authorization/code.rb +1 -1
  30. data/lib/doorkeeper/oauth/authorization/token.rb +4 -2
  31. data/lib/doorkeeper/oauth/authorization_code_request.rb +1 -1
  32. data/lib/doorkeeper/oauth/client.rb +1 -1
  33. data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -3
  34. data/lib/doorkeeper/oauth/code_response.rb +2 -2
  35. data/lib/doorkeeper/oauth/error_response.rb +5 -1
  36. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -8
  37. data/lib/doorkeeper/oauth/helpers/unique_token.rb +12 -1
  38. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +32 -0
  39. data/lib/doorkeeper/oauth/invalid_token_response.rb +4 -0
  40. data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -2
  41. data/lib/doorkeeper/oauth/pre_authorization.rb +8 -3
  42. data/lib/doorkeeper/oauth/refresh_token_request.rb +4 -1
  43. data/lib/doorkeeper/oauth/token_introspection.rb +72 -6
  44. data/lib/doorkeeper/oauth/token_response.rb +2 -2
  45. data/lib/doorkeeper/orm/active_record/access_grant.rb +23 -2
  46. data/lib/doorkeeper/orm/active_record/application.rb +20 -2
  47. data/lib/doorkeeper/secret_storing/base.rb +63 -0
  48. data/lib/doorkeeper/secret_storing/bcrypt.rb +59 -0
  49. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  50. data/lib/doorkeeper/secret_storing/sha256_hash.rb +25 -0
  51. data/lib/doorkeeper/version.rb +3 -3
  52. data/lib/doorkeeper.rb +7 -0
  53. data/lib/generators/doorkeeper/templates/initializer.rb +90 -8
  54. data/spec/controllers/application_metal_controller_spec.rb +18 -4
  55. data/spec/controllers/authorizations_controller_spec.rb +3 -3
  56. data/spec/controllers/token_info_controller_spec.rb +1 -1
  57. data/spec/controllers/tokens_controller_spec.rb +85 -41
  58. data/spec/dummy/app/controllers/application_controller.rb +1 -1
  59. data/spec/dummy/config/application.rb +12 -1
  60. data/spec/factories.rb +3 -3
  61. data/spec/lib/config_spec.rb +168 -0
  62. data/spec/lib/models/expirable_spec.rb +12 -0
  63. data/spec/lib/models/reusable_spec.rb +40 -0
  64. data/spec/lib/models/scopes_spec.rb +13 -1
  65. data/spec/lib/models/secret_storable_spec.rb +113 -0
  66. data/spec/lib/oauth/authorization_code_request_spec.rb +18 -1
  67. data/spec/lib/oauth/base_request_spec.rb +7 -7
  68. data/spec/lib/oauth/client_credentials/creator_spec.rb +51 -7
  69. data/spec/lib/oauth/client_credentials/validation_spec.rb +3 -0
  70. data/spec/lib/oauth/error_response_spec.rb +7 -1
  71. data/spec/lib/oauth/helpers/scope_checker_spec.rb +52 -17
  72. data/spec/lib/oauth/helpers/uri_checker_spec.rb +20 -2
  73. data/spec/lib/oauth/password_access_token_request_spec.rb +43 -12
  74. data/spec/lib/oauth/pre_authorization_spec.rb +24 -0
  75. data/spec/lib/oauth/token_request_spec.rb +16 -1
  76. data/spec/lib/oauth/token_response_spec.rb +13 -13
  77. data/spec/lib/oauth/token_spec.rb +14 -0
  78. data/spec/lib/secret_storing/base_spec.rb +60 -0
  79. data/spec/lib/secret_storing/bcrypt_spec.rb +49 -0
  80. data/spec/lib/secret_storing/plain_spec.rb +44 -0
  81. data/spec/lib/secret_storing/sha256_hash_spec.rb +48 -0
  82. data/spec/models/doorkeeper/access_grant_spec.rb +61 -0
  83. data/spec/models/doorkeeper/access_token_spec.rb +123 -0
  84. data/spec/models/doorkeeper/application_spec.rb +56 -0
  85. data/spec/requests/flows/authorization_code_spec.rb +41 -1
  86. data/spec/requests/flows/client_credentials_spec.rb +2 -2
  87. data/spec/requests/flows/implicit_grant_spec.rb +1 -1
  88. data/spec/requests/flows/password_spec.rb +7 -5
  89. data/spec/requests/flows/revoke_token_spec.rb +14 -30
  90. data/spec/routing/custom_controller_routes_spec.rb +4 -0
  91. data/spec/spec_helper.rb +2 -1
  92. data/spec/support/ruby_2_6_rails_4_2_patch.rb +14 -0
  93. data/spec/support/shared/hashing_shared_context.rb +36 -0
  94. metadata +59 -22
@@ -20,7 +20,7 @@ describe Doorkeeper::TokensController do
20
20
 
21
21
  post :create
22
22
 
23
- expect(response.status).to eq 401
23
+ expect(response.status).to eq 400
24
24
  expect(response.headers['WWW-Authenticate']).to match(/Bearer/)
25
25
  end
26
26
  end
@@ -28,7 +28,7 @@ describe Doorkeeper::TokensController do
28
28
  describe 'when there is a failure due to a custom error' do
29
29
  it 'returns the error response with a custom message' do
30
30
  # I18n looks for `doorkeeper.errors.messages.custom_message` in locale files
31
- custom_message = "my_message"
31
+ custom_message = 'my_message'
32
32
  allow(I18n).to receive(:translate)
33
33
  .with(
34
34
  custom_message,
@@ -49,7 +49,7 @@ describe Doorkeeper::TokensController do
49
49
  "error" => custom_message,
50
50
  "error_description" => "Authorization custom message"
51
51
  }
52
- expect(response.status).to eq 401
52
+ expect(response.status).to eq 400
53
53
  expect(response.headers['WWW-Authenticate']).to match(/Bearer/)
54
54
  expect(JSON.parse(response.body)).to eq expected_response_body
55
55
  end
@@ -60,21 +60,17 @@ describe Doorkeeper::TokensController do
60
60
  let(:client) { FactoryBot.create(:application) }
61
61
  let(:access_token) { FactoryBot.create(:access_token, application: client) }
62
62
 
63
- before(:each) do
64
- allow(controller).to receive(:token) { access_token }
65
- end
66
-
67
63
  context 'when associated app is public' do
68
64
  let(:client) { FactoryBot.create(:application, confidential: false) }
69
65
 
70
66
  it 'returns 200' do
71
- post :revoke
67
+ post :revoke, params: { token: access_token.token }
72
68
 
73
69
  expect(response.status).to eq 200
74
70
  end
75
71
 
76
72
  it 'revokes the access token' do
77
- post :revoke
73
+ post :revoke, params: { token: access_token.token }
78
74
 
79
75
  expect(access_token.reload).to have_attributes(revoked?: true)
80
76
  end
@@ -89,13 +85,13 @@ describe Doorkeeper::TokensController do
89
85
  end
90
86
 
91
87
  it 'returns 200' do
92
- post :revoke
88
+ post :revoke, params: { token: access_token.token }
93
89
 
94
90
  expect(response.status).to eq 200
95
91
  end
96
92
 
97
93
  it 'revokes the access token' do
98
- post :revoke
94
+ post :revoke, params: { token: access_token.token }
99
95
 
100
96
  expect(access_token.reload).to have_attributes(revoked?: true)
101
97
  end
@@ -105,13 +101,13 @@ describe Doorkeeper::TokensController do
105
101
  let(:oauth_client) { Doorkeeper::OAuth::Client.new(some_other_client) }
106
102
 
107
103
  it 'returns 200' do
108
- post :revoke
104
+ post :revoke, params: { token: access_token.token }
109
105
 
110
106
  expect(response.status).to eq 200
111
107
  end
112
108
 
113
109
  it 'does not revoke the access token' do
114
- post :revoke
110
+ post :revoke, params: { token: access_token.token }
115
111
 
116
112
  expect(access_token.reload).to have_attributes(revoked?: false)
117
113
  end
@@ -134,28 +130,26 @@ describe Doorkeeper::TokensController do
134
130
  end
135
131
 
136
132
  describe 'when requested token introspection' do
137
- context 'authorized using Bearer token' do
138
- let(:client) { FactoryBot.create(:application) }
139
- let(:access_token) { FactoryBot.create(:access_token, application: client) }
133
+ let(:client) { FactoryBot.create(:application) }
134
+ let(:access_token) { FactoryBot.create(:access_token, application: client) }
135
+ let(:token_for_introspection) { FactoryBot.create(:access_token, application: client) }
140
136
 
137
+ context 'authorized using valid Bearer token' do
141
138
  it 'responds with full token introspection' do
142
139
  request.headers['Authorization'] = "Bearer #{access_token.token}"
143
140
 
144
- post :introspect, params: { token: access_token.token }
141
+ post :introspect, params: { token: token_for_introspection.token }
145
142
 
146
143
  should_have_json 'active', true
147
144
  expect(json_response).to include('client_id', 'token_type', 'exp', 'iat')
148
145
  end
149
146
  end
150
147
 
151
- context 'authorized using Client Authentication' do
152
- let(:client) { FactoryBot.create(:application) }
153
- let(:access_token) { FactoryBot.create(:access_token, application: client) }
154
-
148
+ context 'authorized using valid Client Authentication' do
155
149
  it 'responds with full token introspection' do
156
150
  request.headers['Authorization'] = basic_auth_header_for_client(client)
157
151
 
158
- post :introspect, params: { token: access_token.token }
152
+ post :introspect, params: { token: token_for_introspection.token }
159
153
 
160
154
  should_have_json 'active', true
161
155
  expect(json_response).to include('client_id', 'token_type', 'exp', 'iat')
@@ -163,14 +157,37 @@ describe Doorkeeper::TokensController do
163
157
  end
164
158
  end
165
159
 
160
+ context 'using custom introspection response' do
161
+ before do
162
+ Doorkeeper.configure do
163
+ orm DOORKEEPER_ORM
164
+ custom_introspection_response do |_token, _context|
165
+ {
166
+ sub: 'Z5O3upPC88QrAjx00dis',
167
+ aud: 'https://protected.example.net/resource'
168
+ }
169
+ end
170
+ end
171
+ end
172
+
173
+ it 'responds with full token introspection' do
174
+ request.headers['Authorization'] = "Bearer #{access_token.token}"
175
+
176
+ post :introspect, params: { token: token_for_introspection.token }
177
+
178
+ expect(json_response).to include('client_id', 'token_type', 'exp', 'iat', 'sub', 'aud')
179
+ should_have_json 'sub', 'Z5O3upPC88QrAjx00dis'
180
+ should_have_json 'aud', 'https://protected.example.net/resource'
181
+ end
182
+ end
183
+
166
184
  context 'public access token' do
167
- let(:client) { FactoryBot.create(:application) }
168
- let(:access_token) { FactoryBot.create(:access_token, application: nil) }
185
+ let(:token_for_introspection) { FactoryBot.create(:access_token, application: nil) }
169
186
 
170
187
  it 'responds with full token introspection' do
171
188
  request.headers['Authorization'] = basic_auth_header_for_client(client)
172
189
 
173
- post :introspect, params: { token: access_token.token }
190
+ post :introspect, params: { token: token_for_introspection.token }
174
191
 
175
192
  should_have_json 'active', true
176
193
  expect(json_response).to include('client_id', 'token_type', 'exp', 'iat')
@@ -179,14 +196,12 @@ describe Doorkeeper::TokensController do
179
196
  end
180
197
 
181
198
  context 'token was issued to a different client than is making this request' do
182
- let(:client) { FactoryBot.create(:application) }
183
199
  let(:different_client) { FactoryBot.create(:application) }
184
- let(:access_token) { FactoryBot.create(:access_token, application: client) }
185
200
 
186
201
  it 'responds with only active state' do
187
202
  request.headers['Authorization'] = basic_auth_header_for_client(different_client)
188
203
 
189
- post :introspect, params: { token: access_token.token }
204
+ post :introspect, params: { token: token_for_introspection.token }
190
205
 
191
206
  expect(response).to be_successful
192
207
 
@@ -195,6 +210,36 @@ describe Doorkeeper::TokensController do
195
210
  end
196
211
  end
197
212
 
213
+ context 'authorized using invalid Bearer token' do
214
+ let(:token_for_introspection) do
215
+ FactoryBot.create(:access_token, application: client, revoked_at: 1.day.ago)
216
+ end
217
+
218
+ it 'responds with invalid token error' do
219
+ request.headers['Authorization'] = "Bearer #{token_for_introspection.token}"
220
+
221
+ post :introspect, params: { token: access_token.token }
222
+
223
+ response_status_should_be 401
224
+
225
+ should_not_have_json 'active'
226
+ should_have_json 'error', 'invalid_token'
227
+ end
228
+ end
229
+
230
+ context 'authorized using the Bearer token that need to be introspected' do
231
+ it 'responds with invalid token error' do
232
+ request.headers['Authorization'] = "Bearer #{access_token.token}"
233
+
234
+ post :introspect, params: { token: access_token.token }
235
+
236
+ response_status_should_be 401
237
+
238
+ should_not_have_json 'active'
239
+ should_have_json 'error', 'invalid_token'
240
+ end
241
+ end
242
+
198
243
  context 'using invalid credentials to authorize' do
199
244
  let(:client) { double(uid: '123123', secret: '666999') }
200
245
  let(:access_token) { FactoryBot.create(:access_token) }
@@ -213,9 +258,6 @@ describe Doorkeeper::TokensController do
213
258
  end
214
259
 
215
260
  context 'using wrong token value' do
216
- let(:client) { FactoryBot.create(:application) }
217
- let(:access_token) { FactoryBot.create(:access_token, application: client) }
218
-
219
261
  it 'responds with only active state' do
220
262
  request.headers['Authorization'] = basic_auth_header_for_client(client)
221
263
 
@@ -226,14 +268,15 @@ describe Doorkeeper::TokensController do
226
268
  end
227
269
  end
228
270
 
229
- context 'when requested Access Token expired' do
230
- let(:client) { FactoryBot.create(:application) }
231
- let(:access_token) { FactoryBot.create(:access_token, application: client, created_at: 1.year.ago) }
271
+ context 'when requested access token expired' do
272
+ let(:token_for_introspection) do
273
+ FactoryBot.create(:access_token, application: client, created_at: 1.year.ago)
274
+ end
232
275
 
233
276
  it 'responds with only active state' do
234
277
  request.headers['Authorization'] = basic_auth_header_for_client(client)
235
278
 
236
- post :introspect, params: { token: access_token.token }
279
+ post :introspect, params: { token: token_for_introspection.token }
237
280
 
238
281
  should_have_json 'active', false
239
282
  expect(json_response).not_to include('client_id', 'token_type', 'exp', 'iat')
@@ -241,13 +284,14 @@ describe Doorkeeper::TokensController do
241
284
  end
242
285
 
243
286
  context 'when requested Access Token revoked' do
244
- let(:client) { FactoryBot.create(:application) }
245
- let(:access_token) { FactoryBot.create(:access_token, application: client, revoked_at: 1.year.ago) }
287
+ let(:token_for_introspection) do
288
+ FactoryBot.create(:access_token, application: client, revoked_at: 1.year.ago)
289
+ end
246
290
 
247
291
  it 'responds with only active state' do
248
292
  request.headers['Authorization'] = basic_auth_header_for_client(client)
249
293
 
250
- post :introspect, params: { token: access_token.token }
294
+ post :introspect, params: { token: token_for_introspection.token }
251
295
 
252
296
  should_have_json 'active', false
253
297
  expect(json_response).not_to include('client_id', 'token_type', 'exp', 'iat')
@@ -255,13 +299,13 @@ describe Doorkeeper::TokensController do
255
299
  end
256
300
 
257
301
  context 'unauthorized (no bearer token or client credentials)' do
258
- let(:access_token) { FactoryBot.create(:access_token) }
302
+ let(:token_for_introspection) { FactoryBot.create(:access_token) }
259
303
 
260
304
  it 'responds with invalid_request error' do
261
- post :introspect, params: { token: access_token.token }
305
+ post :introspect, params: { token: token_for_introspection.token }
262
306
 
263
307
  expect(response).not_to be_successful
264
- response_status_should_be 401
308
+ response_status_should_be 400
265
309
 
266
310
  should_not_have_json 'active'
267
311
  should_have_json 'error', 'invalid_request'
@@ -1,3 +1,3 @@
1
1
  class ApplicationController < ActionController::Base
2
- protect_from_forgery
2
+ protect_from_forgery with: :exception
3
3
  end
@@ -1,6 +1,17 @@
1
1
  require File.expand_path('boot', __dir__)
2
2
 
3
- require 'rails/all'
3
+ require "rails"
4
+
5
+ %w[
6
+ action_controller/railtie
7
+ action_view/railtie
8
+ sprockets/railtie
9
+ ].each do |railtie|
10
+ begin
11
+ require railtie
12
+ rescue LoadError
13
+ end
14
+ end
4
15
 
5
16
  Bundler.require(*Rails.groups)
6
17
 
data/spec/factories.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  FactoryBot.define do
2
- factory :access_grant, class: Doorkeeper::AccessGrant do
2
+ factory :access_grant, class: "Doorkeeper::AccessGrant" do
3
3
  sequence(:resource_owner_id) { |n| n }
4
4
  application
5
5
  redirect_uri { 'https://app.com/callback' }
@@ -7,7 +7,7 @@ FactoryBot.define do
7
7
  scopes { 'public write' }
8
8
  end
9
9
 
10
- factory :access_token, class: Doorkeeper::AccessToken do
10
+ factory :access_token, class: "Doorkeeper::AccessToken" do
11
11
  sequence(:resource_owner_id) { |n| n }
12
12
  application
13
13
  expires_in { 2.hours }
@@ -17,7 +17,7 @@ FactoryBot.define do
17
17
  end
18
18
  end
19
19
 
20
- factory :application, class: Doorkeeper::Application do
20
+ factory :application, class: "Doorkeeper::Application" do
21
21
  sequence(:name) { |n| "Application #{n}" }
22
22
  redirect_uri { 'https://app.com/callback' }
23
23
  end
@@ -141,6 +141,22 @@ describe Doorkeeper, 'configuration' do
141
141
  end
142
142
  end
143
143
 
144
+ describe 'scopes_by_grant_type' do
145
+ it 'is {} by default' do
146
+ expect(subject.scopes_by_grant_type).to eq({})
147
+ end
148
+
149
+ it 'has hash value' do
150
+ hash = {}
151
+ Doorkeeper.configure do
152
+ orm DOORKEEPER_ORM
153
+ scopes_by_grant_type hash
154
+ end
155
+
156
+ expect(subject.scopes_by_grant_type).to eq(hash)
157
+ end
158
+ end
159
+
144
160
  describe 'use_refresh_token' do
145
161
  it 'is false by default' do
146
162
  expect(subject.refresh_token_enabled?).to eq(false)
@@ -191,6 +207,31 @@ describe Doorkeeper, 'configuration' do
191
207
  end
192
208
  end
193
209
 
210
+ describe 'token_reuse_limit' do
211
+ it 'is 100 by default' do
212
+ expect(subject.token_reuse_limit).to eq(100)
213
+ end
214
+
215
+ it 'can change the value' do
216
+ Doorkeeper.configure do
217
+ token_reuse_limit 90
218
+ end
219
+
220
+ expect(subject.token_reuse_limit).to eq(90)
221
+ end
222
+
223
+ it 'sets the value to 100 if invalid value is being set' do
224
+ expect(Rails.logger).to receive(:warn).with(/will be set to default 100/)
225
+
226
+ Doorkeeper.configure do
227
+ reuse_access_token
228
+ token_reuse_limit 110
229
+ end
230
+
231
+ expect(subject.token_reuse_limit).to eq(100)
232
+ end
233
+ end
234
+
194
235
  describe 'enforce_configured_scopes' do
195
236
  it 'is false by default' do
196
237
  expect(subject.enforce_configured_scopes?).to eq(false)
@@ -441,6 +482,22 @@ describe Doorkeeper, 'configuration' do
441
482
  end
442
483
  end
443
484
 
485
+ describe 'default_generator_method' do
486
+ it "is :urlsafe_base64 by default" do
487
+ expect(Doorkeeper.configuration.default_generator_method)
488
+ .to eq(:urlsafe_base64)
489
+ end
490
+
491
+ it 'can change the value' do
492
+ Doorkeeper.configure do
493
+ orm DOORKEEPER_ORM
494
+ default_generator_method :hex
495
+ end
496
+
497
+ expect(subject.default_generator_method).to eq(:hex)
498
+ end
499
+ end
500
+
444
501
  describe 'base_controller' do
445
502
  context 'default' do
446
503
  it { expect(Doorkeeper.configuration.base_controller).to eq('ActionController::Base') }
@@ -525,4 +582,115 @@ describe Doorkeeper, 'configuration' do
525
582
  expect(subject.handle_auth_errors).to eq(:raise)
526
583
  end
527
584
  end
585
+
586
+ describe 'token_secret_strategy' do
587
+ it 'is plain by default' do
588
+ expect(subject.token_secret_strategy).to eq(Doorkeeper::SecretStoring::Plain)
589
+ expect(subject.token_secret_fallback_strategy).to eq(nil)
590
+ end
591
+
592
+ context 'when provided' do
593
+ before do
594
+ Doorkeeper.configure do
595
+ hash_token_secrets
596
+ end
597
+ end
598
+
599
+ it 'will enable hashing for applications' do
600
+ expect(subject.token_secret_strategy).to eq(Doorkeeper::SecretStoring::Sha256Hash)
601
+ expect(subject.token_secret_fallback_strategy).to eq(nil)
602
+ end
603
+ end
604
+
605
+ context 'when manually provided with invalid constant' do
606
+ it 'raises an exception' do
607
+ expect {
608
+ Doorkeeper.configure do
609
+ hash_token_secrets using: 'does not exist'
610
+ end
611
+ }.to raise_error(NameError)
612
+ end
613
+ end
614
+
615
+ context 'when manually provided with invalid option' do
616
+ it 'raises an exception' do
617
+ expect do
618
+ Doorkeeper.configure do
619
+ hash_token_secrets using: 'Doorkeeper::SecretStoring::BCrypt'
620
+ end
621
+ end.to raise_error(ArgumentError,
622
+ /can only be used for storing application secrets/)
623
+ end
624
+ end
625
+
626
+ context 'when provided with fallback' do
627
+ before do
628
+ Doorkeeper.configure do
629
+ hash_token_secrets fallback: :plain
630
+ end
631
+ end
632
+
633
+ it 'will enable hashing for applications' do
634
+ expect(subject.token_secret_strategy).to eq(Doorkeeper::SecretStoring::Sha256Hash)
635
+ expect(subject.token_secret_fallback_strategy).to eq(Doorkeeper::SecretStoring::Plain)
636
+ end
637
+ end
638
+
639
+
640
+ describe 'hash_token_secrets together with reuse_access_token' do
641
+ it 'will disable reuse_access_token' do
642
+ expect(Rails.logger).to receive(:warn).with(/reuse_access_token will be disabled/)
643
+
644
+ Doorkeeper.configure do
645
+ reuse_access_token
646
+ hash_token_secrets
647
+ end
648
+
649
+ expect(subject.reuse_access_token).to eq(false)
650
+ end
651
+ end
652
+ end
653
+
654
+ describe 'application_secret_strategy' do
655
+ it 'is plain by default' do
656
+ expect(subject.application_secret_strategy).to eq(Doorkeeper::SecretStoring::Plain)
657
+ expect(subject.application_secret_fallback_strategy).to eq(nil)
658
+ end
659
+
660
+ context 'when provided' do
661
+ before do
662
+ Doorkeeper.configure do
663
+ hash_application_secrets
664
+ end
665
+ end
666
+
667
+ it 'will enable hashing for applications' do
668
+ expect(subject.application_secret_strategy).to eq(Doorkeeper::SecretStoring::Sha256Hash)
669
+ expect(subject.application_secret_fallback_strategy).to eq(nil)
670
+ end
671
+ end
672
+
673
+ context 'when manually provided with invalid constant' do
674
+ it 'raises an exception' do
675
+ expect {
676
+ Doorkeeper.configure do
677
+ hash_application_secrets using: 'does not exist'
678
+ end
679
+ }.to raise_error(NameError)
680
+ end
681
+ end
682
+
683
+ context 'when provided with fallback' do
684
+ before do
685
+ Doorkeeper.configure do
686
+ hash_application_secrets fallback: :plain
687
+ end
688
+ end
689
+
690
+ it 'will enable hashing for applications' do
691
+ expect(subject.application_secret_strategy).to eq(Doorkeeper::SecretStoring::Sha256Hash)
692
+ expect(subject.application_secret_fallback_strategy).to eq(Doorkeeper::SecretStoring::Plain)
693
+ end
694
+ end
695
+ end
528
696
  end
@@ -44,4 +44,16 @@ describe 'Expirable' do
44
44
  expect(subject.expires_in_seconds).to be_nil
45
45
  end
46
46
  end
47
+
48
+ describe :expires_at do
49
+ it 'should return the expiration time of the token' do
50
+ allow(subject).to receive(:expires_in).and_return(2.minutes)
51
+ expect(subject.expires_at).to be_a(Time)
52
+ end
53
+
54
+ it 'should return nil when expires_in is nil' do
55
+ allow(subject).to receive(:expires_in).and_return(nil)
56
+ expect(subject.expires_at).to be_nil
57
+ end
58
+ end
47
59
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'Reusable' do
6
+ subject do
7
+ Class.new do
8
+ include Doorkeeper::Models::Reusable
9
+ end.new
10
+ end
11
+
12
+ describe :reusable? do
13
+ it 'is reusable if its expires_in is nil' do
14
+ allow(subject).to receive(:expired?).and_return(false)
15
+ allow(subject).to receive(:expires_in).and_return(nil)
16
+ expect(subject).to be_reusable
17
+ end
18
+
19
+ it 'is reusable if its expiry has crossed reusable limit' do
20
+ allow(subject).to receive(:expired?).and_return(false)
21
+ allow(Doorkeeper.configuration).to receive(:token_reuse_limit).and_return(90)
22
+ allow(subject).to receive(:expires_in).and_return(100.seconds)
23
+ allow(subject).to receive(:expires_in_seconds).and_return(20.seconds)
24
+ expect(subject).to be_reusable
25
+ end
26
+
27
+ it 'is not reusable if its expiry has crossed reusable limit' do
28
+ allow(subject).to receive(:expired?).and_return(false)
29
+ allow(Doorkeeper.configuration).to receive(:token_reuse_limit).and_return(90)
30
+ allow(subject).to receive(:expires_in).and_return(100.seconds)
31
+ allow(subject).to receive(:expires_in_seconds).and_return(5.seconds)
32
+ expect(subject).not_to be_reusable
33
+ end
34
+
35
+ it 'is not reusable if it is already expired' do
36
+ allow(subject).to receive(:expired?).and_return(true)
37
+ expect(subject).not_to be_reusable
38
+ end
39
+ end
40
+ end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe 'Doorkeeper::Models::Scopes' do
4
4
  subject do
5
- Class.new(Hash) do
5
+ Class.new(Struct.new(:scopes)) do
6
6
  include Doorkeeper::Models::Scopes
7
7
  end.new
8
8
  end
@@ -21,6 +21,18 @@ describe 'Doorkeeper::Models::Scopes' do
21
21
  end
22
22
  end
23
23
 
24
+ describe :scopes= do
25
+ it 'accepts String' do
26
+ subject.scopes = 'private admin'
27
+ expect(subject.scopes_string).to eq('private admin')
28
+ end
29
+
30
+ it 'accepts Array' do
31
+ subject.scopes = %w[private admin]
32
+ expect(subject.scopes_string).to eq('private admin')
33
+ end
34
+ end
35
+
24
36
  describe :scopes_string do
25
37
  it 'is a `Scopes` class' do
26
38
  expect(subject.scopes_string).to eq('public admin')