doorkeeper 5.1.2 → 5.2.2
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.
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
@@ -166,7 +166,7 @@ describe "doorkeeper authorize filter" do
|
|
166
166
|
it "it renders a custom JSON response", token: :invalid do
|
167
167
|
get :index, params: { access_token: token_string }
|
168
168
|
expect(response.status).to eq 401
|
169
|
-
expect(response.content_type).to
|
169
|
+
expect(response.content_type).to include("application/json")
|
170
170
|
expect(response.header["WWW-Authenticate"]).to match(/^Bearer/)
|
171
171
|
|
172
172
|
expect(json_response).not_to be_nil
|
@@ -196,7 +196,7 @@ describe "doorkeeper authorize filter" do
|
|
196
196
|
it "it renders a custom text response", token: :invalid do
|
197
197
|
get :index, params: { access_token: token_string }
|
198
198
|
expect(response.status).to eq 401
|
199
|
-
expect(response.content_type).to
|
199
|
+
expect(response.content_type).to include("text/plain")
|
200
200
|
expect(response.header["WWW-Authenticate"]).to match(/^Bearer/)
|
201
201
|
expect(response.body).to eq("Unauthorized")
|
202
202
|
end
|
@@ -246,7 +246,7 @@ describe "doorkeeper authorize filter" do
|
|
246
246
|
it "renders a custom JSON response" do
|
247
247
|
get :index, params: { access_token: token_string }
|
248
248
|
expect(response.header).to_not include("WWW-Authenticate")
|
249
|
-
expect(response.content_type).to
|
249
|
+
expect(response.content_type).to include("application/json")
|
250
250
|
expect(response.status).to eq 403
|
251
251
|
|
252
252
|
expect(json_response).not_to be_nil
|
@@ -3,31 +3,139 @@
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
5
|
describe Doorkeeper::TokensController do
|
6
|
-
|
7
|
-
|
6
|
+
let(:client) { FactoryBot.create :application }
|
7
|
+
let!(:user) { User.create!(name: "Joe", password: "sekret") }
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
before do
|
10
|
+
Doorkeeper.configure do
|
11
|
+
resource_owner_from_credentials do
|
12
|
+
User.first
|
13
|
+
end
|
14
|
+
end
|
11
15
|
|
12
|
-
|
16
|
+
allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(["password"])
|
17
|
+
end
|
13
18
|
|
14
|
-
|
19
|
+
subject { JSON.parse(response.body) }
|
20
|
+
|
21
|
+
describe "POST #create" do
|
22
|
+
before do
|
23
|
+
post :create, params: {
|
24
|
+
client_id: client.uid,
|
25
|
+
client_secret: client.secret,
|
26
|
+
grant_type: "password",
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
it "responds after authorization" do
|
31
|
+
expect(response).to be_successful
|
32
|
+
end
|
33
|
+
|
34
|
+
it "includes access token in response" do
|
35
|
+
expect(subject["access_token"]).to eq(Doorkeeper::AccessToken.first.token)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "includes token type in response" do
|
39
|
+
expect(subject["token_type"]).to eq("Bearer")
|
40
|
+
end
|
41
|
+
|
42
|
+
it "includes token expiration in response" do
|
43
|
+
expect(subject["expires_in"].to_i).to eq(Doorkeeper.configuration.access_token_expires_in)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "issues the token for the current client" do
|
47
|
+
expect(Doorkeeper::AccessToken.first.application_id).to eq(client.id)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "issues the token for the current resource owner" do
|
51
|
+
expect(Doorkeeper::AccessToken.first.resource_owner_id).to eq(user.id)
|
15
52
|
end
|
16
53
|
end
|
17
54
|
|
18
|
-
describe "
|
19
|
-
|
20
|
-
|
21
|
-
|
55
|
+
describe "POST #create with errors" do
|
56
|
+
before do
|
57
|
+
post :create, params: {
|
58
|
+
client_id: client.uid,
|
59
|
+
client_secret: "invalid",
|
60
|
+
grant_type: "password",
|
61
|
+
}
|
62
|
+
end
|
22
63
|
|
23
|
-
|
64
|
+
it "responds after authorization" do
|
65
|
+
expect(response).to be_unauthorized
|
66
|
+
end
|
24
67
|
|
25
|
-
|
26
|
-
expect(
|
68
|
+
it "include error in response" do
|
69
|
+
expect(subject["error"]).to eq("invalid_client")
|
70
|
+
end
|
71
|
+
|
72
|
+
it "include error_description in response" do
|
73
|
+
expect(subject["error_description"]).to be
|
74
|
+
end
|
75
|
+
|
76
|
+
it "does not include access token in response" do
|
77
|
+
expect(subject["access_token"]).to be_nil
|
78
|
+
end
|
79
|
+
|
80
|
+
it "does not include token type in response" do
|
81
|
+
expect(subject["token_type"]).to be_nil
|
82
|
+
end
|
83
|
+
|
84
|
+
it "does not include token expiration in response" do
|
85
|
+
expect(subject["expires_in"]).to be_nil
|
86
|
+
end
|
87
|
+
|
88
|
+
it "does not issue any access token" do
|
89
|
+
expect(Doorkeeper::AccessToken.all).to be_empty
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "POST #create with callbacks" do
|
94
|
+
after do
|
95
|
+
client.update_attribute :redirect_uri, "urn:ietf:wg:oauth:2.0:oob"
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "when successful" do
|
99
|
+
after do
|
100
|
+
post :create, params: {
|
101
|
+
client_id: client.uid,
|
102
|
+
client_secret: client.secret,
|
103
|
+
grant_type: "password",
|
104
|
+
}
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should call :before_successful_authorization callback" do
|
108
|
+
expect(Doorkeeper.configuration)
|
109
|
+
.to receive_message_chain(:before_successful_authorization, :call).with(instance_of(described_class))
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should call :after_successful_authorization callback" do
|
113
|
+
expect(Doorkeeper.configuration)
|
114
|
+
.to receive_message_chain(:after_successful_authorization, :call).with(instance_of(described_class))
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "with errors" do
|
119
|
+
after do
|
120
|
+
post :create, params: {
|
121
|
+
client_id: client.uid,
|
122
|
+
client_secret: "invalid",
|
123
|
+
grant_type: "password",
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should call :before_successful_authorization callback" do
|
128
|
+
expect(Doorkeeper.configuration)
|
129
|
+
.to receive_message_chain(:before_successful_authorization, :call).with(instance_of(described_class))
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should not call :after_successful_authorization callback" do
|
133
|
+
expect(Doorkeeper.configuration).not_to receive(:after_successful_authorization)
|
134
|
+
end
|
27
135
|
end
|
28
136
|
end
|
29
137
|
|
30
|
-
describe "
|
138
|
+
describe "POST #create with custom error" do
|
31
139
|
it "returns the error response with a custom message" do
|
32
140
|
# I18n looks for `doorkeeper.errors.messages.custom_message` in locale files
|
33
141
|
custom_message = "my_message"
|
@@ -58,7 +166,7 @@ describe Doorkeeper::TokensController do
|
|
58
166
|
end
|
59
167
|
|
60
168
|
# http://tools.ietf.org/html/rfc7009#section-2.2
|
61
|
-
describe "
|
169
|
+
describe "POST #revoke" do
|
62
170
|
let(:client) { FactoryBot.create(:application) }
|
63
171
|
let(:access_token) { FactoryBot.create(:access_token, application: client) }
|
64
172
|
|
@@ -102,10 +210,10 @@ describe Doorkeeper::TokensController do
|
|
102
210
|
let(:some_other_client) { FactoryBot.create(:application, confidential: true) }
|
103
211
|
let(:oauth_client) { Doorkeeper::OAuth::Client.new(some_other_client) }
|
104
212
|
|
105
|
-
it "returns
|
213
|
+
it "returns 403" do
|
106
214
|
post :revoke, params: { token: access_token.token }
|
107
215
|
|
108
|
-
expect(response.status).to eq
|
216
|
+
expect(response.status).to eq 403
|
109
217
|
end
|
110
218
|
|
111
219
|
it "does not revoke the access token" do
|
@@ -117,21 +225,7 @@ describe Doorkeeper::TokensController do
|
|
117
225
|
end
|
118
226
|
end
|
119
227
|
|
120
|
-
describe "
|
121
|
-
it "memoizes the result of the authorization" do
|
122
|
-
strategy = double(:strategy, authorize: true)
|
123
|
-
expect(strategy).to receive(:authorize).once
|
124
|
-
allow(controller).to receive(:strategy) { strategy }
|
125
|
-
allow(controller).to receive(:create) do
|
126
|
-
2.times { controller.send :authorize_response }
|
127
|
-
controller.render json: {}, status: :ok
|
128
|
-
end
|
129
|
-
|
130
|
-
post :create
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
describe "when requested token introspection" do
|
228
|
+
describe "POST #introspect" do
|
135
229
|
let(:client) { FactoryBot.create(:application) }
|
136
230
|
let(:access_token) { FactoryBot.create(:access_token, application: client) }
|
137
231
|
let(:token_for_introspection) { FactoryBot.create(:access_token, application: client) }
|
@@ -147,7 +241,7 @@ describe Doorkeeper::TokensController do
|
|
147
241
|
end
|
148
242
|
end
|
149
243
|
|
150
|
-
context "authorized using
|
244
|
+
context "authorized using Client Credentials of the client that token is issued to" do
|
151
245
|
it "responds with full token introspection" do
|
152
246
|
request.headers["Authorization"] = basic_auth_header_for_client(client)
|
153
247
|
|
@@ -159,6 +253,26 @@ describe Doorkeeper::TokensController do
|
|
159
253
|
end
|
160
254
|
end
|
161
255
|
|
256
|
+
context "configured token introspection disabled" do
|
257
|
+
before do
|
258
|
+
Doorkeeper.configure do
|
259
|
+
orm DOORKEEPER_ORM
|
260
|
+
allow_token_introspection false
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
it "responds with invalid_token error" do
|
265
|
+
request.headers["Authorization"] = "Bearer #{access_token.token}"
|
266
|
+
|
267
|
+
post :introspect, params: { token: token_for_introspection.token }
|
268
|
+
|
269
|
+
response_status_should_be 401
|
270
|
+
|
271
|
+
should_not_have_json "active"
|
272
|
+
should_have_json "error", "invalid_token"
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
162
276
|
context "using custom introspection response" do
|
163
277
|
before do
|
164
278
|
Doorkeeper.configure do
|
@@ -212,12 +326,64 @@ describe Doorkeeper::TokensController do
|
|
212
326
|
end
|
213
327
|
end
|
214
328
|
|
329
|
+
context "introspection request authorized by a client and allow_token_introspection is true" do
|
330
|
+
let(:different_client) { FactoryBot.create(:application) }
|
331
|
+
|
332
|
+
before do
|
333
|
+
allow(Doorkeeper.configuration).to receive(:allow_token_introspection).and_return(proc do
|
334
|
+
true
|
335
|
+
end)
|
336
|
+
end
|
337
|
+
|
338
|
+
it "responds with full token introspection" do
|
339
|
+
request.headers["Authorization"] = basic_auth_header_for_client(different_client)
|
340
|
+
|
341
|
+
post :introspect, params: { token: token_for_introspection.token }
|
342
|
+
|
343
|
+
should_have_json "active", true
|
344
|
+
expect(json_response).to include("client_id", "token_type", "exp", "iat")
|
345
|
+
should_have_json "client_id", client.uid
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
context "allow_token_introspection requires authorized token with special scope" do
|
350
|
+
let(:access_token) { FactoryBot.create(:access_token, scopes: "introspection") }
|
351
|
+
|
352
|
+
before do
|
353
|
+
allow(Doorkeeper.configuration).to receive(:allow_token_introspection).and_return(proc do |_token, _client, authorized_token|
|
354
|
+
authorized_token.scopes.include?("introspection")
|
355
|
+
end)
|
356
|
+
end
|
357
|
+
|
358
|
+
it "responds with full token introspection if authorized token has introspection scope" do
|
359
|
+
request.headers["Authorization"] = "Bearer #{access_token.token}"
|
360
|
+
|
361
|
+
post :introspect, params: { token: token_for_introspection.token }
|
362
|
+
|
363
|
+
should_have_json "active", true
|
364
|
+
expect(json_response).to include("client_id", "token_type", "exp", "iat")
|
365
|
+
end
|
366
|
+
|
367
|
+
it "responds with invalid_token error if authorized token doesn't have introspection scope" do
|
368
|
+
access_token.update(scopes: "read write")
|
369
|
+
|
370
|
+
request.headers["Authorization"] = "Bearer #{access_token.token}"
|
371
|
+
|
372
|
+
post :introspect, params: { token: token_for_introspection.token }
|
373
|
+
|
374
|
+
response_status_should_be 401
|
375
|
+
|
376
|
+
should_not_have_json "active"
|
377
|
+
should_have_json "error", "invalid_token"
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
215
381
|
context "authorized using invalid Bearer token" do
|
216
382
|
let(:access_token) do
|
217
383
|
FactoryBot.create(:access_token, application: client, revoked_at: 1.day.ago)
|
218
384
|
end
|
219
385
|
|
220
|
-
it "responds with
|
386
|
+
it "responds with invalid_token error" do
|
221
387
|
request.headers["Authorization"] = "Bearer #{access_token.token}"
|
222
388
|
|
223
389
|
post :introspect, params: { token: token_for_introspection.token }
|
@@ -272,13 +438,15 @@ describe Doorkeeper::TokensController do
|
|
272
438
|
end
|
273
439
|
|
274
440
|
context "authorized using valid Bearer token" do
|
275
|
-
it "responds with
|
441
|
+
it "responds with invalid_token error" do
|
276
442
|
request.headers["Authorization"] = "Bearer #{access_token.token}"
|
277
443
|
|
278
444
|
post :introspect, params: { token: SecureRandom.hex(16) }
|
279
445
|
|
280
|
-
|
281
|
-
|
446
|
+
response_status_should_be 401
|
447
|
+
|
448
|
+
should_not_have_json "active"
|
449
|
+
should_have_json "error", "invalid_token"
|
282
450
|
end
|
283
451
|
end
|
284
452
|
end
|
@@ -5,11 +5,13 @@ require "rails"
|
|
5
5
|
%w[
|
6
6
|
action_controller/railtie
|
7
7
|
action_view/railtie
|
8
|
+
action_cable/engine
|
8
9
|
sprockets/railtie
|
9
10
|
].each do |railtie|
|
10
11
|
begin
|
11
12
|
require railtie
|
12
|
-
rescue LoadError
|
13
|
+
rescue LoadError => e
|
14
|
+
puts "Error loading '#{railtie}' (#{e.message})"
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
@@ -65,15 +65,6 @@ Doorkeeper.configure do
|
|
65
65
|
# Check out the wiki for more information on customization
|
66
66
|
# access_token_methods :from_bearer_authorization, :from_access_token_param, :from_bearer_param
|
67
67
|
|
68
|
-
# Change the native redirect uri for client apps
|
69
|
-
# When clients register with the following redirect uri, they won't be redirected to any server and
|
70
|
-
# the authorization code will be displayed within the provider
|
71
|
-
# The value can be any string. Use nil to disable this feature.
|
72
|
-
# When disabled, clients must provide a valid URL
|
73
|
-
# (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi)
|
74
|
-
#
|
75
|
-
# native_redirect_uri 'urn:ietf:wg:oauth:2.0:oob'
|
76
|
-
|
77
68
|
# Forces the usage of the HTTPS protocol in non-native redirect uris (enabled
|
78
69
|
# by default in non-development environments). OAuth2 delegates security in
|
79
70
|
# communication to the HTTPS protocol so it is wise to keep this enabled.
|
@@ -116,6 +107,60 @@ Doorkeeper.configure do
|
|
116
107
|
# client.superapp? or resource_owner.admin?
|
117
108
|
# end
|
118
109
|
|
110
|
+
# Configure custom constraints for the Token Introspection request.
|
111
|
+
# By default this configuration option allows to introspect a token by another
|
112
|
+
# token of the same application, OR to introspect the token that belongs to
|
113
|
+
# authorized client (from authenticated client) OR when token doesn't
|
114
|
+
# belong to any client (public token). Otherwise requester has no access to the
|
115
|
+
# introspection and it will return response as stated in the RFC.
|
116
|
+
#
|
117
|
+
# Block arguments:
|
118
|
+
#
|
119
|
+
# @param token [Doorkeeper::AccessToken]
|
120
|
+
# token to be introspected
|
121
|
+
#
|
122
|
+
# @param authorized_client [Doorkeeper::Application]
|
123
|
+
# authorized client (if request is authorized using Basic auth with
|
124
|
+
# Client Credentials for example)
|
125
|
+
#
|
126
|
+
# @param authorized_token [Doorkeeper::AccessToken]
|
127
|
+
# Bearer token used to authorize the request
|
128
|
+
#
|
129
|
+
# In case the block returns `nil` or `false` introspection responses with 401 status code
|
130
|
+
# when using authorized token to introspect, or you'll get 200 with { "active": false } body
|
131
|
+
# when using authorized client to introspect as stated in the
|
132
|
+
# RFC 7662 section 2.2. Introspection Response.
|
133
|
+
#
|
134
|
+
# Using with caution:
|
135
|
+
# Keep in mind that these three parameters pass to block can be nil as following case:
|
136
|
+
# `authorized_client` is nil if and only if `authorized_token` is present, and vice versa.
|
137
|
+
# `token` will be nil if and only if `authorized_token` is present.
|
138
|
+
# So remember to use `&` or check if it is present before calling method on
|
139
|
+
# them to make sure you doesn't get NoMethodError exception.
|
140
|
+
#
|
141
|
+
# You can define your custom check:
|
142
|
+
#
|
143
|
+
# allow_token_introspection do |token, authorized_client, authorized_token|
|
144
|
+
# if authorized_token
|
145
|
+
# # customize: require `introspection` scope
|
146
|
+
# authorized_token.application == token&.application ||
|
147
|
+
# authorized_token.scopes.include?("introspection")
|
148
|
+
# elsif token.application
|
149
|
+
# # `protected_resource` is a new database boolean column, for example
|
150
|
+
# authorized_client == token.application || authorized_client.protected_resource?
|
151
|
+
# else
|
152
|
+
# # public token (when token.application is nil, token doesn't belong to any application)
|
153
|
+
# true
|
154
|
+
# end
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# Or you can completely disable any token introspection:
|
158
|
+
#
|
159
|
+
# allow_token_introspection false
|
160
|
+
#
|
161
|
+
# If you need to block the request at all, then configure your routes.rb or web-server
|
162
|
+
# like nginx to forbid the request.
|
163
|
+
|
119
164
|
# WWW-Authenticate Realm (default "Doorkeeper").
|
120
165
|
realm "Doorkeeper"
|
121
166
|
end
|
@@ -25,7 +25,7 @@ class CreateDoorkeeperTables < ActiveRecord::Migration[4.2]
|
|
25
25
|
t.text :redirect_uri, null: false
|
26
26
|
t.datetime :created_at, null: false
|
27
27
|
t.datetime :revoked_at
|
28
|
-
t.string :scopes
|
28
|
+
t.string :scopes, null: false, default: ""
|
29
29
|
end
|
30
30
|
|
31
31
|
add_index :oauth_access_grants, :token, unique: true
|
data/spec/lib/config_spec.rb
CHANGED
@@ -502,7 +502,21 @@ describe Doorkeeper, "configuration" do
|
|
502
502
|
|
503
503
|
describe "base_controller" do
|
504
504
|
context "default" do
|
505
|
-
it { expect(Doorkeeper.configuration.base_controller).to
|
505
|
+
it { expect(Doorkeeper.configuration.base_controller).to be_an_instance_of(Proc) }
|
506
|
+
|
507
|
+
it "resolves to a ApplicationController::Base in default mode" do
|
508
|
+
expect(Doorkeeper.configuration.resolve_controller(:base))
|
509
|
+
.to eq(ActionController::Base)
|
510
|
+
end
|
511
|
+
|
512
|
+
it "resolves to a ApplicationController::API in api_only mode" do
|
513
|
+
Doorkeeper.configure do
|
514
|
+
api_only
|
515
|
+
end
|
516
|
+
|
517
|
+
expect(Doorkeeper.configuration.resolve_controller(:base))
|
518
|
+
.to eq(ActionController::API)
|
519
|
+
end
|
506
520
|
end
|
507
521
|
|
508
522
|
context "custom" do
|
@@ -517,6 +531,23 @@ describe Doorkeeper, "configuration" do
|
|
517
531
|
end
|
518
532
|
end
|
519
533
|
|
534
|
+
describe "base_metal_controller" do
|
535
|
+
context "default" do
|
536
|
+
it { expect(Doorkeeper.configuration.base_metal_controller).to eq("ActionController::API") }
|
537
|
+
end
|
538
|
+
|
539
|
+
context "custom" do
|
540
|
+
before do
|
541
|
+
Doorkeeper.configure do
|
542
|
+
orm DOORKEEPER_ORM
|
543
|
+
base_metal_controller { "ApplicationController" }
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
it { expect(Doorkeeper.configuration.resolve_controller(:base_metal)).to eq(ApplicationController) }
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
520
551
|
if DOORKEEPER_ORM == :active_record
|
521
552
|
describe "active_record_options" do
|
522
553
|
let(:models) { [Doorkeeper::AccessGrant, Doorkeeper::AccessToken, Doorkeeper::Application] }
|
@@ -694,4 +725,15 @@ describe Doorkeeper, "configuration" do
|
|
694
725
|
end
|
695
726
|
end
|
696
727
|
end
|
728
|
+
|
729
|
+
describe "options deprecation" do
|
730
|
+
it "prints a warning message when an option is deprecated" do
|
731
|
+
expect(Kernel).to receive(:warn).with(
|
732
|
+
"[DOORKEEPER] native_redirect_uri has been deprecated and will soon be removed"
|
733
|
+
)
|
734
|
+
Doorkeeper.configure do
|
735
|
+
native_redirect_uri "urn:ietf:wg:oauth:2.0:oob"
|
736
|
+
end
|
737
|
+
end
|
738
|
+
end
|
697
739
|
end
|
@@ -23,7 +23,7 @@ module Doorkeeper::OAuth
|
|
23
23
|
end
|
24
24
|
|
25
25
|
subject do
|
26
|
-
AuthorizationCodeRequest.new
|
26
|
+
AuthorizationCodeRequest.new(server, grant, client, params)
|
27
27
|
end
|
28
28
|
|
29
29
|
it "issues a new token for the client" do
|
@@ -65,6 +65,18 @@ module Doorkeeper::OAuth
|
|
65
65
|
subject.redirect_uri = nil
|
66
66
|
subject.validate
|
67
67
|
expect(subject.error).to eq(:invalid_request)
|
68
|
+
expect(subject.missing_param).to eq(:redirect_uri)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "invalid code_verifier param because server does not support pkce" do
|
72
|
+
# Some other ORMs work relies on #respond_to? so it's not a good idea to stub it :\
|
73
|
+
allow_any_instance_of(Doorkeeper::AccessGrant).to receive(:respond_to?).with(anything).and_call_original
|
74
|
+
allow_any_instance_of(Doorkeeper::AccessGrant).to receive(:respond_to?).with(:code_challenge).and_return(false)
|
75
|
+
|
76
|
+
subject.code_verifier = "a45a9fea-0676-477e-95b1-a40f72ac3cfb"
|
77
|
+
subject.validate
|
78
|
+
expect(subject.error).to eq(:invalid_request)
|
79
|
+
expect(subject.invalid_request_reason).to eq(:not_support_pkce)
|
68
80
|
end
|
69
81
|
|
70
82
|
it "matches the redirect_uri with grant's one" do
|
@@ -66,27 +66,44 @@ module Doorkeeper::OAuth
|
|
66
66
|
end
|
67
67
|
|
68
68
|
context "invalid" do
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
69
|
+
context "with error other than invalid_request" do
|
70
|
+
before do
|
71
|
+
allow(subject).to receive(:valid?).and_return(false)
|
72
|
+
allow(subject).to receive(:error).and_return(:server_error)
|
73
|
+
allow(subject).to receive(:state).and_return("hello")
|
74
|
+
end
|
75
|
+
|
76
|
+
it "returns an ErrorResponse object" do
|
77
|
+
result = subject.authorize
|
78
|
+
|
79
|
+
expect(result).to be_an_instance_of(ErrorResponse)
|
80
|
+
|
81
|
+
expect(result.body).to eq(
|
82
|
+
error: :server_error,
|
83
|
+
error_description: translated_error_message(:server_error),
|
84
|
+
state: "hello"
|
85
|
+
)
|
86
|
+
end
|
73
87
|
end
|
74
88
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
89
|
+
context "with invalid_request error" do
|
90
|
+
before do
|
91
|
+
allow(subject).to receive(:valid?).and_return(false)
|
92
|
+
allow(subject).to receive(:error).and_return(:invalid_request)
|
93
|
+
allow(subject).to receive(:state).and_return("hello")
|
94
|
+
end
|
80
95
|
|
81
|
-
|
96
|
+
it "returns an InvalidRequestResponse object" do
|
97
|
+
result = subject.authorize
|
82
98
|
|
83
|
-
|
99
|
+
expect(result).to be_an_instance_of(InvalidRequestResponse)
|
84
100
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
101
|
+
expect(result.body).to eq(
|
102
|
+
error: :invalid_request,
|
103
|
+
error_description: translated_invalid_request_error_message(:unknown, :unknown),
|
104
|
+
state: "hello"
|
105
|
+
)
|
106
|
+
end
|
90
107
|
end
|
91
108
|
end
|
92
109
|
end
|
@@ -55,6 +55,7 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
|
|
55
55
|
|
56
56
|
expect(Doorkeeper::AccessToken.count).to eq(2)
|
57
57
|
expect(result).not_to eq(existing_token)
|
58
|
+
expect(existing_token.reload).to be_revoked
|
58
59
|
end
|
59
60
|
end
|
60
61
|
|
@@ -69,6 +70,7 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
|
|
69
70
|
|
70
71
|
expect(Doorkeeper::AccessToken.count).to eq(2)
|
71
72
|
expect(result).not_to eq(existing_token)
|
73
|
+
expect(existing_token.reload).to be_revoked
|
72
74
|
end
|
73
75
|
end
|
74
76
|
end
|
@@ -82,6 +84,7 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
|
|
82
84
|
|
83
85
|
expect(Doorkeeper::AccessToken.count).to eq(2)
|
84
86
|
expect(result).not_to eq(existing_token)
|
87
|
+
expect(existing_token.reload).to be_revoked
|
85
88
|
end
|
86
89
|
end
|
87
90
|
|