doorkeeper 5.0.0 → 5.0.1
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/.travis.yml +5 -0
- data/Dangerfile +57 -0
- data/NEWS.md +32 -1
- data/README.md +18 -3
- data/app/controllers/doorkeeper/application_controller.rb +2 -0
- data/app/controllers/doorkeeper/application_metal_controller.rb +2 -0
- data/app/controllers/doorkeeper/applications_controller.rb +4 -2
- data/app/controllers/doorkeeper/authorizations_controller.rb +3 -3
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +2 -0
- data/app/controllers/doorkeeper/token_info_controller.rb +2 -0
- data/app/controllers/doorkeeper/tokens_controller.rb +2 -0
- data/app/helpers/doorkeeper/dashboard_helper.rb +2 -0
- data/app/validators/redirect_uri_validator.rb +2 -0
- data/doorkeeper.gemspec +23 -22
- data/lib/doorkeeper.rb +1 -0
- data/lib/doorkeeper/config.rb +7 -2
- data/lib/doorkeeper/engine.rb +2 -0
- data/lib/doorkeeper/errors.rb +17 -0
- data/lib/doorkeeper/grape/authorization_decorator.rb +2 -0
- data/lib/doorkeeper/grape/helpers.rb +2 -0
- data/lib/doorkeeper/helpers/controller.rb +2 -0
- data/lib/doorkeeper/models/access_grant_mixin.rb +5 -3
- data/lib/doorkeeper/models/access_token_mixin.rb +5 -3
- data/lib/doorkeeper/models/application_mixin.rb +2 -0
- data/lib/doorkeeper/models/concerns/accessible.rb +2 -0
- data/lib/doorkeeper/models/concerns/expirable.rb +2 -0
- data/lib/doorkeeper/models/concerns/orderable.rb +2 -0
- data/lib/doorkeeper/models/concerns/ownership.rb +2 -0
- data/lib/doorkeeper/models/concerns/revocable.rb +2 -0
- data/lib/doorkeeper/models/concerns/scopes.rb +2 -0
- data/lib/doorkeeper/oauth/authorization/code.rb +2 -0
- data/lib/doorkeeper/oauth/authorization/context.rb +2 -0
- data/lib/doorkeeper/oauth/authorization/token.rb +2 -0
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +2 -0
- data/lib/doorkeeper/oauth/authorization_code_request.rb +2 -0
- data/lib/doorkeeper/oauth/base_request.rb +2 -0
- data/lib/doorkeeper/oauth/base_response.rb +2 -0
- data/lib/doorkeeper/oauth/client.rb +2 -0
- data/lib/doorkeeper/oauth/client/credentials.rb +2 -0
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +2 -0
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +2 -0
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +2 -0
- data/lib/doorkeeper/oauth/client_credentials_request.rb +2 -0
- data/lib/doorkeeper/oauth/code_request.rb +2 -0
- data/lib/doorkeeper/oauth/code_response.rb +2 -0
- data/lib/doorkeeper/oauth/error.rb +2 -0
- data/lib/doorkeeper/oauth/error_response.rb +10 -0
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +9 -2
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +2 -0
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +2 -0
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +5 -2
- data/lib/doorkeeper/oauth/invalid_token_response.rb +18 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +2 -0
- data/lib/doorkeeper/oauth/pre_authorization.rb +2 -0
- data/lib/doorkeeper/oauth/refresh_token_request.rb +10 -2
- data/lib/doorkeeper/oauth/scopes.rb +2 -0
- data/lib/doorkeeper/oauth/token.rb +2 -0
- data/lib/doorkeeper/oauth/token_introspection.rb +2 -0
- data/lib/doorkeeper/oauth/token_request.rb +2 -0
- data/lib/doorkeeper/oauth/token_response.rb +2 -0
- data/lib/doorkeeper/orm/active_record.rb +2 -0
- data/lib/doorkeeper/rails/helpers.rb +4 -0
- data/lib/doorkeeper/rails/routes.rb +9 -2
- data/lib/doorkeeper/rails/routes/mapper.rb +2 -0
- data/lib/doorkeeper/rails/routes/mapping.rb +2 -0
- data/lib/doorkeeper/rake/db.rake +4 -4
- data/lib/doorkeeper/request.rb +2 -0
- data/lib/doorkeeper/request/authorization_code.rb +2 -0
- data/lib/doorkeeper/request/client_credentials.rb +2 -0
- data/lib/doorkeeper/request/code.rb +2 -0
- data/lib/doorkeeper/request/password.rb +2 -0
- data/lib/doorkeeper/request/refresh_token.rb +2 -0
- data/lib/doorkeeper/request/strategy.rb +2 -0
- data/lib/doorkeeper/request/token.rb +2 -0
- data/lib/doorkeeper/server.rb +2 -0
- data/lib/doorkeeper/stale_records_cleaner.rb +20 -0
- data/lib/doorkeeper/validations.rb +2 -0
- data/lib/doorkeeper/version.rb +3 -1
- data/lib/generators/doorkeeper/templates/initializer.rb +20 -2
- data/lib/generators/doorkeeper/templates/migration.rb.erb +2 -2
- data/spec/controllers/applications_controller_spec.rb +37 -41
- data/spec/controllers/authorizations_controller_spec.rb +71 -18
- data/spec/controllers/protected_resources_controller_spec.rb +44 -2
- data/spec/controllers/tokens_controller_spec.rb +4 -5
- data/spec/dummy/Rakefile +1 -1
- data/spec/dummy/app/controllers/custom_authorizations_controller.rb +1 -1
- data/spec/dummy/app/controllers/home_controller.rb +1 -2
- data/spec/dummy/config.ru +1 -1
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/boot.rb +2 -4
- data/spec/dummy/config/environment.rb +1 -1
- data/spec/dummy/config/environments/test.rb +1 -1
- data/spec/dummy/config/initializers/doorkeeper.rb +2 -1
- data/spec/dummy/config/initializers/new_framework_defaults.rb +1 -3
- data/spec/dummy/config/initializers/secret_token.rb +1 -1
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +4 -4
- data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +1 -1
- data/spec/dummy/script/rails +4 -3
- data/spec/factories.rb +6 -6
- data/spec/generators/install_generator_spec.rb +4 -1
- data/spec/generators/templates/routes.rb +0 -1
- data/spec/generators/views_generator_spec.rb +1 -1
- data/spec/grape/grape_integration_spec.rb +1 -1
- data/spec/lib/config_spec.rb +25 -8
- data/spec/lib/doorkeeper_spec.rb +5 -5
- data/spec/lib/oauth/authorization_code_request_spec.rb +9 -6
- data/spec/lib/oauth/base_request_spec.rb +10 -10
- data/spec/lib/oauth/client/credentials_spec.rb +2 -2
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -2
- data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -1
- data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
- data/spec/lib/oauth/code_request_spec.rb +2 -2
- data/spec/lib/oauth/code_response_spec.rb +1 -1
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +8 -8
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +17 -6
- data/spec/lib/oauth/password_access_token_request_spec.rb +17 -5
- data/spec/lib/oauth/refresh_token_request_spec.rb +11 -7
- data/spec/lib/oauth/token_request_spec.rb +5 -5
- data/spec/lib/oauth/token_spec.rb +4 -1
- data/spec/lib/server_spec.rb +6 -6
- data/spec/lib/{orm/active_record/stale_records_cleaner_spec.rb → stale_records_cleaner_spec.rb} +14 -4
- data/spec/models/doorkeeper/access_token_spec.rb +14 -10
- data/spec/models/doorkeeper/application_spec.rb +4 -4
- data/spec/requests/applications/applications_request_spec.rb +2 -2
- data/spec/requests/endpoints/authorization_spec.rb +2 -2
- data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
- data/spec/requests/flows/authorization_code_spec.rb +75 -15
- data/spec/requests/flows/implicit_grant_errors_spec.rb +2 -2
- data/spec/requests/flows/password_spec.rb +6 -2
- data/spec/requests/flows/refresh_token_spec.rb +57 -0
- data/spec/requests/flows/revoke_token_spec.rb +9 -9
- data/spec/requests/protected_resources/private_api_spec.rb +2 -2
- data/spec/support/doorkeeper_rspec.rb +2 -1
- data/spec/support/helpers/model_helper.rb +8 -4
- data/spec/support/helpers/url_helper.rb +11 -11
- data/spec/support/shared/controllers_shared_context.rb +56 -0
- data/spec/validators/redirect_uri_validator_spec.rb +2 -2
- metadata +20 -4
@@ -210,10 +210,10 @@ module Doorkeeper
|
|
210
210
|
it 'revokes all access tokens and access grants' do
|
211
211
|
application_id = 42
|
212
212
|
resource_owner = double
|
213
|
-
expect(Doorkeeper::AccessToken)
|
214
|
-
to receive(:revoke_all_for).with(application_id, resource_owner)
|
215
|
-
expect(Doorkeeper::AccessGrant)
|
216
|
-
to receive(:revoke_all_for).with(application_id, resource_owner)
|
213
|
+
expect(Doorkeeper::AccessToken)
|
214
|
+
.to receive(:revoke_all_for).with(application_id, resource_owner)
|
215
|
+
expect(Doorkeeper::AccessGrant)
|
216
|
+
.to receive(:revoke_all_for).with(application_id, resource_owner)
|
217
217
|
|
218
218
|
Application.revoke_tokens_and_grants_for(application_id, resource_owner)
|
219
219
|
end
|
@@ -62,7 +62,7 @@ feature 'Adding applications' do
|
|
62
62
|
|
63
63
|
scenario "adding app validating scope, multiple scopes configured" do
|
64
64
|
config_is_set("enforce_configured_scopes", true)
|
65
|
-
scopes = Doorkeeper::OAuth::Scopes.from_array(%w
|
65
|
+
scopes = Doorkeeper::OAuth::Scopes.from_array(%w[read write admin])
|
66
66
|
config_is_set("optional_scopes", scopes)
|
67
67
|
|
68
68
|
fill_in "doorkeeper_application[name]", with: "My Application"
|
@@ -77,7 +77,7 @@ feature 'Adding applications' do
|
|
77
77
|
|
78
78
|
scenario "adding app validating scope, bad scope with multiple scopes configured" do
|
79
79
|
config_is_set("enforce_configured_scopes", true)
|
80
|
-
scopes = Doorkeeper::OAuth::Scopes.from_array(%w
|
80
|
+
scopes = Doorkeeper::OAuth::Scopes.from_array(%w[read write admin])
|
81
81
|
config_is_set("optional_scopes", scopes)
|
82
82
|
|
83
83
|
fill_in "doorkeeper_application[name]", with: "My Application"
|
@@ -60,11 +60,11 @@ feature 'Authorization endpoint' do
|
|
60
60
|
|
61
61
|
scenario 'raises exception on forged requests' do
|
62
62
|
allowing_forgery_protection do
|
63
|
-
expect
|
63
|
+
expect do
|
64
64
|
page.driver.post authorization_endpoint_url(client_id: @client.uid,
|
65
65
|
redirect_uri: @client.redirect_uri,
|
66
66
|
response_type: 'code')
|
67
|
-
|
67
|
+
end.to raise_error(ActionController::InvalidAuthenticityToken)
|
68
68
|
end
|
69
69
|
end
|
70
70
|
end
|
@@ -57,7 +57,7 @@ describe 'Authorization Code Flow Errors', 'after authorization' do
|
|
57
57
|
# Second attempt with same token
|
58
58
|
expect do
|
59
59
|
post token_endpoint_url(code: @authorization.token, client: @client)
|
60
|
-
end.to_not
|
60
|
+
end.to_not(change { Doorkeeper::AccessToken.count })
|
61
61
|
|
62
62
|
should_not_have_json 'access_token'
|
63
63
|
should_have_json 'error', 'invalid_grant'
|
@@ -66,18 +66,36 @@ feature 'Authorization Code Flow' do
|
|
66
66
|
page.driver.post token_endpoint_url(code: authorization_code, client_id: @client.uid,
|
67
67
|
redirect_uri: @client.redirect_uri)
|
68
68
|
|
69
|
-
expect(Doorkeeper::AccessToken).
|
69
|
+
expect(Doorkeeper::AccessToken.count).to be_zero
|
70
70
|
|
71
71
|
should_have_json 'error', 'invalid_client'
|
72
72
|
end
|
73
73
|
|
74
|
+
scenario 'silently authorizes if matching token exists' do
|
75
|
+
default_scopes_exist :public, :write
|
76
|
+
|
77
|
+
access_token_exists application: @client,
|
78
|
+
expires_in: -100, # even expired token
|
79
|
+
resource_owner_id: @resource_owner.id,
|
80
|
+
scopes: 'public write'
|
81
|
+
|
82
|
+
visit authorization_endpoint_url(client: @client, scope: 'public write')
|
83
|
+
|
84
|
+
response_status_should_be 200
|
85
|
+
i_should_not_see 'Authorize'
|
86
|
+
end
|
87
|
+
|
74
88
|
context 'with PKCE' do
|
75
89
|
context 'plain' do
|
76
90
|
let(:code_challenge) { 'a45a9fea-0676-477e-95b1-a40f72ac3cfb' }
|
77
91
|
let(:code_verifier) { 'a45a9fea-0676-477e-95b1-a40f72ac3cfb' }
|
78
92
|
|
79
93
|
scenario 'resource owner authorizes the client with code_challenge parameter set' do
|
80
|
-
visit authorization_endpoint_url(
|
94
|
+
visit authorization_endpoint_url(
|
95
|
+
client: @client,
|
96
|
+
code_challenge: code_challenge,
|
97
|
+
code_challenge_method: 'plain'
|
98
|
+
)
|
81
99
|
click_on 'Authorize'
|
82
100
|
|
83
101
|
url_should_have_param('code', Doorkeeper::AccessGrant.first.token)
|
@@ -96,7 +114,11 @@ feature 'Authorization Code Flow' do
|
|
96
114
|
end
|
97
115
|
|
98
116
|
scenario 'mobile app requests an access token with authorization code and plain code challenge method' do
|
99
|
-
visit authorization_endpoint_url(
|
117
|
+
visit authorization_endpoint_url(
|
118
|
+
client: @client,
|
119
|
+
code_challenge: code_challenge,
|
120
|
+
code_challenge_method: 'plain'
|
121
|
+
)
|
100
122
|
click_on 'Authorize'
|
101
123
|
|
102
124
|
authorization_code = current_params['code']
|
@@ -130,7 +152,11 @@ feature 'Authorization Code Flow' do
|
|
130
152
|
let(:code_verifier) { 'a45a9fea-0676-477e-95b1-a40f72ac3cfb' }
|
131
153
|
|
132
154
|
scenario 'resource owner authorizes the client with code_challenge parameter set' do
|
133
|
-
visit authorization_endpoint_url(
|
155
|
+
visit authorization_endpoint_url(
|
156
|
+
client: @client,
|
157
|
+
code_challenge: code_challenge,
|
158
|
+
code_challenge_method: 'S256'
|
159
|
+
)
|
134
160
|
click_on 'Authorize'
|
135
161
|
|
136
162
|
url_should_have_param('code', Doorkeeper::AccessGrant.first.token)
|
@@ -139,7 +165,11 @@ feature 'Authorization Code Flow' do
|
|
139
165
|
end
|
140
166
|
|
141
167
|
scenario 'mobile app requests an access token with authorization code and S256 code challenge method' do
|
142
|
-
visit authorization_endpoint_url(
|
168
|
+
visit authorization_endpoint_url(
|
169
|
+
client: @client,
|
170
|
+
code_challenge: code_challenge,
|
171
|
+
code_challenge_method: 'S256'
|
172
|
+
)
|
143
173
|
click_on 'Authorize'
|
144
174
|
|
145
175
|
authorization_code = current_params['code']
|
@@ -155,7 +185,11 @@ feature 'Authorization Code Flow' do
|
|
155
185
|
end
|
156
186
|
|
157
187
|
scenario 'mobile app requests an access token with authorization code and without code_verifier' do
|
158
|
-
visit authorization_endpoint_url(
|
188
|
+
visit authorization_endpoint_url(
|
189
|
+
client: @client,
|
190
|
+
code_challenge: code_challenge,
|
191
|
+
code_challenge_method: 'S256'
|
192
|
+
)
|
159
193
|
click_on 'Authorize'
|
160
194
|
authorization_code = current_params['code']
|
161
195
|
create_access_token authorization_code, @client
|
@@ -164,7 +198,11 @@ feature 'Authorization Code Flow' do
|
|
164
198
|
end
|
165
199
|
|
166
200
|
scenario 'mobile app requests an access token with authorization code and without secret' do
|
167
|
-
visit authorization_endpoint_url(
|
201
|
+
visit authorization_endpoint_url(
|
202
|
+
client: @client,
|
203
|
+
code_challenge: code_challenge,
|
204
|
+
code_challenge_method: 'S256'
|
205
|
+
)
|
168
206
|
click_on 'Authorize'
|
169
207
|
|
170
208
|
authorization_code = current_params['code']
|
@@ -180,8 +218,12 @@ feature 'Authorization Code Flow' do
|
|
180
218
|
click_on 'Authorize'
|
181
219
|
|
182
220
|
authorization_code = current_params['code']
|
183
|
-
page.driver.post token_endpoint_url(
|
184
|
-
|
221
|
+
page.driver.post token_endpoint_url(
|
222
|
+
code: authorization_code,
|
223
|
+
client_id: @client.uid,
|
224
|
+
redirect_uri: @client.redirect_uri,
|
225
|
+
code_verifier: code_verifier
|
226
|
+
)
|
185
227
|
should_not_have_json 'error'
|
186
228
|
|
187
229
|
should_have_json 'access_token', Doorkeeper::AccessToken.first.token
|
@@ -190,7 +232,11 @@ feature 'Authorization Code Flow' do
|
|
190
232
|
end
|
191
233
|
|
192
234
|
scenario 'mobile app requests an access token with authorization code but no code verifier' do
|
193
|
-
visit authorization_endpoint_url(
|
235
|
+
visit authorization_endpoint_url(
|
236
|
+
client: @client,
|
237
|
+
code_challenge: code_challenge,
|
238
|
+
code_challenge_method: 'S256'
|
239
|
+
)
|
194
240
|
click_on 'Authorize'
|
195
241
|
|
196
242
|
authorization_code = current_params['code']
|
@@ -201,7 +247,11 @@ feature 'Authorization Code Flow' do
|
|
201
247
|
end
|
202
248
|
|
203
249
|
scenario 'mobile app requests an access token with authorization code with wrong verifier' do
|
204
|
-
visit authorization_endpoint_url(
|
250
|
+
visit authorization_endpoint_url(
|
251
|
+
client: @client,
|
252
|
+
code_challenge: code_challenge,
|
253
|
+
code_challenge_method: 'S256'
|
254
|
+
)
|
205
255
|
click_on 'Authorize'
|
206
256
|
|
207
257
|
authorization_code = current_params['code']
|
@@ -212,12 +262,20 @@ feature 'Authorization Code Flow' do
|
|
212
262
|
end
|
213
263
|
|
214
264
|
scenario 'code_challenge_mehthod in token request is totally ignored' do
|
215
|
-
visit authorization_endpoint_url(
|
265
|
+
visit authorization_endpoint_url(
|
266
|
+
client: @client,
|
267
|
+
code_challenge: code_challenge,
|
268
|
+
code_challenge_method: 'S256'
|
269
|
+
)
|
216
270
|
click_on 'Authorize'
|
217
271
|
|
218
272
|
authorization_code = current_params['code']
|
219
|
-
page.driver.post token_endpoint_url(
|
220
|
-
|
273
|
+
page.driver.post token_endpoint_url(
|
274
|
+
code: authorization_code,
|
275
|
+
client: @client,
|
276
|
+
code_verifier: code_challenge,
|
277
|
+
code_challenge_method: 'plain'
|
278
|
+
)
|
221
279
|
|
222
280
|
should_not_have_json 'access_token'
|
223
281
|
should_have_json 'error', 'invalid_grant'
|
@@ -324,6 +382,7 @@ describe 'Authorization Code Flow' do
|
|
324
382
|
orm DOORKEEPER_ORM
|
325
383
|
use_refresh_token
|
326
384
|
end
|
385
|
+
|
327
386
|
client_exists
|
328
387
|
end
|
329
388
|
|
@@ -334,7 +393,8 @@ describe 'Authorization Code Flow' do
|
|
334
393
|
|
335
394
|
it 'second of simultaneous client requests get an error for revoked acccess token' do
|
336
395
|
authorization_code = Doorkeeper::AccessGrant.first.token
|
337
|
-
allow_any_instance_of(Doorkeeper::AccessGrant)
|
396
|
+
allow_any_instance_of(Doorkeeper::AccessGrant)
|
397
|
+
.to receive(:revoked?).and_return(false, true)
|
338
398
|
|
339
399
|
post token_endpoint_url(code: authorization_code, client: @client)
|
340
400
|
|
@@ -14,8 +14,8 @@ feature 'Implicit Grant Flow Errors' do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
[
|
17
|
-
[
|
18
|
-
[
|
17
|
+
%i[client_id invalid_client],
|
18
|
+
%i[redirect_uri invalid_redirect_uri]
|
19
19
|
].each do |error|
|
20
20
|
scenario "displays #{error.last} error for invalid #{error.first}" do
|
21
21
|
visit authorization_endpoint_url(client: @client, error.first => 'invalid', response_type: 'token')
|
@@ -57,7 +57,11 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
57
57
|
context "when client_secret incorrect" do
|
58
58
|
it "should not issue new token" do
|
59
59
|
expect do
|
60
|
-
post password_token_endpoint_url(
|
60
|
+
post password_token_endpoint_url(
|
61
|
+
client_id: @client.uid,
|
62
|
+
client_secret: 'foobar',
|
63
|
+
resource_owner: @resource_owner
|
64
|
+
)
|
61
65
|
end.not_to(change { Doorkeeper::AccessToken.count })
|
62
66
|
|
63
67
|
expect(response).not_to be_ok
|
@@ -148,7 +152,7 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
148
152
|
|
149
153
|
it 'issues new token without any scope' do
|
150
154
|
expect do
|
151
|
-
|
155
|
+
post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
|
152
156
|
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
153
157
|
|
154
158
|
token = Doorkeeper::AccessToken.first
|
@@ -6,6 +6,7 @@ describe 'Refresh Token Flow' do
|
|
6
6
|
orm DOORKEEPER_ORM
|
7
7
|
use_refresh_token
|
8
8
|
end
|
9
|
+
|
9
10
|
client_exists
|
10
11
|
end
|
11
12
|
|
@@ -95,6 +96,62 @@ describe 'Refresh Token Flow' do
|
|
95
96
|
end
|
96
97
|
end
|
97
98
|
|
99
|
+
context "public & private clients" do
|
100
|
+
let(:public_client) do
|
101
|
+
FactoryBot.create(
|
102
|
+
:application,
|
103
|
+
confidential: false
|
104
|
+
)
|
105
|
+
end
|
106
|
+
|
107
|
+
let(:token_for_private_client) do
|
108
|
+
FactoryBot.create(
|
109
|
+
:access_token,
|
110
|
+
application: @client,
|
111
|
+
resource_owner_id: 1,
|
112
|
+
use_refresh_token: true
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
116
|
+
let(:token_for_public_client) do
|
117
|
+
FactoryBot.create(
|
118
|
+
:access_token,
|
119
|
+
application: public_client,
|
120
|
+
resource_owner_id: 1,
|
121
|
+
use_refresh_token: true
|
122
|
+
)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'issues a new token without client_secret when refresh token was issued to a public client' do
|
126
|
+
post refresh_token_endpoint_url(
|
127
|
+
client_id: public_client.uid,
|
128
|
+
refresh_token: token_for_public_client.refresh_token
|
129
|
+
)
|
130
|
+
|
131
|
+
new_token = Doorkeeper::AccessToken.last
|
132
|
+
should_have_json 'access_token', new_token.token
|
133
|
+
should_have_json 'refresh_token', new_token.refresh_token
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'returns an error without credentials' do
|
137
|
+
post refresh_token_endpoint_url(refresh_token: token_for_private_client.refresh_token)
|
138
|
+
|
139
|
+
should_not_have_json 'refresh_token'
|
140
|
+
should_have_json 'error', 'invalid_grant'
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'returns an error with wrong credentials' do
|
144
|
+
post refresh_token_endpoint_url(
|
145
|
+
client_id: '1',
|
146
|
+
client_secret: '1',
|
147
|
+
refresh_token: token_for_private_client.refresh_token
|
148
|
+
)
|
149
|
+
|
150
|
+
should_not_have_json 'refresh_token'
|
151
|
+
should_have_json 'error', 'invalid_client'
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
98
155
|
it 'client gets an error for invalid refresh token' do
|
99
156
|
post refresh_token_endpoint_url(client: @client, refresh_token: 'invalid')
|
100
157
|
should_not_have_json 'refresh_token'
|
@@ -10,9 +10,9 @@ describe 'Revoke Token Flow' do
|
|
10
10
|
let(:resource_owner) { User.create!(name: 'John', password: 'sekret') }
|
11
11
|
let(:access_token) do
|
12
12
|
FactoryBot.create(:access_token,
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
application: client_application,
|
14
|
+
resource_owner_id: resource_owner.id,
|
15
|
+
use_refresh_token: true)
|
16
16
|
end
|
17
17
|
|
18
18
|
context 'with authenticated, confidential OAuth 2.0 client/application' do
|
@@ -103,9 +103,9 @@ describe 'Revoke Token Flow' do
|
|
103
103
|
context 'with public OAuth 2.0 client/application' do
|
104
104
|
let(:access_token) do
|
105
105
|
FactoryBot.create(:access_token,
|
106
|
-
|
107
|
-
|
108
|
-
|
106
|
+
application: nil,
|
107
|
+
resource_owner_id: resource_owner.id,
|
108
|
+
use_refresh_token: true)
|
109
109
|
end
|
110
110
|
|
111
111
|
it 'should revoke the access token provided' do
|
@@ -129,9 +129,9 @@ describe 'Revoke Token Flow' do
|
|
129
129
|
context 'with a valid token issued for a confidential client' do
|
130
130
|
let(:access_token) do
|
131
131
|
FactoryBot.create(:access_token,
|
132
|
-
|
133
|
-
|
134
|
-
|
132
|
+
application: client_application,
|
133
|
+
resource_owner_id: resource_owner.id,
|
134
|
+
use_refresh_token: true)
|
135
135
|
end
|
136
136
|
|
137
137
|
it 'should not revoke the access token provided' do
|
@@ -41,10 +41,10 @@ feature 'Private API' do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
scenario 'access token with no default scopes' do
|
44
|
-
Doorkeeper.configuration.instance_eval
|
44
|
+
Doorkeeper.configuration.instance_eval do
|
45
45
|
@default_scopes = Doorkeeper::OAuth::Scopes.from_array([:public])
|
46
46
|
@scopes = default_scopes + optional_scopes
|
47
|
-
|
47
|
+
end
|
48
48
|
@token.update_attribute :scopes, 'dummy'
|
49
49
|
with_access_token_header @token.token
|
50
50
|
visit '/full_protected_resources'
|
@@ -4,7 +4,8 @@ module Doorkeeper
|
|
4
4
|
# Doorkeeper configuration, etc.
|
5
5
|
def self.print_configuration_info
|
6
6
|
puts <<-INFO.strip_heredoc
|
7
|
-
====> Doorkeeper ORM
|
7
|
+
====> Doorkeeper ORM: '#{Doorkeeper.configuration.orm}'
|
8
|
+
====> Doorkeeper version: #{Doorkeeper.gem_version}
|
8
9
|
====> Rails version: #{::Rails.version}
|
9
10
|
====> Ruby version: #{RUBY_VERSION} on #{RUBY_PLATFORM}
|
10
11
|
INFO
|
@@ -11,11 +11,15 @@ module ModelHelper
|
|
11
11
|
@authorization = FactoryBot.create(:access_grant, options)
|
12
12
|
end
|
13
13
|
|
14
|
+
def access_token_exists(options = {})
|
15
|
+
@access_token = FactoryBot.create(:access_token, options)
|
16
|
+
end
|
17
|
+
|
14
18
|
def access_grant_should_exist_for(client, resource_owner)
|
15
19
|
grant = Doorkeeper::AccessGrant.first
|
16
20
|
|
17
|
-
expect(grant.application).to have_attributes(id: client.id)
|
18
|
-
and(be_instance_of(Doorkeeper::Application))
|
21
|
+
expect(grant.application).to have_attributes(id: client.id)
|
22
|
+
.and(be_instance_of(Doorkeeper::Application))
|
19
23
|
|
20
24
|
expect(grant.resource_owner_id).to eq(resource_owner.id)
|
21
25
|
end
|
@@ -23,8 +27,8 @@ module ModelHelper
|
|
23
27
|
def access_token_should_exist_for(client, resource_owner)
|
24
28
|
token = Doorkeeper::AccessToken.first
|
25
29
|
|
26
|
-
expect(token.application).to have_attributes(id: client.id)
|
27
|
-
and(be_instance_of(Doorkeeper::Application))
|
30
|
+
expect(token.application).to have_attributes(id: client.id)
|
31
|
+
.and(be_instance_of(Doorkeeper::Application))
|
28
32
|
|
29
33
|
expect(token.resource_owner_id).to eq(resource_owner.id)
|
30
34
|
end
|
@@ -2,9 +2,9 @@ module UrlHelper
|
|
2
2
|
def token_endpoint_url(options = {})
|
3
3
|
parameters = {
|
4
4
|
code: options[:code],
|
5
|
-
client_id: options[:client_id] ||
|
6
|
-
client_secret: options[:client_secret] ||
|
7
|
-
redirect_uri: options[:redirect_uri]
|
5
|
+
client_id: options[:client_id] || options[:client].try(:uid),
|
6
|
+
client_secret: options[:client_secret] || options[:client].try(:secret),
|
7
|
+
redirect_uri: options[:redirect_uri] || options[:client].try(:redirect_uri),
|
8
8
|
grant_type: options[:grant_type] || 'authorization_code',
|
9
9
|
code_verifier: options[:code_verifier],
|
10
10
|
code_challenge_method: options[:code_challenge_method]
|
@@ -15,10 +15,10 @@ module UrlHelper
|
|
15
15
|
def password_token_endpoint_url(options = {})
|
16
16
|
parameters = {
|
17
17
|
code: options[:code],
|
18
|
-
client_id: options[:client_id] ||
|
19
|
-
client_secret: options[:client_secret] ||
|
20
|
-
username: options[:resource_owner_username] ||
|
21
|
-
password: options[:resource_owner_password] ||
|
18
|
+
client_id: options[:client_id] || options[:client].try(:uid),
|
19
|
+
client_secret: options[:client_secret] || options[:client].try(:secret),
|
20
|
+
username: options[:resource_owner_username] || options[:resource_owner].try(:name),
|
21
|
+
password: options[:resource_owner_password] || options[:resource_owner].try(:password),
|
22
22
|
scope: options[:scope],
|
23
23
|
grant_type: 'password'
|
24
24
|
}
|
@@ -27,8 +27,8 @@ module UrlHelper
|
|
27
27
|
|
28
28
|
def authorization_endpoint_url(options = {})
|
29
29
|
parameters = {
|
30
|
-
client_id: options[:client_id] || options[:client].uid,
|
31
|
-
redirect_uri: options[:redirect_uri] || options[:client].redirect_uri,
|
30
|
+
client_id: options[:client_id] || options[:client].try(:uid),
|
31
|
+
redirect_uri: options[:redirect_uri] || options[:client].try(:redirect_uri),
|
32
32
|
response_type: options[:response_type] || 'code',
|
33
33
|
scope: options[:scope],
|
34
34
|
state: options[:state],
|
@@ -41,8 +41,8 @@ module UrlHelper
|
|
41
41
|
def refresh_token_endpoint_url(options = {})
|
42
42
|
parameters = {
|
43
43
|
refresh_token: options[:refresh_token],
|
44
|
-
client_id: options[:client_id] || options[:client].uid,
|
45
|
-
client_secret: options[:client_secret] || options[:client].secret,
|
44
|
+
client_id: options[:client_id] || options[:client].try(:uid),
|
45
|
+
client_secret: options[:client_secret] || options[:client].try(:secret),
|
46
46
|
grant_type: options[:grant_type] || 'refresh_token'
|
47
47
|
}
|
48
48
|
"/oauth/token?#{build_query(parameters)}"
|