doorkeeper 5.1.2 → 5.2.2

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 (107) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +1 -1
  3. data/CHANGELOG.md +854 -0
  4. data/CONTRIBUTING.md +11 -9
  5. data/Dangerfile +2 -2
  6. data/Dockerfile +29 -0
  7. data/Gemfile +3 -2
  8. data/NEWS.md +1 -819
  9. data/README.md +11 -3
  10. data/RELEASING.md +6 -5
  11. data/app/controllers/doorkeeper/application_controller.rb +1 -1
  12. data/app/controllers/doorkeeper/application_metal_controller.rb +2 -1
  13. data/app/controllers/doorkeeper/applications_controller.rb +5 -3
  14. data/app/controllers/doorkeeper/authorizations_controller.rb +14 -7
  15. data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
  16. data/app/controllers/doorkeeper/tokens_controller.rb +32 -9
  17. data/app/views/doorkeeper/applications/_form.html.erb +0 -6
  18. data/app/views/doorkeeper/applications/show.html.erb +1 -1
  19. data/config/locales/en.yml +8 -2
  20. data/doorkeeper.gemspec +9 -1
  21. data/gemfiles/rails_5_0.gemfile +1 -0
  22. data/gemfiles/rails_5_1.gemfile +1 -0
  23. data/gemfiles/rails_5_2.gemfile +1 -0
  24. data/gemfiles/rails_6_0.gemfile +2 -1
  25. data/gemfiles/rails_master.gemfile +1 -0
  26. data/lib/doorkeeper/config/option.rb +13 -7
  27. data/lib/doorkeeper/config.rb +88 -6
  28. data/lib/doorkeeper/errors.rb +13 -18
  29. data/lib/doorkeeper/grape/helpers.rb +5 -1
  30. data/lib/doorkeeper/helpers/controller.rb +23 -4
  31. data/lib/doorkeeper/models/access_token_mixin.rb +43 -2
  32. data/lib/doorkeeper/oauth/authorization/code.rb +11 -13
  33. data/lib/doorkeeper/oauth/authorization/token.rb +1 -1
  34. data/lib/doorkeeper/oauth/authorization_code_request.rb +18 -9
  35. data/lib/doorkeeper/oauth/base_request.rb +2 -0
  36. data/lib/doorkeeper/oauth/client_credentials/creator.rb +14 -0
  37. data/lib/doorkeeper/oauth/client_credentials/validation.rb +8 -0
  38. data/lib/doorkeeper/oauth/code_request.rb +5 -11
  39. data/lib/doorkeeper/oauth/code_response.rb +2 -2
  40. data/lib/doorkeeper/oauth/error_response.rb +1 -1
  41. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +18 -4
  42. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  43. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  44. data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -2
  45. data/lib/doorkeeper/oauth/pre_authorization.rb +70 -37
  46. data/lib/doorkeeper/oauth/refresh_token_request.rb +13 -10
  47. data/lib/doorkeeper/oauth/token_introspection.rb +23 -13
  48. data/lib/doorkeeper/oauth/token_request.rb +4 -18
  49. data/lib/doorkeeper/orm/active_record/access_grant.rb +1 -1
  50. data/lib/doorkeeper/orm/active_record/access_token.rb +2 -2
  51. data/lib/doorkeeper/orm/active_record/application.rb +15 -69
  52. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +61 -0
  53. data/lib/doorkeeper/orm/active_record.rb +19 -3
  54. data/lib/doorkeeper/request/authorization_code.rb +2 -0
  55. data/lib/doorkeeper/request.rb +6 -11
  56. data/lib/doorkeeper/server.rb +2 -6
  57. data/lib/doorkeeper/stale_records_cleaner.rb +6 -2
  58. data/lib/doorkeeper/version.rb +1 -1
  59. data/lib/doorkeeper.rb +4 -0
  60. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +6 -6
  61. data/lib/generators/doorkeeper/templates/initializer.rb +110 -33
  62. data/lib/generators/doorkeeper/templates/migration.rb.erb +4 -1
  63. data/spec/controllers/applications_controller_spec.rb +93 -0
  64. data/spec/controllers/authorizations_controller_spec.rb +143 -62
  65. data/spec/controllers/protected_resources_controller_spec.rb +3 -3
  66. data/spec/controllers/tokens_controller_spec.rb +205 -37
  67. data/spec/dummy/config/application.rb +3 -1
  68. data/spec/dummy/config/initializers/doorkeeper.rb +54 -9
  69. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +1 -1
  70. data/spec/lib/config_spec.rb +43 -1
  71. data/spec/lib/oauth/authorization_code_request_spec.rb +13 -1
  72. data/spec/lib/oauth/base_request_spec.rb +33 -16
  73. data/spec/lib/oauth/client_credentials/creator_spec.rb +3 -0
  74. data/spec/lib/oauth/code_request_spec.rb +27 -28
  75. data/spec/lib/oauth/helpers/uri_checker_spec.rb +17 -2
  76. data/spec/lib/oauth/invalid_request_response_spec.rb +75 -0
  77. data/spec/lib/oauth/pre_authorization_spec.rb +76 -66
  78. data/spec/lib/oauth/refresh_token_request_spec.rb +1 -0
  79. data/spec/lib/oauth/token_request_spec.rb +20 -17
  80. data/spec/lib/server_spec.rb +0 -12
  81. data/spec/models/doorkeeper/access_grant_spec.rb +21 -2
  82. data/spec/models/doorkeeper/access_token_spec.rb +35 -4
  83. data/spec/models/doorkeeper/application_spec.rb +275 -370
  84. data/spec/requests/endpoints/authorization_spec.rb +21 -5
  85. data/spec/requests/endpoints/token_spec.rb +1 -1
  86. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -0
  87. data/spec/requests/flows/authorization_code_spec.rb +93 -27
  88. data/spec/requests/flows/client_credentials_spec.rb +38 -0
  89. data/spec/requests/flows/implicit_grant_errors_spec.rb +22 -10
  90. data/spec/requests/flows/implicit_grant_spec.rb +9 -8
  91. data/spec/requests/flows/password_spec.rb +37 -0
  92. data/spec/requests/flows/refresh_token_spec.rb +1 -1
  93. data/spec/requests/flows/revoke_token_spec.rb +19 -11
  94. data/spec/support/doorkeeper_rspec.rb +1 -1
  95. data/spec/support/helpers/request_spec_helper.rb +14 -2
  96. data/spec/validators/redirect_uri_validator_spec.rb +40 -15
  97. metadata +16 -15
  98. data/.coveralls.yml +0 -1
  99. data/.github/ISSUE_TEMPLATE.md +0 -25
  100. data/.github/PULL_REQUEST_TEMPLATE.md +0 -17
  101. data/.gitignore +0 -20
  102. data/.gitlab-ci.yml +0 -16
  103. data/.hound.yml +0 -3
  104. data/.rspec +0 -1
  105. data/.rubocop.yml +0 -50
  106. data/.travis.yml +0 -35
  107. data/app/validators/redirect_uri_validator.rb +0 -50
@@ -3,469 +3,374 @@
3
3
  require "spec_helper"
4
4
  require "bcrypt"
5
5
 
6
- describe Doorkeeper::Application do
7
- let(:require_owner) { Doorkeeper.configuration.instance_variable_set("@confirm_application_owner", true) }
8
- let(:unset_require_owner) { Doorkeeper.configuration.instance_variable_set("@confirm_application_owner", false) }
9
- let(:new_application) { FactoryBot.build(:application) }
6
+ module Doorkeeper
7
+ describe Application do
8
+ let(:clazz) { Doorkeeper::Application }
9
+ let(:require_owner) { Doorkeeper.configuration.instance_variable_set("@confirm_application_owner", true) }
10
+ let(:unset_require_owner) { Doorkeeper.configuration.instance_variable_set("@confirm_application_owner", false) }
11
+ let(:new_application) { FactoryBot.build(:application) }
10
12
 
11
- let(:uid) { SecureRandom.hex(8) }
12
- let(:secret) { SecureRandom.hex(8) }
13
+ let(:uid) { SecureRandom.hex(8) }
14
+ let(:secret) { SecureRandom.hex(8) }
13
15
 
14
- it "is invalid without a name" do
15
- new_application.name = nil
16
- expect(new_application).not_to be_valid
17
- end
18
-
19
- it "is invalid without determining confidentiality" do
20
- new_application.confidential = nil
21
- expect(new_application).not_to be_valid
22
- end
23
-
24
- it "generates uid on create" do
25
- expect(new_application.uid).to be_nil
26
- new_application.save
27
- expect(new_application.uid).not_to be_nil
28
- end
29
-
30
- it "generates uid on create if an empty string" do
31
- new_application.uid = ""
32
- new_application.save
33
- expect(new_application.uid).not_to be_blank
34
- end
35
-
36
- it "generates uid on create unless one is set" do
37
- new_application.uid = uid
38
- new_application.save
39
- expect(new_application.uid).to eq(uid)
40
- end
41
-
42
- it "is invalid without uid" do
43
- new_application.save
44
- new_application.uid = nil
45
- expect(new_application).not_to be_valid
46
- end
47
-
48
- it "checks uniqueness of uid" do
49
- app1 = FactoryBot.create(:application)
50
- app2 = FactoryBot.create(:application)
51
- app2.uid = app1.uid
52
- expect(app2).not_to be_valid
53
- end
54
-
55
- it "expects database to throw an error when uids are the same" do
56
- app1 = FactoryBot.create(:application)
57
- app2 = FactoryBot.create(:application)
58
- app2.uid = app1.uid
59
- expect { app2.save!(validate: false) }.to raise_error(uniqueness_error)
60
- end
16
+ context "application_owner is enabled" do
17
+ before do
18
+ Doorkeeper.configure do
19
+ orm DOORKEEPER_ORM
20
+ enable_application_owner
21
+ end
22
+ end
61
23
 
62
- it "generate secret on create" do
63
- expect(new_application.secret).to be_nil
64
- new_application.save
65
- expect(new_application.secret).not_to be_nil
66
- end
24
+ context "application owner is not required" do
25
+ before(:each) do
26
+ unset_require_owner
27
+ end
67
28
 
68
- it "generate secret on create if is blank string" do
69
- new_application.secret = ""
70
- new_application.save
71
- expect(new_application.secret).not_to be_blank
72
- end
29
+ it "is valid given valid attributes" do
30
+ expect(new_application).to be_valid
31
+ end
32
+ end
73
33
 
74
- it "generate secret on create unless one is set" do
75
- new_application.secret = secret
76
- new_application.save
77
- expect(new_application.secret).to eq(secret)
78
- end
34
+ context "application owner is required" do
35
+ before(:each) do
36
+ require_owner
37
+ @owner = FactoryBot.build_stubbed(:doorkeeper_testing_user)
38
+ end
79
39
 
80
- it "is invalid without secret" do
81
- new_application.save
82
- new_application.secret = nil
83
- expect(new_application).not_to be_valid
84
- end
40
+ it "is invalid without an owner" do
41
+ expect(new_application).not_to be_valid
42
+ end
85
43
 
86
- context "application_owner is enabled" do
87
- before do
88
- Doorkeeper.configure do
89
- orm DOORKEEPER_ORM
90
- enable_application_owner
44
+ it "is valid with an owner" do
45
+ new_application.owner = @owner
46
+ expect(new_application).to be_valid
47
+ end
91
48
  end
92
49
  end
93
50
 
94
- context "application owner is not required" do
95
- before(:each) do
96
- unset_require_owner
97
- end
98
-
99
- it "is valid given valid attributes" do
100
- expect(new_application).to be_valid
101
- end
51
+ it "is invalid without a name" do
52
+ new_application.name = nil
53
+ expect(new_application).not_to be_valid
102
54
  end
103
55
 
104
- context "application owner is required" do
105
- before do
106
- require_owner
107
- @owner = FactoryBot.build_stubbed(:doorkeeper_testing_user)
108
- end
56
+ it "is invalid without determining confidentiality" do
57
+ new_application.confidential = nil
58
+ expect(new_application).not_to be_valid
59
+ end
109
60
 
110
- it "is invalid without an owner" do
111
- expect(new_application).not_to be_valid
112
- end
61
+ it "generates uid on create" do
62
+ expect(new_application.uid).to be_nil
63
+ new_application.save
64
+ expect(new_application.uid).not_to be_nil
65
+ end
113
66
 
114
- it "is valid with an owner" do
115
- new_application.owner = @owner
116
- expect(new_application).to be_valid
117
- end
67
+ it "generates uid on create if an empty string" do
68
+ new_application.uid = ""
69
+ new_application.save
70
+ expect(new_application.uid).not_to be_blank
118
71
  end
119
- end
120
72
 
121
- context "redirect URI" do
122
- context "when grant flows allow blank redirect URI" do
123
- before do
124
- Doorkeeper.configure do
125
- grant_flows %w[password client_credentials]
126
- end
127
- end
73
+ it "generates uid on create unless one is set" do
74
+ new_application.uid = uid
75
+ new_application.save
76
+ expect(new_application.uid).to eq(uid)
77
+ end
128
78
 
129
- it "is valid without redirect_uri" do
130
- new_application.save
131
- new_application.redirect_uri = nil
132
- expect(new_application).to be_valid
133
- end
79
+ it "is invalid without uid" do
80
+ new_application.save
81
+ new_application.uid = nil
82
+ expect(new_application).not_to be_valid
134
83
  end
135
84
 
136
- context "when grant flows require redirect URI" do
137
- before do
138
- Doorkeeper.configure do
139
- grant_flows %w[password client_credentials authorization_code]
85
+ context "redirect URI" do
86
+ context "when grant flows allow blank redirect URI" do
87
+ before do
88
+ Doorkeeper.configure do
89
+ grant_flows %w[password client_credentials]
90
+ end
140
91
  end
141
- end
142
92
 
143
- it "is invalid without redirect_uri" do
144
- new_application.save
145
- new_application.redirect_uri = nil
146
- expect(new_application).not_to be_valid
93
+ it "is valid without redirect_uri" do
94
+ new_application.save
95
+ new_application.redirect_uri = nil
96
+ expect(new_application).to be_valid
97
+ end
147
98
  end
148
- end
149
99
 
150
- context "when blank URI option disabled" do
151
- before do
152
- Doorkeeper.configure do
153
- grant_flows %w[password client_credentials]
154
- allow_blank_redirect_uri false
100
+ context "when grant flows require redirect URI" do
101
+ before do
102
+ Doorkeeper.configure do
103
+ grant_flows %w[password client_credentials authorization_code]
104
+ end
155
105
  end
156
- end
157
106
 
158
- it "is invalid without redirect_uri" do
159
- new_application.save
160
- new_application.redirect_uri = nil
161
- expect(new_application).not_to be_valid
107
+ it "is invalid without redirect_uri" do
108
+ new_application.save
109
+ new_application.redirect_uri = nil
110
+ expect(new_application).not_to be_valid
111
+ end
162
112
  end
163
- end
164
- end
165
-
166
- context "with hashing enabled" do
167
- include_context "with application hashing enabled"
168
- let(:app) { FactoryBot.create :application }
169
- let(:default_strategy) { Doorkeeper::SecretStoring::Sha256Hash }
170
113
 
171
- it "uses SHA256 to avoid additional dependencies" do
172
- # Ensure token was generated
173
- app.validate
174
- expect(app.secret).to eq(default_strategy.transform_secret(app.plaintext_secret))
175
- end
176
-
177
- context "when bcrypt strategy is configured" do
178
- # In this text context, we have bcrypt loaded so `bcrypt_present?`
179
- # will always be true
180
- before do
181
- Doorkeeper.configure do
182
- hash_application_secrets using: "Doorkeeper::SecretStoring::BCrypt"
114
+ context "when blank URI option disabled" do
115
+ before do
116
+ Doorkeeper.configure do
117
+ grant_flows %w[password client_credentials]
118
+ allow_blank_redirect_uri false
119
+ end
183
120
  end
184
- end
185
121
 
186
- it "holds a volatile plaintext and BCrypt secret" do
187
- expect(app.secret_strategy).to eq Doorkeeper::SecretStoring::BCrypt
188
- expect(app.plaintext_secret).to be_a(String)
189
- expect(app.secret).not_to eq(app.plaintext_secret)
190
- expect { ::BCrypt::Password.create(app.secret) }.not_to raise_error
122
+ it "is invalid without redirect_uri" do
123
+ new_application.save
124
+ new_application.redirect_uri = nil
125
+ expect(new_application).not_to be_valid
126
+ end
191
127
  end
192
128
  end
193
129
 
194
- it "does not fallback to plain lookup by default" do
195
- lookup = described_class.by_uid_and_secret(app.uid, app.secret)
196
- expect(lookup).to eq(nil)
197
-
198
- lookup = described_class.by_uid_and_secret(app.uid, app.plaintext_secret)
199
- expect(lookup).to eq(app)
130
+ it "checks uniqueness of uid" do
131
+ app1 = FactoryBot.create(:application)
132
+ app2 = FactoryBot.create(:application)
133
+ app2.uid = app1.uid
134
+ expect(app2).not_to be_valid
200
135
  end
201
136
 
202
- context "with fallback enabled" do
203
- include_context "with token hashing and fallback lookup enabled"
204
-
205
- it "provides plain and hashed lookup" do
206
- lookup = described_class.by_uid_and_secret(app.uid, app.secret)
207
- expect(lookup).to eq(app)
208
-
209
- lookup = described_class.by_uid_and_secret(app.uid, app.plaintext_secret)
210
- expect(lookup).to eq(app)
211
- end
137
+ it "expects database to throw an error when uids are the same" do
138
+ app1 = FactoryBot.create(:application)
139
+ app2 = FactoryBot.create(:application)
140
+ app2.uid = app1.uid
141
+ expect { app2.save!(validate: false) }.to raise_error(uniqueness_error)
212
142
  end
213
143
 
214
- it "does not provide access to secret after loading" do
215
- lookup = described_class.by_uid_and_secret(app.uid, app.plaintext_secret)
216
- expect(lookup.plaintext_secret).to be_nil
144
+ it "generate secret on create" do
145
+ expect(new_application.secret).to be_nil
146
+ new_application.save
147
+ expect(new_application.secret).not_to be_nil
217
148
  end
218
- end
219
149
 
220
- describe "destroy related models on cascade" do
221
- before(:each) do
150
+ it "generate secret on create if is blank string" do
151
+ new_application.secret = ""
222
152
  new_application.save
153
+ expect(new_application.secret).not_to be_blank
223
154
  end
224
155
 
225
- let(:resource_owner) { FactoryBot.create(:doorkeeper_testing_user) }
226
-
227
- it "should destroy its access grants" do
228
- FactoryBot.create(
229
- :access_grant,
230
- application: new_application,
231
- resource_owner_id: resource_owner.id,
232
- )
233
-
234
- expect { new_application.destroy }.to change { Doorkeeper::AccessGrant.count }.by(-1)
156
+ it "generate secret on create unless one is set" do
157
+ new_application.secret = secret
158
+ new_application.save
159
+ expect(new_application.secret).to eq(secret)
235
160
  end
236
161
 
237
- it "should destroy its access tokens" do
238
- FactoryBot.create(:access_token, application: new_application)
239
- FactoryBot.create(:access_token, application: new_application, revoked_at: Time.now.utc)
240
- expect do
241
- new_application.destroy
242
- end.to change { Doorkeeper::AccessToken.count }.by(-2)
162
+ it "is invalid without secret" do
163
+ new_application.save
164
+ new_application.secret = nil
165
+ expect(new_application).not_to be_valid
243
166
  end
244
- end
245
167
 
246
- describe "#ordered_by" do
247
- let(:applications) { FactoryBot.create_list(:application, 5) }
168
+ context "with hashing enabled" do
169
+ include_context "with application hashing enabled"
170
+ let(:app) { FactoryBot.create :application }
171
+ let(:default_strategy) { Doorkeeper::SecretStoring::Sha256Hash }
248
172
 
249
- context "when a direction is not specified" do
250
- it "calls order with a default order of asc" do
251
- names = applications.map(&:name).sort
252
- expect(described_class.ordered_by(:name).map(&:name)).to eq(names)
173
+ it "uses SHA256 to avoid additional dependencies" do
174
+ # Ensure token was generated
175
+ app.validate
176
+ expect(app.secret).to eq(default_strategy.transform_secret(app.plaintext_secret))
253
177
  end
254
- end
255
178
 
256
- context "when a direction is specified" do
257
- it "calls order with specified direction" do
258
- names = applications.map(&:name).sort.reverse
259
- expect(described_class.ordered_by(:name, :desc).map(&:name)).to eq(names)
260
- end
261
- end
262
- end
179
+ context "when bcrypt strategy is configured" do
180
+ # In this text context, we have bcrypt loaded so `bcrypt_present?`
181
+ # will always be true
182
+ before do
183
+ Doorkeeper.configure do
184
+ hash_application_secrets using: "Doorkeeper::SecretStoring::BCrypt"
185
+ end
186
+ end
263
187
 
264
- describe "#redirect_uri=" do
265
- context "when array of valid redirect_uris" do
266
- it "should join by newline" do
267
- new_application.redirect_uri = ["http://localhost/callback1", "http://localhost/callback2"]
268
- expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
269
- end
270
- end
271
- context "when string of valid redirect_uris" do
272
- it "should store as-is" do
273
- new_application.redirect_uri = "http://localhost/callback1\nhttp://localhost/callback2"
274
- expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
188
+ it "holds a volatile plaintext and BCrypt secret" do
189
+ expect(app.secret_strategy).to eq Doorkeeper::SecretStoring::BCrypt
190
+ expect(app.plaintext_secret).to be_a(String)
191
+ expect(app.secret).not_to eq(app.plaintext_secret)
192
+ expect { ::BCrypt::Password.create(app.secret) }.not_to raise_error
193
+ end
275
194
  end
276
- end
277
- end
278
195
 
279
- describe "#authorized_for" do
280
- let(:resource_owner) { FactoryBot.create(:doorkeeper_testing_user) }
281
- let(:other_resource_owner) { FactoryBot.create(:doorkeeper_testing_user) }
196
+ it "does not fallback to plain lookup by default" do
197
+ lookup = clazz.by_uid_and_secret(app.uid, app.secret)
198
+ expect(lookup).to eq(nil)
282
199
 
283
- it "is empty if the application is not authorized for anyone" do
284
- expect(described_class.authorized_for(resource_owner)).to be_empty
285
- end
200
+ lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
201
+ expect(lookup).to eq(app)
202
+ end
286
203
 
287
- it "returns only application for a specific resource owner" do
288
- FactoryBot.create(
289
- :access_token,
290
- resource_owner_id: other_resource_owner.id,
291
- )
292
- token = FactoryBot.create(
293
- :access_token,
294
- resource_owner_id: resource_owner.id,
295
- )
296
- expect(described_class.authorized_for(resource_owner)).to eq([token.application])
297
- end
204
+ context "with fallback enabled" do
205
+ include_context "with token hashing and fallback lookup enabled"
298
206
 
299
- it "excludes revoked tokens" do
300
- FactoryBot.create(
301
- :access_token,
302
- resource_owner_id: resource_owner.id,
303
- revoked_at: 2.days.ago,
304
- )
305
- expect(described_class.authorized_for(resource_owner)).to be_empty
306
- end
207
+ it "provides plain and hashed lookup" do
208
+ lookup = clazz.by_uid_and_secret(app.uid, app.secret)
209
+ expect(lookup).to eq(app)
307
210
 
308
- it "returns all applications that have been authorized" do
309
- token1 = FactoryBot.create(
310
- :access_token,
311
- resource_owner_id: resource_owner.id,
312
- )
313
- token2 = FactoryBot.create(
314
- :access_token,
315
- resource_owner_id: resource_owner.id,
316
- )
317
- expect(described_class.authorized_for(resource_owner))
318
- .to eq([token1.application, token2.application])
319
- end
211
+ lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
212
+ expect(lookup).to eq(app)
213
+ end
214
+ end
320
215
 
321
- it "returns only one application even if it has been authorized twice" do
322
- application = FactoryBot.create(:application)
323
- FactoryBot.create(
324
- :access_token,
325
- resource_owner_id: resource_owner.id,
326
- application: application,
327
- )
328
- FactoryBot.create(
329
- :access_token,
330
- resource_owner_id: resource_owner.id,
331
- application: application,
332
- )
333
- expect(described_class.authorized_for(resource_owner)).to eq([application])
216
+ it "does not provide access to secret after loading" do
217
+ lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
218
+ expect(lookup.plaintext_secret).to be_nil
219
+ end
334
220
  end
335
- end
336
221
 
337
- describe "#revoke_tokens_and_grants_for" do
338
- it "revokes all access tokens and access grants" do
339
- application_id = 42
340
- resource_owner = double
341
- expect(Doorkeeper::AccessToken)
342
- .to receive(:revoke_all_for).with(application_id, resource_owner)
343
- expect(Doorkeeper::AccessGrant)
344
- .to receive(:revoke_all_for).with(application_id, resource_owner)
222
+ describe "destroy related models on cascade" do
223
+ before(:each) do
224
+ new_application.save
225
+ end
226
+
227
+ it "should destroy its access grants" do
228
+ FactoryBot.create(:access_grant, application: new_application)
229
+ expect { new_application.destroy }.to change { Doorkeeper::AccessGrant.count }.by(-1)
230
+ end
345
231
 
346
- described_class.revoke_tokens_and_grants_for(application_id, resource_owner)
232
+ it "should destroy its access tokens" do
233
+ FactoryBot.create(:access_token, application: new_application)
234
+ FactoryBot.create(:access_token, application: new_application, revoked_at: Time.now.utc)
235
+ expect do
236
+ new_application.destroy
237
+ end.to change { Doorkeeper::AccessToken.count }.by(-2)
238
+ end
347
239
  end
348
- end
349
240
 
350
- describe "#by_uid_and_secret" do
351
- context "when application is private/confidential" do
352
- it "finds the application via uid/secret" do
353
- app = FactoryBot.create :application
354
- authenticated = described_class.by_uid_and_secret(app.uid, app.secret)
355
- expect(authenticated).to eq(app)
241
+ describe :ordered_by do
242
+ let(:applications) { FactoryBot.create_list(:application, 5) }
243
+
244
+ context "when a direction is not specified" do
245
+ it "calls order with a default order of asc" do
246
+ names = applications.map(&:name).sort
247
+ expect(Application.ordered_by(:name).map(&:name)).to eq(names)
248
+ end
356
249
  end
357
- context "when secret is wrong" do
358
- it "should not find the application" do
359
- app = FactoryBot.create :application
360
- authenticated = described_class.by_uid_and_secret(app.uid, "bad")
361
- expect(authenticated).to eq(nil)
250
+
251
+ context "when a direction is specified" do
252
+ it "calls order with specified direction" do
253
+ names = applications.map(&:name).sort.reverse
254
+ expect(Application.ordered_by(:name, :desc).map(&:name)).to eq(names)
362
255
  end
363
256
  end
364
257
  end
365
258
 
366
- context "when application is public/non-confidential" do
367
- context "when secret is blank" do
368
- it "should find the application" do
369
- app = FactoryBot.create :application, confidential: false
370
- authenticated = described_class.by_uid_and_secret(app.uid, nil)
371
- expect(authenticated).to eq(app)
259
+ describe "#redirect_uri=" do
260
+ context "when array of valid redirect_uris" do
261
+ it "should join by newline" do
262
+ new_application.redirect_uri = ["http://localhost/callback1", "http://localhost/callback2"]
263
+ expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
372
264
  end
373
265
  end
374
- context "when secret is wrong" do
375
- it "should not find the application" do
376
- app = FactoryBot.create :application, confidential: false
377
- authenticated = described_class.by_uid_and_secret(app.uid, "bad")
378
- expect(authenticated).to eq(nil)
266
+ context "when string of valid redirect_uris" do
267
+ it "should store as-is" do
268
+ new_application.redirect_uri = "http://localhost/callback1\nhttp://localhost/callback2"
269
+ expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
379
270
  end
380
271
  end
381
272
  end
382
- end
383
273
 
384
- describe "#confidential?" do
385
- subject { FactoryBot.create(:application, confidential: confidential).confidential? }
274
+ describe "#renew_secret" do
275
+ let(:app) { FactoryBot.create :application }
386
276
 
387
- context "when application is private/confidential" do
388
- let(:confidential) { true }
389
- it { expect(subject).to eq(true) }
390
- end
391
-
392
- context "when application is public/non-confidential" do
393
- let(:confidential) { false }
394
- it { expect(subject).to eq(false) }
277
+ it "should generate a new secret" do
278
+ old_secret = app.secret
279
+ app.renew_secret
280
+ expect(old_secret).not_to eq(app.secret)
281
+ end
395
282
  end
396
- end
397
283
 
398
- describe "#as_json" do
399
- let(:app) { FactoryBot.create :application, secret: "123123123" }
284
+ describe :authorized_for do
285
+ let(:resource_owner) { double(:resource_owner, id: 10) }
400
286
 
401
- before do
402
- allow(Doorkeeper.configuration)
403
- .to receive(:application_secret_strategy).and_return(Doorkeeper::SecretStoring::Plain)
404
- end
287
+ it "is empty if the application is not authorized for anyone" do
288
+ expect(Application.authorized_for(resource_owner)).to be_empty
289
+ end
405
290
 
406
- # AR specific feature
407
- if DOORKEEPER_ORM == :active_record
408
- it "correctly works with #to_json" do
409
- ActiveRecord::Base.include_root_in_json = true
410
- expect(app.to_json(include_root_in_json: true)).to match(/application.+?:\{/)
411
- ActiveRecord::Base.include_root_in_json = false
291
+ it "returns only application for a specific resource owner" do
292
+ FactoryBot.create(:access_token, resource_owner_id: resource_owner.id + 1)
293
+ token = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
294
+ expect(Application.authorized_for(resource_owner)).to eq([token.application])
412
295
  end
413
- end
414
296
 
415
- context "when called without authorized resource owner" do
416
- it "includes minimal set of attributes" do
417
- expect(app.as_json).to match(
418
- "id" => app.id,
419
- "name" => app.name,
420
- "created_at" => an_instance_of(String),
421
- )
297
+ it "excludes revoked tokens" do
298
+ FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, revoked_at: 2.days.ago)
299
+ expect(Application.authorized_for(resource_owner)).to be_empty
422
300
  end
423
301
 
424
- it "includes application UID if it's public" do
425
- app = FactoryBot.create :application, secret: "123123123", confidential: false
302
+ it "returns all applications that have been authorized" do
303
+ token1 = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
304
+ token2 = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
305
+ expect(Application.authorized_for(resource_owner)).to eq([token1.application, token2.application])
306
+ end
426
307
 
427
- expect(app.as_json).to match(
428
- "id" => app.id,
429
- "name" => app.name,
430
- "created_at" => an_instance_of(String),
431
- "uid" => app.uid,
432
- )
308
+ it "returns only one application even if it has been authorized twice" do
309
+ application = FactoryBot.create(:application)
310
+ FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, application: application)
311
+ FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, application: application)
312
+ expect(Application.authorized_for(resource_owner)).to eq([application])
433
313
  end
314
+ end
434
315
 
435
- it "respects custom options" do
436
- expect(app.as_json(except: :id)).not_to include("id")
437
- expect(app.as_json(only: %i[name created_at secret]))
438
- .to match(
439
- "name" => app.name,
440
- "created_at" => an_instance_of(String),
441
- )
316
+ describe :revoke_tokens_and_grants_for do
317
+ it "revokes all access tokens and access grants" do
318
+ application_id = 42
319
+ resource_owner = double
320
+ expect(Doorkeeper::AccessToken)
321
+ .to receive(:revoke_all_for).with(application_id, resource_owner)
322
+ expect(Doorkeeper::AccessGrant)
323
+ .to receive(:revoke_all_for).with(application_id, resource_owner)
324
+
325
+ Application.revoke_tokens_and_grants_for(application_id, resource_owner)
442
326
  end
443
327
  end
444
328
 
445
- context "when called with authorized resource owner" do
446
- let(:owner) { FactoryBot.create(:doorkeeper_testing_user) }
447
- let(:other_owner) { FactoryBot.create(:doorkeeper_testing_user) }
448
- let(:app) { FactoryBot.create(:application, secret: "123123123", owner: owner) }
329
+ describe :by_uid_and_secret do
330
+ context "when application is private/confidential" do
331
+ it "finds the application via uid/secret" do
332
+ app = FactoryBot.create :application
333
+ authenticated = Application.by_uid_and_secret(app.uid, app.secret)
334
+ expect(authenticated).to eq(app)
335
+ end
336
+ context "when secret is wrong" do
337
+ it "should not find the application" do
338
+ app = FactoryBot.create :application
339
+ authenticated = Application.by_uid_and_secret(app.uid, "bad")
340
+ expect(authenticated).to eq(nil)
341
+ end
342
+ end
343
+ end
449
344
 
450
- before do
451
- Doorkeeper.configure do
452
- orm DOORKEEPER_ORM
453
- enable_application_owner confirmation: false
345
+ context "when application is public/non-confidential" do
346
+ context "when secret is blank" do
347
+ it "should find the application" do
348
+ app = FactoryBot.create :application, confidential: false
349
+ authenticated = Application.by_uid_and_secret(app.uid, nil)
350
+ expect(authenticated).to eq(app)
351
+ end
352
+ end
353
+ context "when secret is wrong" do
354
+ it "should not find the application" do
355
+ app = FactoryBot.create :application, confidential: false
356
+ authenticated = Application.by_uid_and_secret(app.uid, "bad")
357
+ expect(authenticated).to eq(nil)
358
+ end
454
359
  end
455
360
  end
361
+ end
362
+
363
+ describe :confidential? do
364
+ subject { FactoryBot.create(:application, confidential: confidential).confidential? }
456
365
 
457
- it "includes all the attributes" do
458
- expect(app.as_json(current_resource_owner: owner))
459
- .to include(
460
- "secret" => "123123123",
461
- "redirect_uri" => app.redirect_uri,
462
- "uid" => app.uid,
463
- )
366
+ context "when application is private/confidential" do
367
+ let(:confidential) { true }
368
+ it { expect(subject).to eq(true) }
464
369
  end
465
370
 
466
- it "doesn't include unsafe attributes if current owner isn't the same as owner" do
467
- expect(app.as_json(current_resource_owner: other_owner))
468
- .not_to include("redirect_uri")
371
+ context "when application is public/non-confidential" do
372
+ let(:confidential) { false }
373
+ it { expect(subject).to eq(false) }
469
374
  end
470
375
  end
471
376
  end