blob: 3ebba7383ae5c99cba63f7ce5386aba2719b3cee [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/safe_browsing/chrome_password_protection_service.h"
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "build/build_config.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/ssl/security_state_tab_helper.h"
#include "chrome/browser/sync/sync_service_factory.h"
#include "chrome/browser/sync/test/integration/sync_service_impl_harness.h"
#include "chrome/browser/sync/test/integration/sync_test.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/password_manager/core/browser/hash_password_manager.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/safe_browsing/content/browser/password_protection/password_protection_request_content.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/security_state/core/security_state.h"
#include "components/signin/public/base/signin_pref_names.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/signin/public/identity_manager/identity_test_utils.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync/driver/sync_user_settings.h"
#include "components/sync/test/fake_server/fake_server_network_resources.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace {
const char kLoginPageUrl[] = "/safe_browsing/login_page.html";
const char kChangePasswordUrl[] = "/safe_browsing/change_password_page.html";
} // namespace
using ChromePasswordProtectionService =
safe_browsing::ChromePasswordProtectionService;
using PasswordProtectionTrigger = safe_browsing::PasswordProtectionTrigger;
using password_manager::metrics_util::PasswordType;
using WarningUIType = safe_browsing::WarningUIType;
using WarningAction = safe_browsing::WarningAction;
// This test suite tests functionality that requires Sync to be active.
class ChromePasswordProtectionServiceSyncBrowserTest : public SyncTest {
public:
ChromePasswordProtectionServiceSyncBrowserTest() : SyncTest(SINGLE_CLIENT) {}
ChromePasswordProtectionServiceSyncBrowserTest(
const ChromePasswordProtectionServiceSyncBrowserTest&) = delete;
ChromePasswordProtectionServiceSyncBrowserTest& operator=(
const ChromePasswordProtectionServiceSyncBrowserTest&) = delete;
void SetUpOnMainThread() override {
SyncTest::SetUpOnMainThread();
ASSERT_TRUE(embedded_test_server()->Start());
syncer::SyncServiceImpl* sync_service =
SyncServiceFactory::GetAsSyncServiceImplForProfile(
browser()->profile());
sync_service->OverrideNetworkForTest(
fake_server::CreateFakeServerHttpPostProviderFactory(
GetFakeServer()->AsWeakPtr()));
std::string username;
if (username.empty()) {
username = "user@example.com";
}
std::unique_ptr<SyncServiceImplHarness> harness =
SyncServiceImplHarness::Create(
browser()->profile(), username, "password",
SyncServiceImplHarness::SigninType::FAKE_SIGNIN);
// Sign the profile in.
ASSERT_TRUE(harness->SignInPrimaryAccount());
CoreAccountInfo current_info =
IdentityManagerFactory::GetForProfile(browser()->profile())
->GetPrimaryAccountInfo(signin::ConsentLevel::kSync);
// Need to update hosted domain since it is not populated.
AccountInfo account_info;
account_info.account_id = current_info.account_id;
account_info.gaia = current_info.gaia;
account_info.email = current_info.email;
account_info.hosted_domain = "domain.com";
signin::UpdateAccountInfoForAccount(
IdentityManagerFactory::GetForProfile(browser()->profile()),
account_info);
ASSERT_TRUE(harness->SetupSync());
}
safe_browsing::ChromePasswordProtectionService* GetService(
bool is_incognito) {
return ChromePasswordProtectionService::GetPasswordProtectionService(
is_incognito ? browser()->profile()->GetPrimaryOTRProfile(
/*create_if_needed=*/true)
: browser()->profile());
}
void ConfigureEnterprisePasswordProtection(
PasswordProtectionTrigger trigger_type) {
browser()->profile()->GetPrefs()->SetInteger(
prefs::kPasswordProtectionWarningTrigger, trigger_type);
browser()->profile()->GetPrefs()->SetString(
prefs::kPasswordProtectionChangePasswordURL,
embedded_test_server()->GetURL(kChangePasswordUrl).spec());
}
};
IN_PROC_BROWSER_TEST_F(ChromePasswordProtectionServiceSyncBrowserTest,
GSuitePasswordAlertMode) {
ConfigureEnterprisePasswordProtection(
PasswordProtectionTrigger::PASSWORD_REUSE);
ChromePasswordProtectionService* service = GetService(/*is_incognito=*/false);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL(kLoginPageUrl)));
base::HistogramTester histograms;
// Shows interstitial on current web_contents.
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
safe_browsing::ReusedPasswordAccountType reused_password_account_type;
reused_password_account_type.set_account_type(
safe_browsing::ReusedPasswordAccountType::GSUITE);
reused_password_account_type.set_is_account_syncing(true);
service->set_reused_password_account_type_for_last_shown_warning(
reused_password_account_type);
service->ShowInterstitial(web_contents, reused_password_account_type);
content::WebContents* interstitial_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::TestNavigationObserver observer(interstitial_web_contents,
/*number_of_navigations=*/1);
observer.Wait();
// chrome://reset-password page should be opened in a new foreground tab.
ASSERT_EQ(2, browser()->tab_strip_model()->count());
ASSERT_EQ(GURL(chrome::kChromeUIResetPasswordURL),
interstitial_web_contents->GetVisibleURL());
EXPECT_THAT(histograms.GetAllSamples("PasswordProtection.InterstitialString"),
testing::ElementsAre(base::Bucket(3, 1)));
// Clicks on "Reset Password" button.
std::string script =
"var node = document.getElementById('reset-password-button'); \n"
"node.click();";
ASSERT_TRUE(content::ExecuteScript(interstitial_web_contents, script));
content::TestNavigationObserver observer1(interstitial_web_contents,
/*number_of_navigations=*/1);
observer1.Wait();
EXPECT_EQ(2, browser()->tab_strip_model()->count());
EXPECT_EQ(browser()
->tab_strip_model()
->GetActiveWebContents()
->GetLastCommittedURL(),
embedded_test_server()->GetURL(kChangePasswordUrl));
EXPECT_THAT(
histograms.GetAllSamples(
"PasswordProtection.InterstitialAction.GSuiteSyncPasswordEntry"),
testing::ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1)));
}