doorkeeper 5.2.4 → 5.2.5
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/CHANGELOG.md +10 -0
- data/app/controllers/doorkeeper/applications_controller.rb +3 -3
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
- data/lib/doorkeeper/orm/active_record/application.rb +64 -4
- data/lib/doorkeeper/version.rb +1 -1
- data/spec/models/doorkeeper/application_spec.rb +379 -274
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: acf9b03777c432f388b0df1fb4a8b499c07e9442c30f3a91c33188e1de83a7b3
|
4
|
+
data.tar.gz: 0c4cd8972c0b22df9c9c55e8641757d5bae55be522d125879b4c5e6c07b1a869
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f49977df45f15f00eaab6628c9cfb7b8309f9052ec26d11350cb0e6db380fc6b6c1fc11417f5e8bc5d9a9996cfaf3c8390628d3e8dcd18f2a4f0c65749c5291b
|
7
|
+
data.tar.gz: df1900e4654c6050763f216aa78e32444f38ee96f0366c7672affbef57d117b68ee04a6c67b2e01539818fc176b7601dee039ee89eb10490bba27ffabec1944d
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,16 @@ upgrade guides.
|
|
5
5
|
|
6
6
|
User-visible changes worth mentioning.
|
7
7
|
|
8
|
+
## 5.2.5
|
9
|
+
|
10
|
+
- [#1371] Backport: add `#as_json` method and attributes serialization restriction for Application model.
|
11
|
+
Fixes information disclosure vulnerability (CVE-2020-10187).
|
12
|
+
|
13
|
+
**[IMPORTANT]** you need to re-implement `#as_json` method for Doorkeeper Application model
|
14
|
+
if you previously used `#to_json` serialization with custom options or attributes or rely on
|
15
|
+
JSON response from /oauth/applications.json or /oauth/authorized_applications.json. This change
|
16
|
+
is a breaking change which restricts serialized attributes to a very small set of columns.
|
17
|
+
|
8
18
|
## 5.2.4
|
9
19
|
|
10
20
|
- [#1360] Increase `matching_token_for` batch lookup size to 10 000 and make it configurable.
|
@@ -19,7 +19,7 @@ module Doorkeeper
|
|
19
19
|
def show
|
20
20
|
respond_to do |format|
|
21
21
|
format.html
|
22
|
-
format.json { render json: @application }
|
22
|
+
format.json { render json: @application, as_owner: true }
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -36,7 +36,7 @@ module Doorkeeper
|
|
36
36
|
|
37
37
|
respond_to do |format|
|
38
38
|
format.html { redirect_to oauth_application_url(@application) }
|
39
|
-
format.json { render json: @application }
|
39
|
+
format.json { render json: @application, as_owner: true }
|
40
40
|
end
|
41
41
|
else
|
42
42
|
respond_to do |format|
|
@@ -58,7 +58,7 @@ module Doorkeeper
|
|
58
58
|
|
59
59
|
respond_to do |format|
|
60
60
|
format.html { redirect_to oauth_application_url(@application) }
|
61
|
-
format.json { render json: @application }
|
61
|
+
format.json { render json: @application, as_owner: true }
|
62
62
|
end
|
63
63
|
else
|
64
64
|
respond_to do |format|
|
@@ -70,10 +70,27 @@ module Doorkeeper
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
73
|
+
# Represents client as set of it's attributes in JSON format.
|
74
|
+
# This is the right way how we want to override ActiveRecord #to_json.
|
75
|
+
#
|
76
|
+
# Respects privacy settings and serializes minimum set of attributes
|
77
|
+
# for public/private clients and full set for authorized owners.
|
78
|
+
#
|
79
|
+
# @return [Hash] entity attributes for JSON
|
80
|
+
#
|
81
|
+
def as_json(options = {})
|
82
|
+
# if application belongs to some owner we need to check if it's the same as
|
83
|
+
# the one passed in the options or check if we render the client as an owner
|
84
|
+
if (respond_to?(:owner) && owner && owner == options[:current_resource_owner]) ||
|
85
|
+
options[:as_owner]
|
86
|
+
# Owners can see all the client attributes, fallback to ActiveModel serialization
|
87
|
+
super
|
88
|
+
else
|
89
|
+
# if application has no owner or it's owner doesn't match one from the options
|
90
|
+
# we render only minimum set of attributes that could be exposed to a public
|
91
|
+
only = extract_serializable_attributes(options)
|
92
|
+
super(options.merge(only: only))
|
93
|
+
end
|
77
94
|
end
|
78
95
|
|
79
96
|
private
|
@@ -98,5 +115,48 @@ module Doorkeeper
|
|
98
115
|
def enforce_scopes?
|
99
116
|
Doorkeeper.configuration.enforce_configured_scopes?
|
100
117
|
end
|
118
|
+
|
119
|
+
# Helper method to extract collection of serializable attribute names
|
120
|
+
# considering serialization options (like `only`, `except` and so on).
|
121
|
+
#
|
122
|
+
# @param options [Hash] serialization options
|
123
|
+
#
|
124
|
+
# @return [Array<String>]
|
125
|
+
# collection of attributes to be serialized using #as_json
|
126
|
+
#
|
127
|
+
def extract_serializable_attributes(options = {})
|
128
|
+
opts = options.try(:dup) || {}
|
129
|
+
only = Array.wrap(opts[:only]).map(&:to_s)
|
130
|
+
|
131
|
+
only = if only.blank?
|
132
|
+
serializable_attributes
|
133
|
+
else
|
134
|
+
only & serializable_attributes
|
135
|
+
end
|
136
|
+
|
137
|
+
only -= Array.wrap(opts[:except]).map(&:to_s) if opts.key?(:except)
|
138
|
+
only.uniq
|
139
|
+
end
|
140
|
+
|
141
|
+
# We need to hook into this method to allow serializing plan-text secrets
|
142
|
+
# when secrets hashing enabled.
|
143
|
+
#
|
144
|
+
# @param key [String] attribute name
|
145
|
+
#
|
146
|
+
def read_attribute_for_serialization(key)
|
147
|
+
return super unless key.to_s == "secret"
|
148
|
+
|
149
|
+
plaintext_secret || secret
|
150
|
+
end
|
151
|
+
|
152
|
+
# Collection of attributes that could be serialized for public.
|
153
|
+
# Override this method if you need additional attributes to be serialized.
|
154
|
+
#
|
155
|
+
# @return [Array<String>] collection of serializable attributes
|
156
|
+
def serializable_attributes
|
157
|
+
attributes = %w[id name created_at]
|
158
|
+
attributes << "uid" unless confidential?
|
159
|
+
attributes
|
160
|
+
end
|
101
161
|
end
|
102
162
|
end
|
data/lib/doorkeeper/version.rb
CHANGED
@@ -3,374 +3,479 @@
|
|
3
3
|
require "spec_helper"
|
4
4
|
require "bcrypt"
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
let(:unset_require_owner) { Doorkeeper.configuration.instance_variable_set("@confirm_application_owner", false) }
|
11
|
-
let(:new_application) { FactoryBot.build(:application) }
|
6
|
+
describe Doorkeeper::Application do
|
7
|
+
let(:require_owner) { Doorkeeper.configuration.instance_variable_set("@confirm_application_owner", true) }
|
8
|
+
let(:unset_require_owner) { Doorkeeper.configuration.instance_variable_set("@confirm_application_owner", false) }
|
9
|
+
let(:new_application) { FactoryBot.build(:application) }
|
12
10
|
|
13
|
-
|
14
|
-
|
11
|
+
let(:uid) { SecureRandom.hex(8) }
|
12
|
+
let(:secret) { SecureRandom.hex(8) }
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
enable_application_owner
|
21
|
-
end
|
22
|
-
end
|
14
|
+
it "is invalid without a name" do
|
15
|
+
new_application.name = nil
|
16
|
+
expect(new_application).not_to be_valid
|
17
|
+
end
|
23
18
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
19
|
+
it "is invalid without determining confidentiality" do
|
20
|
+
new_application.confidential = nil
|
21
|
+
expect(new_application).not_to be_valid
|
22
|
+
end
|
28
23
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
24
|
+
it "generates uid on create" do
|
25
|
+
expect(new_application.uid).to be_nil
|
26
|
+
new_application.save
|
27
|
+
expect(new_application.uid).not_to be_nil
|
28
|
+
end
|
33
29
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
30
|
+
it "generates uid on create if an empty string" do
|
31
|
+
new_application.uid = ""
|
32
|
+
new_application.save
|
33
|
+
expect(new_application.uid).not_to be_blank
|
34
|
+
end
|
39
35
|
|
40
|
-
|
41
|
-
|
42
|
-
|
36
|
+
it "generates uid on create unless one is set" do
|
37
|
+
new_application.uid = uid
|
38
|
+
new_application.save
|
39
|
+
expect(new_application.uid).to eq(uid)
|
40
|
+
end
|
43
41
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
it "is invalid without uid" do
|
43
|
+
new_application.save
|
44
|
+
new_application.uid = nil
|
45
|
+
expect(new_application).not_to be_valid
|
46
|
+
end
|
47
|
+
|
48
|
+
it "checks uniqueness of uid" do
|
49
|
+
app1 = FactoryBot.create(:application)
|
50
|
+
app2 = FactoryBot.create(:application)
|
51
|
+
app2.uid = app1.uid
|
52
|
+
expect(app2).not_to be_valid
|
53
|
+
end
|
54
|
+
|
55
|
+
it "expects database to throw an error when uids are the same" do
|
56
|
+
app1 = FactoryBot.create(:application)
|
57
|
+
app2 = FactoryBot.create(:application)
|
58
|
+
app2.uid = app1.uid
|
59
|
+
expect { app2.save!(validate: false) }.to raise_error(uniqueness_error)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "generate secret on create" do
|
63
|
+
expect(new_application.secret).to be_nil
|
64
|
+
new_application.save
|
65
|
+
expect(new_application.secret).not_to be_nil
|
66
|
+
end
|
67
|
+
|
68
|
+
it "generate secret on create if is blank string" do
|
69
|
+
new_application.secret = ""
|
70
|
+
new_application.save
|
71
|
+
expect(new_application.secret).not_to be_blank
|
72
|
+
end
|
73
|
+
|
74
|
+
it "generate secret on create unless one is set" do
|
75
|
+
new_application.secret = secret
|
76
|
+
new_application.save
|
77
|
+
expect(new_application.secret).to eq(secret)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "is invalid without secret" do
|
81
|
+
new_application.save
|
82
|
+
new_application.secret = nil
|
83
|
+
expect(new_application).not_to be_valid
|
84
|
+
end
|
85
|
+
|
86
|
+
context "application_owner is enabled" do
|
87
|
+
before do
|
88
|
+
Doorkeeper.configure do
|
89
|
+
orm DOORKEEPER_ORM
|
90
|
+
enable_application_owner
|
48
91
|
end
|
49
92
|
end
|
50
93
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
94
|
+
context "application owner is not required" do
|
95
|
+
before(:each) do
|
96
|
+
unset_require_owner
|
97
|
+
end
|
55
98
|
|
56
|
-
|
57
|
-
|
58
|
-
|
99
|
+
it "is valid given valid attributes" do
|
100
|
+
expect(new_application).to be_valid
|
101
|
+
end
|
59
102
|
end
|
60
103
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
104
|
+
context "application owner is required" do
|
105
|
+
before do
|
106
|
+
require_owner
|
107
|
+
@owner = FactoryBot.build_stubbed(:doorkeeper_testing_user)
|
108
|
+
end
|
66
109
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
expect(new_application.uid).not_to be_blank
|
71
|
-
end
|
110
|
+
it "is invalid without an owner" do
|
111
|
+
expect(new_application).not_to be_valid
|
112
|
+
end
|
72
113
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
114
|
+
it "is valid with an owner" do
|
115
|
+
new_application.owner = @owner
|
116
|
+
expect(new_application).to be_valid
|
117
|
+
end
|
77
118
|
end
|
119
|
+
end
|
78
120
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
121
|
+
context "redirect URI" do
|
122
|
+
context "when grant flows allow blank redirect URI" do
|
123
|
+
before do
|
124
|
+
Doorkeeper.configure do
|
125
|
+
grant_flows %w[password client_credentials]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
it "is valid without redirect_uri" do
|
130
|
+
new_application.save
|
131
|
+
new_application.redirect_uri = nil
|
132
|
+
expect(new_application).to be_valid
|
133
|
+
end
|
83
134
|
end
|
84
135
|
|
85
|
-
context "redirect URI" do
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
grant_flows %w[password client_credentials]
|
90
|
-
end
|
136
|
+
context "when grant flows require redirect URI" do
|
137
|
+
before do
|
138
|
+
Doorkeeper.configure do
|
139
|
+
grant_flows %w[password client_credentials authorization_code]
|
91
140
|
end
|
141
|
+
end
|
92
142
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end
|
143
|
+
it "is invalid without redirect_uri" do
|
144
|
+
new_application.save
|
145
|
+
new_application.redirect_uri = nil
|
146
|
+
expect(new_application).not_to be_valid
|
98
147
|
end
|
148
|
+
end
|
99
149
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
150
|
+
context "when blank URI option disabled" do
|
151
|
+
before do
|
152
|
+
Doorkeeper.configure do
|
153
|
+
grant_flows %w[password client_credentials]
|
154
|
+
allow_blank_redirect_uri false
|
105
155
|
end
|
156
|
+
end
|
106
157
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
end
|
158
|
+
it "is invalid without redirect_uri" do
|
159
|
+
new_application.save
|
160
|
+
new_application.redirect_uri = nil
|
161
|
+
expect(new_application).not_to be_valid
|
112
162
|
end
|
163
|
+
end
|
164
|
+
end
|
113
165
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
166
|
+
context "with hashing enabled" do
|
167
|
+
include_context "with application hashing enabled"
|
168
|
+
let(:app) { FactoryBot.create :application }
|
169
|
+
let(:default_strategy) { Doorkeeper::SecretStoring::Sha256Hash }
|
170
|
+
|
171
|
+
it "uses SHA256 to avoid additional dependencies" do
|
172
|
+
# Ensure token was generated
|
173
|
+
app.validate
|
174
|
+
expect(app.secret).to eq(default_strategy.transform_secret(app.plaintext_secret))
|
175
|
+
end
|
121
176
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
177
|
+
context "when bcrypt strategy is configured" do
|
178
|
+
# In this text context, we have bcrypt loaded so `bcrypt_present?`
|
179
|
+
# will always be true
|
180
|
+
before do
|
181
|
+
Doorkeeper.configure do
|
182
|
+
hash_application_secrets using: "Doorkeeper::SecretStoring::BCrypt"
|
126
183
|
end
|
127
184
|
end
|
185
|
+
|
186
|
+
it "holds a volatile plaintext and BCrypt secret" do
|
187
|
+
expect(app.secret_strategy).to eq Doorkeeper::SecretStoring::BCrypt
|
188
|
+
expect(app.plaintext_secret).to be_a(String)
|
189
|
+
expect(app.secret).not_to eq(app.plaintext_secret)
|
190
|
+
expect { ::BCrypt::Password.create(app.secret) }.not_to raise_error
|
191
|
+
end
|
128
192
|
end
|
129
193
|
|
130
|
-
it "
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
194
|
+
it "does not fallback to plain lookup by default" do
|
195
|
+
lookup = described_class.by_uid_and_secret(app.uid, app.secret)
|
196
|
+
expect(lookup).to eq(nil)
|
197
|
+
|
198
|
+
lookup = described_class.by_uid_and_secret(app.uid, app.plaintext_secret)
|
199
|
+
expect(lookup).to eq(app)
|
135
200
|
end
|
136
201
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
202
|
+
context "with fallback enabled" do
|
203
|
+
include_context "with token hashing and fallback lookup enabled"
|
204
|
+
|
205
|
+
it "provides plain and hashed lookup" do
|
206
|
+
lookup = described_class.by_uid_and_secret(app.uid, app.secret)
|
207
|
+
expect(lookup).to eq(app)
|
208
|
+
|
209
|
+
lookup = described_class.by_uid_and_secret(app.uid, app.plaintext_secret)
|
210
|
+
expect(lookup).to eq(app)
|
211
|
+
end
|
142
212
|
end
|
143
213
|
|
144
|
-
it "
|
145
|
-
|
146
|
-
|
147
|
-
expect(new_application.secret).not_to be_nil
|
214
|
+
it "does not provide access to secret after loading" do
|
215
|
+
lookup = described_class.by_uid_and_secret(app.uid, app.plaintext_secret)
|
216
|
+
expect(lookup.plaintext_secret).to be_nil
|
148
217
|
end
|
218
|
+
end
|
149
219
|
|
150
|
-
|
151
|
-
|
220
|
+
describe "destroy related models on cascade" do
|
221
|
+
before(:each) do
|
152
222
|
new_application.save
|
153
|
-
expect(new_application.secret).not_to be_blank
|
154
223
|
end
|
155
224
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
225
|
+
let(:resource_owner) { FactoryBot.create(:doorkeeper_testing_user) }
|
226
|
+
|
227
|
+
it "should destroy its access grants" do
|
228
|
+
FactoryBot.create(
|
229
|
+
:access_grant,
|
230
|
+
application: new_application,
|
231
|
+
resource_owner_id: resource_owner.id,
|
232
|
+
)
|
233
|
+
|
234
|
+
expect { new_application.destroy }.to change { Doorkeeper::AccessGrant.count }.by(-1)
|
160
235
|
end
|
161
236
|
|
162
|
-
it "
|
163
|
-
new_application
|
164
|
-
|
165
|
-
expect
|
237
|
+
it "should destroy its access tokens" do
|
238
|
+
FactoryBot.create(:access_token, application: new_application)
|
239
|
+
FactoryBot.create(:access_token, application: new_application, revoked_at: Time.now.utc)
|
240
|
+
expect do
|
241
|
+
new_application.destroy
|
242
|
+
end.to change { Doorkeeper::AccessToken.count }.by(-2)
|
166
243
|
end
|
244
|
+
end
|
167
245
|
|
168
|
-
|
169
|
-
|
170
|
-
let(:app) { FactoryBot.create :application }
|
171
|
-
let(:default_strategy) { Doorkeeper::SecretStoring::Sha256Hash }
|
246
|
+
describe "#ordered_by" do
|
247
|
+
let(:applications) { FactoryBot.create_list(:application, 5) }
|
172
248
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
expect(
|
249
|
+
context "when a direction is not specified" do
|
250
|
+
it "calls order with a default order of asc" do
|
251
|
+
names = applications.map(&:name).sort
|
252
|
+
expect(described_class.ordered_by(:name).map(&:name)).to eq(names)
|
177
253
|
end
|
254
|
+
end
|
178
255
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
Doorkeeper.configure do
|
184
|
-
hash_application_secrets using: "Doorkeeper::SecretStoring::BCrypt"
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
it "holds a volatile plaintext and BCrypt secret" do
|
189
|
-
expect(app.secret_strategy).to eq Doorkeeper::SecretStoring::BCrypt
|
190
|
-
expect(app.plaintext_secret).to be_a(String)
|
191
|
-
expect(app.secret).not_to eq(app.plaintext_secret)
|
192
|
-
expect { ::BCrypt::Password.create(app.secret) }.not_to raise_error
|
193
|
-
end
|
256
|
+
context "when a direction is specified" do
|
257
|
+
it "calls order with specified direction" do
|
258
|
+
names = applications.map(&:name).sort.reverse
|
259
|
+
expect(described_class.ordered_by(:name, :desc).map(&:name)).to eq(names)
|
194
260
|
end
|
261
|
+
end
|
262
|
+
end
|
195
263
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
expect(lookup).to eq(app)
|
264
|
+
describe "#redirect_uri=" do
|
265
|
+
context "when array of valid redirect_uris" do
|
266
|
+
it "should join by newline" do
|
267
|
+
new_application.redirect_uri = ["http://localhost/callback1", "http://localhost/callback2"]
|
268
|
+
expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
|
202
269
|
end
|
270
|
+
end
|
271
|
+
context "when string of valid redirect_uris" do
|
272
|
+
it "should store as-is" do
|
273
|
+
new_application.redirect_uri = "http://localhost/callback1\nhttp://localhost/callback2"
|
274
|
+
expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
203
278
|
|
204
|
-
|
205
|
-
|
279
|
+
describe "#renew_secret" do
|
280
|
+
let(:app) { FactoryBot.create :application }
|
206
281
|
|
207
|
-
|
208
|
-
|
209
|
-
|
282
|
+
it "should generate a new secret" do
|
283
|
+
old_secret = app.secret
|
284
|
+
app.renew_secret
|
285
|
+
expect(old_secret).not_to eq(app.secret)
|
286
|
+
end
|
287
|
+
end
|
210
288
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
end
|
289
|
+
describe "#authorized_for" do
|
290
|
+
let(:resource_owner) { FactoryBot.create(:doorkeeper_testing_user) }
|
291
|
+
let(:other_resource_owner) { FactoryBot.create(:doorkeeper_testing_user) }
|
215
292
|
|
216
|
-
|
217
|
-
|
218
|
-
expect(lookup.plaintext_secret).to be_nil
|
219
|
-
end
|
293
|
+
it "is empty if the application is not authorized for anyone" do
|
294
|
+
expect(described_class.authorized_for(resource_owner)).to be_empty
|
220
295
|
end
|
221
296
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
297
|
+
it "returns only application for a specific resource owner" do
|
298
|
+
FactoryBot.create(
|
299
|
+
:access_token,
|
300
|
+
resource_owner_id: other_resource_owner.id,
|
301
|
+
)
|
302
|
+
token = FactoryBot.create(
|
303
|
+
:access_token,
|
304
|
+
resource_owner_id: resource_owner.id,
|
305
|
+
)
|
306
|
+
expect(described_class.authorized_for(resource_owner)).to eq([token.application])
|
307
|
+
end
|
226
308
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
309
|
+
it "excludes revoked tokens" do
|
310
|
+
FactoryBot.create(
|
311
|
+
:access_token,
|
312
|
+
resource_owner_id: resource_owner.id,
|
313
|
+
revoked_at: 2.days.ago,
|
314
|
+
)
|
315
|
+
expect(described_class.authorized_for(resource_owner)).to be_empty
|
316
|
+
end
|
231
317
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
318
|
+
it "returns all applications that have been authorized" do
|
319
|
+
token1 = FactoryBot.create(
|
320
|
+
:access_token,
|
321
|
+
resource_owner_id: resource_owner.id,
|
322
|
+
)
|
323
|
+
token2 = FactoryBot.create(
|
324
|
+
:access_token,
|
325
|
+
resource_owner_id: resource_owner.id,
|
326
|
+
)
|
327
|
+
expect(described_class.authorized_for(resource_owner))
|
328
|
+
.to eq([token1.application, token2.application])
|
239
329
|
end
|
240
330
|
|
241
|
-
|
242
|
-
|
331
|
+
it "returns only one application even if it has been authorized twice" do
|
332
|
+
application = FactoryBot.create(:application)
|
333
|
+
FactoryBot.create(
|
334
|
+
:access_token,
|
335
|
+
resource_owner_id: resource_owner.id,
|
336
|
+
application: application,
|
337
|
+
)
|
338
|
+
FactoryBot.create(
|
339
|
+
:access_token,
|
340
|
+
resource_owner_id: resource_owner.id,
|
341
|
+
application: application,
|
342
|
+
)
|
343
|
+
expect(described_class.authorized_for(resource_owner)).to eq([application])
|
344
|
+
end
|
345
|
+
end
|
243
346
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
347
|
+
describe "#revoke_tokens_and_grants_for" do
|
348
|
+
it "revokes all access tokens and access grants" do
|
349
|
+
application_id = 42
|
350
|
+
resource_owner = double
|
351
|
+
expect(Doorkeeper::AccessToken)
|
352
|
+
.to receive(:revoke_all_for).with(application_id, resource_owner)
|
353
|
+
expect(Doorkeeper::AccessGrant)
|
354
|
+
.to receive(:revoke_all_for).with(application_id, resource_owner)
|
355
|
+
|
356
|
+
described_class.revoke_tokens_and_grants_for(application_id, resource_owner)
|
357
|
+
end
|
358
|
+
end
|
250
359
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
360
|
+
describe "#by_uid_and_secret" do
|
361
|
+
context "when application is private/confidential" do
|
362
|
+
it "finds the application via uid/secret" do
|
363
|
+
app = FactoryBot.create :application
|
364
|
+
authenticated = described_class.by_uid_and_secret(app.uid, app.secret)
|
365
|
+
expect(authenticated).to eq(app)
|
366
|
+
end
|
367
|
+
context "when secret is wrong" do
|
368
|
+
it "should not find the application" do
|
369
|
+
app = FactoryBot.create :application
|
370
|
+
authenticated = described_class.by_uid_and_secret(app.uid, "bad")
|
371
|
+
expect(authenticated).to eq(nil)
|
255
372
|
end
|
256
373
|
end
|
257
374
|
end
|
258
375
|
|
259
|
-
|
260
|
-
context "when
|
261
|
-
it "should
|
262
|
-
|
263
|
-
|
376
|
+
context "when application is public/non-confidential" do
|
377
|
+
context "when secret is blank" do
|
378
|
+
it "should find the application" do
|
379
|
+
app = FactoryBot.create :application, confidential: false
|
380
|
+
authenticated = described_class.by_uid_and_secret(app.uid, nil)
|
381
|
+
expect(authenticated).to eq(app)
|
264
382
|
end
|
265
383
|
end
|
266
|
-
context "when
|
267
|
-
it "should
|
268
|
-
|
269
|
-
|
384
|
+
context "when secret is wrong" do
|
385
|
+
it "should not find the application" do
|
386
|
+
app = FactoryBot.create :application, confidential: false
|
387
|
+
authenticated = described_class.by_uid_and_secret(app.uid, "bad")
|
388
|
+
expect(authenticated).to eq(nil)
|
270
389
|
end
|
271
390
|
end
|
272
391
|
end
|
392
|
+
end
|
273
393
|
|
274
|
-
|
275
|
-
|
394
|
+
describe "#confidential?" do
|
395
|
+
subject { FactoryBot.create(:application, confidential: confidential).confidential? }
|
276
396
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
expect(old_secret).not_to eq(app.secret)
|
281
|
-
end
|
397
|
+
context "when application is private/confidential" do
|
398
|
+
let(:confidential) { true }
|
399
|
+
it { expect(subject).to eq(true) }
|
282
400
|
end
|
283
401
|
|
284
|
-
|
285
|
-
let(:
|
402
|
+
context "when application is public/non-confidential" do
|
403
|
+
let(:confidential) { false }
|
404
|
+
it { expect(subject).to eq(false) }
|
405
|
+
end
|
406
|
+
end
|
286
407
|
|
287
|
-
|
288
|
-
|
289
|
-
end
|
408
|
+
describe "#as_json" do
|
409
|
+
let(:app) { FactoryBot.create :application, secret: "123123123" }
|
290
410
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
end
|
411
|
+
before do
|
412
|
+
allow(Doorkeeper.configuration)
|
413
|
+
.to receive(:application_secret_strategy).and_return(Doorkeeper::SecretStoring::Plain)
|
414
|
+
end
|
296
415
|
|
297
|
-
|
298
|
-
|
299
|
-
|
416
|
+
# AR specific feature
|
417
|
+
if DOORKEEPER_ORM == :active_record
|
418
|
+
it "correctly works with #to_json" do
|
419
|
+
ActiveRecord::Base.include_root_in_json = true
|
420
|
+
expect(app.to_json(include_root_in_json: true)).to match(/application.+?:\{/)
|
421
|
+
ActiveRecord::Base.include_root_in_json = false
|
300
422
|
end
|
423
|
+
end
|
301
424
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
425
|
+
context "when called without authorized resource owner" do
|
426
|
+
it "includes minimal set of attributes" do
|
427
|
+
expect(app.as_json).to match(
|
428
|
+
"id" => app.id,
|
429
|
+
"name" => app.name,
|
430
|
+
"created_at" => an_instance_of(String),
|
431
|
+
)
|
306
432
|
end
|
307
433
|
|
308
|
-
it "
|
309
|
-
|
310
|
-
FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, application: application)
|
311
|
-
FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, application: application)
|
312
|
-
expect(Application.authorized_for(resource_owner)).to eq([application])
|
313
|
-
end
|
314
|
-
end
|
434
|
+
it "includes application UID if it's public" do
|
435
|
+
app = FactoryBot.create :application, secret: "123123123", confidential: false
|
315
436
|
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
.to receive(:revoke_all_for).with(application_id, resource_owner)
|
437
|
+
expect(app.as_json).to match(
|
438
|
+
"id" => app.id,
|
439
|
+
"name" => app.name,
|
440
|
+
"created_at" => an_instance_of(String),
|
441
|
+
"uid" => app.uid,
|
442
|
+
)
|
443
|
+
end
|
324
444
|
|
325
|
-
|
445
|
+
it "respects custom options" do
|
446
|
+
expect(app.as_json(except: :id)).not_to include("id")
|
447
|
+
expect(app.as_json(only: %i[name created_at secret]))
|
448
|
+
.to match(
|
449
|
+
"name" => app.name,
|
450
|
+
"created_at" => an_instance_of(String),
|
451
|
+
)
|
326
452
|
end
|
327
453
|
end
|
328
454
|
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
authenticated = Application.by_uid_and_secret(app.uid, app.secret)
|
334
|
-
expect(authenticated).to eq(app)
|
335
|
-
end
|
336
|
-
context "when secret is wrong" do
|
337
|
-
it "should not find the application" do
|
338
|
-
app = FactoryBot.create :application
|
339
|
-
authenticated = Application.by_uid_and_secret(app.uid, "bad")
|
340
|
-
expect(authenticated).to eq(nil)
|
341
|
-
end
|
342
|
-
end
|
343
|
-
end
|
455
|
+
context "when called with authorized resource owner" do
|
456
|
+
let(:owner) { FactoryBot.create(:doorkeeper_testing_user) }
|
457
|
+
let(:other_owner) { FactoryBot.create(:doorkeeper_testing_user) }
|
458
|
+
let(:app) { FactoryBot.create(:application, secret: "123123123", owner: owner) }
|
344
459
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
authenticated = Application.by_uid_and_secret(app.uid, nil)
|
350
|
-
expect(authenticated).to eq(app)
|
351
|
-
end
|
352
|
-
end
|
353
|
-
context "when secret is wrong" do
|
354
|
-
it "should not find the application" do
|
355
|
-
app = FactoryBot.create :application, confidential: false
|
356
|
-
authenticated = Application.by_uid_and_secret(app.uid, "bad")
|
357
|
-
expect(authenticated).to eq(nil)
|
358
|
-
end
|
460
|
+
before do
|
461
|
+
Doorkeeper.configure do
|
462
|
+
orm DOORKEEPER_ORM
|
463
|
+
enable_application_owner confirmation: false
|
359
464
|
end
|
360
465
|
end
|
361
|
-
end
|
362
|
-
|
363
|
-
describe :confidential? do
|
364
|
-
subject { FactoryBot.create(:application, confidential: confidential).confidential? }
|
365
466
|
|
366
|
-
|
367
|
-
|
368
|
-
|
467
|
+
it "includes all the attributes" do
|
468
|
+
expect(app.as_json(current_resource_owner: owner))
|
469
|
+
.to include(
|
470
|
+
"secret" => "123123123",
|
471
|
+
"redirect_uri" => app.redirect_uri,
|
472
|
+
"uid" => app.uid,
|
473
|
+
)
|
369
474
|
end
|
370
475
|
|
371
|
-
|
372
|
-
|
373
|
-
|
476
|
+
it "doesn't include unsafe attributes if current owner isn't the same as owner" do
|
477
|
+
expect(app.as_json(current_resource_owner: other_owner))
|
478
|
+
.not_to include("redirect_uri")
|
374
479
|
end
|
375
480
|
end
|
376
481
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: doorkeeper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.2.
|
4
|
+
version: 5.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felipe Elias Philipp
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2020-02
|
14
|
+
date: 2020-05-02 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: railties
|