doorkeeper 5.2.0.rc1 → 5.2.0
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 +33 -2
- data/CONTRIBUTING.md +7 -0
- data/Dangerfile +1 -1
- data/Dockerfile +29 -0
- data/Gemfile +1 -1
- data/README.md +9 -1
- data/app/controllers/doorkeeper/application_controller.rb +1 -1
- data/app/controllers/doorkeeper/application_metal_controller.rb +2 -1
- data/app/controllers/doorkeeper/authorizations_controller.rb +14 -7
- data/app/controllers/doorkeeper/tokens_controller.rb +14 -1
- data/config/locales/en.yml +5 -1
- data/doorkeeper.gemspec +8 -0
- data/gemfiles/rails_6_0.gemfile +1 -1
- data/lib/doorkeeper/config.rb +64 -9
- data/lib/doorkeeper/errors.rb +13 -18
- data/lib/doorkeeper/helpers/controller.rb +6 -2
- data/lib/doorkeeper/models/access_token_mixin.rb +43 -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/creator.rb +14 -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 +16 -7
- data/lib/doorkeeper/oauth/token_request.rb +4 -18
- 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/orm/active_record.rb +2 -2
- data/lib/doorkeeper/request/authorization_code.rb +2 -0
- data/lib/doorkeeper/request.rb +6 -11
- data/lib/doorkeeper/server.rb +2 -6
- data/lib/doorkeeper/version.rb +1 -1
- data/lib/doorkeeper.rb +1 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +88 -43
- data/lib/generators/doorkeeper/templates/migration.rb.erb +1 -1
- data/spec/controllers/authorizations_controller_spec.rb +140 -61
- data/spec/controllers/protected_resources_controller_spec.rb +3 -3
- data/spec/controllers/tokens_controller_spec.rb +140 -40
- data/spec/dummy/config/initializers/doorkeeper.rb +47 -20
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +1 -1
- data/spec/lib/config_spec.rb +32 -1
- 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/client_credentials/creator_spec.rb +3 -0
- 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 +15 -6
- data/app/validators/redirect_uri_validator.rb +0 -60
@@ -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
|
data/spec/lib/server_spec.rb
CHANGED
@@ -10,12 +10,6 @@ describe Doorkeeper::Server do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
describe ".authorization_request" do
|
13
|
-
it "raises error when strategy does not exist" do
|
14
|
-
expect do
|
15
|
-
subject.authorization_request(:duh)
|
16
|
-
end.to raise_error(Doorkeeper::Errors::InvalidAuthorizationStrategy)
|
17
|
-
end
|
18
|
-
|
19
13
|
it "raises error when strategy does not match phase" do
|
20
14
|
expect do
|
21
15
|
subject.token_request(:code)
|
@@ -29,12 +23,6 @@ describe Doorkeeper::Server do
|
|
29
23
|
.and_return(["authorization_code"])
|
30
24
|
end
|
31
25
|
|
32
|
-
it "raises error when using the disabled Implicit strategy" do
|
33
|
-
expect do
|
34
|
-
subject.authorization_request(:token)
|
35
|
-
end.to raise_error(Doorkeeper::Errors::InvalidAuthorizationStrategy)
|
36
|
-
end
|
37
|
-
|
38
26
|
it "raises error when using the disabled Client Credentials strategy" do
|
39
27
|
expect do
|
40
28
|
subject.token_request(:client_credentials)
|
@@ -4,6 +4,7 @@ require "spec_helper"
|
|
4
4
|
|
5
5
|
feature "Authorization endpoint" do
|
6
6
|
background do
|
7
|
+
default_scopes_exist :default
|
7
8
|
config_is_set(:authenticate_resource_owner) { User.first || redirect_to("/sign_in") }
|
8
9
|
client_exists(name: "MyApp")
|
9
10
|
end
|
@@ -34,16 +35,31 @@ feature "Authorization endpoint" do
|
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
37
|
-
context "with a invalid request" do
|
38
|
+
context "with a invalid request's param" do
|
38
39
|
background do
|
39
40
|
create_resource_owner
|
40
41
|
sign_in
|
41
42
|
end
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
context "when missing required param" do
|
45
|
+
scenario "displays invalid_request error when missing client" do
|
46
|
+
visit authorization_endpoint_url(client: nil, response_type: "code")
|
47
|
+
i_should_not_see "Authorize"
|
48
|
+
i_should_see_translated_invalid_request_error_message :missing_param, :client_id
|
49
|
+
end
|
50
|
+
|
51
|
+
scenario "displays invalid_request error when missing response_type param" do
|
52
|
+
visit authorization_endpoint_url(client: @client, response_type: "")
|
53
|
+
i_should_not_see "Authorize"
|
54
|
+
i_should_see_translated_invalid_request_error_message :missing_param, :response_type
|
55
|
+
end
|
56
|
+
|
57
|
+
scenario "displays invalid_request error when missing scope param and authorization server has no default scopes" do
|
58
|
+
config_is_set(:default_scopes, [])
|
59
|
+
visit authorization_endpoint_url(client: @client, response_type: "code", scope: "")
|
60
|
+
i_should_not_see "Authorize"
|
61
|
+
i_should_see_translated_invalid_request_error_message :missing_param, :scope
|
62
|
+
end
|
47
63
|
end
|
48
64
|
|
49
65
|
scenario "displays unsupported_response_type error when using a disabled response type" do
|
@@ -70,6 +70,6 @@ describe "Token endpoint" do
|
|
70
70
|
|
71
71
|
should_not_have_json "access_token"
|
72
72
|
should_have_json "error", "invalid_request"
|
73
|
-
should_have_json "error_description",
|
73
|
+
should_have_json "error_description", translated_invalid_request_error_message(:missing_param, :grant_type)
|
74
74
|
end
|
75
75
|
end
|
@@ -5,6 +5,7 @@ require "spec_helper"
|
|
5
5
|
feature "Authorization Code Flow Errors" do
|
6
6
|
let(:client_params) { {} }
|
7
7
|
background do
|
8
|
+
default_scopes_exist :default
|
8
9
|
config_is_set(:authenticate_resource_owner) { User.first || redirect_to("/sign_in") }
|
9
10
|
client_exists client_params
|
10
11
|
create_resource_owner
|
@@ -4,6 +4,7 @@ require "spec_helper"
|
|
4
4
|
|
5
5
|
feature "Authorization Code Flow" do
|
6
6
|
background do
|
7
|
+
default_scopes_exist :default
|
7
8
|
config_is_set(:authenticate_resource_owner) { User.first || redirect_to("/sign_in") }
|
8
9
|
client_exists
|
9
10
|
create_resource_owner
|
@@ -23,6 +24,39 @@ feature "Authorization Code Flow" do
|
|
23
24
|
url_should_not_have_param("error")
|
24
25
|
end
|
25
26
|
|
27
|
+
context "when configured to check application supported grant flow" do
|
28
|
+
before do
|
29
|
+
config_is_set(:allow_grant_flow_for_client, ->(_grant_flow, client) { client.name == "admin" })
|
30
|
+
end
|
31
|
+
|
32
|
+
scenario "forbids the request when doesn't satisfy condition" do
|
33
|
+
@client.update(name: "sample app")
|
34
|
+
|
35
|
+
visit authorization_endpoint_url(client: @client)
|
36
|
+
|
37
|
+
i_should_see_translated_error_message("unauthorized_client")
|
38
|
+
end
|
39
|
+
|
40
|
+
scenario "allows the request when satisfies condition" do
|
41
|
+
@client.update(name: "admin")
|
42
|
+
|
43
|
+
visit authorization_endpoint_url(client: @client)
|
44
|
+
i_should_not_see_translated_error_message("unauthorized_client")
|
45
|
+
click_on "Authorize"
|
46
|
+
|
47
|
+
authorization_code = Doorkeeper::AccessGrant.first.token
|
48
|
+
create_access_token authorization_code, @client
|
49
|
+
|
50
|
+
access_token_should_exist_for(@client, @resource_owner)
|
51
|
+
|
52
|
+
should_not_have_json "error"
|
53
|
+
|
54
|
+
should_have_json "access_token", Doorkeeper::AccessToken.first.token
|
55
|
+
should_have_json "token_type", "Bearer"
|
56
|
+
should_have_json_within "expires_in", Doorkeeper::AccessToken.first.expires_in, 1
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
26
60
|
context "with grant hashing enabled" do
|
27
61
|
background do
|
28
62
|
config_is_set(:token_secret_strategy, ::Doorkeeper::SecretStoring::Sha256Hash)
|
@@ -83,6 +117,17 @@ feature "Authorization Code Flow" do
|
|
83
117
|
url_should_not_have_param("code_challenge_method")
|
84
118
|
end
|
85
119
|
|
120
|
+
scenario "resource owner requests an access token without authorization code" do
|
121
|
+
create_access_token "", @client
|
122
|
+
|
123
|
+
access_token_should_not_exist
|
124
|
+
|
125
|
+
expect(Doorkeeper::AccessToken.count).to be_zero
|
126
|
+
|
127
|
+
should_have_json "error", "invalid_request"
|
128
|
+
should_have_json "error_description", translated_invalid_request_error_message(:missing_param, :code)
|
129
|
+
end
|
130
|
+
|
86
131
|
scenario "resource owner requests an access token with authorization code" do
|
87
132
|
visit authorization_endpoint_url(client: @client)
|
88
133
|
click_on "Authorize"
|
@@ -110,6 +155,7 @@ feature "Authorization Code Flow" do
|
|
110
155
|
expect(Doorkeeper::AccessToken.count).to be_zero
|
111
156
|
|
112
157
|
should_have_json "error", "invalid_client"
|
158
|
+
should_have_json "error_description", translated_error_message(:invalid_client)
|
113
159
|
end
|
114
160
|
|
115
161
|
scenario "resource owner requests an access token with authorization code but without client id" do
|
@@ -123,6 +169,7 @@ feature "Authorization Code Flow" do
|
|
123
169
|
expect(Doorkeeper::AccessToken.count).to be_zero
|
124
170
|
|
125
171
|
should_have_json "error", "invalid_client"
|
172
|
+
should_have_json "error_description", translated_error_message(:invalid_client)
|
126
173
|
end
|
127
174
|
|
128
175
|
scenario "silently authorizes if matching token exists" do
|
@@ -165,6 +212,7 @@ feature "Authorization Code Flow" do
|
|
165
212
|
create_access_token authorization_code, @client, code_verifier
|
166
213
|
|
167
214
|
should_have_json "error", "invalid_grant"
|
215
|
+
should_have_json "error_description", translated_error_message(:invalid_grant)
|
168
216
|
end
|
169
217
|
|
170
218
|
scenario "mobile app requests an access token with authorization code and plain code challenge method" do
|
@@ -187,17 +235,32 @@ feature "Authorization Code Flow" do
|
|
187
235
|
should_have_json_within "expires_in", Doorkeeper::AccessToken.first.expires_in, 1
|
188
236
|
end
|
189
237
|
|
190
|
-
scenario "mobile app requests an access token with authorization code
|
238
|
+
scenario "mobile app requests an access token with authorization code but without code_verifier" do
|
191
239
|
visit authorization_endpoint_url(client: @client,
|
192
|
-
code_challenge:
|
240
|
+
code_challenge: code_challenge,
|
193
241
|
code_challenge_method: "plain")
|
194
242
|
click_on "Authorize"
|
195
243
|
|
196
244
|
authorization_code = current_params["code"]
|
197
|
-
create_access_token authorization_code, @client,
|
245
|
+
create_access_token authorization_code, @client, nil
|
246
|
+
|
247
|
+
should_not_have_json "access_token"
|
248
|
+
should_have_json "error", "invalid_request"
|
249
|
+
should_have_json "error_description", translated_invalid_request_error_message(:missing_param, :code_verifier)
|
250
|
+
end
|
251
|
+
|
252
|
+
scenario "mobile app requests an access token with authorization code with wrong code_verifier" do
|
253
|
+
visit authorization_endpoint_url(client: @client,
|
254
|
+
code_challenge: code_challenge,
|
255
|
+
code_challenge_method: "plain")
|
256
|
+
click_on "Authorize"
|
257
|
+
|
258
|
+
authorization_code = current_params["code"]
|
259
|
+
create_access_token authorization_code, @client, "wrong_code_verifier"
|
198
260
|
|
199
261
|
should_not_have_json "access_token"
|
200
262
|
should_have_json "error", "invalid_grant"
|
263
|
+
should_have_json "error_description", translated_error_message(:invalid_grant)
|
201
264
|
end
|
202
265
|
end
|
203
266
|
|
@@ -238,19 +301,6 @@ feature "Authorization Code Flow" do
|
|
238
301
|
should_have_json_within "expires_in", Doorkeeper::AccessToken.first.expires_in, 1
|
239
302
|
end
|
240
303
|
|
241
|
-
scenario "mobile app requests an access token with authorization code and without code_verifier" do
|
242
|
-
visit authorization_endpoint_url(
|
243
|
-
client: @client,
|
244
|
-
code_challenge: code_challenge,
|
245
|
-
code_challenge_method: "S256"
|
246
|
-
)
|
247
|
-
click_on "Authorize"
|
248
|
-
authorization_code = current_params["code"]
|
249
|
-
create_access_token authorization_code, @client
|
250
|
-
should_have_json "error", "invalid_request"
|
251
|
-
should_not_have_json "access_token"
|
252
|
-
end
|
253
|
-
|
254
304
|
scenario "mobile app requests an access token with authorization code and without secret" do
|
255
305
|
visit authorization_endpoint_url(
|
256
306
|
client: @client,
|
@@ -262,8 +312,9 @@ feature "Authorization Code Flow" do
|
|
262
312
|
authorization_code = current_params["code"]
|
263
313
|
page.driver.post token_endpoint_url(code: authorization_code, client_id: @client.uid,
|
264
314
|
redirect_uri: @client.redirect_uri, code_verifier: code_verifier)
|
265
|
-
should_have_json "error", "invalid_client"
|
266
315
|
should_not_have_json "access_token"
|
316
|
+
should_have_json "error", "invalid_client"
|
317
|
+
should_have_json "error_description", translated_error_message(:invalid_client)
|
267
318
|
end
|
268
319
|
|
269
320
|
scenario "mobile app requests an access token with authorization code and without secret but is marked as not confidential" do
|
@@ -298,6 +349,7 @@ feature "Authorization Code Flow" do
|
|
298
349
|
|
299
350
|
should_not_have_json "access_token"
|
300
351
|
should_have_json "error", "invalid_request"
|
352
|
+
should_have_json "error_description", translated_invalid_request_error_message(:missing_param, :code_verifier)
|
301
353
|
end
|
302
354
|
|
303
355
|
scenario "mobile app requests an access token with authorization code with wrong verifier" do
|
@@ -313,6 +365,7 @@ feature "Authorization Code Flow" do
|
|
313
365
|
|
314
366
|
should_not_have_json "access_token"
|
315
367
|
should_have_json "error", "invalid_grant"
|
368
|
+
should_have_json "error_description", translated_error_message(:invalid_grant)
|
316
369
|
end
|
317
370
|
|
318
371
|
scenario "code_challenge_mehthod in token request is totally ignored" do
|
@@ -333,6 +386,7 @@ feature "Authorization Code Flow" do
|
|
333
386
|
|
334
387
|
should_not_have_json "access_token"
|
335
388
|
should_have_json "error", "invalid_grant"
|
389
|
+
should_have_json "error_description", translated_error_message(:invalid_grant)
|
336
390
|
end
|
337
391
|
|
338
392
|
scenario "expects to set code_challenge_method explicitely without fallback" do
|
@@ -344,16 +398,15 @@ feature "Authorization Code Flow" do
|
|
344
398
|
|
345
399
|
context "when application scopes are present and no scope is passed" do
|
346
400
|
background do
|
347
|
-
@client.update(scopes: "public write read")
|
401
|
+
@client.update(scopes: "public write read default")
|
348
402
|
end
|
349
403
|
|
350
|
-
scenario "
|
404
|
+
scenario "scope is invalid because default scope is different from application scope" do
|
351
405
|
default_scopes_exist :admin
|
352
406
|
visit authorization_endpoint_url(client: @client)
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
expect(grant.scopes).to be_empty
|
407
|
+
response_status_should_be 200
|
408
|
+
i_should_not_see "Authorize"
|
409
|
+
i_should_see_translated_error_message :invalid_scope
|
357
410
|
end
|
358
411
|
|
359
412
|
scenario "access grant have scopes which are common in application scopees and default scopes" do
|
@@ -454,6 +507,7 @@ describe "Authorization Code Flow" do
|
|
454
507
|
|
455
508
|
should_not_have_json "access_token"
|
456
509
|
should_have_json "error", "invalid_grant"
|
510
|
+
should_have_json "error_description", translated_error_message(:invalid_grant)
|
457
511
|
end
|
458
512
|
end
|
459
513
|
end
|
@@ -66,6 +66,44 @@ describe "Client Credentials Request" do
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
+
context "when configured to check application supported grant flow" do
|
70
|
+
before do
|
71
|
+
Doorkeeper.configuration.instance_variable_set(
|
72
|
+
:@allow_grant_flow_for_client,
|
73
|
+
->(_grant_flow, client) { client.name == "admin" }
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
scenario "forbids the request when doesn't satisfy condition" do
|
78
|
+
client.update(name: "sample app")
|
79
|
+
|
80
|
+
headers = authorization client.uid, client.secret
|
81
|
+
params = { grant_type: "client_credentials" }
|
82
|
+
|
83
|
+
post "/oauth/token", params: params, headers: headers
|
84
|
+
|
85
|
+
should_have_json "error", "unauthorized_client"
|
86
|
+
should_have_json "error_description", translated_error_message(:unauthorized_client)
|
87
|
+
end
|
88
|
+
|
89
|
+
scenario "allows the request when satisfies condition" do
|
90
|
+
client.update(name: "admin")
|
91
|
+
|
92
|
+
headers = authorization client.uid, client.secret
|
93
|
+
params = { grant_type: "client_credentials" }
|
94
|
+
|
95
|
+
post "/oauth/token", params: params, headers: headers
|
96
|
+
|
97
|
+
should_have_json "access_token", Doorkeeper::AccessToken.first.token
|
98
|
+
should_have_json_within "expires_in", Doorkeeper.configuration.access_token_expires_in, 1
|
99
|
+
should_not_have_json "scope"
|
100
|
+
should_not_have_json "refresh_token"
|
101
|
+
|
102
|
+
should_not_have_json "error"
|
103
|
+
should_not_have_json "error_description"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
69
107
|
context "when application scopes contain some of the default scopes and no scope is passed" do
|
70
108
|
before do
|
71
109
|
client.update(scopes: "read write public")
|