doorkeeper 5.0.2 → 5.1.0.rc1
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.
- checksums.yaml +5 -5
- data/.travis.yml +7 -3
- data/Dangerfile +5 -2
- data/Gemfile +3 -1
- data/NEWS.md +18 -10
- data/README.md +1 -1
- data/app/controllers/doorkeeper/tokens_controller.rb +6 -6
- data/app/views/doorkeeper/applications/show.html.erb +1 -1
- data/app/views/layouts/doorkeeper/admin.html.erb +5 -3
- data/bin/console +15 -0
- data/gemfiles/rails_4_2.gemfile +1 -0
- data/gemfiles/rails_5_0.gemfile +1 -0
- data/gemfiles/rails_5_1.gemfile +1 -0
- data/gemfiles/rails_5_2.gemfile +2 -1
- data/gemfiles/rails_master.gemfile +1 -0
- data/lib/doorkeeper/config.rb +73 -6
- data/lib/doorkeeper/helpers/controller.rb +3 -2
- data/lib/doorkeeper/models/access_grant_mixin.rb +8 -1
- data/lib/doorkeeper/models/access_token_mixin.rb +40 -9
- data/lib/doorkeeper/models/application_mixin.rb +52 -1
- data/lib/doorkeeper/models/concerns/hashable.rb +137 -0
- data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
- data/lib/doorkeeper/oauth/authorization/code.rb +1 -1
- data/lib/doorkeeper/oauth/authorization/token.rb +1 -1
- data/lib/doorkeeper/oauth/authorization_code_request.rb +1 -1
- data/lib/doorkeeper/oauth/client.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -3
- data/lib/doorkeeper/oauth/code_response.rb +2 -2
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -8
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +32 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -2
- data/lib/doorkeeper/oauth/pre_authorization.rb +8 -3
- data/lib/doorkeeper/oauth/refresh_token_request.rb +4 -1
- data/lib/doorkeeper/oauth/token_response.rb +2 -2
- data/lib/doorkeeper/orm/active_record/access_grant.rb +22 -2
- data/lib/doorkeeper/orm/active_record/application.rb +16 -2
- data/lib/doorkeeper/version.rb +3 -3
- data/lib/doorkeeper.rb +1 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +41 -1
- data/spec/controllers/application_metal_controller_spec.rb +18 -4
- data/spec/controllers/tokens_controller_spec.rb +7 -11
- data/spec/dummy/app/controllers/application_controller.rb +1 -1
- data/spec/factories.rb +3 -3
- data/spec/lib/config_spec.rb +84 -0
- data/spec/lib/models/hashable_spec.rb +183 -0
- data/spec/lib/oauth/base_request_spec.rb +7 -7
- data/spec/lib/oauth/client_credentials/validation_spec.rb +3 -0
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +52 -17
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +20 -2
- data/spec/lib/oauth/password_access_token_request_spec.rb +32 -11
- data/spec/lib/oauth/pre_authorization_spec.rb +24 -0
- data/spec/lib/oauth/token_response_spec.rb +13 -13
- data/spec/lib/oauth/token_spec.rb +14 -0
- data/spec/models/doorkeeper/access_grant_spec.rb +61 -0
- data/spec/models/doorkeeper/access_token_spec.rb +123 -0
- data/spec/models/doorkeeper/application_spec.rb +37 -0
- data/spec/requests/flows/authorization_code_spec.rb +40 -0
- data/spec/requests/flows/password_spec.rb +4 -2
- data/spec/requests/flows/revoke_token_spec.rb +14 -30
- data/spec/spec_helper.rb +2 -1
- data/spec/support/ruby_2_6_rails_4_2_patch.rb +14 -0
- data/spec/support/shared/hashing_shared_context.rb +29 -0
- metadata +13 -6
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
describe Doorkeeper::AccessGrant do
|
|
4
|
+
let(:clazz) { Doorkeeper::AccessGrant }
|
|
4
5
|
subject { FactoryBot.build(:access_grant) }
|
|
5
6
|
|
|
6
7
|
it { expect(subject).to be_valid }
|
|
@@ -11,6 +12,66 @@ describe Doorkeeper::AccessGrant do
|
|
|
11
12
|
let(:factory_name) { :access_grant }
|
|
12
13
|
end
|
|
13
14
|
|
|
15
|
+
context 'with hashing enabled' do
|
|
16
|
+
let(:grant) { FactoryBot.create :access_grant }
|
|
17
|
+
include_context 'with token hashing enabled'
|
|
18
|
+
|
|
19
|
+
it 'holds a volatile plaintext token when created' do
|
|
20
|
+
expect(grant.plaintext_token).to be_a(String)
|
|
21
|
+
expect(grant.token)
|
|
22
|
+
.to eq(hashed_or_plain_token_func.call(grant.plaintext_token))
|
|
23
|
+
|
|
24
|
+
# Finder method only finds the hashed token
|
|
25
|
+
loaded = clazz.find_by(token: grant.token)
|
|
26
|
+
expect(loaded).to eq(grant)
|
|
27
|
+
expect(loaded.plaintext_token).to be_nil
|
|
28
|
+
expect(loaded.token).to eq(grant.token)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'does not find_by plain text tokens' do
|
|
32
|
+
expect(clazz.find_by(token: grant.plaintext_token)).to be_nil
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe 'with having a plain text token' do
|
|
36
|
+
let(:plain_text_token) { 'plain text token' }
|
|
37
|
+
|
|
38
|
+
before do
|
|
39
|
+
# Assume we have a plain text token from before activating the option
|
|
40
|
+
grant.update_column(:token, plain_text_token)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context 'without fallback lookup' do
|
|
44
|
+
it 'does not provide lookups with either through by_token' do
|
|
45
|
+
expect(clazz.by_token(plain_text_token)).to eq(nil)
|
|
46
|
+
expect(clazz.by_token(grant.token)).to eq(nil)
|
|
47
|
+
|
|
48
|
+
# And it does not touch the token
|
|
49
|
+
grant.reload
|
|
50
|
+
expect(grant.token).to eq(plain_text_token)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context 'with fallback lookup' do
|
|
55
|
+
include_context 'with token hashing and fallback lookup enabled'
|
|
56
|
+
|
|
57
|
+
it 'upgrades a plain token when falling back to it' do
|
|
58
|
+
# Side-effect: This will automatically upgrade the token
|
|
59
|
+
expect(clazz).to receive(:upgrade_fallback_value).and_call_original
|
|
60
|
+
expect(clazz.by_token(plain_text_token)).to eq(grant)
|
|
61
|
+
|
|
62
|
+
# Will find subsequently by hashing the token
|
|
63
|
+
expect(clazz.by_token(plain_text_token)).to eq(grant)
|
|
64
|
+
|
|
65
|
+
# And it modifies the token value
|
|
66
|
+
grant.reload
|
|
67
|
+
expect(grant.token).not_to eq(plain_text_token)
|
|
68
|
+
expect(clazz.find_by(token: plain_text_token)).to eq(nil)
|
|
69
|
+
expect(clazz.find_by(token: grant.token)).not_to be_nil
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
14
75
|
describe 'validations' do
|
|
15
76
|
it 'is invalid without resource_owner_id' do
|
|
16
77
|
subject.resource_owner_id = nil
|
|
@@ -2,6 +2,7 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
module Doorkeeper
|
|
4
4
|
describe AccessToken do
|
|
5
|
+
let(:clazz) { Doorkeeper::AccessToken }
|
|
5
6
|
subject { FactoryBot.build(:access_token) }
|
|
6
7
|
|
|
7
8
|
it { expect(subject).to be_valid }
|
|
@@ -24,6 +25,67 @@ module Doorkeeper
|
|
|
24
25
|
expect(token.token).to be_a(String)
|
|
25
26
|
end
|
|
26
27
|
|
|
28
|
+
context 'with hashing enabled' do
|
|
29
|
+
let(:token) { FactoryBot.create :access_token }
|
|
30
|
+
include_context 'with token hashing enabled'
|
|
31
|
+
|
|
32
|
+
it 'holds a volatile plaintext token when created' do
|
|
33
|
+
expect(token.plaintext_token).to be_a(String)
|
|
34
|
+
expect(token.token)
|
|
35
|
+
.to eq(hashed_or_plain_token_func.call(token.plaintext_token))
|
|
36
|
+
|
|
37
|
+
# Finder method only finds the hashed token
|
|
38
|
+
loaded = clazz.find_by(token: token.token)
|
|
39
|
+
expect(loaded).to eq(token)
|
|
40
|
+
expect(loaded.plaintext_token).to be_nil
|
|
41
|
+
expect(loaded.token).to eq(token.token)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'does not find_by plain text tokens' do
|
|
45
|
+
expect(clazz.find_by(token: token.plaintext_token)).to be_nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe 'with having a plain text token' do
|
|
49
|
+
let(:plain_text_token) { 'plain text token' }
|
|
50
|
+
let(:access_token) { FactoryBot.create :access_token }
|
|
51
|
+
|
|
52
|
+
before do
|
|
53
|
+
# Assume we have a plain text token from before activating the option
|
|
54
|
+
access_token.update_column(:token, plain_text_token)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context 'without fallback lookup' do
|
|
58
|
+
it 'does not provide lookups with either through by_token' do
|
|
59
|
+
expect(clazz.by_token(plain_text_token)).to eq(nil)
|
|
60
|
+
expect(clazz.by_token(access_token.token)).to eq(nil)
|
|
61
|
+
|
|
62
|
+
# And it does not touch the token
|
|
63
|
+
access_token.reload
|
|
64
|
+
expect(access_token.token).to eq(plain_text_token)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
context 'with fallback lookup' do
|
|
69
|
+
include_context 'with token hashing and fallback lookup enabled'
|
|
70
|
+
|
|
71
|
+
it 'upgrades a plain token when falling back to it' do
|
|
72
|
+
# Side-effect: This will automatically upgrade the token
|
|
73
|
+
expect(clazz).to receive(:upgrade_fallback_value).and_call_original
|
|
74
|
+
expect(clazz.by_token(plain_text_token)).to eq(access_token)
|
|
75
|
+
|
|
76
|
+
# Will find subsequently by hashing the token
|
|
77
|
+
expect(clazz.by_token(plain_text_token)).to eq(access_token)
|
|
78
|
+
|
|
79
|
+
# And it modifies the token value
|
|
80
|
+
access_token.reload
|
|
81
|
+
expect(access_token.token).not_to eq(plain_text_token)
|
|
82
|
+
expect(clazz.find_by(token: plain_text_token)).to eq(nil)
|
|
83
|
+
expect(clazz.find_by(token: access_token.token)).not_to be_nil
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
27
89
|
it 'generates a token using a custom object' do
|
|
28
90
|
eigenclass = class << CustomGeneratorArgs; self; end
|
|
29
91
|
eigenclass.class_eval do
|
|
@@ -196,6 +258,67 @@ module Doorkeeper
|
|
|
196
258
|
token2.save(validate: false)
|
|
197
259
|
end.to raise_error(uniqueness_error)
|
|
198
260
|
end
|
|
261
|
+
|
|
262
|
+
context 'with hashing enabled' do
|
|
263
|
+
include_context 'with token hashing enabled'
|
|
264
|
+
let(:token) { FactoryBot.create :access_token, use_refresh_token: true }
|
|
265
|
+
|
|
266
|
+
it 'holds a volatile refresh token when created' do
|
|
267
|
+
expect(token.plaintext_refresh_token).to be_a(String)
|
|
268
|
+
expect(token.refresh_token)
|
|
269
|
+
.to eq(hashed_or_plain_token_func.call(token.plaintext_refresh_token))
|
|
270
|
+
|
|
271
|
+
# Finder method only finds the hashed token
|
|
272
|
+
loaded = clazz.find_by(refresh_token: token.refresh_token)
|
|
273
|
+
expect(loaded).to eq(token)
|
|
274
|
+
expect(loaded.plaintext_refresh_token).to be_nil
|
|
275
|
+
expect(loaded.refresh_token).to eq(token.refresh_token)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
it 'does not find_by plain text refresh tokens' do
|
|
279
|
+
expect(clazz.find_by(refresh_token: token.plaintext_refresh_token)).to be_nil
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
describe 'with having a plain text token' do
|
|
283
|
+
let(:plain_refresh_token) { 'plain refresh token' }
|
|
284
|
+
let(:access_token) { FactoryBot.create :access_token }
|
|
285
|
+
|
|
286
|
+
before do
|
|
287
|
+
# Assume we have a plain text token from before activating the option
|
|
288
|
+
access_token.update_column(:refresh_token, plain_refresh_token)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
context 'without fallback lookup' do
|
|
292
|
+
it 'does not provide lookups with either through by_token' do
|
|
293
|
+
expect(clazz.by_refresh_token(plain_refresh_token)).to eq(nil)
|
|
294
|
+
expect(clazz.by_refresh_token(access_token.refresh_token)).to eq(nil)
|
|
295
|
+
|
|
296
|
+
# And it does not touch the token
|
|
297
|
+
access_token.reload
|
|
298
|
+
expect(access_token.refresh_token).to eq(plain_refresh_token)
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
context 'with fallback lookup' do
|
|
303
|
+
include_context 'with token hashing and fallback lookup enabled'
|
|
304
|
+
|
|
305
|
+
it 'upgrades a plain token when falling back to it' do
|
|
306
|
+
# Side-effect: This will automatically upgrade the token
|
|
307
|
+
expect(clazz).to receive(:upgrade_fallback_value).and_call_original
|
|
308
|
+
expect(clazz.by_refresh_token(plain_refresh_token)).to eq(access_token)
|
|
309
|
+
|
|
310
|
+
# Will find subsequently by hashing the token
|
|
311
|
+
expect(clazz.by_refresh_token(plain_refresh_token)).to eq(access_token)
|
|
312
|
+
|
|
313
|
+
# And it modifies the token value
|
|
314
|
+
access_token.reload
|
|
315
|
+
expect(access_token.refresh_token).not_to eq(plain_refresh_token)
|
|
316
|
+
expect(clazz.find_by(refresh_token: plain_refresh_token)).to eq(nil)
|
|
317
|
+
expect(clazz.find_by(refresh_token: access_token.refresh_token)).not_to be_nil
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
199
322
|
end
|
|
200
323
|
|
|
201
324
|
describe 'validations' do
|
|
@@ -2,6 +2,7 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
module Doorkeeper
|
|
4
4
|
describe Application do
|
|
5
|
+
let(:clazz) { Doorkeeper::Application }
|
|
5
6
|
let(:require_owner) { Doorkeeper.configuration.instance_variable_set('@confirm_application_owner', true) }
|
|
6
7
|
let(:unset_require_owner) { Doorkeeper.configuration.instance_variable_set('@confirm_application_owner', false) }
|
|
7
8
|
let(:new_application) { FactoryBot.build(:application) }
|
|
@@ -122,6 +123,42 @@ module Doorkeeper
|
|
|
122
123
|
expect(new_application).not_to be_valid
|
|
123
124
|
end
|
|
124
125
|
|
|
126
|
+
context 'with hashing enabled' do
|
|
127
|
+
include_context 'with application hashing enabled'
|
|
128
|
+
let(:app) { FactoryBot.create :application }
|
|
129
|
+
|
|
130
|
+
it 'holds a volatile plaintext and BCrypt secret' do
|
|
131
|
+
expect(app.plaintext_secret).to be_a(String)
|
|
132
|
+
expect(app.secret).not_to eq(app.plaintext_secret)
|
|
133
|
+
expect { BCrypt::Password.create(app.secret) }.not_to raise_error
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it 'does not fallback to plain lookup by default' do
|
|
137
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.secret)
|
|
138
|
+
expect(lookup).to eq(nil)
|
|
139
|
+
|
|
140
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
|
|
141
|
+
expect(lookup).to eq(app)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
context 'with fallback enabled' do
|
|
145
|
+
include_context 'with token hashing and fallback lookup enabled'
|
|
146
|
+
|
|
147
|
+
it 'provides plain and hashed lookup' do
|
|
148
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.secret)
|
|
149
|
+
expect(lookup).to eq(app)
|
|
150
|
+
|
|
151
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
|
|
152
|
+
expect(lookup).to eq(app)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it 'does not provide access to secret after loading' do
|
|
157
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
|
|
158
|
+
expect(lookup.plaintext_secret).to be_nil
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
125
162
|
describe 'destroy related models on cascade' do
|
|
126
163
|
before(:each) do
|
|
127
164
|
new_application.save
|
|
@@ -21,6 +21,33 @@ feature 'Authorization Code Flow' do
|
|
|
21
21
|
url_should_not_have_param('error')
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
context 'with grant hashing enabled' do
|
|
25
|
+
background do
|
|
26
|
+
config_is_set(:hash_token_secrets) { true }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
scenario 'Authorization Code Flow with hashing' do
|
|
30
|
+
@client.redirect_uri = Doorkeeper.configuration.native_redirect_uri
|
|
31
|
+
@client.save!
|
|
32
|
+
visit authorization_endpoint_url(client: @client)
|
|
33
|
+
click_on 'Authorize'
|
|
34
|
+
|
|
35
|
+
access_grant_should_exist_for(@client, @resource_owner)
|
|
36
|
+
|
|
37
|
+
code = current_params['code']
|
|
38
|
+
expect(code).not_to be_nil
|
|
39
|
+
|
|
40
|
+
hashed_code = Doorkeeper::AccessGrant.hashed_or_plain_token code
|
|
41
|
+
expect(hashed_code).to eq Doorkeeper::AccessGrant.first.token
|
|
42
|
+
|
|
43
|
+
expect(code).not_to eq(hashed_code)
|
|
44
|
+
|
|
45
|
+
i_should_see 'Authorization code:'
|
|
46
|
+
i_should_see code
|
|
47
|
+
i_should_not_see hashed_code
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
24
51
|
scenario 'resource owner authorizes using test url' do
|
|
25
52
|
@client.redirect_uri = Doorkeeper.configuration.native_redirect_uri
|
|
26
53
|
@client.save!
|
|
@@ -71,6 +98,19 @@ feature 'Authorization Code Flow' do
|
|
|
71
98
|
should_have_json 'error', 'invalid_client'
|
|
72
99
|
end
|
|
73
100
|
|
|
101
|
+
scenario 'resource owner requests an access token with authorization code but without client id' do
|
|
102
|
+
visit authorization_endpoint_url(client: @client)
|
|
103
|
+
click_on 'Authorize'
|
|
104
|
+
|
|
105
|
+
authorization_code = Doorkeeper::AccessGrant.first.token
|
|
106
|
+
page.driver.post token_endpoint_url(code: authorization_code, client_secret: @client.secret,
|
|
107
|
+
redirect_uri: @client.redirect_uri)
|
|
108
|
+
|
|
109
|
+
expect(Doorkeeper::AccessToken.count).to be_zero
|
|
110
|
+
|
|
111
|
+
should_have_json 'error', 'invalid_client'
|
|
112
|
+
end
|
|
113
|
+
|
|
74
114
|
scenario 'silently authorizes if matching token exists' do
|
|
75
115
|
default_scopes_exist :public, :write
|
|
76
116
|
|
|
@@ -64,7 +64,8 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
|
64
64
|
)
|
|
65
65
|
end.not_to(change { Doorkeeper::AccessToken.count })
|
|
66
66
|
|
|
67
|
-
expect(response).
|
|
67
|
+
expect(response.status).to eq(401)
|
|
68
|
+
should_have_json 'error', 'invalid_client'
|
|
68
69
|
end
|
|
69
70
|
end
|
|
70
71
|
end
|
|
@@ -88,7 +89,8 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
|
88
89
|
post password_token_endpoint_url(client_id: @client.uid, resource_owner: @resource_owner)
|
|
89
90
|
end.not_to(change { Doorkeeper::AccessToken.count })
|
|
90
91
|
|
|
91
|
-
expect(response).
|
|
92
|
+
expect(response.status).to eq(401)
|
|
93
|
+
should_have_json 'error', 'invalid_client'
|
|
92
94
|
end
|
|
93
95
|
end
|
|
94
96
|
end
|
|
@@ -26,30 +26,28 @@ describe 'Revoke Token Flow' do
|
|
|
26
26
|
it 'should revoke the access token provided' do
|
|
27
27
|
post revocation_token_endpoint_url, params: { token: access_token.token }, headers: headers
|
|
28
28
|
|
|
29
|
-
access_token.reload
|
|
30
|
-
|
|
31
29
|
expect(response).to be_successful
|
|
32
|
-
expect(access_token.revoked?).to be_truthy
|
|
30
|
+
expect(access_token.reload.revoked?).to be_truthy
|
|
33
31
|
end
|
|
34
32
|
|
|
35
33
|
it 'should revoke the refresh token provided' do
|
|
36
34
|
post revocation_token_endpoint_url, params: { token: access_token.refresh_token }, headers: headers
|
|
37
35
|
|
|
38
|
-
access_token.reload
|
|
39
|
-
|
|
40
36
|
expect(response).to be_successful
|
|
41
|
-
expect(access_token.revoked?).to be_truthy
|
|
37
|
+
expect(access_token.reload.revoked?).to be_truthy
|
|
42
38
|
end
|
|
43
39
|
|
|
44
40
|
context 'with invalid token to revoke' do
|
|
45
41
|
it 'should not revoke any tokens and respond successfully' do
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
expect do
|
|
43
|
+
post revocation_token_endpoint_url,
|
|
44
|
+
params: { token: 'I_AM_AN_INVALID_TOKEN' },
|
|
45
|
+
headers: headers
|
|
46
|
+
end.not_to(change { Doorkeeper::AccessToken.where(revoked_at: nil).count })
|
|
48
47
|
|
|
49
48
|
# The authorization server responds with HTTP status code 200 even if
|
|
50
49
|
# token is invalid
|
|
51
50
|
expect(response).to be_successful
|
|
52
|
-
expect(Doorkeeper::AccessToken.where(revoked_at: nil).count).to eq(num_prev_revoked_tokens)
|
|
53
51
|
end
|
|
54
52
|
end
|
|
55
53
|
|
|
@@ -62,10 +60,8 @@ describe 'Revoke Token Flow' do
|
|
|
62
60
|
it 'should not revoke any tokens and respond successfully' do
|
|
63
61
|
post revocation_token_endpoint_url, params: { token: access_token.token }, headers: headers
|
|
64
62
|
|
|
65
|
-
access_token.reload
|
|
66
|
-
|
|
67
63
|
expect(response).to be_successful
|
|
68
|
-
expect(access_token.revoked?).to be_falsey
|
|
64
|
+
expect(access_token.reload.revoked?).to be_falsey
|
|
69
65
|
end
|
|
70
66
|
end
|
|
71
67
|
|
|
@@ -73,10 +69,8 @@ describe 'Revoke Token Flow' do
|
|
|
73
69
|
it 'should not revoke any tokens and respond successfully' do
|
|
74
70
|
post revocation_token_endpoint_url, params: { token: access_token.token }
|
|
75
71
|
|
|
76
|
-
access_token.reload
|
|
77
|
-
|
|
78
72
|
expect(response).to be_successful
|
|
79
|
-
expect(access_token.revoked?).to be_falsey
|
|
73
|
+
expect(access_token.reload.revoked?).to be_falsey
|
|
80
74
|
end
|
|
81
75
|
end
|
|
82
76
|
|
|
@@ -92,10 +86,8 @@ describe 'Revoke Token Flow' do
|
|
|
92
86
|
it 'should not revoke the token as its unauthorized' do
|
|
93
87
|
post revocation_token_endpoint_url, params: { token: access_token.token }, headers: headers
|
|
94
88
|
|
|
95
|
-
access_token.reload
|
|
96
|
-
|
|
97
89
|
expect(response).to be_successful
|
|
98
|
-
expect(access_token.revoked?).to be_falsey
|
|
90
|
+
expect(access_token.reload.revoked?).to be_falsey
|
|
99
91
|
end
|
|
100
92
|
end
|
|
101
93
|
end
|
|
@@ -111,19 +103,15 @@ describe 'Revoke Token Flow' do
|
|
|
111
103
|
it 'should revoke the access token provided' do
|
|
112
104
|
post revocation_token_endpoint_url, params: { token: access_token.token }
|
|
113
105
|
|
|
114
|
-
access_token.reload
|
|
115
|
-
|
|
116
106
|
expect(response).to be_successful
|
|
117
|
-
expect(access_token.revoked?).to be_truthy
|
|
107
|
+
expect(access_token.reload.revoked?).to be_truthy
|
|
118
108
|
end
|
|
119
109
|
|
|
120
110
|
it 'should revoke the refresh token provided' do
|
|
121
111
|
post revocation_token_endpoint_url, params: { token: access_token.refresh_token }
|
|
122
112
|
|
|
123
|
-
access_token.reload
|
|
124
|
-
|
|
125
113
|
expect(response).to be_successful
|
|
126
|
-
expect(access_token.revoked?).to be_truthy
|
|
114
|
+
expect(access_token.reload.revoked?).to be_truthy
|
|
127
115
|
end
|
|
128
116
|
|
|
129
117
|
context 'with a valid token issued for a confidential client' do
|
|
@@ -137,19 +125,15 @@ describe 'Revoke Token Flow' do
|
|
|
137
125
|
it 'should not revoke the access token provided' do
|
|
138
126
|
post revocation_token_endpoint_url, params: { token: access_token.token }
|
|
139
127
|
|
|
140
|
-
access_token.reload
|
|
141
|
-
|
|
142
128
|
expect(response).to be_successful
|
|
143
|
-
expect(access_token.revoked?).to be_falsey
|
|
129
|
+
expect(access_token.reload.revoked?).to be_falsey
|
|
144
130
|
end
|
|
145
131
|
|
|
146
132
|
it 'should not revoke the refresh token provided' do
|
|
147
133
|
post revocation_token_endpoint_url, params: { token: access_token.token }
|
|
148
134
|
|
|
149
|
-
access_token.reload
|
|
150
|
-
|
|
151
135
|
expect(response).to be_successful
|
|
152
|
-
expect(access_token.revoked?).to be_falsey
|
|
136
|
+
expect(access_token.reload.revoked?).to be_falsey
|
|
153
137
|
end
|
|
154
138
|
end
|
|
155
139
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -28,7 +28,8 @@ end
|
|
|
28
28
|
Doorkeeper::RSpec.print_configuration_info
|
|
29
29
|
|
|
30
30
|
# Remove after dropping support of Rails 4.2
|
|
31
|
-
require "#{File.dirname(__FILE__)}/support/http_method_shim
|
|
31
|
+
require "#{File.dirname(__FILE__)}/support/http_method_shim"
|
|
32
|
+
require "#{File.dirname(__FILE__)}/support/ruby_2_6_rails_4_2_patch"
|
|
32
33
|
|
|
33
34
|
require "support/orm/#{DOORKEEPER_ORM}"
|
|
34
35
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
if RUBY_VERSION >= '2.6.0'
|
|
2
|
+
if Rails::VERSION::MAJOR < 5
|
|
3
|
+
class ActionController::TestResponse < ActionDispatch::TestResponse
|
|
4
|
+
def recycle!
|
|
5
|
+
# hack to avoid MonitorMixin double-initialize error:
|
|
6
|
+
@mon_mutex_owner_object_id = nil
|
|
7
|
+
@mon_mutex = nil
|
|
8
|
+
initialize
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
else
|
|
12
|
+
puts "Monkeypatch for ActionController::TestResponse no longer needed"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
shared_context 'with token hashing enabled' do
|
|
4
|
+
let(:hashed_or_plain_token_func) { Doorkeeper::AccessToken.method(:hashed_or_plain_token) }
|
|
5
|
+
before do
|
|
6
|
+
Doorkeeper.configure do
|
|
7
|
+
hash_token_secrets
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
shared_context 'with token hashing and fallback lookup enabled' do
|
|
13
|
+
let(:hashed_or_plain_token_func) { Doorkeeper::AccessToken.method(:hashed_or_plain_token) }
|
|
14
|
+
before do
|
|
15
|
+
Doorkeeper.configure do
|
|
16
|
+
hash_token_secrets
|
|
17
|
+
fallback_to_plain_secrets
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
shared_context 'with application hashing enabled' do
|
|
23
|
+
let(:hashed_or_plain_token_func) { Doorkeeper::Application.method(:hashed_or_plain_token) }
|
|
24
|
+
before do
|
|
25
|
+
Doorkeeper.configure do
|
|
26
|
+
hash_application_secrets
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: doorkeeper
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.0.
|
|
4
|
+
version: 5.1.0.rc1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Felipe Elias Philipp
|
|
@@ -11,7 +11,7 @@ authors:
|
|
|
11
11
|
autorequire:
|
|
12
12
|
bindir: bin
|
|
13
13
|
cert_chain: []
|
|
14
|
-
date:
|
|
14
|
+
date: 2019-01-17 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
|
16
16
|
- !ruby/object:Gem::Dependency
|
|
17
17
|
name: railties
|
|
@@ -205,6 +205,7 @@ files:
|
|
|
205
205
|
- app/views/doorkeeper/authorized_applications/index.html.erb
|
|
206
206
|
- app/views/layouts/doorkeeper/admin.html.erb
|
|
207
207
|
- app/views/layouts/doorkeeper/application.html.erb
|
|
208
|
+
- bin/console
|
|
208
209
|
- config/locales/en.yml
|
|
209
210
|
- doorkeeper.gemspec
|
|
210
211
|
- gemfiles/rails_4_2.gemfile
|
|
@@ -224,6 +225,7 @@ files:
|
|
|
224
225
|
- lib/doorkeeper/models/application_mixin.rb
|
|
225
226
|
- lib/doorkeeper/models/concerns/accessible.rb
|
|
226
227
|
- lib/doorkeeper/models/concerns/expirable.rb
|
|
228
|
+
- lib/doorkeeper/models/concerns/hashable.rb
|
|
227
229
|
- lib/doorkeeper/models/concerns/orderable.rb
|
|
228
230
|
- lib/doorkeeper/models/concerns/ownership.rb
|
|
229
231
|
- lib/doorkeeper/models/concerns/revocable.rb
|
|
@@ -358,6 +360,7 @@ files:
|
|
|
358
360
|
- spec/lib/config_spec.rb
|
|
359
361
|
- spec/lib/doorkeeper_spec.rb
|
|
360
362
|
- spec/lib/models/expirable_spec.rb
|
|
363
|
+
- spec/lib/models/hashable_spec.rb
|
|
361
364
|
- spec/lib/models/revocable_spec.rb
|
|
362
365
|
- spec/lib/models/scopes_spec.rb
|
|
363
366
|
- spec/lib/oauth/authorization/uri_builder_spec.rb
|
|
@@ -423,7 +426,9 @@ files:
|
|
|
423
426
|
- spec/support/helpers/url_helper.rb
|
|
424
427
|
- spec/support/http_method_shim.rb
|
|
425
428
|
- spec/support/orm/active_record.rb
|
|
429
|
+
- spec/support/ruby_2_6_rails_4_2_patch.rb
|
|
426
430
|
- spec/support/shared/controllers_shared_context.rb
|
|
431
|
+
- spec/support/shared/hashing_shared_context.rb
|
|
427
432
|
- spec/support/shared/models_shared_examples.rb
|
|
428
433
|
- spec/validators/redirect_uri_validator_spec.rb
|
|
429
434
|
- spec/version/version_spec.rb
|
|
@@ -443,12 +448,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
443
448
|
version: '2.1'
|
|
444
449
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
445
450
|
requirements:
|
|
446
|
-
- - "
|
|
451
|
+
- - ">"
|
|
447
452
|
- !ruby/object:Gem::Version
|
|
448
|
-
version:
|
|
453
|
+
version: 1.3.1
|
|
449
454
|
requirements: []
|
|
450
|
-
|
|
451
|
-
rubygems_version: 2.6.11
|
|
455
|
+
rubygems_version: 3.0.2
|
|
452
456
|
signing_key:
|
|
453
457
|
specification_version: 4
|
|
454
458
|
summary: OAuth 2 provider for Rails and Grape
|
|
@@ -514,6 +518,7 @@ test_files:
|
|
|
514
518
|
- spec/lib/config_spec.rb
|
|
515
519
|
- spec/lib/doorkeeper_spec.rb
|
|
516
520
|
- spec/lib/models/expirable_spec.rb
|
|
521
|
+
- spec/lib/models/hashable_spec.rb
|
|
517
522
|
- spec/lib/models/revocable_spec.rb
|
|
518
523
|
- spec/lib/models/scopes_spec.rb
|
|
519
524
|
- spec/lib/oauth/authorization/uri_builder_spec.rb
|
|
@@ -579,7 +584,9 @@ test_files:
|
|
|
579
584
|
- spec/support/helpers/url_helper.rb
|
|
580
585
|
- spec/support/http_method_shim.rb
|
|
581
586
|
- spec/support/orm/active_record.rb
|
|
587
|
+
- spec/support/ruby_2_6_rails_4_2_patch.rb
|
|
582
588
|
- spec/support/shared/controllers_shared_context.rb
|
|
589
|
+
- spec/support/shared/hashing_shared_context.rb
|
|
583
590
|
- spec/support/shared/models_shared_examples.rb
|
|
584
591
|
- spec/validators/redirect_uri_validator_spec.rb
|
|
585
592
|
- spec/version/version_spec.rb
|