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.

Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +1 -1
  3. data/CHANGELOG.md +15 -2
  4. data/Gemfile +1 -1
  5. data/README.md +9 -1
  6. data/app/controllers/doorkeeper/application_metal_controller.rb +1 -1
  7. data/app/controllers/doorkeeper/authorizations_controller.rb +11 -9
  8. data/config/locales/en.yml +5 -1
  9. data/doorkeeper.gemspec +8 -0
  10. data/gemfiles/rails_6_0.gemfile +1 -1
  11. data/lib/doorkeeper.rb +1 -0
  12. data/lib/doorkeeper/config.rb +41 -2
  13. data/lib/doorkeeper/errors.rb +13 -18
  14. data/lib/doorkeeper/helpers/controller.rb +6 -2
  15. data/lib/doorkeeper/oauth/authorization/code.rb +1 -5
  16. data/lib/doorkeeper/oauth/authorization_code_request.rb +18 -9
  17. data/lib/doorkeeper/oauth/base_request.rb +2 -0
  18. data/lib/doorkeeper/oauth/client_credentials/validation.rb +8 -0
  19. data/lib/doorkeeper/oauth/code_request.rb +5 -11
  20. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  21. data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -2
  22. data/lib/doorkeeper/oauth/pre_authorization.rb +70 -37
  23. data/lib/doorkeeper/oauth/refresh_token_request.rb +5 -2
  24. data/lib/doorkeeper/oauth/token_introspection.rb +4 -1
  25. data/lib/doorkeeper/oauth/token_request.rb +4 -18
  26. data/lib/doorkeeper/orm/active_record.rb +2 -2
  27. data/lib/doorkeeper/orm/active_record/application.rb +1 -1
  28. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +61 -0
  29. data/lib/doorkeeper/request.rb +6 -11
  30. data/lib/doorkeeper/request/authorization_code.rb +2 -0
  31. data/lib/doorkeeper/server.rb +2 -6
  32. data/lib/doorkeeper/version.rb +1 -1
  33. data/lib/generators/doorkeeper/templates/initializer.rb +33 -2
  34. data/lib/generators/doorkeeper/templates/migration.rb.erb +1 -1
  35. data/spec/controllers/authorizations_controller_spec.rb +127 -61
  36. data/spec/controllers/protected_resources_controller_spec.rb +3 -3
  37. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +1 -1
  38. data/spec/lib/config_spec.rb +17 -0
  39. data/spec/lib/oauth/authorization_code_request_spec.rb +11 -1
  40. data/spec/lib/oauth/base_request_spec.rb +33 -16
  41. data/spec/lib/oauth/code_request_spec.rb +27 -28
  42. data/spec/lib/oauth/invalid_request_response_spec.rb +75 -0
  43. data/spec/lib/oauth/pre_authorization_spec.rb +80 -55
  44. data/spec/lib/oauth/refresh_token_request_spec.rb +1 -0
  45. data/spec/lib/oauth/token_request_spec.rb +20 -17
  46. data/spec/lib/server_spec.rb +0 -12
  47. data/spec/requests/endpoints/authorization_spec.rb +21 -5
  48. data/spec/requests/endpoints/token_spec.rb +1 -1
  49. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -0
  50. data/spec/requests/flows/authorization_code_spec.rb +77 -23
  51. data/spec/requests/flows/client_credentials_spec.rb +38 -0
  52. data/spec/requests/flows/implicit_grant_errors_spec.rb +22 -10
  53. data/spec/requests/flows/implicit_grant_spec.rb +9 -8
  54. data/spec/requests/flows/password_spec.rb +37 -0
  55. data/spec/requests/flows/refresh_token_spec.rb +1 -1
  56. data/spec/support/helpers/request_spec_helper.rb +14 -2
  57. data/spec/validators/redirect_uri_validator_spec.rb +1 -1
  58. metadata +12 -4
  59. 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(:pre_auth) do
8
- double(
9
- :pre_auth,
10
- client: double(:application, id: 9990),
11
- redirect_uri: "http://tst.com/cb",
12
- scopes: nil,
13
- state: nil,
14
- error: nil,
15
- authorizable?: true,
16
- code_challenge: nil,
17
- code_challenge_method: nil
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
- it "creates an access grant" do
28
- expect do
29
- subject.authorize
30
- end.to change { Doorkeeper::AccessGrant.count }.by(1)
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
- it "returns a code response" do
34
- expect(subject.authorize).to be_a(CodeResponse)
35
- end
36
-
37
- it "does not create grant when not authorizable" do
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.new)
10
- allow(server).to receive(:scopes).and_return(Scopes.from_string("public profile"))
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) do
15
- application = double :application
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: "http://tst.com/auth",
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, client, attributes)
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
- subject.response_type = "code"
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
- subject.response_type = "token"
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
- subject.response_type = "code"
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
- subject.response_type = "token"
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
- subject.response_type = "code"
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
- subject.response_type = "token"
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
- subject.scope = "public"
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
- subject.scope = "invalid"
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
- subject.scope = "public"
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
- subject.scope = "public"
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 = double :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
- subject.scope = "public"
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
- subject.scope = "invalid"
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
- subject.scope = "profile"
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
- subject.scope = "public"
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
- subject.scope = "public"
132
+ attributes[:scope] = "public"
141
133
  expect(subject).not_to be_authorizable
142
134
  end
143
135
  end
144
136
 
145
- it "uses default scopes when none is required" do
146
- allow(server).to receive(:default_scopes).and_return(Scopes.from_string("default"))
147
- subject.scope = nil
148
- expect(subject.scope).to eq("default")
149
- expect(subject.scopes).to eq(Scopes.from_string("default"))
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
- subject.redirect_uri = "http://nothesame.com"
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
- subject.response_type = "whops"
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
- subject.client = nil
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
- subject.redirect_uri = nil
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
- let(:client_id) { "client_uid_123" }
178
- let(:client_name) { "Acme Co." }
182
+ before { subject.authorizable? }
179
183
 
180
- before do
181
- allow(client).to receive(:uid).and_return client_id
182
- allow(client).to receive(:name).and_return client_name
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
- let(:json) { subject.as_json({}) }
198
+ context "when attributes param is not passed" do
199
+ let(:json) { subject.as_json }
186
200
 
187
- it { is_expected.to respond_to :as_json }
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
- it "returns correct values" do
190
- expect(json[:client_id]).to eq client_id
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
@@ -63,6 +63,7 @@ module Doorkeeper::OAuth
63
63
  subject.refresh_token = nil
64
64
  subject.validate
65
65
  expect(subject.error).to eq(:invalid_request)
66
+ expect(subject.missing_param).to eq(:refresh_token)
66
67
  end
67
68
 
68
69
  it "requires credentials to be valid if provided" do
@@ -9,15 +9,21 @@ module Doorkeeper::OAuth
9
9
  end
10
10
 
11
11
  let :pre_auth do
12
- double(
13
- :pre_auth,
14
- client: application,
15
- redirect_uri: "http://tst.com/cb",
16
- state: nil,
17
- scopes: Scopes.from_string("public"),
18
- error: nil,
19
- authorizable?: true
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
- it "does not create token when not authorizable" do
42
- allow(pre_auth).to receive(:authorizable?).and_return(false)
43
- expect { subject.authorize }.not_to(change { Doorkeeper::AccessToken.count })
44
- end
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