doorkeeper 5.1.0.rc1 → 5.1.0.rc2
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 +11 -2
- data/Appraisals +29 -3
- data/Gemfile +13 -5
- data/NEWS.md +52 -15
- data/README.md +68 -487
- data/app/controllers/doorkeeper/token_info_controller.rb +1 -1
- data/app/controllers/doorkeeper/tokens_controller.rb +1 -1
- data/doorkeeper.gemspec +3 -2
- data/gemfiles/rails_4_2.gemfile +8 -5
- data/gemfiles/rails_5_0.gemfile +9 -6
- data/gemfiles/rails_5_1.gemfile +9 -6
- data/gemfiles/rails_5_2.gemfile +9 -6
- data/gemfiles/rails_6_0.gemfile +16 -0
- data/gemfiles/rails_master.gemfile +8 -10
- data/lib/doorkeeper.rb +7 -1
- data/lib/doorkeeper/config.rb +110 -24
- data/lib/doorkeeper/models/access_grant_mixin.rb +15 -7
- data/lib/doorkeeper/models/access_token_mixin.rb +29 -16
- data/lib/doorkeeper/models/application_mixin.rb +18 -28
- data/lib/doorkeeper/models/concerns/expirable.rb +3 -2
- data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
- data/lib/doorkeeper/models/concerns/scopes.rb +4 -0
- data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
- data/lib/doorkeeper/oauth/authorization/token.rb +3 -1
- data/lib/doorkeeper/oauth/error_response.rb +5 -1
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +12 -1
- data/lib/doorkeeper/oauth/invalid_token_response.rb +4 -0
- data/lib/doorkeeper/oauth/token_introspection.rb +72 -6
- data/lib/doorkeeper/orm/active_record/access_grant.rb +9 -8
- data/lib/doorkeeper/orm/active_record/application.rb +10 -6
- data/lib/doorkeeper/secret_storing/base.rb +63 -0
- data/lib/doorkeeper/secret_storing/bcrypt.rb +59 -0
- data/lib/doorkeeper/secret_storing/plain.rb +33 -0
- data/lib/doorkeeper/secret_storing/sha256_hash.rb +25 -0
- data/lib/doorkeeper/version.rb +1 -1
- data/lib/generators/doorkeeper/templates/initializer.rb +62 -20
- data/spec/controllers/authorizations_controller_spec.rb +3 -3
- data/spec/controllers/token_info_controller_spec.rb +1 -1
- data/spec/controllers/tokens_controller_spec.rb +78 -30
- data/spec/dummy/config/application.rb +12 -1
- data/spec/lib/config_spec.rb +119 -35
- data/spec/lib/models/expirable_spec.rb +12 -0
- data/spec/lib/models/reusable_spec.rb +40 -0
- data/spec/lib/models/scopes_spec.rb +13 -1
- data/spec/lib/models/secret_storable_spec.rb +113 -0
- data/spec/lib/oauth/authorization_code_request_spec.rb +18 -1
- data/spec/lib/oauth/client_credentials/creator_spec.rb +51 -7
- data/spec/lib/oauth/error_response_spec.rb +7 -1
- data/spec/lib/oauth/password_access_token_request_spec.rb +11 -1
- data/spec/lib/oauth/token_request_spec.rb +16 -1
- data/spec/lib/secret_storing/base_spec.rb +60 -0
- data/spec/lib/secret_storing/bcrypt_spec.rb +49 -0
- data/spec/lib/secret_storing/plain_spec.rb +44 -0
- data/spec/lib/secret_storing/sha256_hash_spec.rb +48 -0
- data/spec/models/doorkeeper/application_spec.rb +23 -4
- data/spec/requests/flows/authorization_code_spec.rb +3 -3
- data/spec/requests/flows/client_credentials_spec.rb +2 -2
- data/spec/requests/flows/implicit_grant_spec.rb +1 -1
- data/spec/requests/flows/password_spec.rb +3 -3
- data/spec/routing/custom_controller_routes_spec.rb +4 -0
- data/spec/support/shared/hashing_shared_context.rb +12 -5
- metadata +51 -21
- data/lib/doorkeeper/models/concerns/hashable.rb +0 -137
- data/spec/lib/models/hashable_spec.rb +0 -183
@@ -15,15 +15,59 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
|
|
15
15
|
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
16
16
|
end
|
17
17
|
|
18
|
-
context
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
context 'when reuse_access_token is true' do
|
19
|
+
context 'when expiration is disabled' do
|
20
|
+
it 'returns the existing valid token' do
|
21
|
+
allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
|
22
|
+
existing_token = subject.call(client, scopes)
|
22
23
|
|
23
|
-
|
24
|
+
result = subject.call(client, scopes)
|
25
|
+
|
26
|
+
expect(Doorkeeper::AccessToken.count).to eq(1)
|
27
|
+
expect(result).to eq(existing_token)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when existing token has not crossed token_reuse_limit' do
|
32
|
+
it 'returns the existing valid token' do
|
33
|
+
allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
|
34
|
+
allow(Doorkeeper.configuration).to receive(:token_reuse_limit).and_return(50)
|
35
|
+
existing_token = subject.call(client, scopes, expires_in: 1000)
|
36
|
+
|
37
|
+
allow_any_instance_of(Doorkeeper::AccessToken).to receive(:expires_in_seconds).and_return(600)
|
38
|
+
result = subject.call(client, scopes, expires_in: 1000)
|
39
|
+
|
40
|
+
expect(Doorkeeper::AccessToken.count).to eq(1)
|
41
|
+
expect(result).to eq(existing_token)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when existing token has crossed token_reuse_limit' do
|
46
|
+
it "returns a new token" do
|
47
|
+
allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
|
48
|
+
allow(Doorkeeper.configuration).to receive(:token_reuse_limit).and_return(50)
|
49
|
+
existing_token = subject.call(client, scopes, expires_in: 1000)
|
50
|
+
|
51
|
+
allow_any_instance_of(Doorkeeper::AccessToken).to receive(:expires_in_seconds).and_return(400)
|
52
|
+
result = subject.call(client, scopes, expires_in: 1000)
|
53
|
+
|
54
|
+
expect(Doorkeeper::AccessToken.count).to eq(2)
|
55
|
+
expect(result).not_to eq(existing_token)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when existing token has been expired' do
|
60
|
+
it "returns a new token" do
|
61
|
+
allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
|
62
|
+
allow(Doorkeeper.configuration).to receive(:token_reuse_limit).and_return(50)
|
63
|
+
existing_token = subject.call(client, scopes, expires_in: 1000)
|
64
|
+
|
65
|
+
allow_any_instance_of(Doorkeeper::AccessToken).to receive(:expired?).and_return(true)
|
66
|
+
result = subject.call(client, scopes, expires_in: 1000)
|
24
67
|
|
25
|
-
|
26
|
-
|
68
|
+
expect(Doorkeeper::AccessToken.count).to eq(2)
|
69
|
+
expect(result).not_to eq(existing_token)
|
70
|
+
end
|
27
71
|
end
|
28
72
|
end
|
29
73
|
|
@@ -3,7 +3,13 @@ require 'spec_helper'
|
|
3
3
|
module Doorkeeper::OAuth
|
4
4
|
describe ErrorResponse do
|
5
5
|
describe '#status' do
|
6
|
-
it 'should have a status of
|
6
|
+
it 'should have a status of bad_request' do
|
7
|
+
expect(subject.status).to eq(:bad_request)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should have a status of unauthorized for an invalid_client error' do
|
11
|
+
subject = described_class.new(name: :invalid_client)
|
12
|
+
|
7
13
|
expect(subject.status).to eq(:unauthorized)
|
8
14
|
end
|
9
15
|
end
|
@@ -64,7 +64,7 @@ module Doorkeeper::OAuth
|
|
64
64
|
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
65
65
|
end
|
66
66
|
|
67
|
-
it 'skips token creation if there is already one' do
|
67
|
+
it 'skips token creation if there is already one reusable' do
|
68
68
|
allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
|
69
69
|
FactoryBot.create(:access_token, application_id: client.id, resource_owner_id: owner.id)
|
70
70
|
|
@@ -73,6 +73,16 @@ module Doorkeeper::OAuth
|
|
73
73
|
end.not_to(change { Doorkeeper::AccessToken.count })
|
74
74
|
end
|
75
75
|
|
76
|
+
it 'creates token when there is already one but non reusable' do
|
77
|
+
allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
|
78
|
+
FactoryBot.create(:access_token, application_id: client.id, resource_owner_id: owner.id)
|
79
|
+
allow_any_instance_of(Doorkeeper::AccessToken).to receive(:reusable?).and_return(false)
|
80
|
+
|
81
|
+
expect do
|
82
|
+
subject.authorize
|
83
|
+
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
84
|
+
end
|
85
|
+
|
76
86
|
it "calls configured request callback methods" do
|
77
87
|
expect(Doorkeeper.configuration.before_successful_strategy_response)
|
78
88
|
.to receive(:call).with(subject).once
|
@@ -80,7 +80,7 @@ module Doorkeeper::OAuth
|
|
80
80
|
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
81
81
|
end
|
82
82
|
|
83
|
-
it 'skips token creation if there is a matching one' do
|
83
|
+
it 'skips token creation if there is a matching one reusable' do
|
84
84
|
allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
|
85
85
|
allow(application.scopes).to receive(:has_scopes?).and_return(true)
|
86
86
|
allow(application.scopes).to receive(:all?).and_return(true)
|
@@ -90,6 +90,21 @@ module Doorkeeper::OAuth
|
|
90
90
|
|
91
91
|
expect { subject.authorize }.not_to(change { Doorkeeper::AccessToken.count })
|
92
92
|
end
|
93
|
+
|
94
|
+
it 'creates new token if there is a matching one but non reusable' do
|
95
|
+
allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
|
96
|
+
allow(application.scopes).to receive(:has_scopes?).and_return(true)
|
97
|
+
allow(application.scopes).to receive(:all?).and_return(true)
|
98
|
+
|
99
|
+
FactoryBot.create(:access_token, application_id: pre_auth.client.id,
|
100
|
+
resource_owner_id: owner.id, scopes: 'public')
|
101
|
+
|
102
|
+
allow_any_instance_of(Doorkeeper::AccessToken).to receive(:reusable?).and_return(false)
|
103
|
+
|
104
|
+
expect do
|
105
|
+
subject.authorize
|
106
|
+
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
107
|
+
end
|
93
108
|
end
|
94
109
|
end
|
95
110
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ::Doorkeeper::SecretStoring::Base do
|
6
|
+
let(:instance) { double('instance', token: 'foo') }
|
7
|
+
subject { described_class }
|
8
|
+
|
9
|
+
describe '#transform_secret' do
|
10
|
+
it 'raises' do
|
11
|
+
expect { subject.transform_secret('foo') }.to raise_error(NotImplementedError)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#store_secret' do
|
16
|
+
it 'sends to response of #transform_secret to the instance' do
|
17
|
+
expect(described_class)
|
18
|
+
.to receive(:transform_secret).with('bar')
|
19
|
+
.and_return 'bar+transform'
|
20
|
+
|
21
|
+
expect(instance).to receive(:token=).with 'bar+transform'
|
22
|
+
result = subject.store_secret instance, :token, 'bar'
|
23
|
+
expect(result).to eq 'bar+transform'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#restore_secret' do
|
28
|
+
it 'raises' do
|
29
|
+
expect { subject.restore_secret(subject, :token) }.to raise_error(NotImplementedError)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#allows_restoring_secrets?' do
|
34
|
+
it 'does not allow it' do
|
35
|
+
expect(subject.allows_restoring_secrets?).to eq false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'validate_for' do
|
40
|
+
it 'allows for valid model' do
|
41
|
+
expect(subject.validate_for(:application)).to eq true
|
42
|
+
expect(subject.validate_for(:token)).to eq true
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'raises for invalid model' do
|
46
|
+
expect { subject.validate_for(:wat) }.to raise_error(ArgumentError, /can not be used for wat/)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'secret_matches?' do
|
51
|
+
before do
|
52
|
+
allow(subject).to receive(:transform_secret) { |input| "transformed: #{input}" }
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'compares input with #transform_secret' do
|
56
|
+
expect(subject.secret_matches?('input', 'input')).to eq false
|
57
|
+
expect(subject.secret_matches?('a', 'transformed: a')).to eq true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'bcrypt'
|
5
|
+
|
6
|
+
describe ::Doorkeeper::SecretStoring::BCrypt do
|
7
|
+
subject { described_class }
|
8
|
+
let(:instance) { double('instance', token: 'foo') }
|
9
|
+
|
10
|
+
describe '#transform_secret' do
|
11
|
+
it 'creates a bcrypt password' do
|
12
|
+
expect(subject.transform_secret('foo')).to be_a BCrypt::Password
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#restore_secret' do
|
17
|
+
it 'raises' do
|
18
|
+
expect { subject.restore_secret(instance, :token) }.to raise_error(NotImplementedError)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#allows_restoring_secrets?' do
|
23
|
+
it 'does not allow it' do
|
24
|
+
expect(subject.allows_restoring_secrets?).to eq false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'validate_for' do
|
29
|
+
it 'allows for valid model' do
|
30
|
+
expect(subject.validate_for(:application)).to eq true
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'raises for invalid model' do
|
34
|
+
expect { subject.validate_for(:wat) }
|
35
|
+
.to raise_error(ArgumentError, /can only be used for storing application secrets/)
|
36
|
+
expect { subject.validate_for(:token) }
|
37
|
+
.to raise_error(ArgumentError, /can only be used for storing application secrets/)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'secret_matches?' do
|
42
|
+
it 'compares input with #transform_secret' do
|
43
|
+
expect(subject.secret_matches?('input', 'input')).to eq false
|
44
|
+
|
45
|
+
password = BCrypt::Password.create 'foobar'
|
46
|
+
expect(subject.secret_matches?('foobar', password.to_s)).to eq true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ::Doorkeeper::SecretStoring::Plain do
|
6
|
+
subject { described_class }
|
7
|
+
let(:instance) { double('instance', token: 'foo') }
|
8
|
+
|
9
|
+
describe '#transform_secret' do
|
10
|
+
it 'raises' do
|
11
|
+
expect(subject.transform_secret('foo')).to eq 'foo'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#restore_secret' do
|
16
|
+
it 'raises' do
|
17
|
+
expect(subject.restore_secret(instance, :token)).to eq 'foo'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#allows_restoring_secrets?' do
|
22
|
+
it 'does allow it' do
|
23
|
+
expect(subject.allows_restoring_secrets?).to eq true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'validate_for' do
|
28
|
+
it 'allows for valid model' do
|
29
|
+
expect(subject.validate_for(:application)).to eq true
|
30
|
+
expect(subject.validate_for(:token)).to eq true
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'raises for invalid model' do
|
34
|
+
expect { subject.validate_for(:wat) }.to raise_error(ArgumentError, /can not be used for wat/)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'secret_matches?' do
|
39
|
+
it 'compares input with #transform_secret' do
|
40
|
+
expect(subject.secret_matches?('input', 'input')).to eq true
|
41
|
+
expect(subject.secret_matches?('a', 'b')).to eq false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ::Doorkeeper::SecretStoring::Sha256Hash do
|
6
|
+
subject { described_class }
|
7
|
+
let(:instance) { double('instance') }
|
8
|
+
|
9
|
+
let(:hash_function) do
|
10
|
+
->(input) { ::Digest::SHA256.hexdigest(input) }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#transform_secret' do
|
14
|
+
it 'raises' do
|
15
|
+
expect(subject.transform_secret('foo')).to eq hash_function.call('foo')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#restore_secret' do
|
20
|
+
it 'raises' do
|
21
|
+
expect { subject.restore_secret(instance, :token) }.to raise_error(NotImplementedError)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#allows_restoring_secrets?' do
|
26
|
+
it 'does not allow it' do
|
27
|
+
expect(subject.allows_restoring_secrets?).to eq false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'validate_for' do
|
32
|
+
it 'allows for valid model' do
|
33
|
+
expect(subject.validate_for(:application)).to eq true
|
34
|
+
expect(subject.validate_for(:token)).to eq true
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'raises for invalid model' do
|
38
|
+
expect { subject.validate_for(:wat) }.to raise_error(ArgumentError, /can not be used for wat/)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'secret_matches?' do
|
43
|
+
it 'compares input with #transform_secret' do
|
44
|
+
expect(subject.secret_matches?('input', 'input')).to eq false
|
45
|
+
expect(subject.secret_matches?('a', hash_function.call('a'))).to eq true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'bcrypt'
|
2
3
|
|
3
4
|
module Doorkeeper
|
4
5
|
describe Application do
|
@@ -126,11 +127,29 @@ module Doorkeeper
|
|
126
127
|
context 'with hashing enabled' do
|
127
128
|
include_context 'with application hashing enabled'
|
128
129
|
let(:app) { FactoryBot.create :application }
|
130
|
+
let(:default_strategy) { Doorkeeper::SecretStoring::Sha256Hash }
|
129
131
|
|
130
|
-
it '
|
131
|
-
|
132
|
-
|
133
|
-
expect
|
132
|
+
it 'uses SHA256 to avoid additional dependencies' do
|
133
|
+
# Ensure token was generated
|
134
|
+
app.validate
|
135
|
+
expect(app.secret).to eq(default_strategy.transform_secret(app.plaintext_secret))
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'when bcrypt strategy is configured' do
|
139
|
+
# In this text context, we have bcrypt loaded so `bcrypt_present?`
|
140
|
+
# will always be true
|
141
|
+
before do
|
142
|
+
Doorkeeper.configure do
|
143
|
+
hash_application_secrets using: 'Doorkeeper::SecretStoring::BCrypt'
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'holds a volatile plaintext and BCrypt secret' do
|
148
|
+
expect(app.secret_strategy).to eq Doorkeeper::SecretStoring::BCrypt
|
149
|
+
expect(app.plaintext_secret).to be_a(String)
|
150
|
+
expect(app.secret).not_to eq(app.plaintext_secret)
|
151
|
+
expect { ::BCrypt::Password.create(app.secret) }.not_to raise_error
|
152
|
+
end
|
134
153
|
end
|
135
154
|
|
136
155
|
it 'does not fallback to plain lookup by default' do
|
@@ -23,7 +23,7 @@ feature 'Authorization Code Flow' do
|
|
23
23
|
|
24
24
|
context 'with grant hashing enabled' do
|
25
25
|
background do
|
26
|
-
config_is_set(:
|
26
|
+
config_is_set(:token_secret_strategy, ::Doorkeeper::SecretStoring::Sha256Hash)
|
27
27
|
end
|
28
28
|
|
29
29
|
scenario 'Authorization Code Flow with hashing' do
|
@@ -37,7 +37,7 @@ feature 'Authorization Code Flow' do
|
|
37
37
|
code = current_params['code']
|
38
38
|
expect(code).not_to be_nil
|
39
39
|
|
40
|
-
hashed_code = Doorkeeper::AccessGrant.
|
40
|
+
hashed_code = Doorkeeper::AccessGrant.secret_strategy.transform_secret code
|
41
41
|
expect(hashed_code).to eq Doorkeeper::AccessGrant.first.token
|
42
42
|
|
43
43
|
expect(code).not_to eq(hashed_code)
|
@@ -330,7 +330,7 @@ feature 'Authorization Code Flow' do
|
|
330
330
|
|
331
331
|
context 'when application scopes are present and no scope is passed' do
|
332
332
|
background do
|
333
|
-
@client.
|
333
|
+
@client.update(scopes: 'public write read')
|
334
334
|
end
|
335
335
|
|
336
336
|
scenario 'access grant has no scope' do
|
@@ -58,7 +58,7 @@ describe 'Client Credentials Request' do
|
|
58
58
|
should_have_json 'error_description', translated_error_message(:invalid_scope)
|
59
59
|
should_not_have_json 'access_token'
|
60
60
|
|
61
|
-
expect(response.status).to eq(
|
61
|
+
expect(response.status).to eq(400)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
@@ -66,7 +66,7 @@ describe 'Client Credentials Request' do
|
|
66
66
|
|
67
67
|
context 'when application scopes contain some of the default scopes and no scope is passed' do
|
68
68
|
before do
|
69
|
-
client.
|
69
|
+
client.update(scopes: 'read write public')
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'issues new token with one default scope that are present in application scopes' do
|
@@ -20,7 +20,7 @@ feature 'Implicit Grant Flow (feature spec)' do
|
|
20
20
|
|
21
21
|
context 'when application scopes are present and no scope is passed' do
|
22
22
|
background do
|
23
|
-
@client.
|
23
|
+
@client.update(scopes: 'public write read')
|
24
24
|
end
|
25
25
|
|
26
26
|
scenario 'access token has no scopes' do
|
@@ -149,7 +149,7 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
149
149
|
context 'when application scopes are present and differs from configured default scopes and no scope is passed' do
|
150
150
|
before do
|
151
151
|
default_scopes_exist :public
|
152
|
-
@client.
|
152
|
+
@client.update(scopes: 'abc')
|
153
153
|
end
|
154
154
|
|
155
155
|
it 'issues new token without any scope' do
|
@@ -168,7 +168,7 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
168
168
|
|
169
169
|
context 'when application scopes contain some of the default scopes and no scope is passed' do
|
170
170
|
before do
|
171
|
-
@client.
|
171
|
+
@client.update(scopes: 'read write public')
|
172
172
|
end
|
173
173
|
|
174
174
|
it 'issues new token with one default scope that are present in application scopes' do
|
@@ -217,7 +217,7 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
217
217
|
should_have_json 'error_description', translated_error_message(:invalid_scope)
|
218
218
|
should_not_have_json 'access_token'
|
219
219
|
|
220
|
-
expect(response.status).to eq(
|
220
|
+
expect(response.status).to eq(400)
|
221
221
|
end
|
222
222
|
end
|
223
223
|
|