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.
- checksums.yaml +4 -4
- data/Appraisals +1 -1
- data/CHANGELOG.md +854 -0
- data/CONTRIBUTING.md +11 -9
- data/Dangerfile +2 -2
- data/Dockerfile +29 -0
- data/Gemfile +3 -2
- data/NEWS.md +1 -819
- data/README.md +11 -3
- data/RELEASING.md +6 -5
- data/app/controllers/doorkeeper/application_controller.rb +1 -1
- data/app/controllers/doorkeeper/application_metal_controller.rb +2 -1
- data/app/controllers/doorkeeper/applications_controller.rb +5 -3
- data/app/controllers/doorkeeper/authorizations_controller.rb +14 -7
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
- data/app/controllers/doorkeeper/tokens_controller.rb +32 -9
- data/app/views/doorkeeper/applications/_form.html.erb +0 -6
- data/app/views/doorkeeper/applications/show.html.erb +1 -1
- data/config/locales/en.yml +8 -2
- data/doorkeeper.gemspec +9 -1
- data/gemfiles/rails_5_0.gemfile +1 -0
- data/gemfiles/rails_5_1.gemfile +1 -0
- data/gemfiles/rails_5_2.gemfile +1 -0
- data/gemfiles/rails_6_0.gemfile +2 -1
- data/gemfiles/rails_master.gemfile +1 -0
- data/lib/doorkeeper/config/option.rb +13 -7
- data/lib/doorkeeper/config.rb +88 -6
- data/lib/doorkeeper/errors.rb +13 -18
- data/lib/doorkeeper/grape/helpers.rb +5 -1
- data/lib/doorkeeper/helpers/controller.rb +23 -4
- data/lib/doorkeeper/models/access_token_mixin.rb +43 -2
- data/lib/doorkeeper/oauth/authorization/code.rb +11 -13
- data/lib/doorkeeper/oauth/authorization/token.rb +1 -1
- data/lib/doorkeeper/oauth/authorization_code_request.rb +18 -9
- data/lib/doorkeeper/oauth/base_request.rb +2 -0
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +14 -0
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +8 -0
- data/lib/doorkeeper/oauth/code_request.rb +5 -11
- data/lib/doorkeeper/oauth/code_response.rb +2 -2
- data/lib/doorkeeper/oauth/error_response.rb +1 -1
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +18 -4
- data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
- data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -2
- data/lib/doorkeeper/oauth/pre_authorization.rb +70 -37
- data/lib/doorkeeper/oauth/refresh_token_request.rb +13 -10
- data/lib/doorkeeper/oauth/token_introspection.rb +23 -13
- data/lib/doorkeeper/oauth/token_request.rb +4 -18
- data/lib/doorkeeper/orm/active_record/access_grant.rb +1 -1
- data/lib/doorkeeper/orm/active_record/access_token.rb +2 -2
- data/lib/doorkeeper/orm/active_record/application.rb +15 -69
- data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +61 -0
- data/lib/doorkeeper/orm/active_record.rb +19 -3
- data/lib/doorkeeper/request/authorization_code.rb +2 -0
- data/lib/doorkeeper/request.rb +6 -11
- data/lib/doorkeeper/server.rb +2 -6
- data/lib/doorkeeper/stale_records_cleaner.rb +6 -2
- data/lib/doorkeeper/version.rb +1 -1
- data/lib/doorkeeper.rb +4 -0
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +6 -6
- data/lib/generators/doorkeeper/templates/initializer.rb +110 -33
- data/lib/generators/doorkeeper/templates/migration.rb.erb +4 -1
- data/spec/controllers/applications_controller_spec.rb +93 -0
- data/spec/controllers/authorizations_controller_spec.rb +143 -62
- data/spec/controllers/protected_resources_controller_spec.rb +3 -3
- data/spec/controllers/tokens_controller_spec.rb +205 -37
- data/spec/dummy/config/application.rb +3 -1
- data/spec/dummy/config/initializers/doorkeeper.rb +54 -9
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +1 -1
- data/spec/lib/config_spec.rb +43 -1
- data/spec/lib/oauth/authorization_code_request_spec.rb +13 -1
- data/spec/lib/oauth/base_request_spec.rb +33 -16
- data/spec/lib/oauth/client_credentials/creator_spec.rb +3 -0
- data/spec/lib/oauth/code_request_spec.rb +27 -28
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +17 -2
- data/spec/lib/oauth/invalid_request_response_spec.rb +75 -0
- data/spec/lib/oauth/pre_authorization_spec.rb +76 -66
- data/spec/lib/oauth/refresh_token_request_spec.rb +1 -0
- data/spec/lib/oauth/token_request_spec.rb +20 -17
- data/spec/lib/server_spec.rb +0 -12
- data/spec/models/doorkeeper/access_grant_spec.rb +21 -2
- data/spec/models/doorkeeper/access_token_spec.rb +35 -4
- data/spec/models/doorkeeper/application_spec.rb +275 -370
- data/spec/requests/endpoints/authorization_spec.rb +21 -5
- data/spec/requests/endpoints/token_spec.rb +1 -1
- data/spec/requests/flows/authorization_code_errors_spec.rb +1 -0
- data/spec/requests/flows/authorization_code_spec.rb +93 -27
- data/spec/requests/flows/client_credentials_spec.rb +38 -0
- data/spec/requests/flows/implicit_grant_errors_spec.rb +22 -10
- data/spec/requests/flows/implicit_grant_spec.rb +9 -8
- data/spec/requests/flows/password_spec.rb +37 -0
- data/spec/requests/flows/refresh_token_spec.rb +1 -1
- data/spec/requests/flows/revoke_token_spec.rb +19 -11
- data/spec/support/doorkeeper_rspec.rb +1 -1
- data/spec/support/helpers/request_spec_helper.rb +14 -2
- data/spec/validators/redirect_uri_validator_spec.rb +40 -15
- metadata +16 -15
- data/.coveralls.yml +0 -1
- data/.github/ISSUE_TEMPLATE.md +0 -25
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -17
- data/.gitignore +0 -20
- data/.gitlab-ci.yml +0 -16
- data/.hound.yml +0 -3
- data/.rspec +0 -1
- data/.rubocop.yml +0 -50
- data/.travis.yml +0 -35
- 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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
12
|
-
|
13
|
+
let(:uid) { SecureRandom.hex(8) }
|
14
|
+
let(:secret) { SecureRandom.hex(8) }
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
24
|
+
context "application owner is not required" do
|
25
|
+
before(:each) do
|
26
|
+
unset_require_owner
|
27
|
+
end
|
67
28
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
29
|
+
it "is valid given valid attributes" do
|
30
|
+
expect(new_application).to be_valid
|
31
|
+
end
|
32
|
+
end
|
73
33
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
81
|
-
|
82
|
-
|
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
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
95
|
-
|
96
|
-
|
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
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
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
|
-
|
111
|
-
|
112
|
-
|
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
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
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
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
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 "
|
137
|
-
|
138
|
-
|
139
|
-
|
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
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
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
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
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
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
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
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
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
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
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 "
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
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
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
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 "
|
215
|
-
|
216
|
-
|
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
|
-
|
221
|
-
|
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
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
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 "
|
238
|
-
|
239
|
-
|
240
|
-
expect
|
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
|
-
|
247
|
-
|
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
|
-
|
250
|
-
|
251
|
-
|
252
|
-
expect(
|
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
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
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
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
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
|
-
|
280
|
-
|
281
|
-
|
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
|
-
|
284
|
-
|
285
|
-
|
200
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
|
201
|
+
expect(lookup).to eq(app)
|
202
|
+
end
|
286
203
|
|
287
|
-
|
288
|
-
|
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
|
-
|
300
|
-
|
301
|
-
|
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
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
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
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
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
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
.to
|
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
|
-
|
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
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
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
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
expect(
|
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
|
-
|
367
|
-
context "when
|
368
|
-
it "should
|
369
|
-
|
370
|
-
|
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
|
375
|
-
it "should
|
376
|
-
|
377
|
-
|
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
|
-
|
385
|
-
|
274
|
+
describe "#renew_secret" do
|
275
|
+
let(:app) { FactoryBot.create :application }
|
386
276
|
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
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
|
-
|
399
|
-
|
284
|
+
describe :authorized_for do
|
285
|
+
let(:resource_owner) { double(:resource_owner, id: 10) }
|
400
286
|
|
401
|
-
|
402
|
-
|
403
|
-
|
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
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
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
|
-
|
416
|
-
|
417
|
-
expect(
|
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 "
|
425
|
-
|
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
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
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
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
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
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
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
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
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
|
-
|
458
|
-
|
459
|
-
|
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
|
-
|
467
|
-
|
468
|
-
|
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
|