doorkeeper 5.2.0.rc2 → 5.2.0.rc3
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/Appraisals +1 -1
- data/CHANGELOG.md +15 -2
- data/Gemfile +1 -1
- data/README.md +9 -1
- data/app/controllers/doorkeeper/application_metal_controller.rb +1 -1
- data/app/controllers/doorkeeper/authorizations_controller.rb +11 -9
- data/config/locales/en.yml +5 -1
- data/doorkeeper.gemspec +8 -0
- data/gemfiles/rails_6_0.gemfile +1 -1
- data/lib/doorkeeper.rb +1 -0
- data/lib/doorkeeper/config.rb +41 -2
- data/lib/doorkeeper/errors.rb +13 -18
- data/lib/doorkeeper/helpers/controller.rb +6 -2
- data/lib/doorkeeper/oauth/authorization/code.rb +1 -5
- data/lib/doorkeeper/oauth/authorization_code_request.rb +18 -9
- data/lib/doorkeeper/oauth/base_request.rb +2 -0
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +8 -0
- data/lib/doorkeeper/oauth/code_request.rb +5 -11
- data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -2
- data/lib/doorkeeper/oauth/pre_authorization.rb +70 -37
- data/lib/doorkeeper/oauth/refresh_token_request.rb +5 -2
- data/lib/doorkeeper/oauth/token_introspection.rb +4 -1
- data/lib/doorkeeper/oauth/token_request.rb +4 -18
- data/lib/doorkeeper/orm/active_record.rb +2 -2
- data/lib/doorkeeper/orm/active_record/application.rb +1 -1
- data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +61 -0
- data/lib/doorkeeper/request.rb +6 -11
- data/lib/doorkeeper/request/authorization_code.rb +2 -0
- data/lib/doorkeeper/server.rb +2 -6
- data/lib/doorkeeper/version.rb +1 -1
- data/lib/generators/doorkeeper/templates/initializer.rb +33 -2
- data/lib/generators/doorkeeper/templates/migration.rb.erb +1 -1
- data/spec/controllers/authorizations_controller_spec.rb +127 -61
- data/spec/controllers/protected_resources_controller_spec.rb +3 -3
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +1 -1
- data/spec/lib/config_spec.rb +17 -0
- data/spec/lib/oauth/authorization_code_request_spec.rb +11 -1
- data/spec/lib/oauth/base_request_spec.rb +33 -16
- data/spec/lib/oauth/code_request_spec.rb +27 -28
- data/spec/lib/oauth/invalid_request_response_spec.rb +75 -0
- data/spec/lib/oauth/pre_authorization_spec.rb +80 -55
- data/spec/lib/oauth/refresh_token_request_spec.rb +1 -0
- data/spec/lib/oauth/token_request_spec.rb +20 -17
- data/spec/lib/server_spec.rb +0 -12
- data/spec/requests/endpoints/authorization_spec.rb +21 -5
- data/spec/requests/endpoints/token_spec.rb +1 -1
- data/spec/requests/flows/authorization_code_errors_spec.rb +1 -0
- data/spec/requests/flows/authorization_code_spec.rb +77 -23
- data/spec/requests/flows/client_credentials_spec.rb +38 -0
- data/spec/requests/flows/implicit_grant_errors_spec.rb +22 -10
- data/spec/requests/flows/implicit_grant_spec.rb +9 -8
- data/spec/requests/flows/password_spec.rb +37 -0
- data/spec/requests/flows/refresh_token_spec.rb +1 -1
- data/spec/support/helpers/request_spec_helper.rb +14 -2
- data/spec/validators/redirect_uri_validator_spec.rb +1 -1
- metadata +12 -4
- data/app/validators/redirect_uri_validator.rb +0 -60
@@ -4,18 +4,23 @@ require "spec_helper"
|
|
4
4
|
|
5
5
|
module Doorkeeper::OAuth
|
6
6
|
describe CodeRequest do
|
7
|
-
let
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
7
|
+
let :pre_auth do
|
8
|
+
server = Doorkeeper.configuration
|
9
|
+
allow(server).to receive(:default_scopes).and_return(Scopes.from_string("public"))
|
10
|
+
allow(server).to receive(:grant_flows).and_return(Scopes.from_string("authorization_code"))
|
11
|
+
|
12
|
+
application = FactoryBot.create(:application, scopes: "public")
|
13
|
+
client = Doorkeeper::OAuth::Client.new(application)
|
14
|
+
|
15
|
+
attributes = {
|
16
|
+
client_id: client.uid,
|
17
|
+
response_type: "code",
|
18
|
+
redirect_uri: "https://app.com/callback",
|
19
|
+
}
|
20
|
+
|
21
|
+
pre_auth = PreAuthorization.new(server, attributes)
|
22
|
+
pre_auth.authorizable?
|
23
|
+
pre_auth
|
19
24
|
end
|
20
25
|
|
21
26
|
let(:owner) { double :owner, id: 8900 }
|
@@ -24,24 +29,18 @@ module Doorkeeper::OAuth
|
|
24
29
|
CodeRequest.new(pre_auth, owner)
|
25
30
|
end
|
26
31
|
|
27
|
-
|
28
|
-
|
29
|
-
subject.authorize
|
30
|
-
|
32
|
+
context "when pre_auth is authorized" do
|
33
|
+
it "creates an access grant and returns a code response" do
|
34
|
+
expect { subject.authorize }.to change { Doorkeeper::AccessGrant.count }.by(1)
|
35
|
+
expect(subject.authorize).to be_a(CodeResponse)
|
36
|
+
end
|
31
37
|
end
|
32
38
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
allow(pre_auth).to receive(:authorizable?).and_return(false)
|
39
|
-
expect { subject.authorize }.not_to(change { Doorkeeper::AccessGrant.count })
|
40
|
-
end
|
41
|
-
|
42
|
-
it "returns a error response" do
|
43
|
-
allow(pre_auth).to receive(:authorizable?).and_return(false)
|
44
|
-
expect(subject.authorize).to be_a(ErrorResponse)
|
39
|
+
context "when pre_auth is denied" do
|
40
|
+
it "does not create access grant and returns a error response" do
|
41
|
+
expect { subject.deny }.not_to(change { Doorkeeper::AccessGrant.count })
|
42
|
+
expect(subject.deny).to be_a(ErrorResponse)
|
43
|
+
end
|
45
44
|
end
|
46
45
|
end
|
47
46
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
module Doorkeeper::OAuth
|
6
|
+
describe InvalidRequestResponse do
|
7
|
+
describe "#name" do
|
8
|
+
it { expect(subject.name).to eq(:invalid_request) }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#status" do
|
12
|
+
it { expect(subject.status).to eq(:bad_request) }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe :from_request do
|
16
|
+
let(:response) { InvalidRequestResponse.from_request(request) }
|
17
|
+
|
18
|
+
context "missing param" do
|
19
|
+
let(:request) { double(missing_param: "some_param") }
|
20
|
+
|
21
|
+
it "sets a description" do
|
22
|
+
expect(response.description).to eq(
|
23
|
+
I18n.t(:missing_param, scope: %i[doorkeeper errors messages invalid_request], value: "some_param")
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "sets the reason" do
|
28
|
+
expect(response.reason).to eq(:missing_param)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "server doesn not support_pkce" do
|
33
|
+
let(:request) { double(invalid_request_reason: :not_support_pkce) }
|
34
|
+
|
35
|
+
it "sets a description" do
|
36
|
+
expect(response.description).to eq(
|
37
|
+
I18n.t(:not_support_pkce, scope: %i[doorkeeper errors messages invalid_request])
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "sets the reason" do
|
42
|
+
expect(response.reason).to eq(:not_support_pkce)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "request is not authorized" do
|
47
|
+
let(:request) { double(invalid_request_reason: :request_not_authorized) }
|
48
|
+
|
49
|
+
it "sets a description" do
|
50
|
+
expect(response.description).to eq(
|
51
|
+
I18n.t(:request_not_authorized, scope: %i[doorkeeper errors messages invalid_request])
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "sets the reason" do
|
56
|
+
expect(response.reason).to eq(:request_not_authorized)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "unknown reason" do
|
61
|
+
let(:request) { double(invalid_request_reason: :unknown_reason) }
|
62
|
+
|
63
|
+
it "sets a description" do
|
64
|
+
expect(response.description).to eq(
|
65
|
+
I18n.t(:unknown, scope: %i[doorkeeper errors messages invalid_request])
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "unknown reason" do
|
70
|
+
expect(response.reason).to eq(:unknown_reason)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -6,31 +6,25 @@ module Doorkeeper::OAuth
|
|
6
6
|
describe PreAuthorization do
|
7
7
|
let(:server) do
|
8
8
|
server = Doorkeeper.configuration
|
9
|
-
allow(server).to receive(:default_scopes).and_return(Scopes.
|
10
|
-
allow(server).to receive(:
|
9
|
+
allow(server).to receive(:default_scopes).and_return(Scopes.from_string("default"))
|
10
|
+
allow(server).to receive(:optional_scopes).and_return(Scopes.from_string("public profile"))
|
11
11
|
server
|
12
12
|
end
|
13
13
|
|
14
|
-
let(:application)
|
15
|
-
|
16
|
-
allow(application).to receive(:scopes).and_return(Scopes.from_string(""))
|
17
|
-
application
|
18
|
-
end
|
19
|
-
|
20
|
-
let(:client) do
|
21
|
-
double :client, redirect_uri: "http://tst.com/auth", application: application
|
22
|
-
end
|
14
|
+
let(:application) { FactoryBot.create(:application, redirect_uri: "https://app.com/callback") }
|
15
|
+
let(:client) { Client.find(application.uid) }
|
23
16
|
|
24
17
|
let :attributes do
|
25
18
|
{
|
19
|
+
client_id: client.uid,
|
26
20
|
response_type: "code",
|
27
|
-
redirect_uri: "
|
21
|
+
redirect_uri: "https://app.com/callback",
|
28
22
|
state: "save-this",
|
29
23
|
}
|
30
24
|
end
|
31
25
|
|
32
26
|
subject do
|
33
|
-
PreAuthorization.new(server,
|
27
|
+
PreAuthorization.new(server, attributes)
|
34
28
|
end
|
35
29
|
|
36
30
|
it "is authorizable when request is valid" do
|
@@ -38,25 +32,25 @@ module Doorkeeper::OAuth
|
|
38
32
|
end
|
39
33
|
|
40
34
|
it "accepts code as response type" do
|
41
|
-
|
35
|
+
attributes[:response_type] = "code"
|
42
36
|
expect(subject).to be_authorizable
|
43
37
|
end
|
44
38
|
|
45
39
|
it "accepts token as response type" do
|
46
40
|
allow(server).to receive(:grant_flows).and_return(["implicit"])
|
47
|
-
|
41
|
+
attributes[:response_type] = "token"
|
48
42
|
expect(subject).to be_authorizable
|
49
43
|
end
|
50
44
|
|
51
45
|
context "when using default grant flows" do
|
52
46
|
it 'accepts "code" as response type' do
|
53
|
-
|
47
|
+
attributes[:response_type] = "code"
|
54
48
|
expect(subject).to be_authorizable
|
55
49
|
end
|
56
50
|
|
57
51
|
it 'accepts "token" as response type' do
|
58
52
|
allow(server).to receive(:grant_flows).and_return(["implicit"])
|
59
|
-
|
53
|
+
attributes[:response_type] = "token"
|
60
54
|
expect(subject).to be_authorizable
|
61
55
|
end
|
62
56
|
end
|
@@ -67,7 +61,7 @@ module Doorkeeper::OAuth
|
|
67
61
|
end
|
68
62
|
|
69
63
|
it 'does not accept "code" as response type' do
|
70
|
-
|
64
|
+
attributes[:response_type] = "code"
|
71
65
|
expect(subject).not_to be_authorizable
|
72
66
|
end
|
73
67
|
end
|
@@ -78,79 +72,90 @@ module Doorkeeper::OAuth
|
|
78
72
|
end
|
79
73
|
|
80
74
|
it 'does not accept "token" as response type' do
|
81
|
-
|
75
|
+
attributes[:response_type] = "token"
|
82
76
|
expect(subject).not_to be_authorizable
|
83
77
|
end
|
84
78
|
end
|
85
79
|
|
86
80
|
context "client application does not restrict valid scopes" do
|
87
81
|
it "accepts valid scopes" do
|
88
|
-
|
82
|
+
attributes[:scope] = "public"
|
89
83
|
expect(subject).to be_authorizable
|
90
84
|
end
|
91
85
|
|
92
86
|
it "rejects (globally) non-valid scopes" do
|
93
|
-
|
87
|
+
attributes[:scope] = "invalid"
|
94
88
|
expect(subject).not_to be_authorizable
|
95
89
|
end
|
96
90
|
|
97
91
|
it "accepts scopes which are permitted for grant_type" do
|
98
92
|
allow(server).to receive(:scopes_by_grant_type).and_return(authorization_code: [:public])
|
99
|
-
|
93
|
+
attributes[:scope] = "public"
|
100
94
|
expect(subject).to be_authorizable
|
101
95
|
end
|
102
96
|
|
103
97
|
it "rejects scopes which are not permitted for grant_type" do
|
104
98
|
allow(server).to receive(:scopes_by_grant_type).and_return(authorization_code: [:profile])
|
105
|
-
|
99
|
+
attributes[:scope] = "public"
|
106
100
|
expect(subject).not_to be_authorizable
|
107
101
|
end
|
108
102
|
end
|
109
103
|
|
110
104
|
context "client application restricts valid scopes" do
|
111
105
|
let(:application) do
|
112
|
-
application
|
113
|
-
allow(application).to receive(:scopes).and_return(Scopes.from_string("public nonsense"))
|
114
|
-
application
|
106
|
+
FactoryBot.create(:application, scopes: Scopes.from_string("public nonsense"))
|
115
107
|
end
|
116
108
|
|
117
109
|
it "accepts valid scopes" do
|
118
|
-
|
110
|
+
attributes[:scope] = "public"
|
119
111
|
expect(subject).to be_authorizable
|
120
112
|
end
|
121
113
|
|
122
114
|
it "rejects (globally) non-valid scopes" do
|
123
|
-
|
115
|
+
attributes[:scope] = "invalid"
|
124
116
|
expect(subject).not_to be_authorizable
|
125
117
|
end
|
126
118
|
|
127
119
|
it "rejects (application level) non-valid scopes" do
|
128
|
-
|
120
|
+
attributes[:scope] = "profile"
|
129
121
|
expect(subject).to_not be_authorizable
|
130
122
|
end
|
131
123
|
|
132
124
|
it "accepts scopes which are permitted for grant_type" do
|
133
125
|
allow(server).to receive(:scopes_by_grant_type).and_return(authorization_code: [:public])
|
134
|
-
|
126
|
+
attributes[:scope] = "public"
|
135
127
|
expect(subject).to be_authorizable
|
136
128
|
end
|
137
129
|
|
138
130
|
it "rejects scopes which are not permitted for grant_type" do
|
139
131
|
allow(server).to receive(:scopes_by_grant_type).and_return(authorization_code: [:profile])
|
140
|
-
|
132
|
+
attributes[:scope] = "public"
|
141
133
|
expect(subject).not_to be_authorizable
|
142
134
|
end
|
143
135
|
end
|
144
136
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
137
|
+
context "when scope is not provided to pre_authorization" do
|
138
|
+
before { attributes[:scope] = nil }
|
139
|
+
|
140
|
+
context "when default scopes is provided" do
|
141
|
+
it "uses default scopes" do
|
142
|
+
allow(server).to receive(:default_scopes).and_return(Scopes.from_string("default_scope"))
|
143
|
+
expect(subject).to be_authorizable
|
144
|
+
expect(subject.scope).to eq("default_scope")
|
145
|
+
expect(subject.scopes).to eq(Scopes.from_string("default_scope"))
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context "when default scopes is none" do
|
150
|
+
it "not be authorizable when none default scope" do
|
151
|
+
allow(server).to receive(:default_scopes).and_return(Scopes.new)
|
152
|
+
expect(subject).not_to be_authorizable
|
153
|
+
end
|
154
|
+
end
|
150
155
|
end
|
151
156
|
|
152
157
|
it "matches the redirect uri against client's one" do
|
153
|
-
|
158
|
+
attributes[:redirect_uri] = "http://nothesame.com"
|
154
159
|
expect(subject).not_to be_authorizable
|
155
160
|
end
|
156
161
|
|
@@ -159,41 +164,61 @@ module Doorkeeper::OAuth
|
|
159
164
|
end
|
160
165
|
|
161
166
|
it "rejects if response type is not allowed" do
|
162
|
-
|
167
|
+
attributes[:response_type] = "whops"
|
163
168
|
expect(subject).not_to be_authorizable
|
164
169
|
end
|
165
170
|
|
166
171
|
it "requires an existing client" do
|
167
|
-
|
172
|
+
attributes[:client_id] = nil
|
168
173
|
expect(subject).not_to be_authorizable
|
169
174
|
end
|
170
175
|
|
171
176
|
it "requires a redirect uri" do
|
172
|
-
|
177
|
+
attributes[:redirect_uri] = nil
|
173
178
|
expect(subject).not_to be_authorizable
|
174
179
|
end
|
175
180
|
|
176
181
|
describe "as_json" do
|
177
|
-
|
178
|
-
let(:client_name) { "Acme Co." }
|
182
|
+
before { subject.authorizable? }
|
179
183
|
|
180
|
-
|
181
|
-
|
182
|
-
|
184
|
+
it { is_expected.to respond_to :as_json }
|
185
|
+
|
186
|
+
shared_examples "returns the pre authorization" do
|
187
|
+
it "returns the pre authorization" do
|
188
|
+
expect(json[:client_id]).to eq client.uid
|
189
|
+
expect(json[:redirect_uri]).to eq subject.redirect_uri
|
190
|
+
expect(json[:state]).to eq subject.state
|
191
|
+
expect(json[:response_type]).to eq subject.response_type
|
192
|
+
expect(json[:scope]).to eq subject.scope
|
193
|
+
expect(json[:client_name]).to eq client.name
|
194
|
+
expect(json[:status]).to eq I18n.t("doorkeeper.pre_authorization.status")
|
195
|
+
end
|
183
196
|
end
|
184
197
|
|
185
|
-
|
198
|
+
context "when attributes param is not passed" do
|
199
|
+
let(:json) { subject.as_json }
|
186
200
|
|
187
|
-
|
201
|
+
include_examples "returns the pre authorization"
|
202
|
+
end
|
203
|
+
|
204
|
+
context "when attributes param is passed" do
|
205
|
+
context "when attributes is a hash" do
|
206
|
+
let(:custom_attributes) { { custom_id: "1234", custom_name: "a pretty good name" } }
|
207
|
+
let(:json) { subject.as_json(custom_attributes) }
|
208
|
+
|
209
|
+
include_examples "returns the pre authorization"
|
210
|
+
|
211
|
+
it "merges the attributes in params" do
|
212
|
+
expect(json[:custom_id]).to eq custom_attributes[:custom_id]
|
213
|
+
expect(json[:custom_name]).to eq custom_attributes[:custom_name]
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
context "when attributes is not a hash" do
|
218
|
+
let(:json) { subject.as_json(nil) }
|
188
219
|
|
189
|
-
|
190
|
-
|
191
|
-
expect(json[:redirect_uri]).to eq subject.redirect_uri
|
192
|
-
expect(json[:state]).to eq subject.state
|
193
|
-
expect(json[:response_type]).to eq subject.response_type
|
194
|
-
expect(json[:scope]).to eq subject.scope
|
195
|
-
expect(json[:client_name]).to eq client_name
|
196
|
-
expect(json[:status]).to eq I18n.t("doorkeeper.pre_authorization.status")
|
220
|
+
include_examples "returns the pre authorization"
|
221
|
+
end
|
197
222
|
end
|
198
223
|
end
|
199
224
|
end
|
@@ -9,15 +9,21 @@ module Doorkeeper::OAuth
|
|
9
9
|
end
|
10
10
|
|
11
11
|
let :pre_auth do
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
12
|
+
server = Doorkeeper.configuration
|
13
|
+
allow(server).to receive(:default_scopes).and_return(Scopes.from_string("public"))
|
14
|
+
allow(server).to receive(:grant_flows).and_return(Scopes.from_string("implicit"))
|
15
|
+
|
16
|
+
client = Doorkeeper::OAuth::Client.new(application)
|
17
|
+
|
18
|
+
attributes = {
|
19
|
+
client_id: client.uid,
|
20
|
+
response_type: "token",
|
21
|
+
redirect_uri: "https://app.com/callback",
|
22
|
+
}
|
23
|
+
|
24
|
+
pre_auth = PreAuthorization.new(server, attributes)
|
25
|
+
pre_auth.authorizable?
|
26
|
+
pre_auth
|
21
27
|
end
|
22
28
|
|
23
29
|
let :owner do
|
@@ -38,14 +44,11 @@ module Doorkeeper::OAuth
|
|
38
44
|
expect(subject.authorize).to be_a(CodeResponse)
|
39
45
|
end
|
40
46
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
it "returns a error response" do
|
47
|
-
allow(pre_auth).to receive(:authorizable?).and_return(false)
|
48
|
-
expect(subject.authorize).to be_a(ErrorResponse)
|
47
|
+
context "when pre_auth is denied" do
|
48
|
+
it "does not create token and returns a error response" do
|
49
|
+
expect { subject.deny }.not_to(change { Doorkeeper::AccessToken.count })
|
50
|
+
expect(subject.deny).to be_a(ErrorResponse)
|
51
|
+
end
|
49
52
|
end
|
50
53
|
|
51
54
|
describe "with custom expiration" do
|