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 "chrome/browser/safe_browsing/chrome_password_protection_service.h"
5 
6 #include <memory>
7 
8 #include "base/bind.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/run_loop.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/test/bind.h"
14 #include "base/test/scoped_feature_list.h"
15 #include "build/build_config.h"
16 #include "chrome/browser/password_manager/account_password_store_factory.h"
17 #include "chrome/browser/password_manager/password_store_factory.h"
18 #include "chrome/browser/safe_browsing/ui_manager.h"
19 #include "chrome/browser/signin/chrome_signin_client_factory.h"
20 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
21 #include "chrome/browser/signin/test_signin_client_builder.h"
22 #include "chrome/browser/sync/user_event_service_factory.h"
23 #include "chrome/common/pref_names.h"
24 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
25 #include "chrome/test/base/scoped_testing_local_state.h"
26 #include "chrome/test/base/testing_browser_process.h"
27 #include "chrome/test/base/testing_profile.h"
28 #include "components/content_settings/core/browser/host_content_settings_map.h"
29 #include "components/password_manager/core/browser/compromised_credentials_table.h"
30 #include "components/password_manager/core/browser/hash_password_manager.h"
31 #include "components/password_manager/core/browser/mock_password_store.h"
32 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
33 #include "components/password_manager/core/browser/password_manager_test_utils.h"
34 #include "components/password_manager/core/common/password_manager_features.h"
35 #include "components/prefs/pref_service.h"
36 #include "components/prefs/scoped_user_pref_update.h"
37 #include "components/safe_browsing/content/password_protection/password_protection_navigation_throttle.h"
38 #include "components/safe_browsing/content/password_protection/password_protection_request.h"
39 #include "components/safe_browsing/core/common/utils.h"
40 #include "components/safe_browsing/core/db/v4_protocol_manager_util.h"
41 #include "components/safe_browsing/core/features.h"
42 #include "components/safe_browsing/core/verdict_cache_manager.h"
43 #include "components/signin/public/identity_manager/account_info.h"
44 #include "components/strings/grit/components_strings.h"
45 #include "components/sync/model/model_type_controller_delegate.h"
46 #include "components/sync_preferences/testing_pref_service_syncable.h"
47 #include "components/sync_user_events/fake_user_event_service.h"
48 #include "content/public/browser/navigation_handle.h"
49 #include "content/public/browser/web_contents.h"
50 #include "content/public/test/mock_navigation_handle.h"
51 #include "net/http/http_util.h"
52 #include "testing/gmock/include/gmock/gmock.h"
53 #include "testing/gtest/include/gtest/gtest.h"
54 #include "ui/base/l10n/l10n_util.h"
55 
56 // All tests related to extension is disabled on Android, because enterprise
57 // reporting extension is not supported.
58 #if !defined(OS_ANDROID)
59 #include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h"
60 #include "chrome/browser/safe_browsing/test_extension_event_observer.h"
61 #include "chrome/common/extensions/api/safe_browsing_private.h"
62 #include "extensions/browser/test_event_router.h"
63 #endif
64 
65 using sync_pb::UserEventSpecifics;
66 using GaiaPasswordReuse = sync_pb::GaiaPasswordReuse;
67 using GaiaPasswordCaptured = UserEventSpecifics::GaiaPasswordCaptured;
68 using PasswordReuseDialogInteraction =
69     GaiaPasswordReuse::PasswordReuseDialogInteraction;
70 using PasswordReuseEvent =
71     safe_browsing::LoginReputationClientRequest::PasswordReuseEvent;
72 using PasswordReuseLookup = GaiaPasswordReuse::PasswordReuseLookup;
73 using ::testing::_;
74 using ::testing::Return;
75 using ::testing::WithArg;
76 
77 #if !defined(OS_ANDROID)
78 namespace OnPolicySpecifiedPasswordReuseDetected = extensions::api::
79     safe_browsing_private::OnPolicySpecifiedPasswordReuseDetected;
80 namespace OnPolicySpecifiedPasswordChanged =
81     extensions::api::safe_browsing_private::OnPolicySpecifiedPasswordChanged;
82 #endif
83 
84 class MockSecurityEventRecorder : public SecurityEventRecorder {
85  public:
86   MockSecurityEventRecorder() = default;
87   ~MockSecurityEventRecorder() override = default;
88 
Create()89   static BrowserContextKeyedServiceFactory::TestingFactory Create() {
90     return base::BindRepeating(
91         [](content::BrowserContext* context) -> std::unique_ptr<KeyedService> {
92           return std::make_unique<MockSecurityEventRecorder>();
93         });
94   }
95 
96   MOCK_METHOD0(GetControllerDelegate,
97                base::WeakPtr<syncer::ModelTypeControllerDelegate>());
98   MOCK_METHOD1(RecordGaiaPasswordReuse, void(const GaiaPasswordReuse&));
99 };
100 
101 namespace safe_browsing {
102 
103 namespace {
104 
105 const char kPhishingURL[] = "http://phishing.com/";
106 const char kTestEmail[] = "foo@example.com";
107 const char kUserName[] = "username";
108 const char kRedirectURL[] = "http://redirect.com";
109 #if !defined(OS_ANDROID)
110 const char kPasswordReuseURL[] = "http://login.example.com/";
111 const char kTestGmail[] = "foo@gmail.com";
112 #endif
113 
114 BrowserContextKeyedServiceFactory::TestingFactory
GetFakeUserEventServiceFactory()115 GetFakeUserEventServiceFactory() {
116   return base::BindRepeating(
117       [](content::BrowserContext* context) -> std::unique_ptr<KeyedService> {
118         return std::make_unique<syncer::FakeUserEventService>();
119       });
120 }
121 
122 constexpr struct {
123   // The response from the password protection service.
124   RequestOutcome request_outcome;
125   // The enum to log in the user event for that response.
126   PasswordReuseLookup::LookupResult lookup_result;
127 } kTestCasesWithoutVerdict[]{
128     {RequestOutcome::MATCHED_WHITELIST, PasswordReuseLookup::WHITELIST_HIT},
129     {RequestOutcome::URL_NOT_VALID_FOR_REPUTATION_COMPUTING,
130      PasswordReuseLookup::URL_UNSUPPORTED},
131     {RequestOutcome::CANCELED, PasswordReuseLookup::REQUEST_FAILURE},
132     {RequestOutcome::TIMEDOUT, PasswordReuseLookup::REQUEST_FAILURE},
133     {RequestOutcome::DISABLED_DUE_TO_INCOGNITO,
134      PasswordReuseLookup::REQUEST_FAILURE},
135     {RequestOutcome::REQUEST_MALFORMED, PasswordReuseLookup::REQUEST_FAILURE},
136     {RequestOutcome::FETCH_FAILED, PasswordReuseLookup::REQUEST_FAILURE},
137     {RequestOutcome::RESPONSE_MALFORMED, PasswordReuseLookup::REQUEST_FAILURE},
138     {RequestOutcome::SERVICE_DESTROYED, PasswordReuseLookup::REQUEST_FAILURE},
139     {RequestOutcome::DISABLED_DUE_TO_FEATURE_DISABLED,
140      PasswordReuseLookup::REQUEST_FAILURE},
141     {RequestOutcome::DISABLED_DUE_TO_USER_POPULATION,
142      PasswordReuseLookup::REQUEST_FAILURE}};
143 
144 }  // namespace
145 
146 class MockChromePasswordProtectionService
147     : public ChromePasswordProtectionService {
148  public:
MockChromePasswordProtectionService(Profile * profile,scoped_refptr<SafeBrowsingUIManager> ui_manager,StringProvider sync_password_hash_provider,VerdictCacheManager * cache_manager)149   explicit MockChromePasswordProtectionService(
150       Profile* profile,
151       scoped_refptr<SafeBrowsingUIManager> ui_manager,
152       StringProvider sync_password_hash_provider,
153       VerdictCacheManager* cache_manager)
154       : ChromePasswordProtectionService(profile,
155                                         ui_manager,
156                                         sync_password_hash_provider,
157                                         cache_manager),
158         is_incognito_(false),
159         is_extended_reporting_(false),
160         is_syncing_(false),
161         is_no_hosted_domain_found_(false),
162         is_account_signed_in_(false) {}
IsExtendedReporting()163   bool IsExtendedReporting() override { return is_extended_reporting_; }
IsIncognito()164   bool IsIncognito() override { return is_incognito_; }
IsPrimaryAccountSyncing() const165   bool IsPrimaryAccountSyncing() const override { return is_syncing_; }
IsPrimaryAccountSignedIn() const166   bool IsPrimaryAccountSignedIn() const override {
167     return is_account_signed_in_;
168   }
IsPrimaryAccountGmail() const169   bool IsPrimaryAccountGmail() const override {
170     return is_no_hosted_domain_found_;
171   }
GetSignedInNonSyncAccount(const std::string & username) const172   AccountInfo GetSignedInNonSyncAccount(
173       const std::string& username) const override {
174     return account_info_;
175   }
176 
177   safe_browsing::LoginReputationClientRequest::UrlDisplayExperiment
GetUrlDisplayExperiment() const178   GetUrlDisplayExperiment() const override {
179     return safe_browsing::LoginReputationClientRequest::UrlDisplayExperiment();
180   }
181 
182   // Configures the results returned by IsExtendedReporting(), IsIncognito(),
183   // and IsHistorySyncEnabled().
ConfigService(bool is_incognito,bool is_extended_reporting)184   void ConfigService(bool is_incognito, bool is_extended_reporting) {
185     is_incognito_ = is_incognito;
186     is_extended_reporting_ = is_extended_reporting;
187   }
188 
SetIsSyncing(bool is_syncing)189   void SetIsSyncing(bool is_syncing) { is_syncing_ = is_syncing; }
SetIsNoHostedDomainFound(bool is_no_hosted_domain_found)190   void SetIsNoHostedDomainFound(bool is_no_hosted_domain_found) {
191     is_no_hosted_domain_found_ = is_no_hosted_domain_found;
192   }
SetIsAccountSignedIn(bool is_account_signed_in)193   void SetIsAccountSignedIn(bool is_account_signed_in) {
194     is_account_signed_in_ = is_account_signed_in;
195   }
SetAccountInfo(const std::string & username)196   void SetAccountInfo(const std::string& username) {
197     AccountInfo account_info;
198     account_info.account_id = CoreAccountId("account_id");
199     account_info.email = username;
200     account_info.gaia = "gaia";
201     account_info_ = account_info;
202   }
203 
ui_manager()204   SafeBrowsingUIManager* ui_manager() { return ui_manager_.get(); }
205 
206  protected:
207   friend class ChromePasswordProtectionServiceTest;
208 
209  private:
210   bool is_incognito_;
211   bool is_extended_reporting_;
212   bool is_syncing_;
213   bool is_no_hosted_domain_found_;
214   bool is_account_signed_in_;
215   AccountInfo account_info_;
216   std::string mocked_sync_password_hash_;
217 };
218 
219 class ChromePasswordProtectionServiceTest
220     : public ChromeRenderViewHostTestHarness {
221  public:
ChromePasswordProtectionServiceTest()222   ChromePasswordProtectionServiceTest()
223       : local_state_(TestingBrowserProcess::GetGlobal()) {}
224 
SetUp()225   void SetUp() override {
226     ChromeRenderViewHostTestHarness::SetUp();
227 
228     password_store_ =
229         base::WrapRefCounted(static_cast<password_manager::MockPasswordStore*>(
230             PasswordStoreFactory::GetInstance()
231                 ->SetTestingFactoryAndUse(
232                     profile(),
233                     base::BindRepeating(&password_manager::BuildPasswordStore<
234                                         content::BrowserContext,
235                                         password_manager::MockPasswordStore>))
236                 .get()));
237 
238     if (base::FeatureList::IsEnabled(
239             password_manager::features::kEnablePasswordsAccountStorage)) {
240       account_password_store_ = base::WrapRefCounted(
241           static_cast<password_manager::MockPasswordStore*>(
242               AccountPasswordStoreFactory::GetInstance()
243                   ->SetTestingFactoryAndUse(
244                       profile(),
245                       base::BindRepeating(&password_manager::BuildPasswordStore<
246                                           content::BrowserContext,
247                                           password_manager::MockPasswordStore>))
248                   .get()));
249     }
250 
251     profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, true);
252     profile()->GetPrefs()->SetInteger(
253         prefs::kPasswordProtectionWarningTrigger,
254         PasswordProtectionTrigger::PHISHING_REUSE);
255     HostContentSettingsMap::RegisterProfilePrefs(test_pref_service_.registry());
256     content_setting_map_ = new HostContentSettingsMap(
257         &test_pref_service_, /*is_off_the_record=*/false,
258         /*store_last_modified=*/false, /*restore_session=*/false);
259 
260     cache_manager_ = std::make_unique<VerdictCacheManager>(
261         nullptr, content_setting_map_.get());
262 
263     service_ = NewMockPasswordProtectionService();
264     fake_user_event_service_ = static_cast<syncer::FakeUserEventService*>(
265         browser_sync::UserEventServiceFactory::GetInstance()
266             ->SetTestingFactoryAndUse(browser_context(),
267                                       GetFakeUserEventServiceFactory()));
268 #if !defined(OS_ANDROID)
269     test_event_router_ =
270         extensions::CreateAndUseTestEventRouter(browser_context());
271     extensions::SafeBrowsingPrivateEventRouterFactory::GetInstance()
272         ->SetTestingFactory(
273             browser_context(),
274             base::BindRepeating(&BuildSafeBrowsingPrivateEventRouter));
275 #endif
276 
277     identity_test_env_profile_adaptor_ =
278         std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile());
279 
280     security_event_recorder_ = static_cast<MockSecurityEventRecorder*>(
281         SecurityEventRecorderFactory::GetInstance()->SetTestingFactoryAndUse(
282             browser_context(), MockSecurityEventRecorder::Create()));
283     // To make sure we are not accidentally calling the SecurityEventRecorder.
284     EXPECT_CALL(*security_event_recorder_, RecordGaiaPasswordReuse(_)).Times(0);
285   }
286 
TearDown()287   void TearDown() override {
288     base::RunLoop().RunUntilIdle();
289     service_.reset();
290     request_ = nullptr;
291     if (account_password_store_)
292       account_password_store_->ShutdownOnUIThread();
293     password_store_->ShutdownOnUIThread();
294     identity_test_env_profile_adaptor_.reset();
295     cache_manager_.reset();
296     content_setting_map_->ShutdownOnUIThread();
297     ChromeRenderViewHostTestHarness::TearDown();
298   }
299 
300   // This can be called whenever to reset service_, if initialition
301   // conditions have changed.
302   std::unique_ptr<MockChromePasswordProtectionService>
NewMockPasswordProtectionService(const std::string & sync_password_hash=std::string ())303   NewMockPasswordProtectionService(
304       const std::string& sync_password_hash = std::string()) {
305     StringProvider sync_password_hash_provider =
306         base::BindLambdaForTesting([=] { return sync_password_hash; });
307 
308     // TODO(crbug/925153): Port consumers of the SafeBrowsingService
309     // to use the interface in components/safe_browsing, and remove this
310     // cast.
311     return std::make_unique<MockChromePasswordProtectionService>(
312         profile(),
313         new SafeBrowsingUIManager(
314             static_cast<safe_browsing::SafeBrowsingService*>(
315                 SafeBrowsingService::CreateSafeBrowsingService())),
316         sync_password_hash_provider, cache_manager_.get());
317   }
318 
GetTestingFactories() const319   TestingProfile::TestingFactories GetTestingFactories() const override {
320     return IdentityTestEnvironmentProfileAdaptor::
321         GetIdentityTestEnvironmentFactories();
322   }
323 
GetUserEventService()324   syncer::FakeUserEventService* GetUserEventService() {
325     return fake_user_event_service_;
326   }
327 
InitializeRequest(LoginReputationClientRequest::TriggerType trigger_type,PasswordType reused_password_type)328   void InitializeRequest(LoginReputationClientRequest::TriggerType trigger_type,
329                          PasswordType reused_password_type) {
330     std::vector<password_manager::MatchingReusedCredential> credentials = {
331         {"somedomain.com"}};
332     if (trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) {
333       request_ = new PasswordProtectionRequest(
334           web_contents(), GURL(kPhishingURL), GURL(), GURL(), kUserName,
335           PasswordType::PASSWORD_TYPE_UNKNOWN, credentials, trigger_type, true,
336           service_.get(), 0);
337     } else {
338       ASSERT_EQ(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
339                 trigger_type);
340       request_ = new PasswordProtectionRequest(
341           web_contents(), GURL(kPhishingURL), GURL(), GURL(), kUserName,
342           reused_password_type, credentials, trigger_type,
343           /* password_field_exists*/ true, service_.get(),
344           /*request_timeout_in_ms=*/0);
345     }
346   }
347 
InitializeVerdict(LoginReputationClientResponse::VerdictType type)348   void InitializeVerdict(LoginReputationClientResponse::VerdictType type) {
349     verdict_ = std::make_unique<LoginReputationClientResponse>();
350     verdict_->set_verdict_type(type);
351   }
352 
SimulateRequestFinished(LoginReputationClientResponse::VerdictType verdict_type)353   void SimulateRequestFinished(
354       LoginReputationClientResponse::VerdictType verdict_type) {
355     std::unique_ptr<LoginReputationClientResponse> verdict =
356         std::make_unique<LoginReputationClientResponse>();
357     verdict->set_verdict_type(verdict_type);
358     service_->RequestFinished(request_.get(), RequestOutcome::SUCCEEDED,
359                               std::move(verdict));
360   }
361 
SetPrimaryAccount(const std::string & email)362   CoreAccountInfo SetPrimaryAccount(const std::string& email) {
363     identity_test_env()->MakeAccountAvailable(email);
364     return identity_test_env()->SetPrimaryAccount(email);
365   }
366 
SetUpSyncAccount(const std::string & hosted_domain,const CoreAccountInfo & account_info)367   void SetUpSyncAccount(const std::string& hosted_domain,
368                         const CoreAccountInfo& account_info) {
369     identity_test_env()->SimulateSuccessfulFetchOfAccountInfo(
370         account_info.account_id, account_info.email, account_info.gaia,
371         hosted_domain, "full_name", "given_name", "locale",
372         "http://picture.example.com/picture.jpg");
373   }
374 
PrepareRequest(LoginReputationClientRequest::TriggerType trigger_type,PasswordType reused_password_type,bool is_warning_showing)375   void PrepareRequest(LoginReputationClientRequest::TriggerType trigger_type,
376                       PasswordType reused_password_type,
377                       bool is_warning_showing) {
378     InitializeRequest(trigger_type, reused_password_type);
379     request_->set_is_modal_warning_showing(is_warning_showing);
380     service_->pending_requests_.insert(request_);
381   }
382 
GetSizeofUnhandledSyncPasswordReuses()383   int GetSizeofUnhandledSyncPasswordReuses() {
384     DictionaryPrefUpdate unhandled_sync_password_reuses(
385         profile()->GetPrefs(), prefs::kSafeBrowsingUnhandledGaiaPasswordReuses);
386     return unhandled_sync_password_reuses->size();
387   }
388 
GetNumberOfNavigationThrottles()389   size_t GetNumberOfNavigationThrottles() {
390     return request_ ? request_->throttles_.size() : 0u;
391   }
392 
identity_test_env()393   signin::IdentityTestEnvironment* identity_test_env() {
394     return identity_test_env_profile_adaptor_->identity_test_env();
395   }
396 
397  protected:
398   sync_preferences::TestingPrefServiceSyncable test_pref_service_;
399   scoped_refptr<HostContentSettingsMap> content_setting_map_;
400   std::unique_ptr<MockChromePasswordProtectionService> service_;
401   scoped_refptr<PasswordProtectionRequest> request_;
402   std::unique_ptr<LoginReputationClientResponse> verdict_;
403   std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
404       identity_test_env_profile_adaptor_;
405   MockSecurityEventRecorder* security_event_recorder_;
406   scoped_refptr<password_manager::MockPasswordStore> password_store_;
407   scoped_refptr<password_manager::MockPasswordStore> account_password_store_;
408   // Owned by KeyedServiceFactory.
409   syncer::FakeUserEventService* fake_user_event_service_;
410 #if !defined(OS_ANDROID)
411   extensions::TestEventRouter* test_event_router_;
412 #endif
413   std::unique_ptr<VerdictCacheManager> cache_manager_;
414   ScopedTestingLocalState local_state_;
415 };
416 
TEST_F(ChromePasswordProtectionServiceTest,VerifyUserPopulationForPasswordOnFocusPing)417 TEST_F(ChromePasswordProtectionServiceTest,
418        VerifyUserPopulationForPasswordOnFocusPing) {
419   ReusedPasswordAccountType reused_password_type;
420   reused_password_type.set_account_type(ReusedPasswordAccountType::UNKNOWN);
421 
422   // Password field on focus pinging is enabled on !incognito && (SBER ||
423   // enhanced protection).
424   service_->ConfigService(false /*incognito*/, false /*SBER*/);
425   EXPECT_FALSE(service_->IsPingingEnabled(
426       LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
427       reused_password_type));
428 
429   service_->ConfigService(false /*incognito*/, true /*SBER*/);
430   EXPECT_TRUE(service_->IsPingingEnabled(
431       LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
432       reused_password_type));
433 
434   service_->ConfigService(true /*incognito*/, false /*SBER*/);
435   EXPECT_FALSE(service_->IsPingingEnabled(
436       LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
437       reused_password_type));
438 
439   service_->ConfigService(true /*incognito*/, true /*SBER*/);
440   EXPECT_FALSE(service_->IsPingingEnabled(
441       LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
442       reused_password_type));
443 }
444 
TEST_F(ChromePasswordProtectionServiceTest,VerifyUserPopulationForSavedPasswordEntryPing)445 TEST_F(ChromePasswordProtectionServiceTest,
446        VerifyUserPopulationForSavedPasswordEntryPing) {
447   base::test::ScopedFeatureList feature_list;
448 
449   ReusedPasswordAccountType reused_password_type;
450   reused_password_type.set_account_type(
451       ReusedPasswordAccountType::SAVED_PASSWORD);
452 
453   service_->ConfigService(false /*incognito*/, false /*SBER*/);
454   EXPECT_TRUE(service_->IsPingingEnabled(
455       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
456       reused_password_type));
457 
458   service_->ConfigService(false /*incognito*/, true /*SBER*/);
459   EXPECT_TRUE(service_->IsPingingEnabled(
460       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
461       reused_password_type));
462 
463   service_->ConfigService(true /*incognito*/, false /*SBER*/);
464   EXPECT_TRUE(service_->IsPingingEnabled(
465       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
466       reused_password_type));
467 
468   service_->ConfigService(true /*incognito*/, true /*SBER*/);
469   EXPECT_TRUE(service_->IsPingingEnabled(
470       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
471       reused_password_type));
472 
473   service_->ConfigService(false /*incognito*/, false /*SBER*/);
474   reused_password_type.set_account_type(ReusedPasswordAccountType::UNKNOWN);
475   EXPECT_FALSE(service_->IsPingingEnabled(
476       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
477       reused_password_type));
478 }
479 
TEST_F(ChromePasswordProtectionServiceTest,VerifyUserPopulationForSyncPasswordEntryPing)480 TEST_F(ChromePasswordProtectionServiceTest,
481        VerifyUserPopulationForSyncPasswordEntryPing) {
482   // Sets up the account as a gmail account as there is no hosted domain.
483   ReusedPasswordAccountType reused_password_type;
484   reused_password_type.set_account_type(ReusedPasswordAccountType::GMAIL);
485   reused_password_type.set_is_account_syncing(true);
486 
487   // Sync password entry pinging is enabled by default.
488   service_->ConfigService(false /*incognito*/, false /*SBER*/);
489 // Sync password pings are gated by SBER on Android, because warnings are
490 // disabled.
491 #if defined(OS_ANDROID)
492   EXPECT_FALSE(service_->IsPingingEnabled(
493 #else
494   EXPECT_TRUE(service_->IsPingingEnabled(
495 #endif
496       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
497       reused_password_type));
498 
499   service_->ConfigService(false /*incognito*/, true /*SBER*/);
500   EXPECT_TRUE(service_->IsPingingEnabled(
501       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
502       reused_password_type));
503 
504   service_->ConfigService(true /*incognito*/, false /*SBER*/);
505 // Sync password pings are gated by SBER on Android, because warnings are
506 // disabled.
507 #if defined(OS_ANDROID)
508   EXPECT_FALSE(service_->IsPingingEnabled(
509 #else
510   EXPECT_TRUE(service_->IsPingingEnabled(
511 #endif
512       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
513       reused_password_type));
514 
515   // Even if sync password entry pinging is disabled by policy,
516   // |IsPingingEnabled(..)| should still default to true if the
517   // the password reuse type is syncing Gmail account.
518   service_->ConfigService(true /*incognito*/, true /*SBER*/);
519   service_->SetIsNoHostedDomainFound(true);
520   EXPECT_TRUE(service_->IsPingingEnabled(
521       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
522       reused_password_type));
523 
524   profile()->GetPrefs()->SetInteger(prefs::kPasswordProtectionWarningTrigger,
525                                     PASSWORD_PROTECTION_OFF);
526   service_->ConfigService(false /*incognito*/, false /*SBER*/);
527 // Sync password pings are gated by SBER on Android, because warnings are
528 // disabled.
529 #if defined(OS_ANDROID)
530   EXPECT_FALSE(service_->IsPingingEnabled(
531 #else
532   EXPECT_TRUE(service_->IsPingingEnabled(
533 #endif
534       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
535       reused_password_type));
536 
537   profile()->GetPrefs()->SetInteger(prefs::kPasswordProtectionWarningTrigger,
538                                     PASSWORD_REUSE);
539 // Sync password pings are gated by SBER on Android, because warnings are
540 // disabled.
541 #if defined(OS_ANDROID)
542   EXPECT_FALSE(service_->IsPingingEnabled(
543 #else
544   EXPECT_TRUE(service_->IsPingingEnabled(
545 #endif
546       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
547       reused_password_type));
548 }
549 
TEST_F(ChromePasswordProtectionServiceTest,VerifyPingingIsSkippedIfMatchEnterpriseWhitelist)550 TEST_F(ChromePasswordProtectionServiceTest,
551        VerifyPingingIsSkippedIfMatchEnterpriseWhitelist) {
552   ASSERT_FALSE(
553       profile()->GetPrefs()->HasPrefPath(prefs::kSafeBrowsingWhitelistDomains));
554 
555   // If there's no whitelist, IsURLWhitelistedForPasswordEntry(_) should
556   // return false.
557   EXPECT_FALSE(service_->IsURLWhitelistedForPasswordEntry(
558       GURL("https://www.mydomain.com")));
559 
560   // Verify if match enterprise whitelist.
561   base::ListValue whitelist;
562   whitelist.AppendString("mydomain.com");
563   whitelist.AppendString("mydomain.net");
564   profile()->GetPrefs()->Set(prefs::kSafeBrowsingWhitelistDomains, whitelist);
565   EXPECT_TRUE(service_->IsURLWhitelistedForPasswordEntry(
566       GURL("https://www.mydomain.com")));
567 
568   // Verify if matches enterprise change password url.
569   profile()->GetPrefs()->ClearPref(prefs::kSafeBrowsingWhitelistDomains);
570   EXPECT_FALSE(service_->IsURLWhitelistedForPasswordEntry(
571       GURL("https://www.mydomain.com")));
572 
573   profile()->GetPrefs()->SetString(prefs::kPasswordProtectionChangePasswordURL,
574                                    "https://mydomain.com/change_password.html");
575   EXPECT_TRUE(service_->IsURLWhitelistedForPasswordEntry(
576       GURL("https://mydomain.com/change_password.html#ref?user_name=alice")));
577 
578   // Verify if matches enterprise login url.
579   profile()->GetPrefs()->ClearPref(prefs::kSafeBrowsingWhitelistDomains);
580   profile()->GetPrefs()->ClearPref(prefs::kPasswordProtectionChangePasswordURL);
581   EXPECT_FALSE(service_->IsURLWhitelistedForPasswordEntry(
582       GURL("https://www.mydomain.com")));
583   base::ListValue login_urls;
584   login_urls.AppendString("https://mydomain.com/login.html");
585   profile()->GetPrefs()->Set(prefs::kPasswordProtectionLoginURLs, login_urls);
586   EXPECT_TRUE(service_->IsURLWhitelistedForPasswordEntry(
587       GURL("https://mydomain.com/login.html#ref?user_name=alice")));
588 }
589 
TEST_F(ChromePasswordProtectionServiceTest,VerifyPersistPhishedSavedPasswordCredential)590 TEST_F(ChromePasswordProtectionServiceTest,
591        VerifyPersistPhishedSavedPasswordCredential) {
592   service_->ConfigService(/*is_incognito=*/false,
593                           /*is_extended_reporting=*/true);
594   std::vector<password_manager::MatchingReusedCredential> credentials = {
595       {"http://example.test"}, {"http://2.example.com"}};
596 
597   EXPECT_CALL(*password_store_, AddCompromisedCredentialsImpl(_)).Times(2);
598   service_->PersistPhishedSavedPasswordCredential(credentials);
599 }
600 
TEST_F(ChromePasswordProtectionServiceTest,VerifyRemovePhishedSavedPasswordCredential)601 TEST_F(ChromePasswordProtectionServiceTest,
602        VerifyRemovePhishedSavedPasswordCredential) {
603   service_->ConfigService(/*is_incognito=*/false,
604                           /*is_extended_reporting=*/true);
605   std::vector<password_manager::MatchingReusedCredential> credentials = {
606       {"http://example.test", base::ASCIIToUTF16("username1")},
607       {"http://2.example.test", base::ASCIIToUTF16("username2")}};
608 
609   EXPECT_CALL(*password_store_,
610               RemoveCompromisedCredentialsImpl(
611                   _, _,
612                   password_manager::RemoveCompromisedCredentialsReason::
613                       kMarkSiteAsLegitimate))
614       .Times(2);
615   service_->RemovePhishedSavedPasswordCredential(credentials);
616 }
617 
TEST_F(ChromePasswordProtectionServiceTest,VerifyCanSendSamplePing)618 TEST_F(ChromePasswordProtectionServiceTest, VerifyCanSendSamplePing) {
619   // Experiment is on by default.
620   service_->ConfigService(/*is_incognito=*/false,
621                           /*is_extended_reporting=*/true);
622   service_->set_bypass_probability_for_tests(true);
623   EXPECT_TRUE(service_->CanSendSamplePing());
624 
625   // If not SBER, do not send sample ping.
626   service_->ConfigService(/*is_incognito=*/false,
627                           /*is_extended_reporting=*/false);
628   EXPECT_FALSE(service_->CanSendSamplePing());
629 
630   // If incognito, do not send sample ping.
631   service_->ConfigService(/*is_incognito=*/true,
632                           /*is_extended_reporting=*/true);
633   EXPECT_FALSE(service_->CanSendSamplePing());
634 
635   service_->ConfigService(/*is_incognito=*/true,
636                           /*is_extended_reporting=*/false);
637   EXPECT_FALSE(service_->CanSendSamplePing());
638 
639   service_->ConfigService(/*is_incognito=*/false,
640                           /*is_extended_reporting=*/false);
641 }
642 
TEST_F(ChromePasswordProtectionServiceTest,VerifyGetOrganizationTypeGmail)643 TEST_F(ChromePasswordProtectionServiceTest, VerifyGetOrganizationTypeGmail) {
644   ReusedPasswordAccountType reused_password_type;
645   reused_password_type.set_account_type(ReusedPasswordAccountType::GMAIL);
646   reused_password_type.set_is_account_syncing(true);
647   EXPECT_TRUE(service_->GetOrganizationName(reused_password_type).empty());
648   EXPECT_EQ("", service_->GetOrganizationName(reused_password_type));
649 }
650 
TEST_F(ChromePasswordProtectionServiceTest,VerifyGetOrganizationTypeGSuite)651 TEST_F(ChromePasswordProtectionServiceTest, VerifyGetOrganizationTypeGSuite) {
652   CoreAccountInfo account_info = SetPrimaryAccount(kTestEmail);
653   SetUpSyncAccount("example.com", account_info);
654   ReusedPasswordAccountType reused_password_type;
655   reused_password_type.set_account_type(ReusedPasswordAccountType::GSUITE);
656   reused_password_type.set_is_account_syncing(true);
657   EXPECT_EQ("example.com", service_->GetOrganizationName(reused_password_type));
658 }
659 
TEST_F(ChromePasswordProtectionServiceTest,VerifyUpdateSecurityState)660 TEST_F(ChromePasswordProtectionServiceTest, VerifyUpdateSecurityState) {
661   GURL url("http://password_reuse_url.com");
662   NavigateAndCommit(url);
663   SBThreatType current_threat_type = SB_THREAT_TYPE_UNUSED;
664   ASSERT_FALSE(service_->ui_manager()->IsUrlWhitelistedOrPendingForWebContents(
665       url, false, web_contents()->GetController().GetLastCommittedEntry(),
666       web_contents(), false, &current_threat_type));
667   EXPECT_EQ(SB_THREAT_TYPE_UNUSED, current_threat_type);
668 
669   // Cache a verdict for this URL.
670   LoginReputationClientResponse verdict_proto;
671   verdict_proto.set_verdict_type(LoginReputationClientResponse::PHISHING);
672   verdict_proto.set_cache_duration_sec(600);
673   verdict_proto.set_cache_expression("password_reuse_url.com/");
674   ReusedPasswordAccountType reused_password_type;
675   reused_password_type.set_account_type(ReusedPasswordAccountType::GSUITE);
676   reused_password_type.set_is_account_syncing(true);
677   service_->CacheVerdict(
678       url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
679       reused_password_type, verdict_proto, base::Time::Now());
680 
681   service_->UpdateSecurityState(SB_THREAT_TYPE_SIGNED_IN_SYNC_PASSWORD_REUSE,
682                                 reused_password_type, web_contents());
683   ASSERT_TRUE(service_->ui_manager()->IsUrlWhitelistedOrPendingForWebContents(
684       url, false, web_contents()->GetController().GetLastCommittedEntry(),
685       web_contents(), false, &current_threat_type));
686   EXPECT_EQ(SB_THREAT_TYPE_SIGNED_IN_SYNC_PASSWORD_REUSE, current_threat_type);
687 
688   service_->UpdateSecurityState(safe_browsing::SB_THREAT_TYPE_SAFE,
689                                 reused_password_type, web_contents());
690   current_threat_type = SB_THREAT_TYPE_UNUSED;
691   service_->ui_manager()->IsUrlWhitelistedOrPendingForWebContents(
692       url, false, web_contents()->GetController().GetLastCommittedEntry(),
693       web_contents(), false, &current_threat_type);
694   EXPECT_EQ(SB_THREAT_TYPE_UNUSED, current_threat_type);
695   LoginReputationClientResponse verdict;
696   EXPECT_EQ(LoginReputationClientResponse::SAFE,
697             service_->GetCachedVerdict(
698                 url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
699                 reused_password_type, &verdict));
700 }
701 
TEST_F(ChromePasswordProtectionServiceTest,VerifyPasswordReuseUserEventNotRecordedDueToIncognito)702 TEST_F(ChromePasswordProtectionServiceTest,
703        VerifyPasswordReuseUserEventNotRecordedDueToIncognito) {
704   // Configure sync account type to GMAIL.
705   CoreAccountInfo account_info = SetPrimaryAccount(kTestEmail);
706   SetUpSyncAccount(kNoHostedDomainFound, account_info);
707   service_->ConfigService(true /*is_incognito*/,
708                           false /*is_extended_reporting*/);
709   ASSERT_TRUE(service_->IsIncognito());
710 
711   // Nothing should be logged because of incognito.
712   NavigateAndCommit(GURL("https:www.example.com/"));
713 
714   // PasswordReuseDetected
715   service_->MaybeLogPasswordReuseDetectedEvent(web_contents());
716   EXPECT_TRUE(GetUserEventService()->GetRecordedUserEvents().empty());
717   service_->MaybeLogPasswordReuseLookupEvent(
718       web_contents(), RequestOutcome::MATCHED_WHITELIST,
719       PasswordType::PRIMARY_ACCOUNT_PASSWORD, nullptr);
720   EXPECT_TRUE(GetUserEventService()->GetRecordedUserEvents().empty());
721 
722   // PasswordReuseLookup
723   unsigned long t = 0;
724   for (const auto& it : kTestCasesWithoutVerdict) {
725     service_->MaybeLogPasswordReuseLookupEvent(
726         web_contents(), it.request_outcome,
727         PasswordType::PRIMARY_ACCOUNT_PASSWORD, nullptr);
728     ASSERT_TRUE(GetUserEventService()->GetRecordedUserEvents().empty()) << t;
729     t++;
730   }
731 
732   // PasswordReuseDialogInteraction
733   service_->MaybeLogPasswordReuseDialogInteraction(
734       1000 /* navigation_id */,
735       PasswordReuseDialogInteraction::WARNING_ACTION_TAKEN);
736   ASSERT_TRUE(GetUserEventService()->GetRecordedUserEvents().empty());
737 }
738 
TEST_F(ChromePasswordProtectionServiceTest,VerifyPasswordReuseDetectedUserEventRecorded)739 TEST_F(ChromePasswordProtectionServiceTest,
740        VerifyPasswordReuseDetectedUserEventRecorded) {
741   // Configure sync account type to GMAIL.
742   CoreAccountInfo account_info = SetPrimaryAccount(kTestEmail);
743   SetUpSyncAccount(kNoHostedDomainFound, account_info);
744   service_->SetIsAccountSignedIn(true);
745   NavigateAndCommit(GURL("https://www.example.com/"));
746 
747   // Case 1: safe_browsing_enabled = true
748   profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, true);
749   service_->MaybeLogPasswordReuseDetectedEvent(web_contents());
750   ASSERT_EQ(1ul, GetUserEventService()->GetRecordedUserEvents().size());
751   GaiaPasswordReuse event = GetUserEventService()
752                                 ->GetRecordedUserEvents()[0]
753                                 .gaia_password_reuse_event();
754   EXPECT_TRUE(event.reuse_detected().status().enabled());
755 
756   // Case 2: safe_browsing_enabled = false
757   profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, false);
758   service_->MaybeLogPasswordReuseDetectedEvent(web_contents());
759   ASSERT_EQ(2ul, GetUserEventService()->GetRecordedUserEvents().size());
760   event = GetUserEventService()
761               ->GetRecordedUserEvents()[1]
762               .gaia_password_reuse_event();
763   EXPECT_FALSE(event.reuse_detected().status().enabled());
764 
765   // Not checking for the extended_reporting_level since that requires setting
766   // multiple prefs and doesn't add much verification value.
767 }
768 
TEST_F(ChromePasswordProtectionServiceTest,VerifyPasswordReuseDetectedSecurityEventRecorded)769 TEST_F(ChromePasswordProtectionServiceTest,
770        VerifyPasswordReuseDetectedSecurityEventRecorded) {
771   identity_test_env()->SetPrimaryAccount(kTestEmail);
772   service_->set_username_for_last_shown_warning(kTestEmail);
773   EXPECT_CALL(*security_event_recorder_, RecordGaiaPasswordReuse(_))
774       .WillOnce(WithArg<0>([&](const auto& message) {
775         EXPECT_EQ(PasswordReuseLookup::REQUEST_SUCCESS,
776                   message.reuse_lookup().lookup_result());
777         EXPECT_EQ(PasswordReuseLookup::SAFE, message.reuse_lookup().verdict());
778         EXPECT_EQ("verdict_token", message.reuse_lookup().verdict_token());
779       }));
780   service_->MaybeLogPasswordReuseLookupResultWithVerdict(
781       web_contents(), PasswordType::OTHER_GAIA_PASSWORD,
782       PasswordReuseLookup::REQUEST_SUCCESS, PasswordReuseLookup::SAFE,
783       "verdict_token");
784 }
785 
786 // The following tests are disabled on Android, because password capture events
787 // are not enabled on Android.
788 #if !defined(OS_ANDROID)
789 // Check that the PasswordCapturedEvent timer is set for 1 min if password
790 // hash is saved and no timer pref is set yet.
TEST_F(ChromePasswordProtectionServiceTest,VerifyPasswordCaptureEventScheduledOnStartup)791 TEST_F(ChromePasswordProtectionServiceTest,
792        VerifyPasswordCaptureEventScheduledOnStartup) {
793   // Configure sync account type to GMAIL.
794   CoreAccountInfo account_info = SetPrimaryAccount(kTestEmail);
795   SetUpSyncAccount(kNoHostedDomainFound, account_info);
796 
797   // Case 1: Check that the timer is not set in the ctor if no password hash is
798   // saved.
799   service_ = NewMockPasswordProtectionService(
800       /*sync_password_hash=*/"");
801   EXPECT_FALSE(service_->log_password_capture_timer_.IsRunning());
802 
803   // Case 1: Timer is set to 60 sec by default.
804   service_ = NewMockPasswordProtectionService(
805       /*sync_password_hash=*/"some-hash-value");
806   EXPECT_TRUE(service_->log_password_capture_timer_.IsRunning());
807   EXPECT_EQ(
808       60, service_->log_password_capture_timer_.GetCurrentDelay().InSeconds());
809 }
810 
811 // Check that the timer is set for prescribed time based on pref.
TEST_F(ChromePasswordProtectionServiceTest,VerifyPasswordCaptureEventScheduledFromPref)812 TEST_F(ChromePasswordProtectionServiceTest,
813        VerifyPasswordCaptureEventScheduledFromPref) {
814   // Pick a delay and store the deadline in the pref
815   base::TimeDelta delay = base::TimeDelta::FromDays(13);
816   SetDelayInPref(profile()->GetPrefs(),
817                  prefs::kSafeBrowsingNextPasswordCaptureEventLogTime, delay);
818 
819   // Configure sync account type to GMAIL.
820   CoreAccountInfo account_info = SetPrimaryAccount(kTestEmail);
821   SetUpSyncAccount(kNoHostedDomainFound, account_info);
822 
823   service_ = NewMockPasswordProtectionService(
824       /*sync_password_hash=*/"");
825   // Check that the timer is not set if no password hash is saved.
826   EXPECT_EQ(
827       0, service_->log_password_capture_timer_.GetCurrentDelay().InSeconds());
828 
829   // Save a password hash
830   service_ = NewMockPasswordProtectionService(
831       /*sync_password_hash=*/"some-hash-value");
832 
833   // Verify the delay is approx correct (not exact since we're not controlling
834   // the clock).
835   base::TimeDelta cur_delay =
836       service_->log_password_capture_timer_.GetCurrentDelay();
837   EXPECT_GE(14, cur_delay.InDays());
838   EXPECT_LE(12, cur_delay.InDays());
839 }
840 
841 // Check that we do log the event
TEST_F(ChromePasswordProtectionServiceTest,VerifyPasswordCaptureEventRecorded)842 TEST_F(ChromePasswordProtectionServiceTest,
843        VerifyPasswordCaptureEventRecorded) {
844   // Configure sync account type to GMAIL.
845   CoreAccountInfo account_info = SetPrimaryAccount(kTestEmail);
846   SetUpSyncAccount(kNoHostedDomainFound, account_info);
847 
848   // Case 1: Default service_ ctor has an empty password hash. Should not log.
849   service_->MaybeLogPasswordCapture(/*did_log_in=*/false);
850   ASSERT_EQ(0ul, GetUserEventService()->GetRecordedUserEvents().size());
851 
852   // Cases 2 and 3: With a password hash. Should log.
853   service_ = NewMockPasswordProtectionService(
854       /*sync_password_hash=*/"some-hash-value");
855   service_->SetIsAccountSignedIn(true);
856   service_->MaybeLogPasswordCapture(/*did_log_in=*/false);
857   ASSERT_EQ(1ul, GetUserEventService()->GetRecordedUserEvents().size());
858   GaiaPasswordCaptured event = GetUserEventService()
859                                    ->GetRecordedUserEvents()[0]
860                                    .gaia_password_captured_event();
861   EXPECT_EQ(event.event_trigger(), GaiaPasswordCaptured::EXPIRED_28D_TIMER);
862 
863   service_->MaybeLogPasswordCapture(/*did_log_in=*/true);
864   ASSERT_EQ(2ul, GetUserEventService()->GetRecordedUserEvents().size());
865   event = GetUserEventService()
866               ->GetRecordedUserEvents()[1]
867               .gaia_password_captured_event();
868   EXPECT_EQ(event.event_trigger(), GaiaPasswordCaptured::USER_LOGGED_IN);
869 }
870 
871 // Check that we reschedule after logging.
TEST_F(ChromePasswordProtectionServiceTest,VerifyPasswordCaptureEventReschedules)872 TEST_F(ChromePasswordProtectionServiceTest,
873        VerifyPasswordCaptureEventReschedules) {
874   // Configure sync account type to GMAIL.
875   CoreAccountInfo account_info = SetPrimaryAccount(kTestEmail);
876   SetUpSyncAccount(kNoHostedDomainFound, account_info);
877 
878   // Case 1: Default service_ ctor has an empty password hash, so we don't log
879   // or reschedule the logging.
880   service_->MaybeLogPasswordCapture(/*did_log_in=*/false);
881   EXPECT_FALSE(service_->log_password_capture_timer_.IsRunning());
882 
883   // Case 2: A non-empty password hash.
884   service_ = NewMockPasswordProtectionService(
885       /*sync_password_hash=*/"some-hash-value");
886   service_->SetIsAccountSignedIn(true);
887 
888   service_->MaybeLogPasswordCapture(/*did_log_in=*/false);
889 
890   // Verify the delay is approx correct. Will be 24-28 days, +- clock drift.
891   EXPECT_TRUE(service_->log_password_capture_timer_.IsRunning());
892   base::TimeDelta cur_delay =
893       service_->log_password_capture_timer_.GetCurrentDelay();
894   EXPECT_GT(29, cur_delay.InDays());
895   EXPECT_LT(23, cur_delay.InDays());
896 }
897 #endif
898 
TEST_F(ChromePasswordProtectionServiceTest,VerifyPasswordReuseLookupUserEventRecorded)899 TEST_F(ChromePasswordProtectionServiceTest,
900        VerifyPasswordReuseLookupUserEventRecorded) {
901   // Configure sync account type to GMAIL.
902   CoreAccountInfo account_info = SetPrimaryAccount(kTestEmail);
903   SetUpSyncAccount(kNoHostedDomainFound, account_info);
904 
905   NavigateAndCommit(GURL("https://www.example.com/"));
906 
907   unsigned long t = 0;
908   for (const auto& it : kTestCasesWithoutVerdict) {
909     service_->MaybeLogPasswordReuseLookupEvent(
910         web_contents(), it.request_outcome,
911         PasswordType::PRIMARY_ACCOUNT_PASSWORD, nullptr);
912     ASSERT_EQ(t + 1, GetUserEventService()->GetRecordedUserEvents().size())
913         << t;
914     PasswordReuseLookup reuse_lookup = GetUserEventService()
915                                            ->GetRecordedUserEvents()[t]
916                                            .gaia_password_reuse_event()
917                                            .reuse_lookup();
918     EXPECT_EQ(it.lookup_result, reuse_lookup.lookup_result()) << t;
919     t++;
920   }
921 
922   {
923     auto response = std::make_unique<LoginReputationClientResponse>();
924     response->set_verdict_token("token1");
925     response->set_verdict_type(LoginReputationClientResponse::LOW_REPUTATION);
926     service_->MaybeLogPasswordReuseLookupEvent(
927         web_contents(), RequestOutcome::RESPONSE_ALREADY_CACHED,
928         PasswordType::PRIMARY_ACCOUNT_PASSWORD, response.get());
929     ASSERT_EQ(t + 1, GetUserEventService()->GetRecordedUserEvents().size())
930         << t;
931     PasswordReuseLookup reuse_lookup = GetUserEventService()
932                                            ->GetRecordedUserEvents()[t]
933                                            .gaia_password_reuse_event()
934                                            .reuse_lookup();
935     EXPECT_EQ(PasswordReuseLookup::CACHE_HIT, reuse_lookup.lookup_result())
936         << t;
937     EXPECT_EQ(PasswordReuseLookup::LOW_REPUTATION, reuse_lookup.verdict()) << t;
938     EXPECT_EQ("token1", reuse_lookup.verdict_token()) << t;
939     t++;
940   }
941 
942   {
943     auto response = std::make_unique<LoginReputationClientResponse>();
944     response->set_verdict_token("token2");
945     response->set_verdict_type(LoginReputationClientResponse::SAFE);
946     service_->MaybeLogPasswordReuseLookupEvent(
947         web_contents(), RequestOutcome::SUCCEEDED,
948         PasswordType::PRIMARY_ACCOUNT_PASSWORD, response.get());
949     ASSERT_EQ(t + 1, GetUserEventService()->GetRecordedUserEvents().size())
950         << t;
951     PasswordReuseLookup reuse_lookup = GetUserEventService()
952                                            ->GetRecordedUserEvents()[t]
953                                            .gaia_password_reuse_event()
954                                            .reuse_lookup();
955     EXPECT_EQ(PasswordReuseLookup::REQUEST_SUCCESS,
956               reuse_lookup.lookup_result())
957         << t;
958     EXPECT_EQ(PasswordReuseLookup::SAFE, reuse_lookup.verdict()) << t;
959     EXPECT_EQ("token2", reuse_lookup.verdict_token()) << t;
960     t++;
961   }
962 }
963 
TEST_F(ChromePasswordProtectionServiceTest,VerifyGetDefaultChangePasswordURL)964 TEST_F(ChromePasswordProtectionServiceTest, VerifyGetDefaultChangePasswordURL) {
965   CoreAccountInfo account_info = SetPrimaryAccount(kTestEmail);
966   SetUpSyncAccount("example.com", account_info);
967   EXPECT_EQ(GURL("https://accounts.google.com/"
968                  "AccountChooser?Email=foo%40example.com&continue=https%3A%2F%"
969                  "2Fmyaccount.google.com%2Fsigninoptions%2Fpassword%3Futm_"
970                  "source%3DGoogle%26utm_campaign%3DPhishGuard&hl=en"),
971             service_->GetDefaultChangePasswordURL());
972 }
973 
TEST_F(ChromePasswordProtectionServiceTest,VerifyGetEnterprisePasswordURL)974 TEST_F(ChromePasswordProtectionServiceTest, VerifyGetEnterprisePasswordURL) {
975   // If enterprise change password url is not set. This will return the default
976   // GAIA change password url.
977   EXPECT_TRUE(service_->GetEnterpriseChangePasswordURL().DomainIs(
978       "accounts.google.com"));
979 
980   // Sets enterprise change password url.
981   GURL enterprise_change_password_url("https://changepassword.example.com");
982   profile()->GetPrefs()->SetString(prefs::kPasswordProtectionChangePasswordURL,
983                                    enterprise_change_password_url.spec());
984   EXPECT_EQ(enterprise_change_password_url,
985             service_->GetEnterpriseChangePasswordURL());
986 }
987 
TEST_F(ChromePasswordProtectionServiceTest,VerifyNavigationDuringPasswordOnFocusPingNotBlocked)988 TEST_F(ChromePasswordProtectionServiceTest,
989        VerifyNavigationDuringPasswordOnFocusPingNotBlocked) {
990   GURL trigger_url(kPhishingURL);
991   NavigateAndCommit(trigger_url);
992   PrepareRequest(LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
993                  PasswordType::PASSWORD_TYPE_UNKNOWN,
994                  /*is_warning_showing=*/false);
995   GURL redirect_url(kRedirectURL);
996   content::MockNavigationHandle test_handle(redirect_url, main_rfh());
997   std::unique_ptr<PasswordProtectionNavigationThrottle> throttle =
998       service_->MaybeCreateNavigationThrottle(&test_handle);
999   EXPECT_EQ(nullptr, throttle);
1000 }
1001 
TEST_F(ChromePasswordProtectionServiceTest,VerifyNavigationDuringPasswordReusePingDeferred)1002 TEST_F(ChromePasswordProtectionServiceTest,
1003        VerifyNavigationDuringPasswordReusePingDeferred) {
1004   GURL trigger_url(kPhishingURL);
1005   NavigateAndCommit(trigger_url);
1006   service_->SetIsSyncing(true);
1007   service_->SetIsAccountSignedIn(true);
1008 
1009   // Simulate a on-going password reuse request that hasn't received
1010   // verdict yet.
1011   PrepareRequest(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1012                  PasswordType::SAVED_PASSWORD,
1013                  /*is_warning_showing=*/false);
1014 
1015   GURL redirect_url(kRedirectURL);
1016   bool was_navigation_resumed = false;
1017   content::MockNavigationHandle test_handle(redirect_url, main_rfh());
1018   std::unique_ptr<PasswordProtectionNavigationThrottle> throttle =
1019       service_->MaybeCreateNavigationThrottle(&test_handle);
1020   ASSERT_NE(nullptr, throttle);
1021   throttle->set_resume_callback_for_testing(
1022       base::BindLambdaForTesting([&]() { was_navigation_resumed = true; }));
1023 
1024   // Verify navigation get deferred.
1025   EXPECT_EQ(content::NavigationThrottle::DEFER, throttle->WillStartRequest());
1026   base::RunLoop().RunUntilIdle();
1027 
1028   // Simulate receiving a SAFE verdict.
1029   SimulateRequestFinished(LoginReputationClientResponse::SAFE);
1030   base::RunLoop().RunUntilIdle();
1031   EXPECT_EQ(true, was_navigation_resumed);
1032 
1033   // Verify that navigation can be resumed.
1034   EXPECT_EQ(content::NavigationThrottle::PROCEED,
1035             throttle->WillProcessResponse());
1036 }
1037 
TEST_F(ChromePasswordProtectionServiceTest,VerifyNavigationDuringModalWarningCanceled)1038 TEST_F(ChromePasswordProtectionServiceTest,
1039        VerifyNavigationDuringModalWarningCanceled) {
1040   GURL trigger_url(kPhishingURL);
1041   NavigateAndCommit(trigger_url);
1042   // Simulate a password reuse request, whose verdict is triggering a modal
1043   // warning.
1044   PrepareRequest(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1045                  PasswordType::PRIMARY_ACCOUNT_PASSWORD,
1046                  /*is_warning_showing=*/true);
1047   base::RunLoop().RunUntilIdle();
1048 
1049   // Simulate receiving a phishing verdict.
1050   SimulateRequestFinished(LoginReputationClientResponse::PHISHING);
1051   base::RunLoop().RunUntilIdle();
1052 
1053   GURL redirect_url(kRedirectURL);
1054   content::MockNavigationHandle test_handle(redirect_url, main_rfh());
1055   std::unique_ptr<PasswordProtectionNavigationThrottle> throttle =
1056       service_->MaybeCreateNavigationThrottle(&test_handle);
1057 
1058   // Verify that navigation gets canceled.
1059   EXPECT_EQ(content::NavigationThrottle::CANCEL, throttle->WillStartRequest());
1060 }
1061 
TEST_F(ChromePasswordProtectionServiceTest,VerifyNavigationThrottleRemovedWhenNavigationHandleIsGone)1062 TEST_F(ChromePasswordProtectionServiceTest,
1063        VerifyNavigationThrottleRemovedWhenNavigationHandleIsGone) {
1064   GURL trigger_url(kPhishingURL);
1065   NavigateAndCommit(trigger_url);
1066   service_->SetIsSyncing(true);
1067   service_->SetIsAccountSignedIn(true);
1068   // Simulate a on-going password reuse request that hasn't received
1069   // verdict yet.
1070   PrepareRequest(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1071                  PasswordType::SAVED_PASSWORD,
1072                  /*is_warning_showing=*/false);
1073 
1074   GURL redirect_url(kRedirectURL);
1075   content::MockNavigationHandle test_handle(redirect_url, main_rfh());
1076   std::unique_ptr<PasswordProtectionNavigationThrottle> throttle =
1077       service_->MaybeCreateNavigationThrottle(&test_handle);
1078 
1079   // Verify navigation get deferred.
1080   EXPECT_EQ(content::NavigationThrottle::DEFER, throttle->WillStartRequest());
1081 
1082   EXPECT_EQ(1u, GetNumberOfNavigationThrottles());
1083 
1084   // Simulate the deletion of the PasswordProtectionNavigationThrottle.
1085   throttle.reset();
1086   base::RunLoop().RunUntilIdle();
1087 
1088   // Expect no navigation throttle kept by |request_|.
1089   EXPECT_EQ(0u, GetNumberOfNavigationThrottles());
1090 
1091   // Simulate receiving a SAFE verdict.
1092   SimulateRequestFinished(LoginReputationClientResponse::SAFE);
1093   base::RunLoop().RunUntilIdle();
1094 }
1095 
TEST_F(ChromePasswordProtectionServiceTest,VerifyUnhandledSyncPasswordReuseUponClearHistoryDeletion)1096 TEST_F(ChromePasswordProtectionServiceTest,
1097        VerifyUnhandledSyncPasswordReuseUponClearHistoryDeletion) {
1098   ASSERT_EQ(0, GetSizeofUnhandledSyncPasswordReuses());
1099   GURL url_a("https://www.phishinga.com");
1100   GURL url_b("https://www.phishingb.com");
1101   GURL url_c("https://www.phishingc.com");
1102 
1103   DictionaryPrefUpdate update(profile()->GetPrefs(),
1104                               prefs::kSafeBrowsingUnhandledGaiaPasswordReuses);
1105   update->SetKey(Origin::Create(url_a).Serialize(),
1106                  base::Value("navigation_id_a"));
1107   update->SetKey(Origin::Create(url_b).Serialize(),
1108                  base::Value("navigation_id_b"));
1109   update->SetKey(Origin::Create(url_c).Serialize(),
1110                  base::Value("navigation_id_c"));
1111 
1112   // Delete a https://www.phishinga.com URL.
1113   history::URLRows deleted_urls;
1114   deleted_urls.push_back(history::URLRow(url_a));
1115   deleted_urls.push_back(history::URLRow(GURL("https://www.notinlist.com")));
1116 
1117   service_->RemoveUnhandledSyncPasswordReuseOnURLsDeleted(
1118       /*all_history=*/false, deleted_urls);
1119   base::RunLoop().RunUntilIdle();
1120   EXPECT_EQ(2, GetSizeofUnhandledSyncPasswordReuses());
1121 
1122   service_->RemoveUnhandledSyncPasswordReuseOnURLsDeleted(
1123       /*all_history=*/true, {});
1124   EXPECT_EQ(0, GetSizeofUnhandledSyncPasswordReuses());
1125 }
1126 
1127 // The following tests are disabled on Android, because enterprise reporting
1128 // extension is not supported.
1129 #if !defined(OS_ANDROID)
TEST_F(ChromePasswordProtectionServiceTest,VerifyOnPolicySpecifiedPasswordChangedEvent)1130 TEST_F(ChromePasswordProtectionServiceTest,
1131        VerifyOnPolicySpecifiedPasswordChangedEvent) {
1132   TestExtensionEventObserver event_observer(test_event_router_);
1133 
1134   // Preparing sync account.
1135   CoreAccountInfo account_info = SetPrimaryAccount(kTestEmail);
1136   SetUpSyncAccount("example.com", account_info);
1137   service_->SetIsAccountSignedIn(true);
1138 
1139   // Simulates change password.
1140   service_->OnGaiaPasswordChanged("foo@example.com", false);
1141   base::RunLoop().RunUntilIdle();
1142 
1143   ASSERT_EQ(1, test_event_router_->GetEventCount(
1144                    OnPolicySpecifiedPasswordChanged::kEventName));
1145 
1146   auto captured_args = event_observer.PassEventArgs().GetList()[0].Clone();
1147   EXPECT_EQ("foo@example.com", captured_args.GetString());
1148 
1149   // If user is in incognito mode, no event should be sent.
1150   service_->ConfigService(true /*incognito*/, false /*SBER*/);
1151   service_->OnGaiaPasswordChanged("foo@example.com", false);
1152   base::RunLoop().RunUntilIdle();
1153   // Event count should be unchanged.
1154   EXPECT_EQ(1, test_event_router_->GetEventCount(
1155                    OnPolicySpecifiedPasswordChanged::kEventName));
1156 }
1157 
TEST_F(ChromePasswordProtectionServiceTest,VerifyTriggerOnPolicySpecifiedPasswordReuseDetectedForGsuiteUser)1158 TEST_F(ChromePasswordProtectionServiceTest,
1159        VerifyTriggerOnPolicySpecifiedPasswordReuseDetectedForGsuiteUser) {
1160   TestExtensionEventObserver event_observer(test_event_router_);
1161   CoreAccountInfo account_info = SetPrimaryAccount(kTestEmail);
1162   SetUpSyncAccount("example.com", account_info);
1163   profile()->GetPrefs()->SetInteger(prefs::kPasswordProtectionWarningTrigger,
1164                                     PASSWORD_REUSE);
1165   NavigateAndCommit(GURL(kPasswordReuseURL));
1166 
1167   service_->MaybeReportPasswordReuseDetected(web_contents(), kUserName,
1168                                              PasswordType::ENTERPRISE_PASSWORD,
1169                                              /*is_phishing_url =*/true);
1170   base::RunLoop().RunUntilIdle();
1171 
1172   ASSERT_EQ(1, test_event_router_->GetEventCount(
1173                    OnPolicySpecifiedPasswordReuseDetected::kEventName));
1174   auto captured_args = event_observer.PassEventArgs().GetList()[0].Clone();
1175   EXPECT_EQ(kPasswordReuseURL, captured_args.FindKey("url")->GetString());
1176   EXPECT_EQ(kUserName, captured_args.FindKey("userName")->GetString());
1177   EXPECT_TRUE(captured_args.FindKey("isPhishingUrl")->GetBool());
1178 
1179   // If the reused password is not Enterprise password but the account is
1180   // GSuite, event should be sent.
1181   service_->SetAccountInfo(kUserName);
1182   service_->SetIsAccountSignedIn(true);
1183   service_->MaybeReportPasswordReuseDetected(web_contents(), kUserName,
1184                                              PasswordType::OTHER_GAIA_PASSWORD,
1185                                              /*is_phishing_url =*/true);
1186   base::RunLoop().RunUntilIdle();
1187 
1188   ASSERT_EQ(2, test_event_router_->GetEventCount(
1189                    OnPolicySpecifiedPasswordReuseDetected::kEventName));
1190 
1191   // If no password is used , no event should be sent.
1192   service_->MaybeReportPasswordReuseDetected(
1193       web_contents(), kUserName, PasswordType::PASSWORD_TYPE_UNKNOWN,
1194       /*is_phishing_url =*/true);
1195   base::RunLoop().RunUntilIdle();
1196   EXPECT_EQ(2, test_event_router_->GetEventCount(
1197                    OnPolicySpecifiedPasswordReuseDetected::kEventName));
1198 
1199   // If user is in incognito mode, no event should be sent.
1200   service_->ConfigService(true /*incognito*/, false /*SBER*/);
1201   service_->MaybeReportPasswordReuseDetected(web_contents(), kUserName,
1202                                              PasswordType::ENTERPRISE_PASSWORD,
1203                                              /*is_phishing_url =*/true);
1204   base::RunLoop().RunUntilIdle();
1205   EXPECT_EQ(2, test_event_router_->GetEventCount(
1206                    OnPolicySpecifiedPasswordReuseDetected::kEventName));
1207 }
1208 
TEST_F(ChromePasswordProtectionServiceTest,VerifyTriggerOnPolicySpecifiedPasswordReuseDetectedForGmailUser)1209 TEST_F(ChromePasswordProtectionServiceTest,
1210        VerifyTriggerOnPolicySpecifiedPasswordReuseDetectedForGmailUser) {
1211   TestExtensionEventObserver event_observer(test_event_router_);
1212 
1213   // If user is a Gmail user and enterprise password is used, event should be
1214   // sent.
1215   CoreAccountInfo gmail_account_info = SetPrimaryAccount(kTestGmail);
1216   SetUpSyncAccount(kNoHostedDomainFound, gmail_account_info);
1217   profile()->GetPrefs()->SetInteger(prefs::kPasswordProtectionWarningTrigger,
1218                                     PASSWORD_REUSE);
1219   NavigateAndCommit(GURL(kPasswordReuseURL));
1220 
1221   service_->MaybeReportPasswordReuseDetected(web_contents(), kUserName,
1222                                              PasswordType::ENTERPRISE_PASSWORD,
1223                                              /*is_phishing_url =*/true);
1224   base::RunLoop().RunUntilIdle();
1225   EXPECT_EQ(1, test_event_router_->GetEventCount(
1226                    OnPolicySpecifiedPasswordReuseDetected::kEventName));
1227 
1228   // If user is a Gmail user and not an enterprise password is used , no event
1229   // should be sent.
1230   service_->MaybeReportPasswordReuseDetected(web_contents(), kUserName,
1231                                              PasswordType::OTHER_GAIA_PASSWORD,
1232                                              /*is_phishing_url =*/true);
1233   base::RunLoop().RunUntilIdle();
1234   EXPECT_EQ(1, test_event_router_->GetEventCount(
1235                    OnPolicySpecifiedPasswordReuseDetected::kEventName));
1236 
1237   // If user is a Gmail user and no password is used , no event should be sent.
1238   service_->MaybeReportPasswordReuseDetected(
1239       web_contents(), kUserName, PasswordType::PASSWORD_TYPE_UNKNOWN,
1240       /*is_phishing_url =*/true);
1241   base::RunLoop().RunUntilIdle();
1242   EXPECT_EQ(1, test_event_router_->GetEventCount(
1243                    OnPolicySpecifiedPasswordReuseDetected::kEventName));
1244 }
1245 #endif
1246 
TEST_F(ChromePasswordProtectionServiceTest,VerifyGetWarningDetailTextSaved)1247 TEST_F(ChromePasswordProtectionServiceTest, VerifyGetWarningDetailTextSaved) {
1248   base::string16 warning_text =
1249       l10n_util::GetStringUTF16(IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_SAVED);
1250   ReusedPasswordAccountType reused_password_type;
1251   reused_password_type.set_account_type(
1252       ReusedPasswordAccountType::SAVED_PASSWORD);
1253   std::vector<size_t> placeholder_offsets;
1254   EXPECT_EQ(warning_text, service_->GetWarningDetailText(reused_password_type,
1255                                                          &placeholder_offsets));
1256 }
1257 
TEST_F(ChromePasswordProtectionServiceTest,VerifyGetWarningDetailTextSavedDomains)1258 TEST_F(ChromePasswordProtectionServiceTest,
1259        VerifyGetWarningDetailTextSavedDomains) {
1260   base::test::ScopedFeatureList feature_list;
1261   feature_list.InitWithFeaturesAndParameters(
1262       {}, {password_manager::features::kPasswordCheck});
1263   ReusedPasswordAccountType reused_password_type;
1264   reused_password_type.set_account_type(
1265       ReusedPasswordAccountType::SAVED_PASSWORD);
1266   std::vector<std::string> domains{"www.example.com"};
1267   service_->set_saved_passwords_matching_domains(domains);
1268   base::string16 warning_text = l10n_util::GetStringFUTF16(
1269       IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_SAVED_1_DOMAIN,
1270       base::UTF8ToUTF16(domains[0]));
1271   std::vector<size_t> placeholder_offsets;
1272   EXPECT_EQ(warning_text, service_->GetWarningDetailText(reused_password_type,
1273                                                          &placeholder_offsets));
1274   // GetWarningDetailText shouldCall GetWarningDetailTextForSavedPasswords, so
1275   // we can check to see if the placeholder offset values are the same.
1276   // Hardcoding the offset in the expected value cannot be done as it's
1277   // different for different OS.
1278   std::vector<size_t> expected_placeholder_offsets;
1279   service_->GetWarningDetailTextForSavedPasswords(
1280       &expected_placeholder_offsets);
1281   EXPECT_EQ(expected_placeholder_offsets, placeholder_offsets);
1282 
1283   placeholder_offsets.clear();
1284   domains.push_back("www.2.example.com");
1285   service_->set_saved_passwords_matching_domains(domains);
1286   warning_text = l10n_util::GetStringFUTF16(
1287       IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_SAVED_2_DOMAINS,
1288       base::UTF8ToUTF16(domains[0]), base::UTF8ToUTF16(domains[1]));
1289   EXPECT_EQ(warning_text, service_->GetWarningDetailText(reused_password_type,
1290                                                          &placeholder_offsets));
1291   expected_placeholder_offsets.clear();
1292   service_->GetWarningDetailTextForSavedPasswords(
1293       &expected_placeholder_offsets);
1294   EXPECT_EQ(expected_placeholder_offsets, placeholder_offsets);
1295 
1296   placeholder_offsets.clear();
1297   domains.push_back("www.3.example.com");
1298   service_->set_saved_passwords_matching_domains(domains);
1299   warning_text = l10n_util::GetStringFUTF16(
1300       IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_SAVED_3_DOMAINS,
1301       base::UTF8ToUTF16(domains[0]), base::UTF8ToUTF16(domains[1]),
1302       base::UTF8ToUTF16(domains[2]));
1303   EXPECT_EQ(warning_text, service_->GetWarningDetailText(reused_password_type,
1304                                                          &placeholder_offsets));
1305   expected_placeholder_offsets.clear();
1306   service_->GetWarningDetailTextForSavedPasswords(
1307       &expected_placeholder_offsets);
1308   EXPECT_EQ(expected_placeholder_offsets, placeholder_offsets);
1309 
1310   // Default domains should be prioritzed over other domains.
1311   placeholder_offsets.clear();
1312   domains.push_back("yahoo.com");
1313   service_->set_saved_passwords_matching_domains(domains);
1314   warning_text = l10n_util::GetStringFUTF16(
1315       IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_SAVED_3_DOMAINS,
1316       base::UTF8ToUTF16("yahoo.com"), base::UTF8ToUTF16(domains[0]),
1317       base::UTF8ToUTF16(domains[1]));
1318   EXPECT_EQ(warning_text, service_->GetWarningDetailText(reused_password_type,
1319                                                          &placeholder_offsets));
1320   expected_placeholder_offsets.clear();
1321   service_->GetWarningDetailTextForSavedPasswords(
1322       &expected_placeholder_offsets);
1323   EXPECT_EQ(expected_placeholder_offsets, placeholder_offsets);
1324 
1325   // Matching domains that have a suffix of a default domains should be
1326   // prioritzed over other non common spoofed domains.
1327   placeholder_offsets.clear();
1328   domains.push_back("login.amazon.com");
1329   service_->set_saved_passwords_matching_domains(domains);
1330   warning_text = l10n_util::GetStringFUTF16(
1331       IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_SAVED_3_DOMAINS,
1332       base::UTF8ToUTF16("yahoo.com"), base::UTF8ToUTF16("login.amazon.com"),
1333       base::UTF8ToUTF16(domains[0]));
1334   EXPECT_EQ(warning_text, service_->GetWarningDetailText(reused_password_type,
1335                                                          &placeholder_offsets));
1336   expected_placeholder_offsets.clear();
1337   service_->GetWarningDetailTextForSavedPasswords(
1338       &expected_placeholder_offsets);
1339   EXPECT_EQ(expected_placeholder_offsets, placeholder_offsets);
1340 }
1341 
TEST_F(ChromePasswordProtectionServiceTest,VerifyGetWarningDetailTextCheckSavedDomains)1342 TEST_F(ChromePasswordProtectionServiceTest,
1343        VerifyGetWarningDetailTextCheckSavedDomains) {
1344   base::test::ScopedFeatureList feature_list;
1345   feature_list.InitAndEnableFeature(password_manager::features::kPasswordCheck);
1346   ReusedPasswordAccountType reused_password_type;
1347   reused_password_type.set_account_type(
1348       ReusedPasswordAccountType::SAVED_PASSWORD);
1349   std::vector<std::string> domains{"www.example.com"};
1350   service_->set_saved_passwords_matching_domains(domains);
1351   base::string16 warning_text = l10n_util::GetStringFUTF16(
1352       IDS_PAGE_INFO_CHECK_PASSWORD_DETAILS_SAVED_1_DOMAIN,
1353       base::UTF8ToUTF16(domains[0]));
1354   std::vector<size_t> placeholder_offsets;
1355   EXPECT_EQ(warning_text, service_->GetWarningDetailText(reused_password_type,
1356                                                          &placeholder_offsets));
1357 
1358   placeholder_offsets.clear();
1359   domains.push_back("www.2.example.com");
1360   service_->set_saved_passwords_matching_domains(domains);
1361   warning_text = l10n_util::GetStringFUTF16(
1362       IDS_PAGE_INFO_CHECK_PASSWORD_DETAILS_SAVED_2_DOMAIN,
1363       base::UTF8ToUTF16(domains[0]), base::UTF8ToUTF16(domains[1]));
1364   EXPECT_EQ(warning_text, service_->GetWarningDetailText(reused_password_type,
1365                                                          &placeholder_offsets));
1366 
1367   placeholder_offsets.clear();
1368   domains.push_back("www.3.example.com");
1369   service_->set_saved_passwords_matching_domains(domains);
1370   warning_text = l10n_util::GetStringFUTF16(
1371       IDS_PAGE_INFO_CHECK_PASSWORD_DETAILS_SAVED_3_DOMAIN,
1372       base::UTF8ToUTF16(domains[0]), base::UTF8ToUTF16(domains[1]),
1373       base::UTF8ToUTF16(domains[2]));
1374   EXPECT_EQ(warning_text, service_->GetWarningDetailText(reused_password_type,
1375                                                          &placeholder_offsets));
1376   // Default domains should be prioritzed over other domains.
1377   placeholder_offsets.clear();
1378   domains.push_back("amazon.com");
1379   service_->set_saved_passwords_matching_domains(domains);
1380   warning_text = l10n_util::GetStringFUTF16(
1381       IDS_PAGE_INFO_CHECK_PASSWORD_DETAILS_SAVED_3_DOMAIN,
1382       base::UTF8ToUTF16("amazon.com"), base::UTF8ToUTF16(domains[0]),
1383       base::UTF8ToUTF16(domains[1]));
1384   EXPECT_EQ(warning_text, service_->GetWarningDetailText(reused_password_type,
1385                                                          &placeholder_offsets));
1386 }
TEST_F(ChromePasswordProtectionServiceTest,VerifyGetPlaceholdersForSavedPasswordWarningText)1387 TEST_F(ChromePasswordProtectionServiceTest,
1388        VerifyGetPlaceholdersForSavedPasswordWarningText) {
1389   std::vector<std::string> domains{"www.example.com"};
1390   domains.push_back("www.2.example.com");
1391   domains.push_back("www.3.example.com");
1392   domains.push_back("amazon.com");
1393   service_->set_saved_passwords_matching_domains(domains);
1394   // Default domains should be prioritzed over other domains.
1395   std::vector<base::string16> expected_placeholders{
1396       base::UTF8ToUTF16("amazon.com"), base::UTF8ToUTF16(domains[0]),
1397       base::UTF8ToUTF16(domains[1])};
1398   EXPECT_EQ(expected_placeholders,
1399             service_->GetPlaceholdersForSavedPasswordWarningText());
1400 }
1401 
TEST_F(ChromePasswordProtectionServiceTest,VerifyGetWarningDetailTextEnterprise)1402 TEST_F(ChromePasswordProtectionServiceTest,
1403        VerifyGetWarningDetailTextEnterprise) {
1404   base::string16 warning_text_non_sync = l10n_util::GetStringUTF16(
1405       IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_SIGNED_IN_NON_SYNC);
1406   base::string16 generic_enterprise_warning_text = l10n_util::GetStringUTF16(
1407       IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_ENTERPRISE);
1408   base::string16 warning_text_with_org_name = l10n_util::GetStringFUTF16(
1409       IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_ENTERPRISE_WITH_ORG_NAME,
1410       base::UTF8ToUTF16("example.com"));
1411   base::string16 warning_text_sync =
1412       l10n_util::GetStringUTF16(IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_SYNC);
1413 
1414   ReusedPasswordAccountType reused_password_type;
1415   reused_password_type.set_account_type(ReusedPasswordAccountType::GMAIL);
1416   reused_password_type.set_is_account_syncing(true);
1417   std::vector<size_t> placeholder_offsets;
1418   EXPECT_EQ(warning_text_sync, service_->GetWarningDetailText(
1419                                    reused_password_type, &placeholder_offsets));
1420   reused_password_type.set_account_type(
1421       ReusedPasswordAccountType::NON_GAIA_ENTERPRISE);
1422   reused_password_type.set_is_account_syncing(false);
1423   EXPECT_EQ(generic_enterprise_warning_text,
1424             service_->GetWarningDetailText(reused_password_type,
1425                                            &placeholder_offsets));
1426   {
1427     base::test::ScopedFeatureList feature_list;
1428     feature_list.InitAndEnableFeature(
1429         safe_browsing::kPasswordProtectionForSignedInUsers);
1430     reused_password_type.set_account_type(ReusedPasswordAccountType::GSUITE);
1431     EXPECT_EQ(warning_text_non_sync,
1432               service_->GetWarningDetailText(reused_password_type,
1433                                              &placeholder_offsets));
1434   }
1435 
1436   reused_password_type.set_account_type(ReusedPasswordAccountType::GSUITE);
1437   reused_password_type.set_is_account_syncing(true);
1438   CoreAccountInfo core_account_info = SetPrimaryAccount(kTestEmail);
1439   SetUpSyncAccount(std::string("example.com"), core_account_info);
1440   EXPECT_EQ(warning_text_with_org_name,
1441             service_->GetWarningDetailText(reused_password_type,
1442                                            &placeholder_offsets));
1443   reused_password_type.set_account_type(
1444       ReusedPasswordAccountType::NON_GAIA_ENTERPRISE);
1445   EXPECT_EQ(generic_enterprise_warning_text,
1446             service_->GetWarningDetailText(reused_password_type,
1447                                            &placeholder_offsets));
1448 }
1449 
TEST_F(ChromePasswordProtectionServiceTest,VerifyGetWarningDetailTextGmail)1450 TEST_F(ChromePasswordProtectionServiceTest, VerifyGetWarningDetailTextGmail) {
1451   base::string16 warning_text_non_sync = l10n_util::GetStringUTF16(
1452       IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_SIGNED_IN_NON_SYNC);
1453   base::string16 warning_text_sync =
1454       l10n_util::GetStringUTF16(IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_SYNC);
1455 
1456   base::test::ScopedFeatureList feature_list;
1457   feature_list.InitAndEnableFeature(
1458       safe_browsing::kPasswordProtectionForSignedInUsers);
1459   ReusedPasswordAccountType reused_password_type;
1460   reused_password_type.set_account_type(ReusedPasswordAccountType::GMAIL);
1461   std::vector<size_t> placeholder_offsets;
1462   EXPECT_EQ(warning_text_non_sync,
1463             service_->GetWarningDetailText(reused_password_type,
1464                                            &placeholder_offsets));
1465   reused_password_type.set_is_account_syncing(true);
1466   EXPECT_EQ(warning_text_sync, service_->GetWarningDetailText(
1467                                    reused_password_type, &placeholder_offsets));
1468 }
1469 
TEST_F(ChromePasswordProtectionServiceTest,VerifyCanShowInterstitial)1470 TEST_F(ChromePasswordProtectionServiceTest, VerifyCanShowInterstitial) {
1471   // Do not show interstitial if policy not set for password_alert.
1472   ASSERT_FALSE(
1473       profile()->GetPrefs()->HasPrefPath(prefs::kSafeBrowsingWhitelistDomains));
1474   GURL trigger_url = GURL(kPhishingURL);
1475   ReusedPasswordAccountType reused_password_type;
1476   reused_password_type.set_account_type(
1477       ReusedPasswordAccountType::SAVED_PASSWORD);
1478   EXPECT_FALSE(
1479       service_->CanShowInterstitial(reused_password_type, trigger_url));
1480   reused_password_type.set_account_type(ReusedPasswordAccountType::GSUITE);
1481   reused_password_type.set_is_account_syncing(true);
1482   EXPECT_FALSE(
1483       service_->CanShowInterstitial(reused_password_type, trigger_url));
1484   {
1485     base::test::ScopedFeatureList feature_list;
1486     feature_list.InitAndEnableFeature(
1487         safe_browsing::kPasswordProtectionForSignedInUsers);
1488     service_->SetAccountInfo(kUserName);
1489     reused_password_type.set_is_account_syncing(false);
1490     EXPECT_FALSE(
1491         service_->CanShowInterstitial(reused_password_type, trigger_url));
1492   }
1493 
1494   reused_password_type.set_account_type(
1495       ReusedPasswordAccountType::NON_GAIA_ENTERPRISE);
1496   reused_password_type.set_is_account_syncing(false);
1497   EXPECT_FALSE(
1498       service_->CanShowInterstitial(reused_password_type, trigger_url));
1499   reused_password_type.set_account_type(
1500       ReusedPasswordAccountType::SAVED_PASSWORD);
1501   EXPECT_FALSE(
1502       service_->CanShowInterstitial(reused_password_type, trigger_url));
1503   // Show interstitial if user is a syncing GSuite user and the policy is set to
1504   // password_alert.
1505   reused_password_type.set_account_type(ReusedPasswordAccountType::GSUITE);
1506   reused_password_type.set_is_account_syncing(true);
1507   profile()->GetPrefs()->SetInteger(prefs::kPasswordProtectionWarningTrigger,
1508                                     PASSWORD_REUSE);
1509   EXPECT_TRUE(service_->CanShowInterstitial(reused_password_type, trigger_url));
1510   {
1511     base::test::ScopedFeatureList feature_list;
1512     feature_list.InitAndEnableFeature(
1513         safe_browsing::kPasswordProtectionForSignedInUsers);
1514     service_->SetAccountInfo(kUserName);
1515     reused_password_type.set_account_type(ReusedPasswordAccountType::GSUITE);
1516     reused_password_type.set_is_account_syncing(false);
1517     profile()->GetPrefs()->SetInteger(prefs::kPasswordProtectionWarningTrigger,
1518                                       PASSWORD_REUSE);
1519     EXPECT_TRUE(
1520         service_->CanShowInterstitial(reused_password_type, trigger_url));
1521   }
1522   // Show interstitial if user is a Enterprise user and the policy is set to
1523   // password_alert.
1524   reused_password_type.set_account_type(
1525       ReusedPasswordAccountType::NON_GAIA_ENTERPRISE);
1526   reused_password_type.set_is_account_syncing(false);
1527   profile()->GetPrefs()->SetInteger(prefs::kPasswordProtectionWarningTrigger,
1528                                     PASSWORD_REUSE);
1529   EXPECT_TRUE(service_->CanShowInterstitial(reused_password_type, trigger_url));
1530 
1531   // Add |trigger_url| to enterprise whitelist.
1532   base::ListValue whitelisted_domains;
1533   whitelisted_domains.AppendString(trigger_url.host());
1534   profile()->GetPrefs()->Set(prefs::kSafeBrowsingWhitelistDomains,
1535                              whitelisted_domains);
1536   reused_password_type.set_account_type(
1537       ReusedPasswordAccountType::SAVED_PASSWORD);
1538   reused_password_type.set_is_account_syncing(false);
1539   EXPECT_FALSE(
1540       service_->CanShowInterstitial(reused_password_type, trigger_url));
1541   reused_password_type.set_account_type(ReusedPasswordAccountType::GSUITE);
1542   reused_password_type.set_is_account_syncing(true);
1543   EXPECT_FALSE(
1544       service_->CanShowInterstitial(reused_password_type, trigger_url));
1545 }
1546 
TEST_F(ChromePasswordProtectionServiceTest,VerifySendsPingForAboutBlank)1547 TEST_F(ChromePasswordProtectionServiceTest, VerifySendsPingForAboutBlank) {
1548   ReusedPasswordAccountType reused_password_type;
1549   reused_password_type.set_account_type(
1550       ReusedPasswordAccountType::SAVED_PASSWORD);
1551   service_->ConfigService(false /*incognito*/, true /*SBER*/);
1552   EXPECT_TRUE(
1553       service_->CanSendPing(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1554                             GURL("about:blank"), reused_password_type));
1555 }
1556 
TEST_F(ChromePasswordProtectionServiceTest,VerifyGetPingNotSentReason)1557 TEST_F(ChromePasswordProtectionServiceTest, VerifyGetPingNotSentReason) {
1558   {
1559     // SBER disabled.
1560     ReusedPasswordAccountType reused_password_type;
1561     service_->ConfigService(false /*incognito*/, false /*SBER*/);
1562     EXPECT_EQ(RequestOutcome::DISABLED_DUE_TO_USER_POPULATION,
1563               service_->GetPingNotSentReason(
1564                   LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
1565                   GURL("about:blank"), reused_password_type));
1566     reused_password_type.set_account_type(ReusedPasswordAccountType::UNKNOWN);
1567     EXPECT_EQ(RequestOutcome::DISABLED_DUE_TO_USER_POPULATION,
1568               service_->GetPingNotSentReason(
1569                   LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1570                   GURL("about:blank"), reused_password_type));
1571   }
1572   {
1573     // In Incognito.
1574     ReusedPasswordAccountType reused_password_type;
1575     service_->ConfigService(true /*incognito*/, true /*SBER*/);
1576     EXPECT_EQ(RequestOutcome::DISABLED_DUE_TO_INCOGNITO,
1577               service_->GetPingNotSentReason(
1578                   LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
1579                   GURL("about:blank"), reused_password_type));
1580   }
1581   {
1582     // Turned off by admin.
1583     ReusedPasswordAccountType reused_password_type;
1584     service_->ConfigService(false /*incognito*/, false /*SBER*/);
1585     reused_password_type.set_account_type(ReusedPasswordAccountType::GSUITE);
1586     profile()->GetPrefs()->SetInteger(prefs::kPasswordProtectionWarningTrigger,
1587                                       PASSWORD_PROTECTION_OFF);
1588     EXPECT_EQ(RequestOutcome::TURNED_OFF_BY_ADMIN,
1589               service_->GetPingNotSentReason(
1590                   LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1591                   GURL("about:blank"), reused_password_type));
1592   }
1593   {
1594     // Whitelisted by policy.
1595     ReusedPasswordAccountType reused_password_type;
1596     service_->ConfigService(false /*incognito*/, false /*SBER*/);
1597     reused_password_type.set_account_type(ReusedPasswordAccountType::GSUITE);
1598     profile()->GetPrefs()->SetInteger(prefs::kPasswordProtectionWarningTrigger,
1599                                       PHISHING_REUSE);
1600     base::ListValue whitelist;
1601     whitelist.AppendString("mydomain.com");
1602     whitelist.AppendString("mydomain.net");
1603     profile()->GetPrefs()->Set(prefs::kSafeBrowsingWhitelistDomains, whitelist);
1604     EXPECT_EQ(RequestOutcome::MATCHED_ENTERPRISE_WHITELIST,
1605               service_->GetPingNotSentReason(
1606                   LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1607                   GURL("https://www.mydomain.com"), reused_password_type));
1608   }
1609   {
1610     // Password alert mode.
1611     ReusedPasswordAccountType reused_password_type;
1612     service_->ConfigService(false /*incognito*/, false /*SBER*/);
1613     reused_password_type.set_account_type(ReusedPasswordAccountType::UNKNOWN);
1614     profile()->GetPrefs()->SetInteger(prefs::kPasswordProtectionWarningTrigger,
1615                                       PASSWORD_REUSE);
1616     EXPECT_EQ(RequestOutcome::PASSWORD_ALERT_MODE,
1617               service_->GetPingNotSentReason(
1618                   LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
1619                   GURL("about:blank"), reused_password_type));
1620   }
1621 }
1622 
1623 namespace {
1624 
1625 class ChromePasswordProtectionServiceWithAccountPasswordStoreTest
1626     : public ChromePasswordProtectionServiceTest {
1627  public:
ChromePasswordProtectionServiceWithAccountPasswordStoreTest()1628   ChromePasswordProtectionServiceWithAccountPasswordStoreTest() {
1629     feature_list_.InitAndEnableFeature(
1630         password_manager::features::kEnablePasswordsAccountStorage);
1631   }
1632 
1633  private:
1634   base::test::ScopedFeatureList feature_list_;
1635 };
1636 
TEST_F(ChromePasswordProtectionServiceWithAccountPasswordStoreTest,VerifyPersistPhishedSavedPasswordCredential)1637 TEST_F(ChromePasswordProtectionServiceWithAccountPasswordStoreTest,
1638        VerifyPersistPhishedSavedPasswordCredential) {
1639   service_->ConfigService(/*is_incognito=*/false,
1640                           /*is_extended_reporting=*/true);
1641   std::vector<password_manager::MatchingReusedCredential> credentials = {
1642       {.signon_realm = "http://example.test",
1643        .in_store = password_manager::PasswordForm::Store::kAccountStore},
1644       {.signon_realm = "http://2.example.test",
1645        .in_store = password_manager::PasswordForm::Store::kAccountStore}};
1646 
1647   EXPECT_CALL(*account_password_store_, AddCompromisedCredentialsImpl(_))
1648       .Times(2);
1649   service_->PersistPhishedSavedPasswordCredential(credentials);
1650 }
1651 
TEST_F(ChromePasswordProtectionServiceWithAccountPasswordStoreTest,VerifyRemovePhishedSavedPasswordCredential)1652 TEST_F(ChromePasswordProtectionServiceWithAccountPasswordStoreTest,
1653        VerifyRemovePhishedSavedPasswordCredential) {
1654   service_->ConfigService(/*is_incognito=*/false,
1655                           /*is_extended_reporting=*/true);
1656   std::vector<password_manager::MatchingReusedCredential> credentials = {
1657       {"http://example.test", base::ASCIIToUTF16("username1"),
1658        password_manager::PasswordForm::Store::kAccountStore},
1659       {"http://2.example.test", base::ASCIIToUTF16("username2"),
1660        password_manager::PasswordForm::Store::kAccountStore}};
1661 
1662   EXPECT_CALL(*account_password_store_,
1663               RemoveCompromisedCredentialsImpl(
1664                   _, _,
1665                   password_manager::RemoveCompromisedCredentialsReason::
1666                       kMarkSiteAsLegitimate))
1667       .Times(2);
1668   service_->RemovePhishedSavedPasswordCredential(credentials);
1669 }
1670 
1671 }  // namespace
1672 
1673 }  // namespace safe_browsing
1674