Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 LoginReputationClientResponse verdict_proto; | |
| 53 verdict_proto.set_verdict_type(verdict); | |
| 54 verdict_proto.set_cache_duration_sec(cache_duration_sec); | |
| 55 verdict_proto.set_cache_expression(cache_expression); | |
| 56 return verdict_proto; | |
| 57 } | |
| 58 | |
| 42 void SetUp() override { | 59 void SetUp() override { |
| 43 database_manager_ = new MockSafeBrowsingDatabaseManager(); | 60 database_manager_ = new MockSafeBrowsingDatabaseManager(); |
| 44 password_protection_service_ = | 61 password_protection_service_ = |
| 45 base::MakeUnique<PasswordProtectionService>(database_manager_); | 62 base::MakeUnique<PasswordProtectionService>(database_manager_); |
| 63 HostContentSettingsMap::RegisterProfilePrefs(test_pref_service_.registry()); | |
| 64 content_setting_map_ = new HostContentSettingsMap( | |
| 65 &test_pref_service_, false /* incognito */, false /* guest_profile */); | |
| 46 } | 66 } |
| 47 | 67 |
| 48 protected: | 68 protected: |
| 49 // |thread_bundle_| is needed here because this test involves both UI and IO | 69 // |thread_bundle_| is needed here because this test involves both UI and IO |
| 50 // threads. | 70 // threads. |
| 51 content::TestBrowserThreadBundle thread_bundle_; | 71 content::TestBrowserThreadBundle thread_bundle_; |
| 52 scoped_refptr<MockSafeBrowsingDatabaseManager> database_manager_; | 72 scoped_refptr<MockSafeBrowsingDatabaseManager> database_manager_; |
| 53 std::unique_ptr<PasswordProtectionService> password_protection_service_; | 73 std::unique_ptr<PasswordProtectionService> password_protection_service_; |
| 74 sync_preferences::TestingPrefServiceSyncable test_pref_service_; | |
| 75 scoped_refptr<HostContentSettingsMap> content_setting_map_; | |
| 54 }; | 76 }; |
| 55 | 77 |
| 56 TEST_F(PasswordProtectionServiceTest, | 78 TEST_F(PasswordProtectionServiceTest, |
| 57 TestPasswordReuseMatchWhitelistHistogram) { | 79 TestPasswordReuseMatchWhitelistHistogram) { |
| 58 const GURL whitelisted_url(kWhitelistedUrl); | 80 const GURL whitelisted_url(kWhitelistedUrl); |
| 59 const GURL not_whitelisted_url(kNoneWhitelistedUrl); | 81 const GURL not_whitelisted_url(kNoneWhitelistedUrl); |
| 60 EXPECT_CALL(*database_manager_.get(), MatchCsdWhitelistUrl(whitelisted_url)) | 82 EXPECT_CALL(*database_manager_.get(), MatchCsdWhitelistUrl(whitelisted_url)) |
| 61 .WillOnce(testing::Return(true)); | 83 .WillOnce(testing::Return(true)); |
| 62 EXPECT_CALL(*database_manager_.get(), | 84 EXPECT_CALL(*database_manager_.get(), |
| 63 MatchCsdWhitelistUrl(not_whitelisted_url)) | 85 MatchCsdWhitelistUrl(not_whitelisted_url)) |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 78 testing::ElementsAre(base::Bucket(1, 1))); | 100 testing::ElementsAre(base::Bucket(1, 1))); |
| 79 | 101 |
| 80 // Non-whitelisted url should increase "False" bucket by 1. | 102 // Non-whitelisted url should increase "False" bucket by 1. |
| 81 password_protection_service_->RecordPasswordReuse(not_whitelisted_url); | 103 password_protection_service_->RecordPasswordReuse(not_whitelisted_url); |
| 82 base::RunLoop().RunUntilIdle(); | 104 base::RunLoop().RunUntilIdle(); |
| 83 EXPECT_THAT( | 105 EXPECT_THAT( |
| 84 histograms.GetAllSamples(kPasswordReuseMatchWhitelistHistogramName), | 106 histograms.GetAllSamples(kPasswordReuseMatchWhitelistHistogramName), |
| 85 testing::ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1))); | 107 testing::ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1))); |
| 86 } | 108 } |
| 87 | 109 |
| 110 TEST_F(PasswordProtectionServiceTest, TestParseVerdictEntry) { | |
|
Nathan Parker
2017/03/16 21:27:11
nit: split valid/invalid cases into two tests, sin
Jialiu Lin
2017/03/18 23:46:32
Done.
| |
| 111 int now_in_sec = static_cast<int>(base::Time::Now().ToDoubleT()); | |
| 112 std::unique_ptr<base::DictionaryValue> valid_verdict_entry = | |
| 113 base::MakeUnique<base::DictionaryValue>(); | |
| 114 valid_verdict_entry->SetInteger("cache_ttl", 10 * 60); | |
| 115 valid_verdict_entry->SetInteger("cache_creation_time", now_in_sec); | |
| 116 valid_verdict_entry->SetInteger("verdict", 1 /* SAFE */); | |
| 117 | |
| 118 std::unique_ptr<base::DictionaryValue> invalid_verdict_entry = | |
| 119 base::MakeUnique<base::DictionaryValue>(); | |
| 120 invalid_verdict_entry->SetString("cache_ttl", "invalid_ttl"); | |
| 121 | |
| 122 int cache_creation_time, cache_ttl, verdict_type_value; | |
| 123 // ParseVerdictEntry fails if input is empty. | |
| 124 EXPECT_FALSE(PasswordProtectionService::ParseVerdictEntry( | |
| 125 nullptr, &cache_creation_time, &cache_ttl, &verdict_type_value)); | |
| 126 | |
| 127 // ParseVerdictEntry fails if the input dict value is invalid. | |
| 128 EXPECT_FALSE(PasswordProtectionService::ParseVerdictEntry( | |
| 129 invalid_verdict_entry.get(), &cache_creation_time, &cache_ttl, | |
| 130 &verdict_type_value)); | |
| 131 | |
| 132 // ParseVerdictEntry success case. | |
| 133 ASSERT_TRUE(PasswordProtectionService::ParseVerdictEntry( | |
| 134 valid_verdict_entry.get(), &cache_creation_time, &cache_ttl, | |
| 135 &verdict_type_value)); | |
| 136 EXPECT_EQ(600, cache_ttl); | |
| 137 EXPECT_EQ(now_in_sec, cache_creation_time); | |
| 138 EXPECT_EQ(LoginReputationClientResponse::SAFE, | |
| 139 static_cast<LoginReputationClientResponse::VerdictType>( | |
| 140 verdict_type_value)); | |
| 141 } | |
| 142 | |
| 143 TEST_F(PasswordProtectionServiceTest, TestUrlMatchCacheExpression) { | |
| 144 // Cache expression without path. | |
| 145 std::string cache_expression("google.com"); | |
| 146 EXPECT_TRUE(PasswordProtectionService::UrlMatchCacheExpression( | |
| 147 GURL("https://www.google.com"), cache_expression)); | |
|
Nathan Parker
2017/03/16 21:27:11
How about w/ and w/o the trailing slash? Is there
Jialiu Lin
2017/03/18 23:46:32
Sure.
| |
| 148 EXPECT_TRUE(PasswordProtectionService::UrlMatchCacheExpression( | |
| 149 GURL("http://google.com"), cache_expression)); | |
| 150 EXPECT_TRUE(PasswordProtectionService::UrlMatchCacheExpression( | |
| 151 GURL("https://maps.google.com"), cache_expression)); | |
| 152 EXPECT_TRUE(PasswordProtectionService::UrlMatchCacheExpression( | |
| 153 GURL("https://www.google.com/maps/local/"), cache_expression)); | |
| 154 | |
| 155 // Cache expression with sub-domain. | |
| 156 cache_expression = "maps.google.com"; | |
| 157 EXPECT_FALSE(PasswordProtectionService::UrlMatchCacheExpression( | |
| 158 GURL("https://google.com"), cache_expression)); | |
| 159 EXPECT_FALSE(PasswordProtectionService::UrlMatchCacheExpression( | |
| 160 GURL("https://www.google.com"), cache_expression)); | |
| 161 EXPECT_TRUE(PasswordProtectionService::UrlMatchCacheExpression( | |
| 162 GURL("https://maps.google.com"), cache_expression)); | |
| 163 EXPECT_TRUE(PasswordProtectionService::UrlMatchCacheExpression( | |
| 164 GURL("https://maps.google.com/local/"), cache_expression)); | |
| 165 | |
| 166 // Cache expression with path. | |
| 167 cache_expression = std::string("evil.com/bad"); | |
| 168 EXPECT_TRUE(PasswordProtectionService::UrlMatchCacheExpression( | |
| 169 GURL("http://evil.com/bad/index.html"), cache_expression)); | |
| 170 EXPECT_FALSE(PasswordProtectionService::UrlMatchCacheExpression( | |
| 171 GURL("http://evil.com/worse/index.html"), cache_expression)); | |
| 172 EXPECT_TRUE(PasswordProtectionService::UrlMatchCacheExpression( | |
| 173 GURL("http://phishing.malware.evil.com/bad/index.html"), | |
| 174 cache_expression)); | |
| 175 } | |
| 176 | |
| 177 TEST_F(PasswordProtectionServiceTest, TestSetGetAndClearCachedVerdict) { | |
| 178 // Assume each verdict has a TTL of 10 minutes. | |
| 179 LoginReputationClientResponse verdict_proto_1(CreateVerdictProto( | |
| 180 LoginReputationClientResponse::SAFE, 10 * 60, "test.com/foo")); | |
| 181 LoginReputationClientResponse verdict_proto_2(CreateVerdictProto( | |
| 182 LoginReputationClientResponse::LOW_REPUTATION, 10 * 60, "test.com/bar")); | |
| 183 LoginReputationClientResponse verdict_proto_3(CreateVerdictProto( | |
| 184 LoginReputationClientResponse::PHISHING, 10 * 60, "evil.com")); | |
| 185 | |
| 186 base::Time now = base::Time::Now(); | |
| 187 base::Time yesterday = | |
| 188 base::Time::FromDoubleT(now.ToDoubleT() - 24.0 * 60.0 * 60.0); | |
| 189 base::Time one_minute_ago = base::Time::FromDoubleT(now.ToDoubleT() - 60.0); | |
| 190 password_protection_service_->CacheVerdict( | |
|
Nathan Parker
2017/03/16 21:27:11
nit: I find these a bit hard to reason about. Wou
Jialiu Lin
2017/03/18 23:46:32
Regrouped test case.
There are multiple SAFE enum
| |
| 191 content_setting_map_.get(), GURL("http://www.test.com/foo/index.html"), | |
| 192 &verdict_proto_1, now); | |
| 193 password_protection_service_->CacheVerdict( | |
| 194 content_setting_map_.get(), GURL("http://www.test.com/bar/index.html"), | |
| 195 &verdict_proto_2, yesterday); | |
| 196 password_protection_service_->CacheVerdict( | |
| 197 content_setting_map_.get(), | |
| 198 GURL("http://phishing.evil.com/local/login.html"), &verdict_proto_3, | |
| 199 one_minute_ago); | |
| 200 | |
| 201 // Return VERDICT_TYPE_UNSPECIFIED if content setting map has nothing of this | |
| 202 // origin. | |
| 203 EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED, | |
| 204 password_protection_service_->GetCachedVerdict( | |
| 205 content_setting_map_.get(), | |
| 206 GURL("http://www.unkown.com/index.html"))); | |
|
Nathan Parker
2017/03/16 21:27:11
(nit: www.unknown.com)
Jialiu Lin
2017/03/18 23:46:32
Good eye!
| |
| 207 | |
| 208 // Return VERDICT_TYPE_UNSPECIFIED if verdict is expired. | |
| 209 EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED, | |
| 210 password_protection_service_->GetCachedVerdict( | |
| 211 content_setting_map_.get(), | |
| 212 GURL("http://www.test.com/bar/test.html"))); | |
| 213 | |
| 214 // Return its corresponding verdict type if verdict is available and not | |
| 215 // expired. | |
| 216 EXPECT_EQ(LoginReputationClientResponse::SAFE, | |
| 217 password_protection_service_->GetCachedVerdict( | |
| 218 content_setting_map_.get(), | |
| 219 GURL("http://www.test.com/foo/index1.html"))); | |
| 220 EXPECT_EQ(LoginReputationClientResponse::PHISHING, | |
| 221 password_protection_service_->GetCachedVerdict( | |
| 222 content_setting_map_.get(), | |
| 223 GURL("http://phishing.evil.com/phishing/"))); | |
| 224 | |
| 225 // Cache www.test.com/bar again, but this time it is not expired. | |
| 226 password_protection_service_->CacheVerdict( | |
| 227 content_setting_map_.get(), GURL("http://www.test.com/bar/index.html"), | |
| 228 &verdict_proto_2, now); | |
| 229 EXPECT_EQ(LoginReputationClientResponse::LOW_REPUTATION, | |
| 230 password_protection_service_->GetCachedVerdict( | |
| 231 content_setting_map_.get(), | |
| 232 GURL("http://www.test.com/bar/test2.html"))); | |
| 233 | |
| 234 // Now, there should be cached verdicts for 2 origins: http://www.test.com, | |
| 235 // and http://phishing.evil.com | |
| 236 ContentSettingsForOneType password_protection_settings; | |
| 237 content_setting_map_->GetSettingsForOneType( | |
| 238 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), | |
| 239 &password_protection_settings); | |
| 240 EXPECT_EQ(2U, password_protection_settings.size()); | |
| 241 | |
| 242 history::URLRows deleted_urls; | |
| 243 deleted_urls.push_back( | |
| 244 history::URLRow(GURL("http://phishing.evil.com/phishing/"))); | |
| 245 // We delete the history of http://phishing.evil.com/phishing. | |
| 246 password_protection_service_->RemoveContentSettingsOnURLsDeleted( | |
| 247 content_setting_map_.get(), false, deleted_urls); | |
| 248 content_setting_map_->GetSettingsForOneType( | |
| 249 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), | |
| 250 &password_protection_settings); | |
| 251 EXPECT_EQ(1U, password_protection_settings.size()); | |
| 252 EXPECT_EQ(LoginReputationClientResponse::LOW_REPUTATION, | |
| 253 password_protection_service_->GetCachedVerdict( | |
| 254 content_setting_map_.get(), | |
| 255 GURL("http://www.test.com/bar/test2.html"))); | |
| 256 | |
| 257 // Now we delete all history. All password protection content settings will be | |
| 258 // gone too. | |
| 259 password_protection_service_->RemoveContentSettingsOnURLsDeleted( | |
| 260 content_setting_map_.get(), true, deleted_urls); | |
| 261 content_setting_map_->GetSettingsForOneType( | |
| 262 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), | |
| 263 &password_protection_settings); | |
| 264 EXPECT_EQ(0U, password_protection_settings.size()); | |
| 265 } | |
|
Nathan Parker
2017/03/16 21:27:11
This is a long test testing multiple different thi
Jialiu Lin
2017/03/18 23:46:32
Done. Separated this one into 3 tests.
| |
| 266 | |
| 88 } // namespace safe_browsing | 267 } // namespace safe_browsing |
| OLD | NEW |