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
3 // found in the LICENSE file.
4 #include "components/safe_browsing/content/password_protection/password_protection_service.h"
5
6 #include <memory>
7
8 #include "base/bind.h"
9 #include "base/memory/ptr_util.h"
10 #include "base/run_loop.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/test/metrics/histogram_tester.h"
15 #include "base/test/null_task_runner.h"
16 #include "base/test/scoped_feature_list.h"
17 #include "base/time/time.h"
18 #include "base/timer/timer.h"
19 #include "build/build_config.h"
20 #include "components/content_settings/core/browser/host_content_settings_map.h"
21 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
22 #include "components/password_manager/core/browser/password_reuse_detector.h"
23 #include "components/safe_browsing/content/common/safe_browsing.mojom-forward.h"
24 #include "components/safe_browsing/content/common/safe_browsing.mojom.h"
25 #include "components/safe_browsing/content/password_protection/metrics_util.h"
26 #include "components/safe_browsing/content/password_protection/mock_password_protection_service.h"
27 #include "components/safe_browsing/content/password_protection/password_protection_navigation_throttle.h"
28 #include "components/safe_browsing/content/password_protection/password_protection_request.h"
29 #include "components/safe_browsing/core/db/test_database_manager.h"
30 #include "components/safe_browsing/core/features.h"
31 #include "components/safe_browsing/core/proto/csd.pb.h"
32 #include "components/safe_browsing/core/verdict_cache_manager.h"
33 #include "components/signin/public/identity_manager/account_info.h"
34 #include "components/sync_preferences/testing_pref_service_syncable.h"
35 #include "content/public/browser/web_contents.h"
36 #include "content/public/test/browser_task_environment.h"
37 #include "content/public/test/test_browser_context.h"
38 #include "content/public/test/test_renderer_host.h"
39 #include "content/public/test/web_contents_tester.h"
40 #include "mojo/public/cpp/bindings/pending_receiver.h"
41 #include "mojo/public/cpp/bindings/receiver.h"
42 #include "mojo/public/cpp/system/message_pipe.h"
43 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
44 #include "services/network/test/test_url_loader_factory.h"
45 #include "services/service_manager/public/cpp/interface_provider.h"
46 #include "testing/gmock/include/gmock/gmock.h"
47 #include "testing/gtest/include/gtest/gtest.h"
48
49 using base::ASCIIToUTF16;
50 using testing::_;
51 using testing::AnyNumber;
52 using testing::ElementsAre;
53 using testing::IsEmpty;
54 using testing::Return;
55
56 namespace {
57
58 const char kFormActionUrl[] = "https://form_action.com/";
59 const char kPasswordFrameUrl[] = "https://password_frame.com/";
60 const char kSavedDomain[] = "http://saved_domain.com";
61 const char kSavedDomain2[] = "http://saved_domain2.com";
62 const char kTargetUrl[] = "http://foo.com/";
63 const char kUserName[] = "username";
64
65 const unsigned int kMinute = 60;
66 const unsigned int kDay = 24 * 60 * kMinute;
67
68 } // namespace
69
70 namespace safe_browsing {
71
72 using PasswordReuseEvent = LoginReputationClientRequest::PasswordReuseEvent;
73
74 class MockSafeBrowsingDatabaseManager : public TestSafeBrowsingDatabaseManager {
75 public:
MockSafeBrowsingDatabaseManager()76 MockSafeBrowsingDatabaseManager() {}
77
78 MOCK_METHOD2(CheckCsdWhitelistUrl,
79 AsyncMatch(const GURL&, SafeBrowsingDatabaseManager::Client*));
80
81 protected:
~MockSafeBrowsingDatabaseManager()82 ~MockSafeBrowsingDatabaseManager() override {}
83
84 private:
85 DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager);
86 };
87
88 // PhishingDetector is not supported on Android.
89 #if !defined(OS_ANDROID)
90 class TestPhishingDetector : public mojom::PhishingDetector {
91 public:
TestPhishingDetector()92 TestPhishingDetector() : should_timeout_(false) {}
~TestPhishingDetector()93 ~TestPhishingDetector() override {}
94
Bind(mojo::ScopedMessagePipeHandle handle)95 void Bind(mojo::ScopedMessagePipeHandle handle) {
96 receiver_.Bind(
97 mojo::PendingReceiver<mojom::PhishingDetector>(std::move(handle)));
98 }
99
SetPhishingModel(const std::string & model)100 void SetPhishingModel(const std::string& model) override {}
101
StartPhishingDetection(const GURL & url,StartPhishingDetectionCallback callback)102 void StartPhishingDetection(
103 const GURL& url,
104 StartPhishingDetectionCallback callback) override {
105 if (should_timeout_) {
106 deferred_callbacks_.push_back(std::move(callback));
107 } else {
108 ReturnFeatures(url, std::move(callback));
109 }
110 }
ReturnFeatures(const GURL & url,StartPhishingDetectionCallback callback)111 void ReturnFeatures(const GURL& url,
112 StartPhishingDetectionCallback callback) {
113 ClientPhishingRequest verdict;
114 verdict.set_is_phishing(false);
115 verdict.set_client_score(0.1);
116 std::move(callback).Run(mojom::PhishingDetectorResult::SUCCESS,
117 verdict.SerializeAsString());
118 }
119
set_should_timeout(bool timeout)120 void set_should_timeout(bool timeout) { should_timeout_ = timeout; }
121
122 private:
123 bool should_timeout_;
124 std::vector<StartPhishingDetectionCallback> deferred_callbacks_;
125 mojo::Receiver<mojom::PhishingDetector> receiver_{this};
126
127 DISALLOW_COPY_AND_ASSIGN(TestPhishingDetector);
128 };
129 #endif
130
131 class TestPasswordProtectionService : public MockPasswordProtectionService {
132 public:
TestPasswordProtectionService(const scoped_refptr<SafeBrowsingDatabaseManager> & database_manager,scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,scoped_refptr<HostContentSettingsMap> content_setting_map)133 TestPasswordProtectionService(
134 const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
135 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
136 scoped_refptr<HostContentSettingsMap> content_setting_map)
137 : MockPasswordProtectionService(database_manager,
138 url_loader_factory,
139 nullptr),
140 cache_manager_(
141 std::make_unique<VerdictCacheManager>(nullptr,
142 content_setting_map.get())) {
143 cache_manager_->StopCleanUpTimerForTesting();
144 }
145
RequestFinished(PasswordProtectionRequest * request,RequestOutcome outcome,std::unique_ptr<LoginReputationClientResponse> response)146 void RequestFinished(
147 PasswordProtectionRequest* request,
148 RequestOutcome outcome,
149 std::unique_ptr<LoginReputationClientResponse> response) override {
150 latest_request_ = request;
151 latest_response_ = std::move(response);
152 run_loop_.Quit();
153 }
154
latest_response()155 LoginReputationClientResponse* latest_response() {
156 return latest_response_.get();
157 }
158
WaitForResponse()159 void WaitForResponse() { run_loop_.Run(); }
160
~TestPasswordProtectionService()161 ~TestPasswordProtectionService() override {}
162
GetPendingRequestsCount()163 size_t GetPendingRequestsCount() { return pending_requests_.size(); }
164
GetLatestRequestProto()165 const LoginReputationClientRequest* GetLatestRequestProto() {
166 return latest_request_ ? latest_request_->request_proto() : nullptr;
167 }
168
169 #if !defined(OS_ANDROID)
GetPhishingDetector(service_manager::InterfaceProvider * provider,mojo::Remote<mojom::PhishingDetector> * phishing_detector)170 void GetPhishingDetector(
171 service_manager::InterfaceProvider* provider,
172 mojo::Remote<mojom::PhishingDetector>* phishing_detector) override {
173 service_manager::InterfaceProvider::TestApi test_api(provider);
174 test_api.SetBinderForName(
175 mojom::PhishingDetector::Name_,
176 base::BindRepeating(&TestPhishingDetector::Bind,
177 base::Unretained(&test_phishing_detector_)));
178 provider->GetInterface(phishing_detector->BindNewPipeAndPassReceiver());
179 test_api.ClearBinderForName(mojom::PhishingDetector::Name_);
180 }
181 #endif
182
CacheVerdict(const GURL & url,LoginReputationClientRequest::TriggerType trigger_type,ReusedPasswordAccountType password_type,const LoginReputationClientResponse & verdict,const base::Time & receive_time)183 void CacheVerdict(const GURL& url,
184 LoginReputationClientRequest::TriggerType trigger_type,
185 ReusedPasswordAccountType password_type,
186 const LoginReputationClientResponse& verdict,
187 const base::Time& receive_time) override {
188 if (!CanGetReputationOfURL(url) || IsIncognito())
189 return;
190
191 cache_manager_->CachePhishGuardVerdict(trigger_type, password_type, verdict,
192 receive_time);
193 }
194
GetCachedVerdict(const GURL & url,LoginReputationClientRequest::TriggerType trigger_type,ReusedPasswordAccountType password_type,LoginReputationClientResponse * out_response)195 LoginReputationClientResponse::VerdictType GetCachedVerdict(
196 const GURL& url,
197 LoginReputationClientRequest::TriggerType trigger_type,
198 ReusedPasswordAccountType password_type,
199 LoginReputationClientResponse* out_response) override {
200 if (!url.is_valid() || !CanGetReputationOfURL(url))
201 return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED;
202
203 return cache_manager_->GetCachedPhishGuardVerdict(
204 url, trigger_type, password_type, out_response);
205 }
206
GetStoredVerdictCount(LoginReputationClientRequest::TriggerType trigger_type)207 int GetStoredVerdictCount(
208 LoginReputationClientRequest::TriggerType trigger_type) override {
209 return cache_manager_->GetStoredPhishGuardVerdictCount(trigger_type);
210 }
211
212 #if !defined(OS_ANDROID)
SetDomFeatureCollectionTimeout(bool should_timeout)213 void SetDomFeatureCollectionTimeout(bool should_timeout) {
214 test_phishing_detector_.set_should_timeout(should_timeout);
215 }
216 #endif
217
218 private:
219 PasswordProtectionRequest* latest_request_;
220 base::RunLoop run_loop_;
221 std::unique_ptr<LoginReputationClientResponse> latest_response_;
222 #if !defined(OS_ANDROID)
223 TestPhishingDetector test_phishing_detector_;
224 #endif
225
226 // The TestPasswordProtectionService manages its own cache, rather than using
227 // the global one.
228 std::unique_ptr<VerdictCacheManager> cache_manager_;
229
230 DISALLOW_COPY_AND_ASSIGN(TestPasswordProtectionService);
231 };
232
233 class MockPasswordProtectionNavigationThrottle
234 : public PasswordProtectionNavigationThrottle {
235 public:
MockPasswordProtectionNavigationThrottle(content::NavigationHandle * navigation_handle,scoped_refptr<PasswordProtectionRequest> request,bool is_warning_showing)236 MockPasswordProtectionNavigationThrottle(
237 content::NavigationHandle* navigation_handle,
238 scoped_refptr<PasswordProtectionRequest> request,
239 bool is_warning_showing)
240 : PasswordProtectionNavigationThrottle(navigation_handle,
241 request,
242 is_warning_showing) {}
243
244 private:
245 DISALLOW_COPY_AND_ASSIGN(MockPasswordProtectionNavigationThrottle);
246 };
247
248 class PasswordProtectionServiceTest : public ::testing::TestWithParam<bool> {
249 public:
PasswordProtectionServiceTest()250 PasswordProtectionServiceTest()
251 : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
252
CreateVerdictProto(LoginReputationClientResponse::VerdictType verdict,int cache_duration_sec,const std::string & cache_expression)253 LoginReputationClientResponse CreateVerdictProto(
254 LoginReputationClientResponse::VerdictType verdict,
255 int cache_duration_sec,
256 const std::string& cache_expression) {
257 LoginReputationClientResponse verdict_proto;
258 verdict_proto.set_verdict_type(verdict);
259 verdict_proto.set_cache_duration_sec(cache_duration_sec);
260 verdict_proto.set_cache_expression(cache_expression);
261 return verdict_proto;
262 }
263
SetUp()264 void SetUp() override {
265 HostContentSettingsMap::RegisterProfilePrefs(test_pref_service_.registry());
266 content_setting_map_ = new HostContentSettingsMap(
267 &test_pref_service_, false /* is_off_the_record */,
268 false /* store_last_modified */,
269 false /* restore_session*/);
270 database_manager_ = new MockSafeBrowsingDatabaseManager();
271 password_protection_service_ =
272 std::make_unique<TestPasswordProtectionService>(
273 database_manager_,
274 base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
275 &test_url_loader_factory_),
276 content_setting_map_);
277 EXPECT_CALL(*password_protection_service_, IsExtendedReporting())
278 .WillRepeatedly(Return(GetParam()));
279 EXPECT_CALL(*password_protection_service_, IsIncognito())
280 .WillRepeatedly(Return(false));
281 EXPECT_CALL(*password_protection_service_,
282 IsURLWhitelistedForPasswordEntry(_))
283 .WillRepeatedly(Return(false));
284 EXPECT_CALL(*password_protection_service_,
285 GetPasswordProtectionWarningTriggerPref(_))
286 .WillRepeatedly(Return(PASSWORD_PROTECTION_OFF));
287 EXPECT_CALL(*password_protection_service_, IsUserMBBOptedIn())
288 .WillRepeatedly(Return(true));
289 url_ = PasswordProtectionService::GetPasswordProtectionRequestUrl();
290 }
291
TearDown()292 void TearDown() override {
293 password_protection_service_.reset();
294 content_setting_map_->ShutdownOnUIThread();
295 }
296
297 // Sets up |database_manager_| and |pending_requests_| as needed.
InitializeAndStartPasswordOnFocusRequest(bool match_whitelist,int timeout_in_ms,content::WebContents * web_contents)298 void InitializeAndStartPasswordOnFocusRequest(
299 bool match_whitelist,
300 int timeout_in_ms,
301 content::WebContents* web_contents) {
302 GURL target_url(kTargetUrl);
303 EXPECT_CALL(*database_manager_, CheckCsdWhitelistUrl(target_url, _))
304 .WillRepeatedly(
305 Return(match_whitelist ? AsyncMatch::MATCH : AsyncMatch::NO_MATCH));
306
307 request_ = new PasswordProtectionRequest(
308 web_contents, target_url, GURL(kFormActionUrl), GURL(kPasswordFrameUrl),
309 kUserName, PasswordType::PASSWORD_TYPE_UNKNOWN, {},
310 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true,
311 password_protection_service_.get(), timeout_in_ms);
312 request_->Start();
313 }
314
InitializeAndStartPasswordEntryRequest(PasswordType type,const std::vector<password_manager::MatchingReusedCredential> & matching_reused_credentials,bool match_whitelist,int timeout_in_ms,content::WebContents * web_contents)315 void InitializeAndStartPasswordEntryRequest(
316 PasswordType type,
317 const std::vector<password_manager::MatchingReusedCredential>&
318 matching_reused_credentials,
319 bool match_whitelist,
320 int timeout_in_ms,
321 content::WebContents* web_contents) {
322 GURL target_url(kTargetUrl);
323 EXPECT_CALL(*database_manager_, CheckCsdWhitelistUrl(target_url, _))
324 .WillRepeatedly(
325 Return(match_whitelist ? AsyncMatch::MATCH : AsyncMatch::NO_MATCH));
326
327 request_ = new PasswordProtectionRequest(
328 web_contents, target_url, GURL(), GURL(), kUserName, type,
329 matching_reused_credentials,
330 LoginReputationClientRequest::PASSWORD_REUSE_EVENT, true,
331 password_protection_service_.get(), timeout_in_ms);
332 request_->Start();
333 }
334
CacheVerdict(const GURL & url,LoginReputationClientRequest::TriggerType trigger,ReusedPasswordAccountType password_type,LoginReputationClientResponse::VerdictType verdict,int cache_duration_sec,const std::string & cache_expression,const base::Time & verdict_received_time)335 void CacheVerdict(const GURL& url,
336 LoginReputationClientRequest::TriggerType trigger,
337 ReusedPasswordAccountType password_type,
338 LoginReputationClientResponse::VerdictType verdict,
339 int cache_duration_sec,
340 const std::string& cache_expression,
341 const base::Time& verdict_received_time) {
342 ASSERT_FALSE(cache_expression.empty());
343 LoginReputationClientResponse response(
344 CreateVerdictProto(verdict, cache_duration_sec, cache_expression));
345 password_protection_service_->CacheVerdict(url, trigger, password_type,
346 response, verdict_received_time);
347 }
348
CacheInvalidVerdict(ReusedPasswordAccountType password_type)349 void CacheInvalidVerdict(ReusedPasswordAccountType password_type) {
350 GURL invalid_hostname("http://invalid.com");
351 std::unique_ptr<base::DictionaryValue> verdict_dictionary =
352 base::DictionaryValue::From(content_setting_map_->GetWebsiteSetting(
353 invalid_hostname, GURL(), ContentSettingsType::PASSWORD_PROTECTION,
354 nullptr));
355
356 if (!verdict_dictionary)
357 verdict_dictionary = std::make_unique<base::DictionaryValue>();
358
359 std::unique_ptr<base::DictionaryValue> invalid_verdict_entry =
360 std::make_unique<base::DictionaryValue>();
361 invalid_verdict_entry->SetString("invalid", "invalid_string");
362
363 std::unique_ptr<base::DictionaryValue> invalid_cache_expression_entry =
364 std::make_unique<base::DictionaryValue>();
365 invalid_cache_expression_entry->SetWithoutPathExpansion(
366 "invalid_cache_expression", std::move(invalid_verdict_entry));
367 verdict_dictionary->SetWithoutPathExpansion(
368 base::NumberToString(static_cast<std::underlying_type_t<PasswordType>>(
369 password_protection_service_
370 ->ConvertReusedPasswordAccountTypeToPasswordType(
371 password_type))),
372 std::move(invalid_cache_expression_entry));
373 content_setting_map_->SetWebsiteSettingDefaultScope(
374 invalid_hostname, GURL(), ContentSettingsType::PASSWORD_PROTECTION,
375 std::move(verdict_dictionary));
376 }
377
GetStoredVerdictCount(LoginReputationClientRequest::TriggerType type)378 size_t GetStoredVerdictCount(LoginReputationClientRequest::TriggerType type) {
379 return password_protection_service_->GetStoredVerdictCount(type);
380 }
381
GetWebContents()382 std::unique_ptr<content::WebContents> GetWebContents() {
383 return base::WrapUnique(content::WebContentsTester::CreateTestWebContents(
384 content::WebContents::CreateParams(&browser_context_)));
385 }
386
387 // Visual features are not supported on Android.
388 #if !defined(OS_ANDROID)
VerifyContentAreaSizeCollection(const LoginReputationClientRequest & request)389 void VerifyContentAreaSizeCollection(
390 const LoginReputationClientRequest& request) {
391 bool should_report_content_size =
392 password_protection_service_->IsExtendedReporting() &&
393 !password_protection_service_->IsIncognito();
394 EXPECT_EQ(should_report_content_size, request.has_content_area_height());
395 EXPECT_EQ(should_report_content_size, request.has_content_area_width());
396 }
397 #endif
398
GetNumberOfNavigationThrottles()399 size_t GetNumberOfNavigationThrottles() {
400 return request_ ? request_->throttles_.size() : 0u;
401 }
402
403 protected:
404 // |task_environment_| is needed here because this test involves both UI and
405 // IO threads.
406 content::BrowserTaskEnvironment task_environment_;
407 scoped_refptr<MockSafeBrowsingDatabaseManager> database_manager_;
408 sync_preferences::TestingPrefServiceSyncable test_pref_service_;
409 scoped_refptr<HostContentSettingsMap> content_setting_map_;
410 GURL url_;
411 network::TestURLLoaderFactory test_url_loader_factory_;
412 std::unique_ptr<TestPasswordProtectionService> password_protection_service_;
413 scoped_refptr<PasswordProtectionRequest> request_;
414 base::HistogramTester histograms_;
415 content::TestBrowserContext browser_context_;
416 content::RenderViewHostTestEnabler rvh_test_enabler_;
417 };
418
TEST_P(PasswordProtectionServiceTest,TestCachePasswordReuseVerdicts)419 TEST_P(PasswordProtectionServiceTest, TestCachePasswordReuseVerdicts) {
420 ASSERT_EQ(0U, GetStoredVerdictCount(
421 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
422 EXPECT_CALL(*password_protection_service_, IsPrimaryAccountSignedIn())
423 .WillRepeatedly(Return(true));
424 // Assume each verdict has a TTL of 10 minutes.
425 // Cache a verdict for http://www.test.com/foo/index.html
426 ReusedPasswordAccountType reused_password_account_type;
427 reused_password_account_type.set_account_type(
428 ReusedPasswordAccountType::GSUITE);
429 reused_password_account_type.set_is_account_syncing(true);
430 CacheVerdict(GURL("http://www.test.com/foo/index.html"),
431 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
432 reused_password_account_type,
433 LoginReputationClientResponse::SAFE, 10 * kMinute,
434 "test.com/foo/", base::Time::Now());
435
436 EXPECT_EQ(1U, GetStoredVerdictCount(
437 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
438
439 // Cache another verdict with the some origin and cache_expression should
440 // override the cache.
441 CacheVerdict(GURL("http://www.test.com/foo/index2.html"),
442 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
443 reused_password_account_type,
444 LoginReputationClientResponse::PHISHING, 10 * kMinute,
445 "test.com/foo/", base::Time::Now());
446 EXPECT_EQ(1U, GetStoredVerdictCount(
447 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
448 LoginReputationClientResponse out_verdict;
449 EXPECT_EQ(LoginReputationClientResponse::PHISHING,
450 password_protection_service_->GetCachedVerdict(
451 GURL("http://www.test.com/foo/index2.html"),
452 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
453 reused_password_account_type, &out_verdict));
454
455 // Cache a password reuse verdict with a different password type but same
456 // origin and cache expression should add a new entry.
457 reused_password_account_type.set_account_type(
458 ReusedPasswordAccountType::NON_GAIA_ENTERPRISE);
459 CacheVerdict(GURL("http://www.test.com/foo/index2.html"),
460 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
461 reused_password_account_type,
462 LoginReputationClientResponse::PHISHING, 10 * kMinute,
463 "test.com/foo/", base::Time::Now());
464 EXPECT_EQ(2U, GetStoredVerdictCount(
465 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
466 EXPECT_EQ(LoginReputationClientResponse::PHISHING,
467 password_protection_service_->GetCachedVerdict(
468 GURL("http://www.test.com/foo/index2.html"),
469 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
470 reused_password_account_type, &out_verdict));
471
472 // Cache another verdict with the same origin but different cache_expression
473 // will not increase setting count, but will increase the number of verdicts
474 // in the given origin.
475 CacheVerdict(GURL("http://www.test.com/bar/index2.html"),
476 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
477 reused_password_account_type,
478 LoginReputationClientResponse::SAFE, 10 * kMinute,
479 "test.com/bar/", base::Time::Now());
480 EXPECT_EQ(3U, GetStoredVerdictCount(
481 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
482
483 // Now cache a UNFAMILIAR_LOGIN_PAGE verdict, stored verdict count for
484 // PASSWORD_REUSE_EVENT should be the same.
485 CacheVerdict(GURL("http://www.test.com/foobar/index3.html"),
486 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
487 reused_password_account_type,
488 LoginReputationClientResponse::SAFE, 10 * kMinute,
489 "test.com/foobar/", base::Time::Now());
490 EXPECT_EQ(3U, GetStoredVerdictCount(
491 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
492 EXPECT_EQ(1U, GetStoredVerdictCount(
493 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
494 }
495
TEST_P(PasswordProtectionServiceTest,TestCachePasswordReuseVerdictsIncognito)496 TEST_P(PasswordProtectionServiceTest, TestCachePasswordReuseVerdictsIncognito) {
497 EXPECT_CALL(*password_protection_service_, IsIncognito())
498 .WillRepeatedly(Return(true));
499 ASSERT_EQ(0U, GetStoredVerdictCount(
500 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
501
502 ReusedPasswordAccountType reused_password_account_type;
503 reused_password_account_type.set_account_type(
504 ReusedPasswordAccountType::GSUITE);
505 reused_password_account_type.set_is_account_syncing(true);
506 // No verdict will be cached for incognito profile.
507 CacheVerdict(GURL("http://www.test.com/foo/index.html"),
508 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
509 reused_password_account_type,
510 LoginReputationClientResponse::SAFE, 10 * kMinute,
511 "test.com/foo/", base::Time::Now());
512
513 EXPECT_EQ(0U, GetStoredVerdictCount(
514 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
515
516 // Try cache another verdict with the some origin and cache_expression.
517 // Verdict count should not increase.
518 CacheVerdict(GURL("http://www.test.com/foo/index2.html"),
519 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
520 reused_password_account_type,
521 LoginReputationClientResponse::PHISHING, 10 * kMinute,
522 "test.com/foo/", base::Time::Now());
523 EXPECT_EQ(0U, GetStoredVerdictCount(
524 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
525
526 // Now cache a UNFAMILIAR_LOGIN_PAGE verdict, verdict count should not
527 // increase.
528 CacheVerdict(GURL("http://www.test.com/foobar/index3.html"),
529 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
530 reused_password_account_type,
531 LoginReputationClientResponse::SAFE, 10 * kMinute,
532 "test.com/foobar/", base::Time::Now());
533 EXPECT_EQ(0U, GetStoredVerdictCount(
534 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
535 EXPECT_EQ(0U, GetStoredVerdictCount(
536 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
537 }
538
TEST_P(PasswordProtectionServiceTest,TestCacheUnfamiliarLoginVerdicts)539 TEST_P(PasswordProtectionServiceTest, TestCacheUnfamiliarLoginVerdicts) {
540 ASSERT_EQ(0U, GetStoredVerdictCount(
541 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
542 ReusedPasswordAccountType reused_password_account_type;
543 reused_password_account_type.set_account_type(
544 ReusedPasswordAccountType::UNKNOWN);
545 reused_password_account_type.set_is_account_syncing(true);
546 // Assume each verdict has a TTL of 10 minutes.
547 // Cache a verdict for http://www.test.com/foo/index.html
548 CacheVerdict(GURL("http://www.test.com/foo/index.html"),
549 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
550 reused_password_account_type,
551 LoginReputationClientResponse::SAFE, 10 * kMinute,
552 "test.com/foo/", base::Time::Now());
553
554 EXPECT_EQ(1U, GetStoredVerdictCount(
555 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
556
557 // Cache another verdict with the same origin but different cache_expression
558 // will not increase setting count, but will increase the number of verdicts
559 // in the given origin.
560 CacheVerdict(GURL("http://www.test.com/bar/index2.html"),
561 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
562 reused_password_account_type,
563 LoginReputationClientResponse::SAFE, 10 * kMinute,
564 "test.com/bar/", base::Time::Now());
565 EXPECT_EQ(2U, GetStoredVerdictCount(
566 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
567
568 // Now cache a PASSWORD_REUSE_EVENT verdict, stored verdict count for
569 // UNFAMILIAR_LOGIN_PAGE should be the same.
570 CacheVerdict(GURL("http://www.test.com/foobar/index3.html"),
571 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
572 reused_password_account_type,
573 LoginReputationClientResponse::SAFE, 10 * kMinute,
574 "test.com/foobar/", base::Time::Now());
575 EXPECT_EQ(2U, GetStoredVerdictCount(
576 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
577 EXPECT_EQ(1U, GetStoredVerdictCount(
578 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
579 }
580
TEST_P(PasswordProtectionServiceTest,TestCacheUnfamiliarLoginVerdictsIncognito)581 TEST_P(PasswordProtectionServiceTest,
582 TestCacheUnfamiliarLoginVerdictsIncognito) {
583 EXPECT_CALL(*password_protection_service_, IsIncognito())
584 .WillRepeatedly(Return(true));
585 ASSERT_EQ(0U, GetStoredVerdictCount(
586 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
587
588 ReusedPasswordAccountType reused_password_account_type;
589 reused_password_account_type.set_account_type(
590 ReusedPasswordAccountType::UNKNOWN);
591 reused_password_account_type.set_is_account_syncing(true);
592 // No verdict will be cached for incognito profile.
593 CacheVerdict(GURL("http://www.test.com/foo/index.html"),
594 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
595 reused_password_account_type,
596 LoginReputationClientResponse::SAFE, 10 * kMinute,
597 "test.com/foo/", base::Time::Now());
598
599 EXPECT_EQ(0U, GetStoredVerdictCount(
600 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
601
602 CacheVerdict(GURL("http://www.test.com/bar/index2.html"),
603 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
604 reused_password_account_type,
605 LoginReputationClientResponse::SAFE, 10 * kMinute,
606 "test.com/bar/", base::Time::Now());
607 EXPECT_EQ(0U, GetStoredVerdictCount(
608 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
609
610 // Now cache a PASSWORD_REUSE_EVENT verdict. Verdict count should not
611 // increase.
612 reused_password_account_type.set_account_type(
613 ReusedPasswordAccountType::GSUITE);
614 reused_password_account_type.set_is_account_syncing(true);
615 CacheVerdict(GURL("http://www.test.com/foobar/index3.html"),
616 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
617 reused_password_account_type,
618 LoginReputationClientResponse::SAFE, 10 * kMinute,
619 "test.com/foobar/", base::Time::Now());
620 EXPECT_EQ(0U, GetStoredVerdictCount(
621 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
622 EXPECT_EQ(0U, GetStoredVerdictCount(
623 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
624 }
625
TEST_P(PasswordProtectionServiceTest,TestGetCachedVerdicts)626 TEST_P(PasswordProtectionServiceTest, TestGetCachedVerdicts) {
627 ASSERT_EQ(0U, GetStoredVerdictCount(
628 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
629 ASSERT_EQ(0U, GetStoredVerdictCount(
630 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
631 ReusedPasswordAccountType reused_password_account_type;
632 reused_password_account_type.set_account_type(
633 ReusedPasswordAccountType::GSUITE);
634 reused_password_account_type.set_is_account_syncing(true);
635 // Prepare 4 verdicts of the same origin with different cache expressions,
636 // or password type, one is expired, one is not, one is of a different
637 // trigger type, and the other is with a different password type.
638 base::Time now = base::Time::Now();
639 CacheVerdict(GURL("http://test.com/login.html"),
640 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
641 reused_password_account_type,
642 LoginReputationClientResponse::SAFE, 10 * kMinute, "test.com/",
643 now);
644 CacheVerdict(
645 GURL("http://test.com/def/index.jsp"),
646 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
647 reused_password_account_type, LoginReputationClientResponse::PHISHING,
648 10 * kMinute, "test.com/def/",
649 base::Time::FromDoubleT(now.ToDoubleT() - kDay)); // Yesterday, expired.
650 reused_password_account_type.set_account_type(
651 ReusedPasswordAccountType::UNKNOWN);
652 CacheVerdict(GURL("http://test.com/bar/login.html"),
653 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
654 reused_password_account_type,
655 LoginReputationClientResponse::PHISHING, 10 * kMinute,
656 "test.com/bar/", now);
657 reused_password_account_type.set_account_type(
658 ReusedPasswordAccountType::NON_GAIA_ENTERPRISE);
659 CacheVerdict(GURL("http://test.com/login.html"),
660 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
661 reused_password_account_type,
662 LoginReputationClientResponse::SAFE, 10 * kMinute, "test.com/",
663 now);
664
665 ASSERT_EQ(3U, GetStoredVerdictCount(
666 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
667 ASSERT_EQ(1U, GetStoredVerdictCount(
668 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
669
670 // Return VERDICT_TYPE_UNSPECIFIED if look up for a URL with unknown origin.
671 LoginReputationClientResponse actual_verdict;
672 reused_password_account_type.set_account_type(
673 ReusedPasswordAccountType::GSUITE);
674 EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
675 password_protection_service_->GetCachedVerdict(
676 GURL("http://www.unknown.com/"),
677 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
678 reused_password_account_type, &actual_verdict));
679 reused_password_account_type.set_account_type(
680 ReusedPasswordAccountType::NON_GAIA_ENTERPRISE);
681 EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
682 password_protection_service_->GetCachedVerdict(
683 GURL("http://www.unknown.com/"),
684 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
685 reused_password_account_type, &actual_verdict));
686
687 // Return SAFE if look up for a URL that matches "test.com" cache expression.
688 reused_password_account_type.set_account_type(
689 ReusedPasswordAccountType::GSUITE);
690 EXPECT_EQ(LoginReputationClientResponse::SAFE,
691 password_protection_service_->GetCachedVerdict(
692 GURL("http://test.com/xyz/foo.jsp"),
693 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
694 reused_password_account_type, &actual_verdict));
695 reused_password_account_type.set_account_type(
696 ReusedPasswordAccountType::NON_GAIA_ENTERPRISE);
697 EXPECT_EQ(LoginReputationClientResponse::SAFE,
698 password_protection_service_->GetCachedVerdict(
699 GURL("http://test.com/xyz/foo.jsp"),
700 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
701 reused_password_account_type, &actual_verdict));
702
703 // Return VERDICT_TYPE_UNSPECIFIED if look up for a URL whose variants match
704 // test.com/def, but the corresponding verdict is expired.
705 reused_password_account_type.set_account_type(
706 ReusedPasswordAccountType::GSUITE);
707 EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
708 password_protection_service_->GetCachedVerdict(
709 GURL("http://test.com/def/ghi/index.html"),
710 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
711 reused_password_account_type, &actual_verdict));
712
713 // Return PHISHING. Matches "test.com/bar/" cache expression.
714 reused_password_account_type.set_account_type(
715 ReusedPasswordAccountType::UNKNOWN);
716 EXPECT_EQ(LoginReputationClientResponse::PHISHING,
717 password_protection_service_->GetCachedVerdict(
718 GURL("http://test.com/bar/foo.jsp"),
719 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
720 reused_password_account_type, &actual_verdict));
721
722 // Now cache SAFE verdict for the full path.
723 CacheVerdict(GURL("http://test.com/bar/foo.jsp"),
724 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
725 reused_password_account_type,
726 LoginReputationClientResponse::SAFE, 10 * kMinute,
727 "test.com/bar/foo.jsp", now);
728
729 // Return SAFE now. Matches the full cache expression.
730 EXPECT_EQ(LoginReputationClientResponse::SAFE,
731 password_protection_service_->GetCachedVerdict(
732 GURL("http://test.com/bar/foo.jsp"),
733 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
734 reused_password_account_type, &actual_verdict));
735 }
736
TEST_P(PasswordProtectionServiceTest,TestDoesNotCacheAboutBlank)737 TEST_P(PasswordProtectionServiceTest, TestDoesNotCacheAboutBlank) {
738 ASSERT_EQ(0U, GetStoredVerdictCount(
739 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
740 ReusedPasswordAccountType reused_password_account_type;
741 reused_password_account_type.set_account_type(
742 ReusedPasswordAccountType::UNKNOWN);
743
744 // Should not actually cache, since about:blank is not valid for reputation
745 // computing.
746 CacheVerdict(
747 GURL("about:blank"), LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
748 reused_password_account_type, LoginReputationClientResponse::SAFE,
749 10 * kMinute, "about:blank", base::Time::Now());
750
751 EXPECT_EQ(0U, GetStoredVerdictCount(
752 LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
753 }
754
TEST_P(PasswordProtectionServiceTest,VerifyCanGetReputationOfURL)755 TEST_P(PasswordProtectionServiceTest, VerifyCanGetReputationOfURL) {
756 // Invalid main frame URL.
757 EXPECT_FALSE(PasswordProtectionService::CanGetReputationOfURL(GURL()));
758
759 // Main frame URL scheme is not HTTP or HTTPS.
760 EXPECT_FALSE(PasswordProtectionService::CanGetReputationOfURL(
761 GURL("data:text/html, <p>hellow")));
762
763 // Main frame URL is a local host.
764 EXPECT_FALSE(PasswordProtectionService::CanGetReputationOfURL(
765 GURL("http://localhost:80")));
766 EXPECT_FALSE(PasswordProtectionService::CanGetReputationOfURL(
767 GURL("http://127.0.0.1")));
768
769 // Main frame URL is a private IP address or anything in an IANA-reserved
770 // range.
771 EXPECT_FALSE(PasswordProtectionService::CanGetReputationOfURL(
772 GURL("http://192.168.1.0/")));
773 EXPECT_FALSE(PasswordProtectionService::CanGetReputationOfURL(
774 GURL("http://10.0.1.0/")));
775 EXPECT_FALSE(PasswordProtectionService::CanGetReputationOfURL(
776 GURL("http://[FEED::BEEF]")));
777
778 // Main frame URL is a no-yet-assigned y ICANN gTLD.
779 EXPECT_FALSE(PasswordProtectionService::CanGetReputationOfURL(
780 GURL("http://intranet")));
781 EXPECT_FALSE(PasswordProtectionService::CanGetReputationOfURL(
782 GURL("http://host.intranet.example")));
783
784 // Main frame URL is a dotless domain.
785 EXPECT_FALSE(PasswordProtectionService::CanGetReputationOfURL(
786 GURL("http://go/example")));
787
788 // Main frame URL is anything else.
789 EXPECT_TRUE(PasswordProtectionService::CanGetReputationOfURL(
790 GURL("http://www.chromium.org")));
791 }
792
TEST_P(PasswordProtectionServiceTest,TestNoRequestSentForWhitelistedURL)793 TEST_P(PasswordProtectionServiceTest, TestNoRequestSentForWhitelistedURL) {
794 histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
795 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
796 content::WebContentsTester::For(web_contents.get())
797 ->SetLastCommittedURL(GURL("http://safe.com/"));
798 InitializeAndStartPasswordOnFocusRequest(true /* match whitelist */,
799 10000 /* timeout in ms */,
800 web_contents.get());
801 base::RunLoop().RunUntilIdle();
802 EXPECT_EQ(nullptr, password_protection_service_->latest_response());
803 EXPECT_THAT(
804 histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogram),
805 ElementsAre(base::Bucket(4 /* MATCHED_WHITELIST */, 1)));
806 }
807
808 // crbug.com/1010007: crashes on win
809 #if defined(OS_WIN)
810 #define MAYBE_TestNoRequestSentIfVerdictAlreadyCached \
811 DISABLED_TestNoRequestSentIfVerdictAlreadyCached
812 #else
813 #define MAYBE_TestNoRequestSentIfVerdictAlreadyCached \
814 TestNoRequestSentIfVerdictAlreadyCached
815 #endif
TEST_P(PasswordProtectionServiceTest,MAYBE_TestNoRequestSentIfVerdictAlreadyCached)816 TEST_P(PasswordProtectionServiceTest,
817 MAYBE_TestNoRequestSentIfVerdictAlreadyCached) {
818 histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
819 ReusedPasswordAccountType reused_password_account_type;
820 reused_password_account_type.set_account_type(
821 ReusedPasswordAccountType::UNKNOWN);
822 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
823 CacheVerdict(GURL(kTargetUrl),
824 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
825 reused_password_account_type,
826 LoginReputationClientResponse::LOW_REPUTATION, 10 * kMinute,
827 GURL(kTargetUrl).host().append("/"), base::Time::Now());
828 InitializeAndStartPasswordOnFocusRequest(/*match_whitelist=*/false,
829 /*timeout_in_ms=*/10000,
830 web_contents.get());
831 base::RunLoop().RunUntilIdle();
832 EXPECT_THAT(
833 histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogram),
834 ElementsAre(base::Bucket(5 /* RESPONSE_ALREADY_CACHED */, 1)));
835 EXPECT_EQ(LoginReputationClientResponse::LOW_REPUTATION,
836 password_protection_service_->latest_response()->verdict_type());
837 }
838
TEST_P(PasswordProtectionServiceTest,TestResponseFetchFailed)839 TEST_P(PasswordProtectionServiceTest, TestResponseFetchFailed) {
840 histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
841 // Set up failed response.
842 network::URLLoaderCompletionStatus status(net::ERR_FAILED);
843 test_url_loader_factory_.AddResponse(
844 url_, network::mojom::URLResponseHead::New(), std::string(), status);
845 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
846
847 InitializeAndStartPasswordOnFocusRequest(/*match_whitelist=*/false,
848 /*timeout_in_ms=*/10000,
849 web_contents.get());
850 password_protection_service_->WaitForResponse();
851 EXPECT_EQ(nullptr, password_protection_service_->latest_response());
852 EXPECT_THAT(
853 histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogram),
854 ElementsAre(base::Bucket(9 /* FETCH_FAILED */, 1)));
855 }
856
TEST_P(PasswordProtectionServiceTest,TestMalformedResponse)857 TEST_P(PasswordProtectionServiceTest, TestMalformedResponse) {
858 histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
859 // Set up malformed response.
860 test_url_loader_factory_.AddResponse(url_.spec(), "invalid response");
861 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
862
863 InitializeAndStartPasswordOnFocusRequest(/*match_whitelist=*/false,
864 /*timeout_in_ms=*/10000,
865 web_contents.get());
866 password_protection_service_->WaitForResponse();
867 EXPECT_EQ(nullptr, password_protection_service_->latest_response());
868 EXPECT_THAT(
869 histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogram),
870 ElementsAre(base::Bucket(10 /* RESPONSE_MALFORMED */, 1)));
871 }
872
TEST_P(PasswordProtectionServiceTest,TestRequestTimedout)873 TEST_P(PasswordProtectionServiceTest, TestRequestTimedout) {
874 histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
875 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
876 InitializeAndStartPasswordOnFocusRequest(/*match_whitelist=*/false,
877 /*timeout_in_ms=*/0,
878 web_contents.get());
879 base::RunLoop().RunUntilIdle();
880 EXPECT_EQ(nullptr, password_protection_service_->latest_response());
881 EXPECT_THAT(
882 histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogram),
883 ElementsAre(base::Bucket(3 /* TIMEDOUT */, 1)));
884 }
885
TEST_P(PasswordProtectionServiceTest,TestPasswordOnFocusRequestAndResponseSuccessfull)886 TEST_P(PasswordProtectionServiceTest,
887 TestPasswordOnFocusRequestAndResponseSuccessfull) {
888 histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
889 // Set up valid response.
890 LoginReputationClientResponse expected_response =
891 CreateVerdictProto(LoginReputationClientResponse::PHISHING, 10 * kMinute,
892 GURL(kTargetUrl).host());
893 test_url_loader_factory_.AddResponse(url_.spec(),
894 expected_response.SerializeAsString());
895 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
896
897 InitializeAndStartPasswordOnFocusRequest(/*match_whitelist=*/false,
898 /*timeout_in_ms=*/10000,
899 web_contents.get());
900 password_protection_service_->WaitForResponse();
901 EXPECT_THAT(
902 histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogram),
903 ElementsAre(base::Bucket(1 /* SUCCEEDED */, 1)));
904 EXPECT_THAT(histograms_.GetAllSamples(kPasswordOnFocusVerdictHistogram),
905 ElementsAre(base::Bucket(3 /* PHISHING */, 1)));
906 LoginReputationClientResponse* actual_response =
907 password_protection_service_->latest_response();
908 EXPECT_EQ(expected_response.verdict_type(), actual_response->verdict_type());
909 EXPECT_EQ(expected_response.cache_expression(),
910 actual_response->cache_expression());
911 EXPECT_EQ(expected_response.cache_duration_sec(),
912 actual_response->cache_duration_sec());
913 }
914
TEST_P(PasswordProtectionServiceTest,TestProtectedPasswordEntryRequestAndResponseSuccessfull)915 TEST_P(PasswordProtectionServiceTest,
916 TestProtectedPasswordEntryRequestAndResponseSuccessfull) {
917 histograms_.ExpectTotalCount(kAnyPasswordEntryRequestOutcomeHistogram, 0);
918 histograms_.ExpectTotalCount(kSyncPasswordEntryRequestOutcomeHistogram, 0);
919 histograms_.ExpectTotalCount(kNonSyncPasswordEntryRequestOutcomeHistogram, 0);
920 // Set up valid response.
921 LoginReputationClientResponse expected_response =
922 CreateVerdictProto(LoginReputationClientResponse::PHISHING, 10 * kMinute,
923 GURL(kTargetUrl).host());
924 test_url_loader_factory_.AddResponse(url_.spec(),
925 expected_response.SerializeAsString());
926 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
927
928 // Initiate a saved password entry request (w/ no sync password).
929 AccountInfo account_info;
930 account_info.account_id = CoreAccountId("account_id");
931 account_info.email = "email";
932 account_info.gaia = "gaia";
933 EXPECT_CALL(*password_protection_service_, GetSignedInNonSyncAccount(_))
934 .WillRepeatedly(Return(account_info));
935
936 InitializeAndStartPasswordEntryRequest(
937 PasswordType::OTHER_GAIA_PASSWORD,
938 {{"gmail.com", ASCIIToUTF16("username")}},
939 /*match_whitelist=*/false,
940 /*timeout_in_ms=*/10000, web_contents.get());
941 password_protection_service_->WaitForResponse();
942
943 // UMA: request outcomes
944 EXPECT_THAT(
945 histograms_.GetAllSamples(kAnyPasswordEntryRequestOutcomeHistogram),
946 ElementsAre(base::Bucket(1 /* SUCCEEDED */, 1)));
947 histograms_.ExpectTotalCount(kSyncPasswordEntryRequestOutcomeHistogram, 0);
948 EXPECT_THAT(
949 histograms_.GetAllSamples(kNonSyncPasswordEntryRequestOutcomeHistogram),
950 ElementsAre(base::Bucket(1 /* SUCCEEDED */, 1)));
951 EXPECT_THAT(histograms_.GetAllSamples(kNonSyncPasswordEntryVerdictHistogram),
952 ElementsAre(base::Bucket(3 /* PHISHING */, 1)));
953
954 // UMA: verdicts
955 EXPECT_THAT(histograms_.GetAllSamples(kAnyPasswordEntryVerdictHistogram),
956 ElementsAre(base::Bucket(3 /* PHISHING */, 1)));
957 histograms_.ExpectTotalCount(kSyncPasswordEntryVerdictHistogram, 0);
958 EXPECT_THAT(histograms_.GetAllSamples(kNonSyncPasswordEntryVerdictHistogram),
959 ElementsAre(base::Bucket(3 /* PHISHING */, 1)));
960 }
961
TEST_P(PasswordProtectionServiceTest,TestSyncPasswordEntryRequestAndResponseSuccessfull)962 TEST_P(PasswordProtectionServiceTest,
963 TestSyncPasswordEntryRequestAndResponseSuccessfull) {
964 histograms_.ExpectTotalCount(kAnyPasswordEntryRequestOutcomeHistogram, 0);
965 histograms_.ExpectTotalCount(kSyncPasswordEntryRequestOutcomeHistogram, 0);
966 histograms_.ExpectTotalCount(kNonSyncPasswordEntryRequestOutcomeHistogram, 0);
967 // Set up valid response.
968 LoginReputationClientResponse expected_response =
969 CreateVerdictProto(LoginReputationClientResponse::PHISHING, 10 * kMinute,
970 GURL(kTargetUrl).host());
971 test_url_loader_factory_.AddResponse(url_.spec(),
972 expected_response.SerializeAsString());
973 EXPECT_CALL(*password_protection_service_, IsPrimaryAccountSyncing())
974 .WillRepeatedly(Return(true));
975 EXPECT_CALL(*password_protection_service_, IsPrimaryAccountSignedIn())
976 .WillRepeatedly(Return(true));
977 // Initiate a sync password entry request (w/ no saved password).
978 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
979 InitializeAndStartPasswordEntryRequest(
980 PasswordType::PRIMARY_ACCOUNT_PASSWORD, {},
981 /*match_whitelist=*/false,
982 /*timeout_in_ms=*/10000, web_contents.get());
983 password_protection_service_->WaitForResponse();
984
985 // UMA: request outcomes
986 EXPECT_THAT(
987 histograms_.GetAllSamples(kAnyPasswordEntryRequestOutcomeHistogram),
988 ElementsAre(base::Bucket(1 /* SUCCEEDED */, 1)));
989 EXPECT_THAT(
990 histograms_.GetAllSamples(kSyncPasswordEntryRequestOutcomeHistogram),
991 ElementsAre(base::Bucket(1 /* SUCCEEDED */, 1)));
992 histograms_.ExpectTotalCount(kNonSyncPasswordEntryRequestOutcomeHistogram, 0);
993
994 // UMA: verdicts
995 EXPECT_THAT(histograms_.GetAllSamples(kAnyPasswordEntryVerdictHistogram),
996 ElementsAre(base::Bucket(3 /* PHISHING */, 1)));
997 EXPECT_THAT(histograms_.GetAllSamples(kSyncPasswordEntryVerdictHistogram),
998 ElementsAre(base::Bucket(3 /* PHISHING */, 1)));
999 histograms_.ExpectTotalCount(kNonSyncPasswordEntryVerdictHistogram, 0);
1000 }
1001
TEST_P(PasswordProtectionServiceTest,TestTearDownWithPendingRequests)1002 TEST_P(PasswordProtectionServiceTest, TestTearDownWithPendingRequests) {
1003 histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
1004 GURL target_url(kTargetUrl);
1005 EXPECT_CALL(*database_manager_, CheckCsdWhitelistUrl(target_url, _))
1006 .WillRepeatedly(Return(AsyncMatch::NO_MATCH));
1007 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
1008 password_protection_service_->StartRequest(
1009 web_contents.get(), target_url, GURL("http://foo.com/submit"),
1010 GURL("http://foo.com/frame"), "username", PasswordType::SAVED_PASSWORD,
1011 {}, LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true);
1012
1013 // Destroy password_protection_service_ while there is one request pending.
1014 password_protection_service_.reset();
1015 base::RunLoop().RunUntilIdle();
1016
1017 // We should not log on TearDown, since that can dispatch calls to pure
1018 // virtual methods.
1019 EXPECT_THAT(
1020 histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogram),
1021 IsEmpty());
1022 }
1023
TEST_P(PasswordProtectionServiceTest,VerifyPasswordOnFocusRequestProto)1024 TEST_P(PasswordProtectionServiceTest, VerifyPasswordOnFocusRequestProto) {
1025 // Set up valid response.
1026 LoginReputationClientResponse expected_response =
1027 CreateVerdictProto(LoginReputationClientResponse::PHISHING, 10 * kMinute,
1028 GURL(kTargetUrl).host());
1029 test_url_loader_factory_.AddResponse(url_.spec(),
1030 expected_response.SerializeAsString());
1031 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
1032
1033 InitializeAndStartPasswordOnFocusRequest(/*match_whitelist=*/false,
1034 /*timeout_in_ms=*/10000,
1035 web_contents.get());
1036 password_protection_service_->WaitForResponse();
1037
1038 const LoginReputationClientRequest* actual_request =
1039 password_protection_service_->GetLatestRequestProto();
1040 EXPECT_EQ(kTargetUrl, actual_request->page_url());
1041 EXPECT_EQ(LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
1042 actual_request->trigger_type());
1043 ASSERT_EQ(2, actual_request->frames_size());
1044 EXPECT_EQ(kTargetUrl, actual_request->frames(0).url());
1045 EXPECT_EQ(kPasswordFrameUrl, actual_request->frames(1).url());
1046 EXPECT_EQ(true, actual_request->frames(1).has_password_field());
1047 ASSERT_EQ(1, actual_request->frames(1).forms_size());
1048 EXPECT_EQ(kFormActionUrl, actual_request->frames(1).forms(0).action_url());
1049 #if !defined(OS_ANDROID)
1050 VerifyContentAreaSizeCollection(*actual_request);
1051 #endif
1052 }
1053
TEST_P(PasswordProtectionServiceTest,VerifyPasswordOnFocusRequestProtoForAllowlistMatch)1054 TEST_P(PasswordProtectionServiceTest,
1055 VerifyPasswordOnFocusRequestProtoForAllowlistMatch) {
1056 // Set up valid response.
1057 LoginReputationClientResponse expected_response =
1058 CreateVerdictProto(LoginReputationClientResponse::PHISHING, 10 * kMinute,
1059 GURL(kTargetUrl).host());
1060 test_url_loader_factory_.AddResponse(url_.spec(),
1061 expected_response.SerializeAsString());
1062 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
1063
1064 EXPECT_CALL(*password_protection_service_, CanSendSamplePing())
1065 .WillRepeatedly(Return(true));
1066 InitializeAndStartPasswordOnFocusRequest(/*match_whitelist=*/true,
1067 /*timeout_in_ms=*/10000,
1068 web_contents.get());
1069 password_protection_service_->WaitForResponse();
1070
1071 const LoginReputationClientRequest* actual_request =
1072 password_protection_service_->GetLatestRequestProto();
1073 EXPECT_EQ(kTargetUrl, actual_request->page_url());
1074 ASSERT_EQ(1, actual_request->frames_size());
1075 EXPECT_EQ(kTargetUrl, actual_request->frames(0).url());
1076 }
1077
TEST_P(PasswordProtectionServiceTest,VerifySyncPasswordProtectionRequestProto)1078 TEST_P(PasswordProtectionServiceTest,
1079 VerifySyncPasswordProtectionRequestProto) {
1080 // Set up valid response.
1081 LoginReputationClientResponse expected_response =
1082 CreateVerdictProto(LoginReputationClientResponse::PHISHING, 10 * kMinute,
1083 GURL(kTargetUrl).host());
1084 test_url_loader_factory_.AddResponse(url_.spec(),
1085 expected_response.SerializeAsString());
1086 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
1087
1088 // Initialize request triggered by chrome sync password reuse.
1089 InitializeAndStartPasswordEntryRequest(
1090 PasswordType::PRIMARY_ACCOUNT_PASSWORD, {}, false /* match whitelist */,
1091 100000 /* timeout in ms*/, web_contents.get());
1092 password_protection_service_->WaitForResponse();
1093
1094 const LoginReputationClientRequest* actual_request =
1095 password_protection_service_->GetLatestRequestProto();
1096 EXPECT_TRUE(actual_request->population().is_mbb_enabled());
1097 EXPECT_EQ(kTargetUrl, actual_request->page_url());
1098 EXPECT_EQ(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1099 actual_request->trigger_type());
1100 EXPECT_EQ(1, actual_request->frames_size());
1101 EXPECT_EQ(kTargetUrl, actual_request->frames(0).url());
1102 EXPECT_TRUE(actual_request->frames(0).has_password_field());
1103 ASSERT_TRUE(actual_request->has_password_reuse_event());
1104 const auto& reuse_event = actual_request->password_reuse_event();
1105 EXPECT_TRUE(reuse_event.is_chrome_signin_password());
1106 EXPECT_EQ(0, reuse_event.domains_matching_password_size());
1107 #if !defined(OS_ANDROID)
1108 VerifyContentAreaSizeCollection(*actual_request);
1109 #endif
1110 }
1111
TEST_P(PasswordProtectionServiceTest,VerifySavePasswordProtectionRequestProto)1112 TEST_P(PasswordProtectionServiceTest,
1113 VerifySavePasswordProtectionRequestProto) {
1114 // Set up valid response.
1115 LoginReputationClientResponse expected_response =
1116 CreateVerdictProto(LoginReputationClientResponse::PHISHING, 10 * kMinute,
1117 GURL(kTargetUrl).host());
1118 test_url_loader_factory_.AddResponse(url_.spec(),
1119 expected_response.SerializeAsString());
1120 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
1121
1122 // Initialize request triggered by saved password reuse.
1123 InitializeAndStartPasswordEntryRequest(
1124 PasswordType::SAVED_PASSWORD,
1125 {{kSavedDomain, ASCIIToUTF16("username")},
1126 {kSavedDomain2, ASCIIToUTF16("username")},
1127 {"http://localhost:8080", ASCIIToUTF16("username")}},
1128 false /* match whitelist */, 100000 /* timeout in ms*/,
1129 web_contents.get());
1130 password_protection_service_->WaitForResponse();
1131
1132 const LoginReputationClientRequest* actual_request =
1133 password_protection_service_->GetLatestRequestProto();
1134 EXPECT_TRUE(actual_request->population().is_mbb_enabled());
1135 ASSERT_TRUE(actual_request->has_password_reuse_event());
1136 const auto& reuse_event = actual_request->password_reuse_event();
1137 EXPECT_FALSE(reuse_event.is_chrome_signin_password());
1138
1139 if (password_protection_service_->IsExtendedReporting() &&
1140 !password_protection_service_->IsIncognito()) {
1141 ASSERT_EQ(3, reuse_event.domains_matching_password_size());
1142 EXPECT_EQ("localhost:8080", reuse_event.domains_matching_password(0));
1143 EXPECT_EQ("saved_domain.com", reuse_event.domains_matching_password(1));
1144 EXPECT_EQ("saved_domain2.com", reuse_event.domains_matching_password(2));
1145 } else {
1146 EXPECT_EQ(0, reuse_event.domains_matching_password_size());
1147 }
1148 #if !defined(OS_ANDROID)
1149 VerifyContentAreaSizeCollection(*actual_request);
1150 #endif
1151 }
1152
TEST_P(PasswordProtectionServiceTest,VerifyShouldShowModalWarning)1153 TEST_P(PasswordProtectionServiceTest, VerifyShouldShowModalWarning) {
1154 EXPECT_CALL(*password_protection_service_,
1155 GetPasswordProtectionWarningTriggerPref(_))
1156 .WillRepeatedly(Return(PHISHING_REUSE));
1157 EXPECT_CALL(*password_protection_service_, IsPrimaryAccountSignedIn())
1158 .WillRepeatedly(Return(true));
1159 AccountInfo account_info;
1160 account_info.account_id = CoreAccountId("account_id");
1161 account_info.email = "email";
1162 account_info.gaia = "gaia";
1163 EXPECT_CALL(*password_protection_service_, GetSignedInNonSyncAccount(_))
1164 .WillRepeatedly(Return(account_info));
1165
1166 // Don't show modal warning if it is not a password reuse ping.
1167 ReusedPasswordAccountType reused_password_account_type;
1168 reused_password_account_type.set_account_type(
1169 ReusedPasswordAccountType::UNKNOWN);
1170 reused_password_account_type.set_is_account_syncing(true);
1171 EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
1172 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
1173 reused_password_account_type, LoginReputationClientResponse::PHISHING));
1174
1175 reused_password_account_type.set_account_type(
1176 ReusedPasswordAccountType::SAVED_PASSWORD);
1177
1178 EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
1179 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1180 reused_password_account_type,
1181 LoginReputationClientResponse::LOW_REPUTATION));
1182
1183 {
1184 base::test::ScopedFeatureList feature_list;
1185 feature_list.InitAndDisableFeature(
1186 safe_browsing::kPasswordProtectionForSignedInUsers);
1187
1188 // Don't show modal warning if non-sync gaia account experiment is not
1189 // on.
1190 reused_password_account_type.set_account_type(
1191 ReusedPasswordAccountType::GMAIL);
1192 reused_password_account_type.set_is_account_syncing(false);
1193 EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
1194 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1195 reused_password_account_type, LoginReputationClientResponse::PHISHING));
1196 }
1197 {
1198 base::test::ScopedFeatureList feature_list;
1199 feature_list.InitAndEnableFeature(
1200 safe_browsing::kPasswordProtectionForSignedInUsers);
1201 // Show modal warning if non-sync gaia account experiment is on.
1202 reused_password_account_type.set_account_type(
1203 ReusedPasswordAccountType::GMAIL);
1204 reused_password_account_type.set_is_account_syncing(false);
1205 // Currently password reuse warnings are only supported for saved passwords on
1206 // Android.
1207 #if defined(OS_ANDROID)
1208 EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
1209 #else
1210 EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
1211 #endif
1212 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1213 reused_password_account_type, LoginReputationClientResponse::PHISHING));
1214 }
1215
1216 // Don't show modal warning if reused password type unknown.
1217 reused_password_account_type.set_account_type(
1218 ReusedPasswordAccountType::UNKNOWN);
1219 EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
1220 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1221 reused_password_account_type, LoginReputationClientResponse::PHISHING));
1222
1223 reused_password_account_type.set_account_type(
1224 ReusedPasswordAccountType::GMAIL);
1225 reused_password_account_type.set_is_account_syncing(true);
1226 // Currently password reuse warnings are only supported for saved passwords on
1227 // Android.
1228 #if defined(OS_ANDROID)
1229 EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
1230 #else
1231 EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
1232 #endif
1233 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1234 reused_password_account_type, LoginReputationClientResponse::PHISHING));
1235
1236 // For a GSUITE account, don't show warning if password protection is set to
1237 // off by enterprise policy.
1238 reused_password_account_type.set_account_type(
1239 ReusedPasswordAccountType::GSUITE);
1240 EXPECT_CALL(*password_protection_service_,
1241 GetPasswordProtectionWarningTriggerPref(_))
1242 .WillRepeatedly(Return(PASSWORD_PROTECTION_OFF));
1243 EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
1244 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1245 reused_password_account_type, LoginReputationClientResponse::PHISHING));
1246
1247 // For a GSUITE account, show warning if password protection is set to
1248 // PHISHING_REUSE.
1249 EXPECT_CALL(*password_protection_service_,
1250 GetPasswordProtectionWarningTriggerPref(_))
1251 .WillRepeatedly(Return(PHISHING_REUSE));
1252 EXPECT_EQ(
1253 PHISHING_REUSE,
1254 password_protection_service_->GetPasswordProtectionWarningTriggerPref(
1255 reused_password_account_type));
1256 // Currently password reuse warnings are only supported for saved passwords on
1257 // Android.
1258 #if defined(OS_ANDROID)
1259 EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
1260 #else
1261 EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
1262 #endif
1263 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1264 reused_password_account_type, LoginReputationClientResponse::PHISHING));
1265
1266 // Modal dialog warning is also shown on LOW_REPUTATION verdict.
1267 // Currently password reuse warnings are only supported for saved passwords on
1268 // Android.
1269 #if defined(OS_ANDROID)
1270 EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
1271 #else
1272 EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
1273 #endif
1274 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1275 reused_password_account_type,
1276 LoginReputationClientResponse::LOW_REPUTATION));
1277
1278 // Modal dialog warning should not be shown for enterprise password reuse
1279 // if it is turned off by policy.
1280 EXPECT_CALL(*password_protection_service_,
1281 GetPasswordProtectionWarningTriggerPref(_))
1282 .WillRepeatedly(Return(PASSWORD_PROTECTION_OFF));
1283 EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
1284 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1285 reused_password_account_type, LoginReputationClientResponse::PHISHING));
1286
1287 // Show modal warning for enterprise password reuse if the trigger is
1288 // configured to PHISHING_REUSE.
1289 reused_password_account_type.set_account_type(
1290 ReusedPasswordAccountType::NON_GAIA_ENTERPRISE);
1291 EXPECT_CALL(*password_protection_service_,
1292 GetPasswordProtectionWarningTriggerPref(_))
1293 .WillRepeatedly(Return(PHISHING_REUSE));
1294 // Currently password reuse warnings are only supported for saved passwords on
1295 // Android.
1296 #if defined(OS_ANDROID)
1297 EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
1298 #else
1299 EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
1300 #endif
1301 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1302 reused_password_account_type, LoginReputationClientResponse::PHISHING));
1303 }
1304
TEST_P(PasswordProtectionServiceTest,VerifyContentTypeIsPopulated)1305 TEST_P(PasswordProtectionServiceTest, VerifyContentTypeIsPopulated) {
1306 LoginReputationClientResponse response =
1307 CreateVerdictProto(LoginReputationClientResponse::SAFE, 10 * kMinute,
1308 GURL(kTargetUrl).host());
1309 test_url_loader_factory_.AddResponse(url_.spec(),
1310 response.SerializeAsString());
1311
1312 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
1313
1314 content::WebContentsTester::For(web_contents.get())
1315 ->SetMainFrameMimeType("application/pdf");
1316
1317 InitializeAndStartPasswordOnFocusRequest(false /* match whitelist */,
1318 10000 /* timeout in ms */,
1319 web_contents.get());
1320
1321 password_protection_service_->WaitForResponse();
1322
1323 EXPECT_EQ(
1324 "application/pdf",
1325 password_protection_service_->GetLatestRequestProto()->content_type());
1326 }
1327
TEST_P(PasswordProtectionServiceTest,VerifyIsSupportedPasswordTypeForPinging)1328 TEST_P(PasswordProtectionServiceTest, VerifyIsSupportedPasswordTypeForPinging) {
1329 EXPECT_CALL(*password_protection_service_, IsPrimaryAccountSignedIn())
1330 .WillRepeatedly(Return(true));
1331 AccountInfo account_info;
1332 account_info.account_id = CoreAccountId("account_id");
1333 account_info.email = "email";
1334 account_info.gaia = "gaia";
1335 EXPECT_CALL(*password_protection_service_, GetSignedInNonSyncAccount(_))
1336 .WillRepeatedly(Return(account_info));
1337
1338 EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
1339 PasswordType::PRIMARY_ACCOUNT_PASSWORD));
1340 #if defined(OS_ANDROID)
1341 EXPECT_FALSE(password_protection_service_->IsSupportedPasswordTypeForPinging(
1342 PasswordType::OTHER_GAIA_PASSWORD));
1343 #else
1344 EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
1345 PasswordType::OTHER_GAIA_PASSWORD));
1346 #endif
1347 EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
1348 PasswordType::ENTERPRISE_PASSWORD));
1349 EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
1350 PasswordType::SAVED_PASSWORD));
1351 {
1352 base::test::ScopedFeatureList feature_list;
1353 feature_list.InitAndDisableFeature(
1354 safe_browsing::kPasswordProtectionForSignedInUsers);
1355 EXPECT_FALSE(
1356 password_protection_service_->IsSupportedPasswordTypeForPinging(
1357 PasswordType::OTHER_GAIA_PASSWORD));
1358 }
1359 }
1360
TEST_P(PasswordProtectionServiceTest,TestPingsForAboutBlank)1361 TEST_P(PasswordProtectionServiceTest, TestPingsForAboutBlank) {
1362 histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
1363 LoginReputationClientResponse expected_response =
1364 CreateVerdictProto(LoginReputationClientResponse::PHISHING, 10 * kMinute,
1365 GURL("about:blank").host());
1366 test_url_loader_factory_.AddResponse(url_.spec(),
1367 expected_response.SerializeAsString());
1368 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
1369 password_protection_service_->StartRequest(
1370 web_contents.get(), GURL("about:blank"), GURL(), GURL(), "username",
1371 PasswordType::SAVED_PASSWORD,
1372 {{"example1.com", ASCIIToUTF16("username")}},
1373 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true);
1374 base::RunLoop().RunUntilIdle();
1375 histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 1);
1376 }
1377
1378 // DOM features and visual features are not supported on Android.
1379 #if !defined(OS_ANDROID)
TEST_P(PasswordProtectionServiceTest,TestVisualFeaturesPopulatedInOnFocusPing)1380 TEST_P(PasswordProtectionServiceTest,
1381 TestVisualFeaturesPopulatedInOnFocusPing) {
1382 LoginReputationClientResponse expected_response =
1383 CreateVerdictProto(LoginReputationClientResponse::PHISHING, 10 * kMinute,
1384 GURL("about:blank").host());
1385 test_url_loader_factory_.AddResponse(url_.spec(),
1386 expected_response.SerializeAsString());
1387 EXPECT_CALL(*password_protection_service_, GetCurrentContentAreaSize())
1388 .Times(AnyNumber())
1389 .WillOnce(Return(gfx::Size(1000, 1000)));
1390 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
1391 password_protection_service_->StartRequest(
1392 web_contents.get(), GURL("about:blank"), GURL(), GURL(), kUserName,
1393 PasswordType::SAVED_PASSWORD, {{"example.com", ASCIIToUTF16("username")}},
1394 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true);
1395 base::RunLoop().RunUntilIdle();
1396
1397 bool is_sber = GetParam();
1398 if (is_sber) {
1399 password_protection_service_->WaitForResponse();
1400 ASSERT_NE(nullptr, password_protection_service_->GetLatestRequestProto());
1401 EXPECT_TRUE(password_protection_service_->GetLatestRequestProto()
1402 ->has_visual_features());
1403 }
1404 }
1405
TEST_P(PasswordProtectionServiceTest,TestDomFeaturesPopulated)1406 TEST_P(PasswordProtectionServiceTest, TestDomFeaturesPopulated) {
1407 LoginReputationClientResponse expected_response =
1408 CreateVerdictProto(LoginReputationClientResponse::PHISHING, 10 * kMinute,
1409 GURL("about:blank").host());
1410 test_url_loader_factory_.AddResponse(url_.spec(),
1411 expected_response.SerializeAsString());
1412 EXPECT_CALL(*password_protection_service_, GetCurrentContentAreaSize())
1413 .Times(AnyNumber())
1414 .WillOnce(Return(gfx::Size(1000, 1000)));
1415 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
1416 password_protection_service_->StartRequest(
1417 web_contents.get(), GURL("about:blank"), GURL(), GURL(), kUserName,
1418 PasswordType::SAVED_PASSWORD, {{"example.com", ASCIIToUTF16("username")}},
1419 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true);
1420 base::RunLoop().RunUntilIdle();
1421
1422 password_protection_service_->WaitForResponse();
1423 ASSERT_NE(nullptr, password_protection_service_->GetLatestRequestProto());
1424 EXPECT_TRUE(password_protection_service_->GetLatestRequestProto()
1425 ->has_dom_features());
1426 }
1427
TEST_P(PasswordProtectionServiceTest,TestDomFeaturesTimeout)1428 TEST_P(PasswordProtectionServiceTest, TestDomFeaturesTimeout) {
1429 password_protection_service_->SetDomFeatureCollectionTimeout(true);
1430 LoginReputationClientResponse expected_response =
1431 CreateVerdictProto(LoginReputationClientResponse::PHISHING, 10 * kMinute,
1432 GURL("about:blank").host());
1433 test_url_loader_factory_.AddResponse(url_.spec(),
1434 expected_response.SerializeAsString());
1435 EXPECT_CALL(*password_protection_service_, GetCurrentContentAreaSize())
1436 .Times(AnyNumber())
1437 .WillOnce(Return(gfx::Size(1000, 1000)));
1438 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
1439 password_protection_service_->StartRequest(
1440 web_contents.get(), GURL("about:blank"), GURL(), GURL(), kUserName,
1441 PasswordType::SAVED_PASSWORD, {{"example.com", ASCIIToUTF16("username")}},
1442 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true);
1443 task_environment_.FastForwardUntilNoTasksRemain();
1444
1445 password_protection_service_->WaitForResponse();
1446 ASSERT_NE(nullptr, password_protection_service_->GetLatestRequestProto());
1447 EXPECT_FALSE(password_protection_service_->GetLatestRequestProto()
1448 ->has_dom_features());
1449 }
1450 #endif
1451
TEST_P(PasswordProtectionServiceTest,TestRequestCancelOnTimeout)1452 TEST_P(PasswordProtectionServiceTest, TestRequestCancelOnTimeout) {
1453 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
1454 InitializeAndStartPasswordOnFocusRequest(true /* match whitelist */,
1455 10000 /* timeout in ms */,
1456 web_contents.get());
1457 auto throttle = std::make_unique<MockPasswordProtectionNavigationThrottle>(
1458 nullptr, request_, false);
1459 EXPECT_EQ(1U, GetNumberOfNavigationThrottles());
1460 request_->Cancel(true /* timeout */);
1461 EXPECT_EQ(1U, GetNumberOfNavigationThrottles());
1462 }
1463
TEST_P(PasswordProtectionServiceTest,TestRequestCancelNotOnTimeout)1464 TEST_P(PasswordProtectionServiceTest, TestRequestCancelNotOnTimeout) {
1465 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
1466 InitializeAndStartPasswordOnFocusRequest(true /* match whitelist */,
1467 10000 /* timeout in ms */,
1468 web_contents.get());
1469 auto throttle = std::make_unique<MockPasswordProtectionNavigationThrottle>(
1470 nullptr, request_, false);
1471 EXPECT_EQ(1U, GetNumberOfNavigationThrottles());
1472 request_->Cancel(false /* timeout */);
1473 EXPECT_EQ(0U, GetNumberOfNavigationThrottles());
1474 }
1475
TEST_P(PasswordProtectionServiceTest,TestWebContentsDestroyed)1476 TEST_P(PasswordProtectionServiceTest, TestWebContentsDestroyed) {
1477 std::unique_ptr<content::WebContents> web_contents = GetWebContents();
1478 InitializeAndStartPasswordOnFocusRequest(false /* match whitelist */,
1479 10000 /* timeout in ms */,
1480 web_contents.get());
1481 web_contents.reset();
1482 task_environment_.FastForwardUntilNoTasksRemain();
1483 }
1484
1485 INSTANTIATE_TEST_SUITE_P(Regular,
1486 PasswordProtectionServiceTest,
1487 ::testing::Values(false));
1488 INSTANTIATE_TEST_SUITE_P(SBER,
1489 PasswordProtectionServiceTest,
1490 ::testing::Values(true));
1491 } // namespace safe_browsing
1492