Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(135)

Side by Side Diff: components/safe_browsing/password_protection/password_protection_service_unittest.cc

Issue 2747313002: PasswordProtectionService verdict cache management (Closed)
Patch Set: Cache verdict based on hostname Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/safe_browsing/password_protection/password_protection_service.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 #include "components/safe_browsing/password_protection/password_protection_servi ce.h" 4 #include "components/safe_browsing/password_protection/password_protection_servi ce.h"
5 5
6 #include "base/memory/ptr_util.h" 6 #include "base/memory/ptr_util.h"
7 #include "base/run_loop.h" 7 #include "base/run_loop.h"
8 #include "base/strings/string_number_conversions.h"
8 #include "base/test/histogram_tester.h" 9 #include "base/test/histogram_tester.h"
9 #include "components/safe_browsing_db/test_database_manager.h" 10 #include "components/safe_browsing_db/test_database_manager.h"
11 #include "components/sync_preferences/testing_pref_service_syncable.h"
10 #include "content/public/test/test_browser_thread_bundle.h" 12 #include "content/public/test/test_browser_thread_bundle.h"
11 #include "testing/gmock/include/gmock/gmock.h" 13 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h" 14 #include "testing/gtest/include/gtest/gtest.h"
13 15
14 namespace { 16 namespace {
15 17
16 const char kPasswordReuseMatchWhitelistHistogramName[] = 18 const char kPasswordReuseMatchWhitelistHistogramName[] =
17 "PasswordManager.PasswordReuse.MainFrameMatchCsdWhitelist"; 19 "PasswordManager.PasswordReuse.MainFrameMatchCsdWhitelist";
18 const char kWhitelistedUrl[] = "http://inwhitelist.com"; 20 const char kWhitelistedUrl[] = "http://inwhitelist.com";
19 const char kNoneWhitelistedUrl[] = "http://notinwhitelist.com"; 21 const char kNoneWhitelistedUrl[] = "http://notinwhitelist.com";
(...skipping 12 matching lines...) Expand all
32 ~MockSafeBrowsingDatabaseManager() override {} 34 ~MockSafeBrowsingDatabaseManager() override {}
33 35
34 private: 36 private:
35 DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager); 37 DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager);
36 }; 38 };
37 39
38 class PasswordProtectionServiceTest : public testing::Test { 40 class PasswordProtectionServiceTest : public testing::Test {
39 public: 41 public:
40 PasswordProtectionServiceTest(){}; 42 PasswordProtectionServiceTest(){};
41 43
44 ~PasswordProtectionServiceTest() override {
45 content_setting_map_->ShutdownOnUIThread();
46 }
47
48 LoginReputationClientResponse CreateVerdictProto(
49 LoginReputationClientResponse::VerdictType verdict,
50 int cache_duration_sec,
51 const std::string& cache_expression,
52 bool exact_match) {
53 LoginReputationClientResponse verdict_proto;
54 verdict_proto.set_verdict_type(verdict);
55 verdict_proto.set_cache_duration_sec(cache_duration_sec);
56 verdict_proto.set_cache_expression(cache_expression);
57 verdict_proto.set_cache_expression_exact_match(exact_match);
58 return verdict_proto;
59 }
60
42 void SetUp() override { 61 void SetUp() override {
43 database_manager_ = new MockSafeBrowsingDatabaseManager(); 62 database_manager_ = new MockSafeBrowsingDatabaseManager();
44 password_protection_service_ = 63 password_protection_service_ =
45 base::MakeUnique<PasswordProtectionService>(database_manager_); 64 base::MakeUnique<PasswordProtectionService>(database_manager_);
65 HostContentSettingsMap::RegisterProfilePrefs(test_pref_service_.registry());
66 content_setting_map_ = new HostContentSettingsMap(
67 &test_pref_service_, false /* incognito */, false /* guest_profile */);
68 }
69
70 bool PathVariantsMatchCacheExpression(const GURL& url,
71 const std::string& cache_expression) {
72 std::vector<std::string> paths;
73 PasswordProtectionService::GeneratePathVariantsWithoutQuery(url, &paths);
74 return PasswordProtectionService::PathVariantsMatchCacheExpression(
75 paths,
76 PasswordProtectionService::GetCacheExpressionPath(cache_expression));
77 }
78
79 bool PathMatchCacheExpressionExactly(const GURL& url,
80 const std::string& cache_expression) {
81 std::vector<std::string> paths;
82 PasswordProtectionService::GeneratePathVariantsWithoutQuery(url, &paths);
83 return PasswordProtectionService::PathMatchCacheExpressionExactly(
84 paths,
85 PasswordProtectionService::GetCacheExpressionPath(cache_expression));
86 }
87
88 void CacheVerdict(const GURL& url,
89 LoginReputationClientResponse::VerdictType verdict,
90 int cache_duration_sec,
91 const std::string& cache_expression,
92 bool exact_match,
93 const base::Time& verdict_received_time) {
94 LoginReputationClientResponse response(CreateVerdictProto(
95 verdict, cache_duration_sec, cache_expression, exact_match));
96 password_protection_service_->CacheVerdict(
97 url, &response, verdict_received_time, content_setting_map_.get());
98 }
99
100 size_t GetPasswordProtectionSettingCount() {
101 ContentSettingsForOneType password_protection_settings;
102 content_setting_map_->GetSettingsForOneType(
103 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(),
104 &password_protection_settings);
105 return password_protection_settings.size();
106 }
107
108 size_t GetVerdictCountForOrigin(const GURL& origin_url) {
109 std::unique_ptr<base::DictionaryValue> verdict_dictionary =
110 base::DictionaryValue::From(content_setting_map_->GetWebsiteSetting(
111 origin_url, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
112 std::string(), nullptr));
113 return verdict_dictionary->size();
46 } 114 }
47 115
48 protected: 116 protected:
49 // |thread_bundle_| is needed here because this test involves both UI and IO 117 // |thread_bundle_| is needed here because this test involves both UI and IO
50 // threads. 118 // threads.
51 content::TestBrowserThreadBundle thread_bundle_; 119 content::TestBrowserThreadBundle thread_bundle_;
52 scoped_refptr<MockSafeBrowsingDatabaseManager> database_manager_; 120 scoped_refptr<MockSafeBrowsingDatabaseManager> database_manager_;
53 std::unique_ptr<PasswordProtectionService> password_protection_service_; 121 std::unique_ptr<PasswordProtectionService> password_protection_service_;
122 sync_preferences::TestingPrefServiceSyncable test_pref_service_;
123 scoped_refptr<HostContentSettingsMap> content_setting_map_;
54 }; 124 };
55 125
56 TEST_F(PasswordProtectionServiceTest, 126 TEST_F(PasswordProtectionServiceTest,
57 TestPasswordReuseMatchWhitelistHistogram) { 127 TestPasswordReuseMatchWhitelistHistogram) {
58 const GURL whitelisted_url(kWhitelistedUrl); 128 const GURL whitelisted_url(kWhitelistedUrl);
59 const GURL not_whitelisted_url(kNoneWhitelistedUrl); 129 const GURL not_whitelisted_url(kNoneWhitelistedUrl);
60 EXPECT_CALL(*database_manager_.get(), MatchCsdWhitelistUrl(whitelisted_url)) 130 EXPECT_CALL(*database_manager_.get(), MatchCsdWhitelistUrl(whitelisted_url))
61 .WillOnce(testing::Return(true)); 131 .WillOnce(testing::Return(true));
62 EXPECT_CALL(*database_manager_.get(), 132 EXPECT_CALL(*database_manager_.get(),
63 MatchCsdWhitelistUrl(not_whitelisted_url)) 133 MatchCsdWhitelistUrl(not_whitelisted_url))
(...skipping 14 matching lines...) Expand all
78 testing::ElementsAre(base::Bucket(1, 1))); 148 testing::ElementsAre(base::Bucket(1, 1)));
79 149
80 // Non-whitelisted url should increase "False" bucket by 1. 150 // Non-whitelisted url should increase "False" bucket by 1.
81 password_protection_service_->RecordPasswordReuse(not_whitelisted_url); 151 password_protection_service_->RecordPasswordReuse(not_whitelisted_url);
82 base::RunLoop().RunUntilIdle(); 152 base::RunLoop().RunUntilIdle();
83 EXPECT_THAT( 153 EXPECT_THAT(
84 histograms.GetAllSamples(kPasswordReuseMatchWhitelistHistogramName), 154 histograms.GetAllSamples(kPasswordReuseMatchWhitelistHistogramName),
85 testing::ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1))); 155 testing::ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1)));
86 } 156 }
87 157
158 TEST_F(PasswordProtectionServiceTest, TestParseInvalidVerdictEntry) {
159 std::unique_ptr<base::DictionaryValue> invalid_verdict_entry =
160 base::MakeUnique<base::DictionaryValue>();
161 invalid_verdict_entry->SetString("cache_creation_time", "invalid_time");
162
163 int cache_creation_time;
164 LoginReputationClientResponse response;
165 // ParseVerdictEntry fails if input is empty.
166 EXPECT_FALSE(PasswordProtectionService::ParseVerdictEntry(
167 nullptr, &cache_creation_time, &response));
168
169 // ParseVerdictEntry fails if the input dict value is invalid.
170 EXPECT_FALSE(PasswordProtectionService::ParseVerdictEntry(
171 invalid_verdict_entry.get(), &cache_creation_time, &response));
172 }
173
174 TEST_F(PasswordProtectionServiceTest, TestParseValidVerdictEntry) {
175 base::Time expected_creation_time = base::Time::Now();
176 LoginReputationClientResponse expected_verdict(CreateVerdictProto(
177 LoginReputationClientResponse::SAFE, 10 * 60, "test.com/foo", true));
178 std::unique_ptr<base::DictionaryValue> valid_verdict_entry =
179 PasswordProtectionService::CreateDictionaryFromVerdict(
180 &expected_verdict, expected_creation_time);
181
182 int actual_cache_creation_time;
183 LoginReputationClientResponse actual_verdict;
184 ASSERT_TRUE(PasswordProtectionService::ParseVerdictEntry(
185 valid_verdict_entry.get(), &actual_cache_creation_time, &actual_verdict));
186
187 EXPECT_EQ(static_cast<int>(expected_creation_time.ToDoubleT()),
188 actual_cache_creation_time);
189 EXPECT_EQ(expected_verdict.cache_duration_sec(),
190 actual_verdict.cache_duration_sec());
191 EXPECT_EQ(expected_verdict.verdict_type(), actual_verdict.verdict_type());
192 EXPECT_EQ(expected_verdict.cache_expression(),
193 actual_verdict.cache_expression());
194 EXPECT_EQ(expected_verdict.cache_expression_exact_match(),
195 actual_verdict.cache_expression_exact_match());
196 }
197
198 TEST_F(PasswordProtectionServiceTest, TestPathVariantsMatchCacheExpression) {
199 // Cache expression without path.
200 std::string cache_expression("google.com");
201 std::string cache_expression_with_slash("google.com/");
202 EXPECT_TRUE(PathVariantsMatchCacheExpression(GURL("https://www.google.com"),
203 cache_expression));
204 EXPECT_TRUE(PathVariantsMatchCacheExpression(GURL("https://www.google.com"),
205 cache_expression_with_slash));
206 EXPECT_TRUE(PathVariantsMatchCacheExpression(GURL("https://www.google.com/"),
207 cache_expression));
208 EXPECT_TRUE(PathVariantsMatchCacheExpression(GURL("https://www.google.com/"),
209 cache_expression_with_slash));
210 EXPECT_TRUE(PathVariantsMatchCacheExpression(
211 GURL("https://www.google.com/maps/local/"), cache_expression));
212 EXPECT_TRUE(PathVariantsMatchCacheExpression(
213 GURL("https://www.google.com/maps/local/"), cache_expression_with_slash));
214
215 // Cache expression with path.
216 cache_expression = "evil.com/bad";
217 cache_expression_with_slash = "evil.com/bad/";
218 EXPECT_TRUE(PathVariantsMatchCacheExpression(GURL("http://evil.com/bad/"),
219 cache_expression));
220 EXPECT_TRUE(PathVariantsMatchCacheExpression(GURL("http://evil.com/bad/"),
221 cache_expression_with_slash));
222 EXPECT_TRUE(PathVariantsMatchCacheExpression(
223 GURL("http://evil.com/bad/index.html"), cache_expression));
224 EXPECT_TRUE(PathVariantsMatchCacheExpression(
225 GURL("http://evil.com/bad/index.html"), cache_expression_with_slash));
226 EXPECT_TRUE(PathVariantsMatchCacheExpression(
227 GURL("http://evil.com/bad/foo/index.html"), cache_expression));
228 EXPECT_TRUE(PathVariantsMatchCacheExpression(
229 GURL("http://evil.com/bad/foo/index.html"), cache_expression_with_slash));
230 EXPECT_FALSE(PathVariantsMatchCacheExpression(
231 GURL("http://evil.com/worse/index.html"), cache_expression));
232 EXPECT_FALSE(PathVariantsMatchCacheExpression(
233 GURL("http://evil.com/worse/index.html"), cache_expression_with_slash));
234 }
235
236 TEST_F(PasswordProtectionServiceTest, TestPathMatchCacheExpressionExactly) {
237 // Cache expression without path.
238 std::string cache_expression("www.google.com");
239 EXPECT_TRUE(PathMatchCacheExpressionExactly(GURL("https://www.google.com"),
240 cache_expression));
241 EXPECT_TRUE(PathMatchCacheExpressionExactly(GURL("https://www.google.com/"),
242 cache_expression));
243 EXPECT_TRUE(PathMatchCacheExpressionExactly(
244 GURL("https://www.google.com/index.html"), cache_expression));
245 EXPECT_FALSE(PathMatchCacheExpressionExactly(
246 GURL("https://www.google.com/abc/"), cache_expression));
247 EXPECT_FALSE(PathMatchCacheExpressionExactly(
248 GURL("https://www.google.com/def/login"), cache_expression));
249
250 // Cache expression with path.
251 cache_expression = "evil.com/bad";
252 EXPECT_FALSE(PathMatchCacheExpressionExactly(GURL("http://evil.com"),
253 cache_expression));
254 EXPECT_FALSE(PathMatchCacheExpressionExactly(GURL("http://evil.com/"),
255 cache_expression));
256 EXPECT_TRUE(PathMatchCacheExpressionExactly(GURL("http://evil.com/bad/"),
257 cache_expression));
258 EXPECT_TRUE(PathMatchCacheExpressionExactly(
259 GURL("http://evil.com/bad/index.html"), cache_expression));
260 EXPECT_FALSE(PathMatchCacheExpressionExactly(GURL("http://evil.com/bad/abc/"),
261 cache_expression));
262 EXPECT_FALSE(PathMatchCacheExpressionExactly(
263 GURL("http://evil.com/bad/abc/login.jsp"), cache_expression));
264 }
265
266 TEST_F(PasswordProtectionServiceTest, TestCachedVerdicts) {
267 ASSERT_EQ(0U, GetPasswordProtectionSettingCount());
268 // Assume each verdict has a TTL of 10 minutes.
269 // Cache a verdict for http://www.test.com/foo/index.html
270 CacheVerdict(GURL("http://www.test.com/foo/index.html"),
271 LoginReputationClientResponse::SAFE, 10 * 60, "test.com/foo",
272 false, base::Time::Now());
273
274 EXPECT_EQ(1U, GetPasswordProtectionSettingCount());
275 EXPECT_EQ(1U, GetVerdictCountForOrigin(
276 GURL("http://www.test.com/foo/index.html").GetOrigin()));
277
278 // Cache another verdict with the some origin and cache_expression should
279 // override the cache.
280 CacheVerdict(GURL("http://www.test.com/foo/index2.html"),
281 LoginReputationClientResponse::PHISHING, 10 * 60, "test.com/foo",
282 false, base::Time::Now());
283 EXPECT_EQ(1U, GetPasswordProtectionSettingCount());
284 EXPECT_EQ(1U,
285 GetVerdictCountForOrigin(GURL("http://www.test.com/").GetOrigin()));
286 EXPECT_EQ(LoginReputationClientResponse::PHISHING,
287 password_protection_service_->GetCachedVerdict(
288 content_setting_map_.get(),
289 GURL("http://www.test.com/foo/index2.html")));
290
291 // Cache another verdict with the same origin but different cache_expression
292 // will not increase setting count, but will increase the number of verdicts
293 // in the given origin.
294 CacheVerdict(GURL("http://www.test.com/bar/index2.html"),
295 LoginReputationClientResponse::SAFE, 10 * 60, "test.com/bar",
296 false, base::Time::Now());
297 EXPECT_EQ(1U, GetPasswordProtectionSettingCount());
298 EXPECT_EQ(2U,
299 GetVerdictCountForOrigin(GURL("http://www.test.com/").GetOrigin()));
300 }
301
302 TEST_F(PasswordProtectionServiceTest, TestGetCachedVerdicts) {
303 ASSERT_EQ(0U, GetPasswordProtectionSettingCount());
304 // Prepare 3 verdicts of the same origin with different cache expressions:
305 // (1) require exact match, not expired.
306 // (2) not require exact match, not expired.
307 // (3) require exact match, expired.
308 base::Time now = base::Time::Now();
309 CacheVerdict(GURL("http://test.com/login.html"),
310 LoginReputationClientResponse::SAFE, 10 * 60, "test.com", true,
311 now);
312 CacheVerdict(GURL("http://test.com/abc/index.jsp"),
313 LoginReputationClientResponse::LOW_REPUTATION, 10 * 60,
314 "test.com/abc", false, now);
315 CacheVerdict(
316 GURL("http://test.com/def/index.jsp"),
317 LoginReputationClientResponse::PHISHING, 10 * 60, "test.com/def", false,
318 base::Time::FromDoubleT(now.ToDoubleT() -
319 24.0 * 60.0 * 60.0)); // Yesterday, expired.
320 ASSERT_EQ(1U, GetPasswordProtectionSettingCount());
321
322 // Return VERDICT_TYPE_UNSPECIFIED if look up for a URL with unknown origin.
323 EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
324 password_protection_service_->GetCachedVerdict(
325 content_setting_map_.get(), GURL("http://www.unknown.com/")));
326
327 // Return VERDICT_TYPE_UNSPECIFIED if look up for a URL with http://test.com
328 // origin, but doesn't match any known cache_expression.
329 EXPECT_EQ(
330 LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
331 password_protection_service_->GetCachedVerdict(
332 content_setting_map_.get(), GURL("http://test.com/xyz/foo.jsp")));
333
334 // Return VERDICT_TYPE_UNSPECIFIED if look up for a URL whose variants match
335 // test.com/def, since corresponding entry is expired.
336 EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
337 password_protection_service_->GetCachedVerdict(
338 content_setting_map_.get(),
339 GURL("http://test.com/def/ghi/index.html")));
340
341 // Return VERDICT_TYPE_UNSPECIFIED if look up for a URL whose variants match
342 // test.com, but not match it exactly. Return SAFE if it is a exact match of
343 // test.com.
344 EXPECT_EQ(
345 LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
346 password_protection_service_->GetCachedVerdict(
347 content_setting_map_.get(), GURL("http://test.com/ghi/index.html")));
348 EXPECT_EQ(LoginReputationClientResponse::SAFE,
349 password_protection_service_->GetCachedVerdict(
350 content_setting_map_.get(),
351 GURL("http://test.com/term_of_service.html")));
352
353 // Return LOW_REPUTATION if look up for a URL whose variants match
354 // test.com/abc.
355 EXPECT_EQ(LoginReputationClientResponse::LOW_REPUTATION,
356 password_protection_service_->GetCachedVerdict(
357 content_setting_map_.get(), GURL("http://test.com/abc/")));
358 EXPECT_EQ(
359 LoginReputationClientResponse::LOW_REPUTATION,
360 password_protection_service_->GetCachedVerdict(
361 content_setting_map_.get(), GURL("http://test.com/abc/bar.jsp")));
362 EXPECT_EQ(LoginReputationClientResponse::LOW_REPUTATION,
363 password_protection_service_->GetCachedVerdict(
364 content_setting_map_.get(),
365 GURL("http://test.com/abc/foo/bar.html")));
366 }
367
368 TEST_F(PasswordProtectionServiceTest, TestCleanUpCachedVerdicts) {
369 ASSERT_EQ(0U, GetPasswordProtectionSettingCount());
370 // Prepare 2 verdicts. One is for origin "http://foo.com", and the other is
371 // for "http://bar.com".
372 base::Time now = base::Time::Now();
373 CacheVerdict(GURL("http://foo.com/abc/index.jsp"),
374 LoginReputationClientResponse::LOW_REPUTATION, 10 * 60,
375 "foo.com/abc", false, now);
376 CacheVerdict(GURL("http://bar.com/index.jsp"),
377 LoginReputationClientResponse::PHISHING, 10 * 60, "bar.com",
378 false, now);
379 ASSERT_EQ(2U, GetPasswordProtectionSettingCount());
380
381 // Delete a bar.com URL. Corresponding content setting keyed on
382 // origin "http://bar.com" should be removed,
383 history::URLRows deleted_urls;
384 deleted_urls.push_back(history::URLRow(GURL("http://bar.com")));
385 password_protection_service_->RemoveContentSettingsOnURLsDeleted(
386 false /* all_history */, deleted_urls, content_setting_map_.get());
387 EXPECT_EQ(1U, GetPasswordProtectionSettingCount());
388 EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
389 password_protection_service_->GetCachedVerdict(
390 content_setting_map_.get(), GURL("http://bar.com")));
391
392 // If delete all history. All password protection content settings should be
393 // gone.
394 password_protection_service_->RemoveContentSettingsOnURLsDeleted(
395 true /* all_history */, history::URLRows(), content_setting_map_.get());
396 EXPECT_EQ(0U, GetPasswordProtectionSettingCount());
397 }
398
88 } // namespace safe_browsing 399 } // namespace safe_browsing
OLDNEW
« no previous file with comments | « components/safe_browsing/password_protection/password_protection_service.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698