doorkeeper 5.3.3 → 5.4.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.
- checksums.yaml +4 -4
- data/Appraisals +0 -14
- data/CHANGELOG.md +35 -10
- data/Dangerfile +7 -7
- data/Dockerfile +2 -2
- data/Gemfile +9 -9
- data/README.md +6 -4
- data/app/controllers/doorkeeper/applications_controller.rb +7 -7
- data/app/controllers/doorkeeper/authorizations_controller.rb +31 -12
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +3 -3
- data/app/controllers/doorkeeper/tokens_controller.rb +57 -20
- data/app/views/doorkeeper/applications/show.html.erb +19 -2
- data/bin/console +14 -0
- data/config/locales/en.yml +3 -1
- data/doorkeeper.gemspec +1 -1
- data/gemfiles/rails_5_0.gemfile +8 -7
- data/gemfiles/rails_5_1.gemfile +8 -7
- data/gemfiles/rails_5_2.gemfile +8 -7
- data/gemfiles/rails_6_0.gemfile +8 -7
- data/gemfiles/rails_master.gemfile +8 -7
- data/lib/doorkeeper.rb +106 -79
- data/lib/doorkeeper/config.rb +40 -17
- data/lib/doorkeeper/config/abstract_builder.rb +28 -0
- data/lib/doorkeeper/config/option.rb +28 -14
- data/lib/doorkeeper/grape/helpers.rb +1 -1
- data/lib/doorkeeper/models/access_grant_mixin.rb +9 -11
- data/lib/doorkeeper/models/access_token_mixin.rb +100 -41
- data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
- data/lib/doorkeeper/models/concerns/revocable.rb +1 -1
- data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
- data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
- data/lib/doorkeeper/oauth/authorization/code.rb +14 -5
- data/lib/doorkeeper/oauth/authorization/context.rb +2 -2
- data/lib/doorkeeper/oauth/authorization/token.rb +7 -11
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
- data/lib/doorkeeper/oauth/authorization_code_request.rb +18 -8
- data/lib/doorkeeper/oauth/base_request.rb +11 -19
- data/lib/doorkeeper/oauth/client.rb +1 -1
- data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +25 -7
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +3 -2
- data/lib/doorkeeper/oauth/client_credentials/validator.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
- data/lib/doorkeeper/oauth/code_request.rb +1 -1
- data/lib/doorkeeper/oauth/code_response.rb +6 -2
- data/lib/doorkeeper/oauth/error_response.rb +2 -4
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -5
- data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
- data/lib/doorkeeper/oauth/invalid_token_response.rb +2 -2
- data/lib/doorkeeper/oauth/password_access_token_request.rb +3 -5
- data/lib/doorkeeper/oauth/pre_authorization.rb +32 -27
- data/lib/doorkeeper/oauth/refresh_token_request.rb +18 -22
- data/lib/doorkeeper/oauth/token.rb +1 -1
- data/lib/doorkeeper/oauth/token_introspection.rb +3 -3
- data/lib/doorkeeper/oauth/token_request.rb +2 -2
- data/lib/doorkeeper/oauth/token_response.rb +1 -1
- data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +7 -2
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +6 -2
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +9 -64
- data/lib/doorkeeper/rails/routes.rb +13 -17
- data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
- data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
- data/lib/doorkeeper/rails/routes/registry.rb +45 -0
- data/lib/doorkeeper/request/strategy.rb +2 -2
- data/lib/doorkeeper/server.rb +3 -3
- data/lib/doorkeeper/version.rb +3 -3
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +1 -1
- data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
- data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +39 -3
- data/lib/generators/doorkeeper/templates/migration.rb.erb +2 -0
- data/spec/controllers/applications_controller_spec.rb +2 -2
- data/spec/controllers/authorizations_controller_spec.rb +165 -30
- data/spec/controllers/tokens_controller_spec.rb +6 -5
- data/spec/dummy/app/helpers/application_helper.rb +1 -1
- data/spec/dummy/app/models/user.rb +5 -1
- data/spec/dummy/config/application.rb +6 -4
- data/spec/dummy/config/boot.rb +4 -4
- data/spec/dummy/config/environment.rb +1 -1
- data/spec/dummy/config/routes.rb +4 -4
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +2 -2
- data/spec/dummy/db/schema.rb +3 -1
- data/spec/factories.rb +1 -1
- data/spec/generators/enable_polymorphic_resource_owner_generator_spec.rb +47 -0
- data/spec/lib/config_spec.rb +15 -11
- data/spec/lib/models/revocable_spec.rb +2 -3
- data/spec/lib/models/scopes_spec.rb +8 -0
- data/spec/lib/oauth/authorization_code_request_spec.rb +25 -15
- data/spec/lib/oauth/base_request_spec.rb +6 -20
- data/spec/lib/oauth/client_credentials/creator_spec.rb +90 -89
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +84 -86
- data/spec/lib/oauth/client_credentials/validation_spec.rb +38 -40
- data/spec/lib/oauth/client_credentials_request_spec.rb +5 -4
- data/spec/lib/oauth/code_request_spec.rb +1 -1
- data/spec/lib/oauth/code_response_spec.rb +5 -1
- data/spec/lib/oauth/error_response_spec.rb +1 -1
- data/spec/lib/oauth/password_access_token_request_spec.rb +24 -13
- data/spec/lib/oauth/pre_authorization_spec.rb +13 -18
- data/spec/lib/oauth/refresh_token_request_spec.rb +19 -30
- data/spec/lib/oauth/token_request_spec.rb +14 -7
- data/spec/lib/option_spec.rb +51 -0
- data/spec/lib/stale_records_cleaner_spec.rb +18 -5
- data/spec/models/doorkeeper/access_grant_spec.rb +18 -4
- data/spec/models/doorkeeper/access_token_spec.rb +507 -479
- data/spec/models/doorkeeper/application_spec.rb +22 -62
- data/spec/requests/endpoints/token_spec.rb +5 -1
- data/spec/requests/flows/authorization_code_errors_spec.rb +4 -1
- data/spec/requests/flows/authorization_code_spec.rb +6 -1
- data/spec/requests/flows/client_credentials_spec.rb +41 -0
- data/spec/requests/flows/refresh_token_spec.rb +16 -8
- data/spec/requests/flows/revoke_token_spec.rb +143 -104
- data/spec/support/helpers/access_token_request_helper.rb +1 -0
- data/spec/support/helpers/authorization_request_helper.rb +4 -4
- data/spec/support/helpers/config_helper.rb +1 -1
- data/spec/support/shared/controllers_shared_context.rb +2 -2
- data/spec/support/shared/models_shared_examples.rb +6 -4
- metadata +16 -5
@@ -102,7 +102,7 @@ describe Doorkeeper::Application do
|
|
102
102
|
end
|
103
103
|
|
104
104
|
context "application owner is required" do
|
105
|
-
before do
|
105
|
+
before(:each) do
|
106
106
|
require_owner
|
107
107
|
@owner = FactoryBot.build_stubbed(:doorkeeper_testing_user)
|
108
108
|
end
|
@@ -222,13 +222,14 @@ describe Doorkeeper::Application do
|
|
222
222
|
new_application.save
|
223
223
|
end
|
224
224
|
|
225
|
-
let(:resource_owner) { FactoryBot.create(:
|
225
|
+
let(:resource_owner) { FactoryBot.create(:resource_owner) }
|
226
226
|
|
227
227
|
it "should destroy its access grants" do
|
228
228
|
FactoryBot.create(
|
229
229
|
:access_grant,
|
230
230
|
application: new_application,
|
231
231
|
resource_owner_id: resource_owner.id,
|
232
|
+
resource_owner_type: resource_owner.class.name,
|
232
233
|
)
|
233
234
|
|
234
235
|
expect { new_application.destroy }.to change { Doorkeeper::AccessGrant.count }.by(-1)
|
@@ -287,8 +288,8 @@ describe Doorkeeper::Application do
|
|
287
288
|
end
|
288
289
|
|
289
290
|
describe "#authorized_for" do
|
290
|
-
let(:resource_owner) { FactoryBot.create(:
|
291
|
-
let(:other_resource_owner) { FactoryBot.create(:
|
291
|
+
let(:resource_owner) { FactoryBot.create(:resource_owner) }
|
292
|
+
let(:other_resource_owner) { FactoryBot.create(:resource_owner) }
|
292
293
|
|
293
294
|
it "is empty if the application is not authorized for anyone" do
|
294
295
|
expect(described_class.authorized_for(resource_owner)).to be_empty
|
@@ -298,10 +299,12 @@ describe Doorkeeper::Application do
|
|
298
299
|
FactoryBot.create(
|
299
300
|
:access_token,
|
300
301
|
resource_owner_id: other_resource_owner.id,
|
302
|
+
resource_owner_type: other_resource_owner.class.name,
|
301
303
|
)
|
302
304
|
token = FactoryBot.create(
|
303
305
|
:access_token,
|
304
306
|
resource_owner_id: resource_owner.id,
|
307
|
+
resource_owner_type: resource_owner.class.name,
|
305
308
|
)
|
306
309
|
expect(described_class.authorized_for(resource_owner)).to eq([token.application])
|
307
310
|
end
|
@@ -310,6 +313,7 @@ describe Doorkeeper::Application do
|
|
310
313
|
FactoryBot.create(
|
311
314
|
:access_token,
|
312
315
|
resource_owner_id: resource_owner.id,
|
316
|
+
resource_owner_type: resource_owner.class.name,
|
313
317
|
revoked_at: 2.days.ago,
|
314
318
|
)
|
315
319
|
expect(described_class.authorized_for(resource_owner)).to be_empty
|
@@ -319,10 +323,12 @@ describe Doorkeeper::Application do
|
|
319
323
|
token1 = FactoryBot.create(
|
320
324
|
:access_token,
|
321
325
|
resource_owner_id: resource_owner.id,
|
326
|
+
resource_owner_type: resource_owner.class.name,
|
322
327
|
)
|
323
328
|
token2 = FactoryBot.create(
|
324
329
|
:access_token,
|
325
330
|
resource_owner_id: resource_owner.id,
|
331
|
+
resource_owner_type: resource_owner.class.name,
|
326
332
|
)
|
327
333
|
expect(described_class.authorized_for(resource_owner))
|
328
334
|
.to eq([token1.application, token2.application])
|
@@ -333,11 +339,13 @@ describe Doorkeeper::Application do
|
|
333
339
|
FactoryBot.create(
|
334
340
|
:access_token,
|
335
341
|
resource_owner_id: resource_owner.id,
|
342
|
+
resource_owner_type: resource_owner.class.name,
|
336
343
|
application: application,
|
337
344
|
)
|
338
345
|
FactoryBot.create(
|
339
346
|
:access_token,
|
340
347
|
resource_owner_id: resource_owner.id,
|
348
|
+
resource_owner_type: resource_owner.class.name,
|
341
349
|
application: application,
|
342
350
|
)
|
343
351
|
expect(described_class.authorized_for(resource_owner)).to eq([application])
|
@@ -413,7 +421,16 @@ describe Doorkeeper::Application do
|
|
413
421
|
.to receive(:application_secret_strategy).and_return(Doorkeeper::SecretStoring::Plain)
|
414
422
|
end
|
415
423
|
|
416
|
-
|
424
|
+
it "includes plaintext secret" do
|
425
|
+
expect(app.as_json).to include("secret" => "123123123")
|
426
|
+
end
|
427
|
+
|
428
|
+
it "respects custom options" do
|
429
|
+
expect(app.as_json(except: :secret)).not_to include("secret")
|
430
|
+
expect(app.as_json(only: :id)).to match("id" => app.id)
|
431
|
+
end
|
432
|
+
|
433
|
+
# AR specific
|
417
434
|
if DOORKEEPER_ORM == :active_record
|
418
435
|
it "correctly works with #to_json" do
|
419
436
|
ActiveRecord::Base.include_root_in_json = true
|
@@ -421,62 +438,5 @@ describe Doorkeeper::Application do
|
|
421
438
|
ActiveRecord::Base.include_root_in_json = false
|
422
439
|
end
|
423
440
|
end
|
424
|
-
|
425
|
-
context "when called without authorized resource owner" do
|
426
|
-
it "includes minimal set of attributes" do
|
427
|
-
expect(app.as_json).to match(
|
428
|
-
"id" => app.id,
|
429
|
-
"name" => app.name,
|
430
|
-
"created_at" => an_instance_of(String),
|
431
|
-
)
|
432
|
-
end
|
433
|
-
|
434
|
-
it "includes application UID if it's public" do
|
435
|
-
app = FactoryBot.create :application, secret: "123123123", confidential: false
|
436
|
-
|
437
|
-
expect(app.as_json).to match(
|
438
|
-
"id" => app.id,
|
439
|
-
"name" => app.name,
|
440
|
-
"created_at" => an_instance_of(String),
|
441
|
-
"uid" => app.uid,
|
442
|
-
)
|
443
|
-
end
|
444
|
-
|
445
|
-
it "respects custom options" do
|
446
|
-
expect(app.as_json(except: :id)).not_to include("id")
|
447
|
-
expect(app.as_json(only: %i[name created_at secret]))
|
448
|
-
.to match(
|
449
|
-
"name" => app.name,
|
450
|
-
"created_at" => an_instance_of(String),
|
451
|
-
)
|
452
|
-
end
|
453
|
-
end
|
454
|
-
|
455
|
-
context "when called with authorized resource owner" do
|
456
|
-
let(:owner) { FactoryBot.create(:doorkeeper_testing_user) }
|
457
|
-
let(:other_owner) { FactoryBot.create(:doorkeeper_testing_user) }
|
458
|
-
let(:app) { FactoryBot.create(:application, secret: "123123123", owner: owner) }
|
459
|
-
|
460
|
-
before do
|
461
|
-
Doorkeeper.configure do
|
462
|
-
orm DOORKEEPER_ORM
|
463
|
-
enable_application_owner confirmation: false
|
464
|
-
end
|
465
|
-
end
|
466
|
-
|
467
|
-
it "includes all the attributes" do
|
468
|
-
expect(app.as_json(current_resource_owner: owner))
|
469
|
-
.to include(
|
470
|
-
"secret" => "123123123",
|
471
|
-
"redirect_uri" => app.redirect_uri,
|
472
|
-
"uid" => app.uid,
|
473
|
-
)
|
474
|
-
end
|
475
|
-
|
476
|
-
it "doesn't include unsafe attributes if current owner isn't the same as owner" do
|
477
|
-
expect(app.as_json(current_resource_owner: other_owner))
|
478
|
-
.not_to include("redirect_uri")
|
479
|
-
end
|
480
|
-
end
|
481
441
|
end
|
482
442
|
end
|
@@ -5,7 +5,11 @@ require "spec_helper"
|
|
5
5
|
describe "Token endpoint" do
|
6
6
|
before do
|
7
7
|
client_exists
|
8
|
-
|
8
|
+
create_resource_owner
|
9
|
+
authorization_code_exists application: @client,
|
10
|
+
scopes: "public",
|
11
|
+
resource_owner_id: @resource_owner.id,
|
12
|
+
resource_owner_type: @resource_owner.class.name
|
9
13
|
end
|
10
14
|
|
11
15
|
it "respond with correct headers" do
|
@@ -50,7 +50,10 @@ end
|
|
50
50
|
describe "Authorization Code Flow Errors", "after authorization" do
|
51
51
|
before do
|
52
52
|
client_exists
|
53
|
-
|
53
|
+
create_resource_owner
|
54
|
+
authorization_code_exists application: @client,
|
55
|
+
resource_owner_id: @resource_owner.id,
|
56
|
+
resource_owner_type: @resource_owner.class.name
|
54
57
|
end
|
55
58
|
|
56
59
|
it "returns :invalid_grant error when posting an already revoked grant code" do
|
@@ -182,6 +182,7 @@ feature "Authorization Code Flow" do
|
|
182
182
|
access_token_exists application: @client,
|
183
183
|
expires_in: -100, # even expired token
|
184
184
|
resource_owner_id: @resource_owner.id,
|
185
|
+
resource_owner_type: @resource_owner.class.name,
|
185
186
|
scopes: "public write"
|
186
187
|
|
187
188
|
visit authorization_endpoint_url(client: @client, scope: "public write")
|
@@ -506,8 +507,12 @@ describe "Authorization Code Flow" do
|
|
506
507
|
end
|
507
508
|
|
508
509
|
context "issuing a refresh token" do
|
510
|
+
let(:resource_owner) { FactoryBot.create(:resource_owner) }
|
511
|
+
|
509
512
|
before do
|
510
|
-
authorization_code_exists application: @client
|
513
|
+
authorization_code_exists application: @client,
|
514
|
+
resource_owner_id: resource_owner.id,
|
515
|
+
resource_owner_type: resource_owner.class.name
|
511
516
|
end
|
512
517
|
|
513
518
|
it "second of simultaneous client requests get an error for revoked acccess token" do
|
@@ -159,6 +159,47 @@ describe "Client Credentials Request" do
|
|
159
159
|
end
|
160
160
|
end
|
161
161
|
|
162
|
+
context "when revoke_previous_client_credentials_token is true" do
|
163
|
+
before do
|
164
|
+
allow(Doorkeeper.config).to receive(:reuse_access_token) { false }
|
165
|
+
allow(Doorkeeper.config).to receive(:revoke_previous_client_credentials_token) { true }
|
166
|
+
end
|
167
|
+
|
168
|
+
it "revokes the previous token" do
|
169
|
+
headers = authorization client.uid, client.secret
|
170
|
+
params = { grant_type: "client_credentials" }
|
171
|
+
|
172
|
+
post "/oauth/token", params: params, headers: headers
|
173
|
+
should_have_json "access_token", Doorkeeper::AccessToken.first.token
|
174
|
+
|
175
|
+
token = Doorkeeper::AccessToken.first
|
176
|
+
|
177
|
+
post "/oauth/token", params: params, headers: headers
|
178
|
+
should_have_json "access_token", Doorkeeper::AccessToken.last.token
|
179
|
+
|
180
|
+
expect(token.reload.revoked?).to be_truthy
|
181
|
+
expect(Doorkeeper::AccessToken.last.revoked?).to be_falsey
|
182
|
+
end
|
183
|
+
|
184
|
+
context "with a simultaneous request" do
|
185
|
+
let!(:access_token) { FactoryBot.create :access_token, resource_owner_id: nil }
|
186
|
+
|
187
|
+
before do
|
188
|
+
allow(Doorkeeper.config.access_token_model).to receive(:matching_token_for) { access_token }
|
189
|
+
allow(access_token).to receive(:revoked?).and_return(true)
|
190
|
+
end
|
191
|
+
|
192
|
+
it "returns an error" do
|
193
|
+
headers = authorization client.uid, client.secret
|
194
|
+
params = { grant_type: "client_credentials" }
|
195
|
+
|
196
|
+
post "/oauth/token", params: params, headers: headers
|
197
|
+
should_not_have_json "access_token"
|
198
|
+
should_have_json "error", "invalid_token_reuse"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
162
203
|
def authorization(username, password)
|
163
204
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials username, password
|
164
205
|
{ "HTTP_AUTHORIZATION" => credentials }
|
@@ -12,9 +12,13 @@ describe "Refresh Token Flow" do
|
|
12
12
|
client_exists
|
13
13
|
end
|
14
14
|
|
15
|
+
let(:resource_owner) { FactoryBot.create(:resource_owner) }
|
16
|
+
|
15
17
|
context "issuing a refresh token" do
|
16
18
|
before do
|
17
|
-
authorization_code_exists application: @client
|
19
|
+
authorization_code_exists application: @client,
|
20
|
+
resource_owner_id: resource_owner.id,
|
21
|
+
resource_owner_type: resource_owner.class.name
|
18
22
|
end
|
19
23
|
|
20
24
|
it "client gets the refresh token and refreshes it" do
|
@@ -43,7 +47,8 @@ describe "Refresh Token Flow" do
|
|
43
47
|
@token = FactoryBot.create(
|
44
48
|
:access_token,
|
45
49
|
application: @client,
|
46
|
-
resource_owner_id:
|
50
|
+
resource_owner_id: resource_owner.id,
|
51
|
+
resource_owner_type: resource_owner.class.name,
|
47
52
|
use_refresh_token: true,
|
48
53
|
)
|
49
54
|
end
|
@@ -110,7 +115,8 @@ describe "Refresh Token Flow" do
|
|
110
115
|
FactoryBot.create(
|
111
116
|
:access_token,
|
112
117
|
application: @client,
|
113
|
-
resource_owner_id:
|
118
|
+
resource_owner_id: resource_owner.id,
|
119
|
+
resource_owner_type: resource_owner.class.name,
|
114
120
|
use_refresh_token: true,
|
115
121
|
)
|
116
122
|
end
|
@@ -119,7 +125,8 @@ describe "Refresh Token Flow" do
|
|
119
125
|
FactoryBot.create(
|
120
126
|
:access_token,
|
121
127
|
application: public_client,
|
122
|
-
resource_owner_id:
|
128
|
+
resource_owner_id: resource_owner.id,
|
129
|
+
resource_owner_type: resource_owner.class.name,
|
123
130
|
use_refresh_token: true,
|
124
131
|
)
|
125
132
|
end
|
@@ -185,14 +192,15 @@ describe "Refresh Token Flow" do
|
|
185
192
|
end
|
186
193
|
create_resource_owner
|
187
194
|
_another_token = post password_token_endpoint_url(
|
188
|
-
client: @client, resource_owner:
|
195
|
+
client: @client, resource_owner: resource_owner,
|
189
196
|
)
|
190
|
-
last_token.
|
197
|
+
last_token.update(created_at: 5.seconds.ago)
|
191
198
|
|
192
199
|
@token = FactoryBot.create(
|
193
200
|
:access_token,
|
194
201
|
application: @client,
|
195
|
-
resource_owner_id:
|
202
|
+
resource_owner_id: resource_owner.id,
|
203
|
+
resource_owner_type: resource_owner.class.name,
|
196
204
|
use_refresh_token: true,
|
197
205
|
)
|
198
206
|
@token.update_attribute :expires_in, -100
|
@@ -226,7 +234,7 @@ describe "Refresh Token Flow" do
|
|
226
234
|
|
227
235
|
def last_token
|
228
236
|
Doorkeeper::AccessToken.last_authorized_token_for(
|
229
|
-
@client.id,
|
237
|
+
@client.id, resource_owner,
|
230
238
|
)
|
231
239
|
end
|
232
240
|
end
|
@@ -7,151 +7,190 @@ describe "Revoke Token Flow" do
|
|
7
7
|
Doorkeeper.configure { orm DOORKEEPER_ORM }
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
let(:private_client_application) { FactoryBot.create :application }
|
11
|
+
let(:public_client_application) { FactoryBot.create :application, confidential: false }
|
12
|
+
let(:resource_owner) { User.create!(name: "John", password: "sekret") }
|
13
|
+
|
14
|
+
context "with authenticated, confidential OAuth 2.0 client/application" do
|
13
15
|
let(:access_token) do
|
14
16
|
FactoryBot.create(
|
15
17
|
:access_token,
|
16
|
-
application:
|
18
|
+
application: private_client_application,
|
17
19
|
resource_owner_id: resource_owner.id,
|
20
|
+
resource_owner_type: resource_owner.class.name,
|
18
21
|
use_refresh_token: true,
|
19
22
|
)
|
20
23
|
end
|
21
24
|
|
22
|
-
|
25
|
+
let(:headers) do
|
26
|
+
client_id = private_client_application.uid
|
27
|
+
client_secret = private_client_application.secret
|
28
|
+
credentials = Base64.encode64("#{client_id}:#{client_secret}")
|
29
|
+
{ "HTTP_AUTHORIZATION" => "Basic #{credentials}" }
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should revoke the access token provided" do
|
33
|
+
post revocation_token_endpoint_url, params: { token: access_token.token }, headers: headers
|
34
|
+
|
35
|
+
expect(response).to be_successful
|
36
|
+
expect(access_token.reload.revoked?).to be_truthy
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should revoke the refresh token provided" do
|
40
|
+
post revocation_token_endpoint_url, params: { token: access_token.refresh_token }, headers: headers
|
41
|
+
|
42
|
+
expect(response).to be_successful
|
43
|
+
expect(access_token.reload.revoked?).to be_truthy
|
44
|
+
end
|
45
|
+
|
46
|
+
context "with invalid token to revoke" do
|
47
|
+
it "should not revoke any tokens and must respond with success" do
|
48
|
+
expect do
|
49
|
+
post revocation_token_endpoint_url,
|
50
|
+
params: { token: "I_AM_AN_INVALID_TOKEN" },
|
51
|
+
headers: headers
|
52
|
+
end.not_to(change { Doorkeeper::AccessToken.where(revoked_at: nil).count })
|
53
|
+
|
54
|
+
expect(response).to be_successful
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "with bad credentials and a valid token" do
|
23
59
|
let(:headers) do
|
24
|
-
client_id =
|
25
|
-
|
26
|
-
credentials = Base64.encode64("#{client_id}:#{client_secret}")
|
60
|
+
client_id = private_client_application.uid
|
61
|
+
credentials = Base64.encode64("#{client_id}:poop")
|
27
62
|
{ "HTTP_AUTHORIZATION" => "Basic #{credentials}" }
|
28
63
|
end
|
29
64
|
|
30
|
-
it "should revoke
|
65
|
+
it "should not revoke any tokens and respond with forbidden" do
|
31
66
|
post revocation_token_endpoint_url, params: { token: access_token.token }, headers: headers
|
32
67
|
|
33
|
-
expect(response).to
|
34
|
-
expect(
|
68
|
+
expect(response).to be_forbidden
|
69
|
+
expect(response.body).to include("unauthorized_client")
|
70
|
+
expect(response.body).to include(I18n.t("doorkeeper.errors.messages.revoke.unauthorized"))
|
71
|
+
expect(access_token.reload.revoked?).to be_falsey
|
35
72
|
end
|
73
|
+
end
|
36
74
|
|
37
|
-
|
38
|
-
|
75
|
+
context "with no credentials and a valid token" do
|
76
|
+
it "should not revoke any tokens and respond with forbidden" do
|
77
|
+
post revocation_token_endpoint_url, params: { token: access_token.token }
|
39
78
|
|
40
|
-
expect(response).to
|
41
|
-
expect(
|
79
|
+
expect(response).to be_forbidden
|
80
|
+
expect(response.body).to include("unauthorized_client")
|
81
|
+
expect(response.body).to include(I18n.t("doorkeeper.errors.messages.revoke.unauthorized"))
|
82
|
+
expect(access_token.reload.revoked?).to be_falsey
|
42
83
|
end
|
84
|
+
end
|
43
85
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
expect(response).to be_forbidden
|
53
|
-
end
|
86
|
+
context "with valid token for another client application" do
|
87
|
+
let(:other_client_application) { FactoryBot.create :application }
|
88
|
+
let(:headers) do
|
89
|
+
client_id = other_client_application.uid
|
90
|
+
client_secret = other_client_application.secret
|
91
|
+
credentials = Base64.encode64("#{client_id}:#{client_secret}")
|
92
|
+
{ "HTTP_AUTHORIZATION" => "Basic #{credentials}" }
|
54
93
|
end
|
55
94
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
post revocation_token_endpoint_url, params: { token: access_token.token }, headers: headers
|
64
|
-
|
65
|
-
expect(response).to be_forbidden
|
66
|
-
expect(response.body).to include("unauthorized_client")
|
67
|
-
expect(response.body).to include(I18n.t("doorkeeper.errors.messages.revoke.unauthorized"))
|
68
|
-
expect(access_token.reload.revoked?).to be_falsey
|
69
|
-
end
|
95
|
+
it "should not revoke the token as it's unauthorized" do
|
96
|
+
post revocation_token_endpoint_url, params: { token: access_token.token }, headers: headers
|
97
|
+
|
98
|
+
expect(response).to be_forbidden
|
99
|
+
expect(response.body).to include("unauthorized_client")
|
100
|
+
expect(response.body).to include(I18n.t("doorkeeper.errors.messages.revoke.unauthorized"))
|
101
|
+
expect(access_token.reload.revoked?).to be_falsey
|
70
102
|
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "with authenticated public OAuth 2.0 client/application" do
|
107
|
+
let(:access_token) do
|
108
|
+
FactoryBot.create(
|
109
|
+
:access_token,
|
110
|
+
application: nil,
|
111
|
+
resource_owner_id: resource_owner.id,
|
112
|
+
resource_owner_type: resource_owner.class.name,
|
113
|
+
use_refresh_token: true,
|
114
|
+
)
|
115
|
+
end
|
71
116
|
|
72
|
-
|
73
|
-
|
74
|
-
|
117
|
+
it "should revoke the access token provided" do
|
118
|
+
post revocation_token_endpoint_url,
|
119
|
+
params: { client_id: public_client_application.uid, token: access_token.token },
|
120
|
+
headers: headers
|
75
121
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
expect(access_token.reload.revoked?).to be_falsey
|
80
|
-
end
|
81
|
-
end
|
122
|
+
expect(response).to be_successful
|
123
|
+
expect(access_token.reload.revoked?).to be_truthy
|
124
|
+
end
|
82
125
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
it "should not revoke the token as its unauthorized" do
|
93
|
-
post revocation_token_endpoint_url, params: { token: access_token.token }, headers: headers
|
94
|
-
|
95
|
-
expect(response).to be_forbidden
|
96
|
-
expect(response.body).to include("unauthorized_client")
|
97
|
-
expect(response.body).to include(I18n.t("doorkeeper.errors.messages.revoke.unauthorized"))
|
98
|
-
expect(access_token.reload.revoked?).to be_falsey
|
99
|
-
end
|
100
|
-
end
|
126
|
+
it "should revoke the refresh token provided" do
|
127
|
+
post revocation_token_endpoint_url,
|
128
|
+
params: { client_id: public_client_application.uid, token: access_token.refresh_token },
|
129
|
+
headers: headers
|
130
|
+
|
131
|
+
expect(response).to be_successful
|
132
|
+
expect(access_token.reload.revoked?).to be_truthy
|
101
133
|
end
|
102
134
|
|
103
|
-
|
135
|
+
it "should response with success even for invalid token" do
|
136
|
+
post revocation_token_endpoint_url,
|
137
|
+
params: { client_id: public_client_application.uid, token: "dont_exist" },
|
138
|
+
headers: headers
|
139
|
+
|
140
|
+
expect(response).to be_successful
|
141
|
+
end
|
142
|
+
|
143
|
+
context "with a valid token issued for a confidential client" do
|
104
144
|
let(:access_token) do
|
105
145
|
FactoryBot.create(
|
106
146
|
:access_token,
|
107
|
-
application:
|
147
|
+
application: private_client_application,
|
108
148
|
resource_owner_id: resource_owner.id,
|
149
|
+
resource_owner_type: resource_owner.class.name,
|
109
150
|
use_refresh_token: true,
|
110
151
|
)
|
111
152
|
end
|
112
153
|
|
113
|
-
it "should revoke the access token provided" do
|
114
|
-
post revocation_token_endpoint_url,
|
154
|
+
it "should not revoke the access token provided" do
|
155
|
+
post revocation_token_endpoint_url,
|
156
|
+
params: { client_id: public_client_application.uid, token: access_token.token }
|
115
157
|
|
116
|
-
expect(response).to
|
117
|
-
expect(
|
158
|
+
expect(response).to be_forbidden
|
159
|
+
expect(response.body).to include("unauthorized_client")
|
160
|
+
expect(response.body).to include(I18n.t("doorkeeper.errors.messages.revoke.unauthorized"))
|
161
|
+
expect(access_token.reload.revoked?).to be_falsey
|
118
162
|
end
|
119
163
|
|
120
|
-
it "should revoke the refresh token provided" do
|
121
|
-
post revocation_token_endpoint_url,
|
164
|
+
it "should not revoke the refresh token provided" do
|
165
|
+
post revocation_token_endpoint_url,
|
166
|
+
params: { client_id: public_client_application.uid, token: access_token.token }
|
122
167
|
|
123
|
-
expect(response).to
|
124
|
-
expect(
|
168
|
+
expect(response).to be_forbidden
|
169
|
+
expect(response.body).to include("unauthorized_client")
|
170
|
+
expect(response.body).to include(I18n.t("doorkeeper.errors.messages.revoke.unauthorized"))
|
171
|
+
expect(access_token.reload.revoked?).to be_falsey
|
125
172
|
end
|
173
|
+
end
|
174
|
+
end
|
126
175
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
it "should not revoke the refresh token provided" do
|
147
|
-
post revocation_token_endpoint_url, params: { token: access_token.token }
|
148
|
-
|
149
|
-
expect(response).to be_forbidden
|
150
|
-
expect(response.body).to include("unauthorized_client")
|
151
|
-
expect(response.body).to include(I18n.t("doorkeeper.errors.messages.revoke.unauthorized"))
|
152
|
-
expect(access_token.reload.revoked?).to be_falsey
|
153
|
-
end
|
154
|
-
end
|
176
|
+
context "without client authentication" do
|
177
|
+
let(:access_token) do
|
178
|
+
FactoryBot.create(
|
179
|
+
:access_token,
|
180
|
+
application: nil,
|
181
|
+
resource_owner_id: resource_owner.id,
|
182
|
+
resource_owner_type: resource_owner.class.name,
|
183
|
+
use_refresh_token: true,
|
184
|
+
)
|
185
|
+
end
|
186
|
+
|
187
|
+
it "shouldn't remove the token and must response with an error" do
|
188
|
+
post revocation_token_endpoint_url,
|
189
|
+
params: { token: access_token.token },
|
190
|
+
headers: headers
|
191
|
+
|
192
|
+
expect(response).not_to be_successful
|
193
|
+
expect(access_token.reload.revoked?).to be_falsey
|
155
194
|
end
|
156
195
|
end
|
157
196
|
end
|