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