doorkeeper 5.3.0 → 5.4.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 +4 -4
- data/Appraisals +0 -14
- data/CHANGELOG.md +44 -1
- data/Dangerfile +7 -7
- data/Dockerfile +2 -2
- data/Gemfile +9 -9
- data/README.md +6 -4
- data/app/controllers/doorkeeper/applications_controller.rb +4 -4
- data/app/controllers/doorkeeper/authorizations_controller.rb +31 -12
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +2 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +57 -20
- data/app/views/doorkeeper/applications/show.html.erb +19 -2
- data/bin/console +14 -0
- data/config/locales/en.yml +3 -1
- data/doorkeeper.gemspec +1 -1
- data/gemfiles/rails_5_0.gemfile +8 -7
- data/gemfiles/rails_5_1.gemfile +8 -7
- data/gemfiles/rails_5_2.gemfile +8 -7
- data/gemfiles/rails_6_0.gemfile +8 -7
- data/gemfiles/rails_master.gemfile +8 -7
- data/lib/doorkeeper/config/abstract_builder.rb +28 -0
- data/lib/doorkeeper/config/option.rb +28 -14
- data/lib/doorkeeper/config.rb +41 -17
- data/lib/doorkeeper/grape/helpers.rb +1 -1
- data/lib/doorkeeper/models/access_grant_mixin.rb +9 -11
- data/lib/doorkeeper/models/access_token_mixin.rb +102 -42
- data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
- data/lib/doorkeeper/models/concerns/revocable.rb +1 -1
- data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
- data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
- data/lib/doorkeeper/oauth/authorization/code.rb +14 -5
- data/lib/doorkeeper/oauth/authorization/context.rb +2 -2
- data/lib/doorkeeper/oauth/authorization/token.rb +7 -11
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
- data/lib/doorkeeper/oauth/authorization_code_request.rb +18 -8
- data/lib/doorkeeper/oauth/base_request.rb +11 -19
- data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
- data/lib/doorkeeper/oauth/client.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +25 -7
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +3 -2
- data/lib/doorkeeper/oauth/client_credentials/validator.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
- data/lib/doorkeeper/oauth/code_request.rb +1 -1
- data/lib/doorkeeper/oauth/code_response.rb +6 -2
- data/lib/doorkeeper/oauth/error_response.rb +2 -4
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -5
- data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
- data/lib/doorkeeper/oauth/invalid_token_response.rb +2 -2
- data/lib/doorkeeper/oauth/password_access_token_request.rb +3 -5
- data/lib/doorkeeper/oauth/pre_authorization.rb +32 -27
- data/lib/doorkeeper/oauth/refresh_token_request.rb +18 -22
- data/lib/doorkeeper/oauth/token.rb +1 -1
- data/lib/doorkeeper/oauth/token_introspection.rb +3 -3
- data/lib/doorkeeper/oauth/token_request.rb +2 -2
- data/lib/doorkeeper/oauth/token_response.rb +1 -1
- data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +7 -2
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +6 -2
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +6 -2
- data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
- data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
- data/lib/doorkeeper/rails/routes/registry.rb +45 -0
- data/lib/doorkeeper/rails/routes.rb +13 -17
- data/lib/doorkeeper/request/strategy.rb +2 -2
- data/lib/doorkeeper/server.rb +3 -3
- data/lib/doorkeeper/version.rb +2 -2
- data/lib/doorkeeper.rb +106 -79
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +1 -1
- data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
- data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +47 -3
- data/lib/generators/doorkeeper/templates/migration.rb.erb +2 -0
- data/spec/controllers/applications_controller_spec.rb +2 -2
- data/spec/controllers/authorizations_controller_spec.rb +165 -30
- data/spec/controllers/tokens_controller_spec.rb +6 -5
- data/spec/dummy/app/helpers/application_helper.rb +1 -1
- data/spec/dummy/app/models/user.rb +5 -1
- data/spec/dummy/config/application.rb +6 -4
- data/spec/dummy/config/boot.rb +4 -4
- data/spec/dummy/config/environment.rb +1 -1
- data/spec/dummy/config/routes.rb +4 -4
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +2 -2
- data/spec/dummy/db/schema.rb +3 -1
- data/spec/factories.rb +1 -1
- data/spec/generators/enable_polymorphic_resource_owner_generator_spec.rb +47 -0
- data/spec/lib/config_spec.rb +30 -11
- data/spec/lib/models/revocable_spec.rb +2 -3
- data/spec/lib/models/scopes_spec.rb +8 -0
- data/spec/lib/oauth/authorization_code_request_spec.rb +25 -15
- data/spec/lib/oauth/base_request_spec.rb +6 -20
- data/spec/lib/oauth/client_credentials/creator_spec.rb +90 -89
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +84 -86
- data/spec/lib/oauth/client_credentials/validation_spec.rb +38 -40
- data/spec/lib/oauth/client_credentials_request_spec.rb +5 -4
- data/spec/lib/oauth/code_request_spec.rb +1 -1
- data/spec/lib/oauth/code_response_spec.rb +5 -1
- data/spec/lib/oauth/error_response_spec.rb +1 -1
- data/spec/lib/oauth/password_access_token_request_spec.rb +24 -13
- data/spec/lib/oauth/pre_authorization_spec.rb +13 -18
- data/spec/lib/oauth/refresh_token_request_spec.rb +19 -30
- data/spec/lib/oauth/token_request_spec.rb +14 -7
- data/spec/lib/option_spec.rb +51 -0
- data/spec/lib/stale_records_cleaner_spec.rb +18 -5
- data/spec/models/doorkeeper/access_grant_spec.rb +18 -4
- data/spec/models/doorkeeper/access_token_spec.rb +507 -479
- data/spec/models/doorkeeper/application_spec.rb +338 -300
- data/spec/requests/endpoints/token_spec.rb +5 -1
- data/spec/requests/flows/authorization_code_errors_spec.rb +4 -1
- data/spec/requests/flows/authorization_code_spec.rb +6 -1
- data/spec/requests/flows/client_credentials_spec.rb +41 -0
- data/spec/requests/flows/refresh_token_spec.rb +16 -8
- data/spec/requests/flows/revoke_token_spec.rb +143 -104
- data/spec/support/helpers/access_token_request_helper.rb +1 -0
- data/spec/support/helpers/authorization_request_helper.rb +4 -4
- data/spec/support/helpers/config_helper.rb +1 -1
- data/spec/support/shared/controllers_shared_context.rb +2 -2
- data/spec/support/shared/models_shared_examples.rb +6 -4
- metadata +15 -4
|
@@ -12,7 +12,12 @@ describe Doorkeeper::OAuth::AuthorizationCodeRequest do
|
|
|
12
12
|
}
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
let(:
|
|
15
|
+
let(:resource_owner) { FactoryBot.create :resource_owner }
|
|
16
|
+
let(:grant) do
|
|
17
|
+
FactoryBot.create :access_grant,
|
|
18
|
+
resource_owner_id: resource_owner.id,
|
|
19
|
+
resource_owner_type: resource_owner.class.name
|
|
20
|
+
end
|
|
16
21
|
let(:client) { grant.application }
|
|
17
22
|
let(:redirect_uri) { client.redirect_uri }
|
|
18
23
|
let(:params) { { redirect_uri: redirect_uri } }
|
|
@@ -49,43 +54,42 @@ describe Doorkeeper::OAuth::AuthorizationCodeRequest do
|
|
|
49
54
|
end
|
|
50
55
|
|
|
51
56
|
it "requires the grant" do
|
|
52
|
-
subject
|
|
57
|
+
subject = described_class.new(server, nil, client, params)
|
|
53
58
|
subject.validate
|
|
54
59
|
expect(subject.error).to eq(:invalid_grant)
|
|
55
60
|
end
|
|
56
61
|
|
|
57
62
|
it "requires the client" do
|
|
58
|
-
subject
|
|
63
|
+
subject = described_class.new(server, grant, nil, params)
|
|
59
64
|
subject.validate
|
|
60
65
|
expect(subject.error).to eq(:invalid_client)
|
|
61
66
|
end
|
|
62
67
|
|
|
63
68
|
it "requires the redirect_uri" do
|
|
64
|
-
subject
|
|
69
|
+
subject = described_class.new(server, grant, nil, params.except(:redirect_uri))
|
|
65
70
|
subject.validate
|
|
66
71
|
expect(subject.error).to eq(:invalid_request)
|
|
67
72
|
expect(subject.missing_param).to eq(:redirect_uri)
|
|
68
73
|
end
|
|
69
74
|
|
|
70
75
|
it "invalid code_verifier param because server does not support pkce" do
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
subject.code_verifier = "a45a9fea-0676-477e-95b1-a40f72ac3cfb"
|
|
76
|
+
allow(Doorkeeper::AccessGrant).to receive(:pkce_supported?).and_return(false)
|
|
77
|
+
code_verifier = "a45a9fea-0676-477e-95b1-a40f72ac3cfb"
|
|
78
|
+
subject = described_class.new(server, grant, client, params.merge(code_verifier: code_verifier))
|
|
76
79
|
subject.validate
|
|
77
80
|
expect(subject.error).to eq(:invalid_request)
|
|
78
81
|
expect(subject.invalid_request_reason).to eq(:not_support_pkce)
|
|
79
82
|
end
|
|
80
83
|
|
|
81
84
|
it "matches the redirect_uri with grant's one" do
|
|
82
|
-
subject.redirect_uri
|
|
85
|
+
subject = described_class.new(server, grant, client, params.merge(redirect_uri: "http://other.com"))
|
|
83
86
|
subject.validate
|
|
84
87
|
expect(subject.error).to eq(:invalid_grant)
|
|
85
88
|
end
|
|
86
89
|
|
|
87
90
|
it "matches the client with grant's one" do
|
|
88
|
-
|
|
91
|
+
other_client = FactoryBot.create :application
|
|
92
|
+
subject = described_class.new(server, grant, other_client, params)
|
|
89
93
|
subject.validate
|
|
90
94
|
expect(subject.error).to eq(:invalid_grant)
|
|
91
95
|
end
|
|
@@ -100,8 +104,11 @@ describe Doorkeeper::OAuth::AuthorizationCodeRequest do
|
|
|
100
104
|
end
|
|
101
105
|
|
|
102
106
|
FactoryBot.create(
|
|
103
|
-
:access_token,
|
|
104
|
-
|
|
107
|
+
:access_token,
|
|
108
|
+
application_id: client.id,
|
|
109
|
+
resource_owner_id: grant.resource_owner_id,
|
|
110
|
+
resource_owner_type: grant.resource_owner_type,
|
|
111
|
+
scopes: grant.scopes.to_s,
|
|
105
112
|
)
|
|
106
113
|
|
|
107
114
|
expect { subject.authorize }.to_not(change { Doorkeeper::AccessToken.count })
|
|
@@ -117,8 +124,11 @@ describe Doorkeeper::OAuth::AuthorizationCodeRequest do
|
|
|
117
124
|
end
|
|
118
125
|
|
|
119
126
|
FactoryBot.create(
|
|
120
|
-
:access_token,
|
|
121
|
-
|
|
127
|
+
:access_token,
|
|
128
|
+
application_id: client.id,
|
|
129
|
+
resource_owner_id: grant.resource_owner_id,
|
|
130
|
+
resource_owner_type: grant.resource_owner_type,
|
|
131
|
+
scopes: grant.scopes.to_s,
|
|
122
132
|
)
|
|
123
133
|
|
|
124
134
|
allow_any_instance_of(Doorkeeper::AccessToken).to receive(:reusable?).and_return(false)
|
|
@@ -117,10 +117,12 @@ describe Doorkeeper::OAuth::BaseRequest do
|
|
|
117
117
|
end
|
|
118
118
|
|
|
119
119
|
describe "#find_or_create_access_token" do
|
|
120
|
+
let(:resource_owner) { FactoryBot.build_stubbed(:resource_owner) }
|
|
121
|
+
|
|
120
122
|
it "returns an instance of AccessToken" do
|
|
121
123
|
result = subject.find_or_create_access_token(
|
|
122
124
|
client,
|
|
123
|
-
|
|
125
|
+
resource_owner,
|
|
124
126
|
"public",
|
|
125
127
|
server,
|
|
126
128
|
)
|
|
@@ -140,7 +142,7 @@ describe Doorkeeper::OAuth::BaseRequest do
|
|
|
140
142
|
|
|
141
143
|
result = subject.find_or_create_access_token(
|
|
142
144
|
client,
|
|
143
|
-
|
|
145
|
+
resource_owner,
|
|
144
146
|
"public",
|
|
145
147
|
server,
|
|
146
148
|
)
|
|
@@ -161,7 +163,7 @@ describe Doorkeeper::OAuth::BaseRequest do
|
|
|
161
163
|
|
|
162
164
|
result = subject.find_or_create_access_token(
|
|
163
165
|
client,
|
|
164
|
-
|
|
166
|
+
resource_owner,
|
|
165
167
|
"public",
|
|
166
168
|
server,
|
|
167
169
|
)
|
|
@@ -169,7 +171,7 @@ describe Doorkeeper::OAuth::BaseRequest do
|
|
|
169
171
|
|
|
170
172
|
result = subject.find_or_create_access_token(
|
|
171
173
|
client,
|
|
172
|
-
|
|
174
|
+
resource_owner,
|
|
173
175
|
"private",
|
|
174
176
|
server,
|
|
175
177
|
)
|
|
@@ -205,20 +207,4 @@ describe Doorkeeper::OAuth::BaseRequest do
|
|
|
205
207
|
end
|
|
206
208
|
end
|
|
207
209
|
end
|
|
208
|
-
|
|
209
|
-
describe "#valid?" do
|
|
210
|
-
context "error is nil" do
|
|
211
|
-
it "returns true" do
|
|
212
|
-
allow(subject).to receive(:error).and_return(nil).once
|
|
213
|
-
expect(subject.valid?).to eq(true)
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
context "error is not nil" do
|
|
218
|
-
it "returns false" do
|
|
219
|
-
allow(subject).to receive(:error).and_return(Object.new).once
|
|
220
|
-
expect(subject.valid?).to eq(false)
|
|
221
|
-
end
|
|
222
|
-
end
|
|
223
|
-
end
|
|
224
210
|
end
|
|
@@ -2,133 +2,134 @@
|
|
|
2
2
|
|
|
3
3
|
require "spec_helper"
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
let(:scopes) { Doorkeeper::OAuth::Scopes.from_string("public") }
|
|
5
|
+
describe Doorkeeper::OAuth::ClientCredentials::Creator do
|
|
6
|
+
let(:client) { FactoryBot.create :application }
|
|
7
|
+
let(:scopes) { Doorkeeper::OAuth::Scopes.from_string("public") }
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
before do
|
|
10
|
+
default_scopes_exist :public
|
|
11
|
+
end
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
it "creates a new token" do
|
|
14
|
+
expect do
|
|
15
|
+
subject.call(client, scopes)
|
|
16
|
+
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
context "when reuse_access_token is true" do
|
|
20
|
+
before do
|
|
21
|
+
allow(Doorkeeper.config).to receive(:reuse_access_token).and_return(true)
|
|
18
22
|
end
|
|
19
23
|
|
|
20
|
-
context "when
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
|
|
24
|
-
existing_token = subject.call(client, scopes)
|
|
24
|
+
context "when expiration is disabled" do
|
|
25
|
+
it "returns the existing valid token" do
|
|
26
|
+
existing_token = subject.call(client, scopes)
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
result = subject.call(client, scopes)
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
end
|
|
30
|
+
expect(Doorkeeper::AccessToken.count).to eq(1)
|
|
31
|
+
expect(result).to eq(existing_token)
|
|
31
32
|
end
|
|
33
|
+
end
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
before do
|
|
37
|
-
allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
|
|
38
|
-
allow(Doorkeeper.configuration).to receive(:token_reuse_limit).and_return(50)
|
|
39
|
-
allow_any_instance_of(Doorkeeper::AccessToken).to receive(:expires_in_seconds).and_return(600)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
it "returns the existing valid token" do
|
|
43
|
-
result = subject.call(client, scopes, expires_in: 1000)
|
|
35
|
+
context "when existing token has not crossed token_reuse_limit" do
|
|
36
|
+
let!(:existing_token) { subject.call(client, scopes, expires_in: 1000) }
|
|
44
37
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
before do
|
|
39
|
+
allow(Doorkeeper.config).to receive(:token_reuse_limit).and_return(50)
|
|
40
|
+
allow_any_instance_of(Doorkeeper::AccessToken).to receive(:expires_in_seconds).and_return(600)
|
|
41
|
+
end
|
|
48
42
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
allow(Doorkeeper.configuration).to receive(:revoke_previous_client_credentials_token).and_return(false)
|
|
52
|
-
end
|
|
43
|
+
it "returns the existing valid token" do
|
|
44
|
+
result = subject.call(client, scopes, expires_in: 1000)
|
|
53
45
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
expect(existing_token.reload).not_to be_revoked
|
|
57
|
-
end
|
|
58
|
-
end
|
|
46
|
+
expect(Doorkeeper::AccessToken.count).to eq(1)
|
|
47
|
+
expect(result).to eq(existing_token)
|
|
59
48
|
end
|
|
60
49
|
|
|
61
|
-
context "when
|
|
62
|
-
|
|
63
|
-
allow(Doorkeeper.
|
|
64
|
-
|
|
65
|
-
existing_token = subject.call(client, scopes, expires_in: 1000)
|
|
66
|
-
|
|
67
|
-
allow_any_instance_of(Doorkeeper::AccessToken).to receive(:expires_in_seconds).and_return(400)
|
|
68
|
-
result = subject.call(client, scopes, expires_in: 1000)
|
|
50
|
+
context "and when revoke_previous_client_credentials_token is false" do
|
|
51
|
+
before do
|
|
52
|
+
allow(Doorkeeper.config).to receive(:revoke_previous_client_credentials_token).and_return(false)
|
|
53
|
+
end
|
|
69
54
|
|
|
70
|
-
|
|
71
|
-
|
|
55
|
+
it "does not revoke the existing valid token" do
|
|
56
|
+
subject.call(client, scopes, expires_in: 1000)
|
|
57
|
+
expect(existing_token.reload).not_to be_revoked
|
|
72
58
|
end
|
|
73
59
|
end
|
|
60
|
+
end
|
|
74
61
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
existing_token = subject.call(client, scopes, expires_in: 1000)
|
|
62
|
+
context "when existing token has crossed token_reuse_limit" do
|
|
63
|
+
it "returns a new token" do
|
|
64
|
+
allow(Doorkeeper.config).to receive(:token_reuse_limit).and_return(50)
|
|
65
|
+
existing_token = subject.call(client, scopes, expires_in: 1000)
|
|
80
66
|
|
|
81
|
-
|
|
82
|
-
|
|
67
|
+
allow_any_instance_of(Doorkeeper::AccessToken).to receive(:expires_in_seconds).and_return(400)
|
|
68
|
+
result = subject.call(client, scopes, expires_in: 1000)
|
|
83
69
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
end
|
|
70
|
+
expect(Doorkeeper::AccessToken.count).to eq(2)
|
|
71
|
+
expect(result).not_to eq(existing_token)
|
|
87
72
|
end
|
|
88
73
|
end
|
|
89
74
|
|
|
90
|
-
context "when
|
|
75
|
+
context "when existing token has been expired" do
|
|
91
76
|
it "returns a new token" do
|
|
92
|
-
allow(Doorkeeper.configuration).to receive(:
|
|
93
|
-
existing_token = subject.call(client, scopes)
|
|
77
|
+
allow(Doorkeeper.configuration).to receive(:token_reuse_limit).and_return(50)
|
|
78
|
+
existing_token = subject.call(client, scopes, expires_in: 1000)
|
|
94
79
|
|
|
95
|
-
|
|
80
|
+
allow_any_instance_of(Doorkeeper::AccessToken).to receive(:expired?).and_return(true)
|
|
81
|
+
result = subject.call(client, scopes, expires_in: 1000)
|
|
96
82
|
|
|
97
83
|
expect(Doorkeeper::AccessToken.count).to eq(2)
|
|
98
84
|
expect(result).not_to eq(existing_token)
|
|
99
85
|
end
|
|
100
86
|
end
|
|
87
|
+
end
|
|
101
88
|
|
|
102
|
-
|
|
103
|
-
|
|
89
|
+
context "when reuse_access_token is false" do
|
|
90
|
+
before do
|
|
91
|
+
allow(Doorkeeper.config).to receive(:reuse_access_token).and_return(false)
|
|
92
|
+
end
|
|
104
93
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
end
|
|
94
|
+
it "returns a new token" do
|
|
95
|
+
existing_token = subject.call(client, scopes)
|
|
108
96
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
97
|
+
result = subject.call(client, scopes)
|
|
98
|
+
|
|
99
|
+
expect(Doorkeeper::AccessToken.count).to eq(2)
|
|
100
|
+
expect(result).not_to eq(existing_token)
|
|
113
101
|
end
|
|
102
|
+
end
|
|
114
103
|
|
|
115
|
-
|
|
116
|
-
|
|
104
|
+
context "when revoke_previous_client_credentials_token is true" do
|
|
105
|
+
let!(:existing_token) { subject.call(client, scopes, expires_in: 1000) }
|
|
117
106
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
107
|
+
before do
|
|
108
|
+
allow(Doorkeeper.configuration).to receive(:revoke_previous_client_credentials_token).and_return(true)
|
|
109
|
+
end
|
|
121
110
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
111
|
+
it "revokes the existing token" do
|
|
112
|
+
subject.call(client, scopes, expires_in: 1000)
|
|
113
|
+
expect(existing_token.reload).to be_revoked
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
context "when revoke_previous_client_credentials_token is false" do
|
|
118
|
+
let!(:existing_token) { subject.call(client, scopes, expires_in: 1000) }
|
|
119
|
+
|
|
120
|
+
before do
|
|
121
|
+
allow(Doorkeeper.configuration).to receive(:revoke_previous_client_credentials_token).and_return(false)
|
|
126
122
|
end
|
|
127
123
|
|
|
128
|
-
it "
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
expect(created).to be_falsey
|
|
124
|
+
it "does not revoke the existing token" do
|
|
125
|
+
subject.call(client, scopes, expires_in: 1000)
|
|
126
|
+
expect(existing_token.reload).not_to be_revoked
|
|
132
127
|
end
|
|
133
128
|
end
|
|
129
|
+
|
|
130
|
+
it "returns false if creation fails" do
|
|
131
|
+
expect(Doorkeeper::AccessToken).to receive(:find_or_create_for).and_return(false)
|
|
132
|
+
created = subject.call(client, scopes)
|
|
133
|
+
expect(created).to be_falsey
|
|
134
|
+
end
|
|
134
135
|
end
|
|
@@ -2,110 +2,108 @@
|
|
|
2
2
|
|
|
3
3
|
require "spec_helper"
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
describe Doorkeeper::OAuth::ClientCredentials::Issuer do
|
|
6
|
+
let(:creator) { double :access_token_creator }
|
|
7
|
+
let(:server) do
|
|
8
|
+
double(
|
|
9
|
+
:server,
|
|
10
|
+
access_token_expires_in: 100,
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
let(:validator) { double :validator, valid?: true }
|
|
14
|
+
|
|
15
|
+
before do
|
|
16
|
+
allow(server).to receive(:option_defined?).with(:custom_access_token_expires_in).and_return(false)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
subject { described_class.new(server, validator) }
|
|
20
|
+
|
|
21
|
+
describe "#create" do
|
|
22
|
+
let(:client) { double :client, id: "some-id" }
|
|
23
|
+
let(:scopes) { "some scope" }
|
|
24
|
+
|
|
25
|
+
it "creates and sets the token" do
|
|
26
|
+
expect(creator).to receive(:call).and_return("token")
|
|
27
|
+
subject.create client, scopes, creator
|
|
28
|
+
|
|
29
|
+
expect(subject.token).to eq("token")
|
|
13
30
|
end
|
|
14
|
-
let(:validator) { double :validator, valid?: true }
|
|
15
31
|
|
|
16
|
-
|
|
17
|
-
|
|
32
|
+
it "creates with correct token parameters" do
|
|
33
|
+
expect(creator).to receive(:call).with(
|
|
34
|
+
client,
|
|
35
|
+
scopes,
|
|
36
|
+
expires_in: 100,
|
|
37
|
+
use_refresh_token: false,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
subject.create client, scopes, creator
|
|
18
41
|
end
|
|
19
42
|
|
|
20
|
-
|
|
43
|
+
it "has error set to :server_error if creator fails" do
|
|
44
|
+
expect(creator).to receive(:call).and_return(false)
|
|
45
|
+
subject.create client, scopes, creator
|
|
46
|
+
|
|
47
|
+
expect(subject.error).to eq(:server_error)
|
|
48
|
+
end
|
|
21
49
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
50
|
+
context "when validator fails" do
|
|
51
|
+
before do
|
|
52
|
+
allow(validator).to receive(:valid?).and_return(false)
|
|
53
|
+
allow(validator).to receive(:error).and_return(:validation_error)
|
|
54
|
+
expect(creator).not_to receive(:create)
|
|
55
|
+
end
|
|
25
56
|
|
|
26
|
-
it "
|
|
27
|
-
expect(creator).to receive(:call).and_return("token")
|
|
57
|
+
it "has error set from validator" do
|
|
28
58
|
subject.create client, scopes, creator
|
|
59
|
+
expect(subject.error).to eq(:validation_error)
|
|
60
|
+
end
|
|
29
61
|
|
|
30
|
-
|
|
62
|
+
it "returns false" do
|
|
63
|
+
expect(subject.create(client, scopes, creator)).to be_falsey
|
|
31
64
|
end
|
|
65
|
+
end
|
|
32
66
|
|
|
33
|
-
|
|
67
|
+
context "with custom expiration" do
|
|
68
|
+
let(:custom_ttl_grant) { 1234 }
|
|
69
|
+
let(:custom_ttl_scope) { 1235 }
|
|
70
|
+
let(:custom_scope) { "special" }
|
|
71
|
+
let(:server) do
|
|
72
|
+
double(
|
|
73
|
+
:server,
|
|
74
|
+
custom_access_token_expires_in: lambda { |context|
|
|
75
|
+
# scopes is normally an object but is a string in this test
|
|
76
|
+
if context.scopes == custom_scope
|
|
77
|
+
custom_ttl_scope
|
|
78
|
+
elsif context.grant_type == Doorkeeper::OAuth::CLIENT_CREDENTIALS
|
|
79
|
+
custom_ttl_grant
|
|
80
|
+
end
|
|
81
|
+
},
|
|
82
|
+
)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
before do
|
|
86
|
+
allow(server).to receive(:option_defined?).with(:custom_access_token_expires_in).and_return(true)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "respects grant based rules" do
|
|
34
90
|
expect(creator).to receive(:call).with(
|
|
35
91
|
client,
|
|
36
92
|
scopes,
|
|
37
|
-
expires_in:
|
|
93
|
+
expires_in: custom_ttl_grant,
|
|
38
94
|
use_refresh_token: false,
|
|
39
95
|
)
|
|
40
|
-
|
|
41
96
|
subject.create client, scopes, creator
|
|
42
97
|
end
|
|
43
98
|
|
|
44
|
-
it "
|
|
45
|
-
expect(creator).to receive(:call).
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
before do
|
|
53
|
-
allow(validator).to receive(:valid?).and_return(false)
|
|
54
|
-
allow(validator).to receive(:error).and_return(:validation_error)
|
|
55
|
-
expect(creator).not_to receive(:create)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
it "has error set from validator" do
|
|
59
|
-
subject.create client, scopes, creator
|
|
60
|
-
expect(subject.error).to eq(:validation_error)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
it "returns false" do
|
|
64
|
-
expect(subject.create(client, scopes, creator)).to be_falsey
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
context "with custom expiration" do
|
|
69
|
-
let(:custom_ttl_grant) { 1234 }
|
|
70
|
-
let(:custom_ttl_scope) { 1235 }
|
|
71
|
-
let(:custom_scope) { "special" }
|
|
72
|
-
let(:server) do
|
|
73
|
-
double(
|
|
74
|
-
:server,
|
|
75
|
-
custom_access_token_expires_in: lambda { |context|
|
|
76
|
-
# scopes is normally an object but is a string in this test
|
|
77
|
-
if context.scopes == custom_scope
|
|
78
|
-
custom_ttl_scope
|
|
79
|
-
elsif context.grant_type == Doorkeeper::OAuth::CLIENT_CREDENTIALS
|
|
80
|
-
custom_ttl_grant
|
|
81
|
-
end
|
|
82
|
-
},
|
|
83
|
-
)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
before do
|
|
87
|
-
allow(server).to receive(:option_defined?).with(:custom_access_token_expires_in).and_return(true)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
it "respects grant based rules" do
|
|
91
|
-
expect(creator).to receive(:call).with(
|
|
92
|
-
client,
|
|
93
|
-
scopes,
|
|
94
|
-
expires_in: custom_ttl_grant,
|
|
95
|
-
use_refresh_token: false,
|
|
96
|
-
)
|
|
97
|
-
subject.create client, scopes, creator
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
it "respects scope based rules" do
|
|
101
|
-
expect(creator).to receive(:call).with(
|
|
102
|
-
client,
|
|
103
|
-
custom_scope,
|
|
104
|
-
expires_in: custom_ttl_scope,
|
|
105
|
-
use_refresh_token: false,
|
|
106
|
-
)
|
|
107
|
-
subject.create client, custom_scope, creator
|
|
108
|
-
end
|
|
99
|
+
it "respects scope based rules" do
|
|
100
|
+
expect(creator).to receive(:call).with(
|
|
101
|
+
client,
|
|
102
|
+
custom_scope,
|
|
103
|
+
expires_in: custom_ttl_scope,
|
|
104
|
+
use_refresh_token: false,
|
|
105
|
+
)
|
|
106
|
+
subject.create client, custom_scope, creator
|
|
109
107
|
end
|
|
110
108
|
end
|
|
111
109
|
end
|
|
@@ -2,58 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
require "spec_helper"
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
let(:request) { double :request, client: client, scopes: nil }
|
|
5
|
+
describe Doorkeeper::OAuth::ClientCredentials::Validator do
|
|
6
|
+
let(:server) { double :server, scopes: nil }
|
|
7
|
+
let(:application) { double scopes: nil }
|
|
8
|
+
let(:client) { double application: application }
|
|
9
|
+
let(:request) { double :request, client: client, scopes: nil }
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
subject { described_class.new(server, request) }
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
it "is valid with valid request" do
|
|
14
|
+
expect(subject).to be_valid
|
|
15
|
+
end
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
it "is invalid when client is not present" do
|
|
18
|
+
allow(request).to receive(:client).and_return(nil)
|
|
19
|
+
expect(subject).not_to be_valid
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
context "with scopes" do
|
|
23
|
+
it "is invalid when scopes are not included in the server" do
|
|
24
|
+
server_scopes = Doorkeeper::OAuth::Scopes.from_string "email"
|
|
25
|
+
allow(request).to receive(:grant_type).and_return(Doorkeeper::OAuth::CLIENT_CREDENTIALS)
|
|
26
|
+
allow(server).to receive(:scopes).and_return(server_scopes)
|
|
27
|
+
allow(request).to receive(:scopes).and_return(
|
|
28
|
+
Doorkeeper::OAuth::Scopes.from_string("invalid"),
|
|
29
|
+
)
|
|
20
30
|
expect(subject).not_to be_valid
|
|
21
31
|
end
|
|
22
32
|
|
|
23
|
-
context "with scopes" do
|
|
24
|
-
it "is
|
|
25
|
-
|
|
33
|
+
context "with application scopes" do
|
|
34
|
+
it "is valid when scopes are included in the application" do
|
|
35
|
+
application_scopes = Doorkeeper::OAuth::Scopes.from_string "app"
|
|
36
|
+
server_scopes = Doorkeeper::OAuth::Scopes.from_string "email app"
|
|
37
|
+
allow(application).to receive(:scopes).and_return(application_scopes)
|
|
38
|
+
allow(server).to receive(:scopes).and_return(server_scopes)
|
|
39
|
+
allow(request).to receive(:grant_type).and_return(Doorkeeper::OAuth::CLIENT_CREDENTIALS)
|
|
40
|
+
allow(request).to receive(:scopes).and_return(application_scopes)
|
|
41
|
+
expect(subject).to be_valid
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "is invalid when scopes are not included in the application" do
|
|
45
|
+
application_scopes = Doorkeeper::OAuth::Scopes.from_string "app"
|
|
46
|
+
server_scopes = Doorkeeper::OAuth::Scopes.from_string "email app"
|
|
47
|
+
allow(application).to receive(:scopes).and_return(application_scopes)
|
|
26
48
|
allow(request).to receive(:grant_type).and_return(Doorkeeper::OAuth::CLIENT_CREDENTIALS)
|
|
27
49
|
allow(server).to receive(:scopes).and_return(server_scopes)
|
|
28
50
|
allow(request).to receive(:scopes).and_return(
|
|
29
|
-
Doorkeeper::OAuth::Scopes.from_string("
|
|
51
|
+
Doorkeeper::OAuth::Scopes.from_string("email"),
|
|
30
52
|
)
|
|
31
53
|
expect(subject).not_to be_valid
|
|
32
54
|
end
|
|
33
|
-
|
|
34
|
-
context "with application scopes" do
|
|
35
|
-
it "is valid when scopes are included in the application" do
|
|
36
|
-
application_scopes = Doorkeeper::OAuth::Scopes.from_string "app"
|
|
37
|
-
server_scopes = Doorkeeper::OAuth::Scopes.from_string "email app"
|
|
38
|
-
allow(application).to receive(:scopes).and_return(application_scopes)
|
|
39
|
-
allow(server).to receive(:scopes).and_return(server_scopes)
|
|
40
|
-
allow(request).to receive(:grant_type).and_return(Doorkeeper::OAuth::CLIENT_CREDENTIALS)
|
|
41
|
-
allow(request).to receive(:scopes).and_return(application_scopes)
|
|
42
|
-
expect(subject).to be_valid
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
it "is invalid when scopes are not included in the application" do
|
|
46
|
-
application_scopes = Doorkeeper::OAuth::Scopes.from_string "app"
|
|
47
|
-
server_scopes = Doorkeeper::OAuth::Scopes.from_string "email app"
|
|
48
|
-
allow(application).to receive(:scopes).and_return(application_scopes)
|
|
49
|
-
allow(request).to receive(:grant_type).and_return(Doorkeeper::OAuth::CLIENT_CREDENTIALS)
|
|
50
|
-
allow(server).to receive(:scopes).and_return(server_scopes)
|
|
51
|
-
allow(request).to receive(:scopes).and_return(
|
|
52
|
-
Doorkeeper::OAuth::Scopes.from_string("email"),
|
|
53
|
-
)
|
|
54
|
-
expect(subject).not_to be_valid
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
55
|
end
|
|
58
56
|
end
|
|
59
57
|
end
|