Skip to content

Commit 82dfe06

Browse files
committed
Fix admin password hashes being exposed to other admins.
1 parent aac482e commit 82dfe06

4 files changed

Lines changed: 172 additions & 1 deletion

File tree

src/api-umbrella/web-app/app/models/admin.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,12 @@ def disallowed_roles
204204

205205
def serializable_hash(options = nil)
206206
options ||= {}
207-
options[:force_except] = options.fetch(:force_except, []) + [:authentication_token]
207+
options[:force_except] = options.fetch(:force_except, []) + [
208+
:authentication_token,
209+
:encrypted_password,
210+
:reset_password_token,
211+
:unlock_token,
212+
]
208213
hash = super(options)
209214
hash["group_names"] = self.group_names
210215
hash

test/apis/v1/admins/test_index.rb

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,100 @@ def setup
1212

1313
include ApiUmbrellaSharedTests::DataTablesApi
1414

15+
def test_filled_attributes_response_fields
16+
record = FactoryGirl.create(:filled_attributes_admin)
17+
18+
response = Typhoeus.get(data_tables_api_url, http_options.deep_merge(admin_token).deep_merge({
19+
:params => {
20+
:search => { :value => record.id },
21+
},
22+
}))
23+
assert_response_code(200, response)
24+
data = MultiJson.load(response.body)
25+
assert_data_tables_root_fields(data)
26+
assert_equal(1, data.fetch("data").length)
27+
28+
record_data = data.fetch("data").first
29+
assert_base_record_fields(record_data)
30+
31+
assert_equal("2017-01-01T00:00:00Z", record_data.fetch("created_at"))
32+
assert_match_uuid(record_data.fetch("created_by"))
33+
assert_equal(record.created_by, record_data.fetch("created_by"))
34+
assert_equal("2017-01-05T00:00:00Z", record_data.fetch("current_sign_in_at"))
35+
assert_equal("10.11.2.3", record_data.fetch("current_sign_in_ip"))
36+
assert_equal("Provider1", record_data.fetch("current_sign_in_provider"))
37+
assert_match(/@example.com/, record_data.fetch("email"))
38+
assert_equal(3, record_data.fetch("failed_attempts"))
39+
assert_equal(1, record_data.fetch("group_ids").length)
40+
assert_match_uuid(record_data.fetch("group_ids").first)
41+
assert_equal(record.groups.first.id, record_data.fetch("group_ids").first)
42+
assert_equal(2, record_data.fetch("group_names").length)
43+
assert_equal([
44+
"ExampleFilledGroup",
45+
"Superuser",
46+
], record_data.fetch("group_names").sort)
47+
assert_equal("2017-01-06T00:00:00Z", record_data.fetch("last_sign_in_at"))
48+
assert_equal("10.11.2.4", record_data.fetch("last_sign_in_ip"))
49+
assert_equal("Provider2", record_data.fetch("last_sign_in_provider"))
50+
assert_equal("2017-01-07T00:00:00Z", record_data.fetch("locked_at"))
51+
assert_equal("Name", record_data.fetch("name"))
52+
assert_equal("Notes", record_data.fetch("notes"))
53+
assert_equal("2017-01-04T00:00:00Z", record_data.fetch("remember_created_at"))
54+
assert_equal("2017-01-03T00:00:00Z", record_data.fetch("reset_password_sent_at"))
55+
assert_equal(10, record_data.fetch("sign_in_count"))
56+
assert_equal(true, record_data.fetch("superuser"))
57+
assert_equal("2017-01-02T00:00:00Z", record_data.fetch("updated_at"))
58+
assert_match_uuid(record_data.fetch("updated_by"))
59+
assert_equal(record.updated_by, record_data.fetch("updated_by"))
60+
assert_match(/@example.com/, record_data.fetch("username"))
61+
end
62+
63+
def test_empty_attributes_response_fields
64+
record = FactoryGirl.create(:empty_attributes_admin)
65+
66+
response = Typhoeus.get(data_tables_api_url, http_options.deep_merge(admin_token).deep_merge({
67+
:params => {
68+
:search => { :value => record.id },
69+
},
70+
}))
71+
assert_response_code(200, response)
72+
data = MultiJson.load(response.body)
73+
assert_data_tables_root_fields(data)
74+
assert_equal(1, data.fetch("data").length)
75+
76+
record_data = data.fetch("data").first
77+
assert_base_record_fields(record_data)
78+
79+
assert_nil(record_data.fetch("created_by"))
80+
assert_nil(record_data.fetch("updated_by"))
81+
assert_equal([], record_data.fetch("group_ids"))
82+
assert_equal(["Superuser"], record_data.fetch("group_names"))
83+
end
84+
85+
def test_search_name
86+
assert_data_tables_search(:name, "NameSearchTest", "amesearcht")
87+
end
88+
89+
def test_search_email
90+
assert_data_tables_search(:email, "EmailSearchTest@example.com", "mailsearchtest@exampl")
91+
end
92+
93+
def test_search_username
94+
assert_data_tables_search(:username, "usernametest", "ernametes")
95+
end
96+
97+
def test_order_email
98+
assert_data_tables_order(:email, ["a@example.com", "b@example.com"])
99+
end
100+
101+
def test_order_current_sign_in_at
102+
assert_data_tables_order(:current_sign_in_at, [Time.utc(2017, 1, 1), Time.utc(2017, 1, 2)])
103+
end
104+
105+
def test_order_created_at
106+
assert_data_tables_order(:created_at, [Time.utc(2017, 1, 1), Time.utc(2017, 1, 2)])
107+
end
108+
15109
private
16110

17111
def data_tables_api_url
@@ -25,4 +119,46 @@ def data_tables_factory_name
25119
def data_tables_record_count
26120
Admin.where(:deleted_at => nil).count
27121
end
122+
123+
def assert_base_record_fields(record_data)
124+
assert_equal([
125+
"created_at",
126+
"created_by",
127+
"current_sign_in_at",
128+
"current_sign_in_ip",
129+
"current_sign_in_provider",
130+
"deleted_at",
131+
"email",
132+
"failed_attempts",
133+
"group_ids",
134+
"group_names",
135+
"id",
136+
"last_sign_in_at",
137+
"last_sign_in_ip",
138+
"last_sign_in_provider",
139+
"locked_at",
140+
"name",
141+
"notes",
142+
"remember_created_at",
143+
"reset_password_sent_at",
144+
"sign_in_count",
145+
"superuser",
146+
"updated_at",
147+
"updated_by",
148+
"username",
149+
"version",
150+
].sort, record_data.keys.sort)
151+
assert_match_iso8601(record_data.fetch("created_at"))
152+
assert_nil(record_data.fetch("deleted_at"))
153+
assert_kind_of(String, record_data.fetch("email"))
154+
assert_kind_of(Integer, record_data.fetch("failed_attempts"))
155+
assert_kind_of(Array, record_data.fetch("group_ids"))
156+
assert_kind_of(Array, record_data.fetch("group_names"))
157+
assert_match_uuid(record_data.fetch("id"))
158+
assert_kind_of(Integer, record_data.fetch("sign_in_count"))
159+
assert_includes([true, false], record_data.fetch("superuser"))
160+
assert_match_iso8601(record_data.fetch("updated_at"))
161+
assert_kind_of(String, record_data.fetch("username"))
162+
assert_kind_of(Integer, record_data.fetch("version"))
163+
end
28164
end

test/factories/admins.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,33 @@
4040
end
4141
end
4242
end
43+
44+
factory :empty_attributes_admin do
45+
end
46+
47+
factory :filled_attributes_admin do
48+
created_at Time.utc(2017, 1, 1)
49+
created_by { SecureRandom.uuid }
50+
current_sign_in_at Time.utc(2017, 1, 5)
51+
current_sign_in_ip "10.11.2.3"
52+
current_sign_in_provider "Provider1"
53+
failed_attempts 3
54+
last_sign_in_at Time.utc(2017, 1, 6)
55+
last_sign_in_ip "10.11.2.4"
56+
last_sign_in_provider "Provider2"
57+
locked_at Time.utc(2017, 1, 7)
58+
name "Name"
59+
notes "Notes"
60+
remember_created_at Time.utc(2017, 1, 4)
61+
reset_password_sent_at Time.utc(2017, 1, 3)
62+
reset_password_token { SecureRandom.hex(20) }
63+
sign_in_count 10
64+
unlock_token { SecureRandom.hex(20) }
65+
updated_at Time.utc(2017, 1, 2)
66+
updated_by { SecureRandom.uuid }
67+
groups do
68+
[FactoryGirl.create(:admin_group, :name => "ExampleFilledGroup")]
69+
end
70+
end
4371
end
4472
end

test/support/models/admin.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,7 @@ class Admin
2222
field :failed_attempts, :type => Integer, :default => 0
2323
field :unlock_token, :type => String
2424
field :locked_at, :type => Time
25+
field :created_by, :type => String
26+
field :updated_by, :type => String
2527
has_and_belongs_to_many :groups, :class_name => "AdminGroup", :inverse_of => nil
2628
end

0 commit comments

Comments
 (0)