| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| #include <string> |
| #include <vector> |
| |
| #include "base/memory/ptr_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/values.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/policy/safe_browsing_policy_test.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/safe_browsing/chrome_password_protection_service.h" |
| #include "chrome/test/base/chrome_test_utils.h" |
| #include "components/policy/core/common/policy_map.h" |
| #include "components/policy/policy_constants.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/safe_browsing/core/common/features.h" |
| #include "components/safe_browsing/core/common/safe_browsing_prefs.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "url/gurl.h" |
| |
| using safe_browsing::ReusedPasswordAccountType; |
| using testing::Return; |
| |
| namespace policy { |
| |
| int IsEnhancedProtectionMessageVisibleOnInterstitial( |
| SafeBrowsingPolicyTest* browser_test) { |
| const std::string command = base::StringPrintf( |
| "var node = document.getElementById('enhanced-protection-message');" |
| "var result;" |
| "if (node) {" |
| " result = node.offsetWidth > 0 || " |
| " node.offsetHeight > 0 ? %d : %d;" |
| "} else {" |
| // The node should be present but not visible, so trigger an error |
| // by sending false if it's not present. |
| " result = %d;" |
| "}" |
| "result;", |
| security_interstitials::CMD_TEXT_FOUND, |
| security_interstitials::CMD_TEXT_NOT_FOUND, |
| security_interstitials::CMD_ERROR); |
| |
| content::WebContents* tab = |
| chrome_test_utils::GetActiveWebContents(browser_test); |
| if (!browser_test->IsShowingInterstitial(tab)) { |
| ADD_FAILURE() << "Expected interstitial when checking for enhanced " |
| "protection message."; |
| } |
| return content::EvalJs(tab->GetPrimaryMainFrame(), command).ExtractInt(); |
| } |
| |
| // Test extended reporting is managed by policy. |
| IN_PROC_BROWSER_TEST_F(SafeBrowsingPolicyTest, |
| SafeBrowsingExtendedReportingPolicyManaged) { |
| // Set the extended reporting pref to True and ensure the enterprise policy |
| // can overwrite it. |
| PrefService* prefs = chrome_test_utils::GetProfile(this)->GetPrefs(); |
| prefs->SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled, true); |
| |
| // Set the enterprise policy to disable extended reporting. |
| EXPECT_TRUE( |
| prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingOptInAllowed)); |
| PolicyMap policies; |
| policies.Set(key::kSafeBrowsingExtendedReportingEnabled, |
| POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, |
| base::Value(false), nullptr); |
| UpdateProviderPolicy(policies); |
| // Policy should have overwritten the pref, and it should be managed. |
| EXPECT_FALSE(prefs->GetBoolean(prefs::kSafeBrowsingScoutReportingEnabled)); |
| EXPECT_TRUE( |
| prefs->IsManagedPreference(prefs::kSafeBrowsingScoutReportingEnabled)); |
| |
| // Also make sure the SafeBrowsing prefs helper functions agree with the |
| // policy. |
| EXPECT_TRUE(safe_browsing::IsExtendedReportingPolicyManaged(*prefs)); |
| // Note that making SBER policy managed does NOT affect the SBEROptInAllowed |
| // setting, which is intentionally kept distinct for now. When the latter is |
| // deprecated, then SBER's policy management will imply whether the checkbox |
| // is visible. |
| EXPECT_TRUE(safe_browsing::IsExtendedReportingOptInAllowed(*prefs)); |
| } |
| |
| #if !BUILDFLAG(IS_ANDROID) |
| // Test that when Safe Browsing state is managed by policy, the enhanced |
| // protection message does not appear on SSL blocking pages. |
| IN_PROC_BROWSER_TEST_F(SafeBrowsingPolicyTest, SafeBrowsingStatePolicyManaged) { |
| net::EmbeddedTestServer https_server_expired( |
| net::EmbeddedTestServer::TYPE_HTTPS); |
| https_server_expired.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED); |
| https_server_expired.ServeFilesFromSourceDirectory("chrome/test/data"); |
| ASSERT_TRUE(https_server_expired.Start()); |
| |
| // Set the Safe Browsing state to standard protection. |
| PrefService* prefs = chrome_test_utils::GetProfile(this)->GetPrefs(); |
| safe_browsing::SetSafeBrowsingState( |
| prefs, safe_browsing::SafeBrowsingState::STANDARD_PROTECTION); |
| |
| // First, navigate to an SSL error page and make sure the enhanced protection |
| // message appears by default. |
| ASSERT_TRUE(NavigateToUrl(https_server_expired.GetURL("/"), this)); |
| EXPECT_EQ(security_interstitials::CMD_TEXT_FOUND, |
| IsEnhancedProtectionMessageVisibleOnInterstitial(this)); |
| |
| // Set the enterprise policy to force standard protection. |
| PolicyMap policies; |
| policies.Set(policy::key::kSafeBrowsingProtectionLevel, |
| policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER, |
| policy::POLICY_SOURCE_CLOUD, |
| base::Value(/* standard protection */ 1), nullptr); |
| UpdateProviderPolicy(policies); |
| // Policy should have overwritten the pref, and it should be managed. |
| EXPECT_EQ(safe_browsing::SafeBrowsingState::STANDARD_PROTECTION, |
| safe_browsing::GetSafeBrowsingState(*prefs)); |
| EXPECT_TRUE(prefs->IsManagedPreference(prefs::kSafeBrowsingEnabled)); |
| EXPECT_TRUE(prefs->IsManagedPreference(prefs::kSafeBrowsingEnhanced)); |
| |
| // Navigate to an SSL error page, the enhanced protection message should not |
| // appear. |
| ASSERT_TRUE(NavigateToUrl(https_server_expired.GetURL("/"), this)); |
| EXPECT_EQ(security_interstitials::CMD_TEXT_NOT_FOUND, |
| IsEnhancedProtectionMessageVisibleOnInterstitial(this)); |
| } |
| |
| // Test that when safe browsing allowlist domains are set by policy, safe |
| // browsing service gets the correct value. |
| IN_PROC_BROWSER_TEST_F(SafeBrowsingPolicyTest, SafeBrowsingAllowlistDomains) { |
| // Without setting up the enterprise policy, |
| // |GetSafeBrowsingDomainsPref(..) should return empty list. |
| const PrefService* const prefs = |
| chrome_test_utils::GetProfile(this)->GetPrefs(); |
| EXPECT_FALSE( |
| prefs->FindPreference(prefs::kSafeBrowsingAllowlistDomains)->IsManaged()); |
| std::vector<std::string> canonicalized_domains; |
| safe_browsing::GetSafeBrowsingAllowlistDomainsPref(*prefs, |
| &canonicalized_domains); |
| EXPECT_TRUE(canonicalized_domains.empty()); |
| |
| // Add 2 allowlisted domains to this policy. |
| PolicyMap policies; |
| base::Value::List allowlist_domains; |
| allowlist_domains.Append("mydomain.com"); |
| allowlist_domains.Append("mydomain.net"); |
| policies.Set(key::kSafeBrowsingAllowlistDomains, POLICY_LEVEL_MANDATORY, |
| POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, |
| base::Value(allowlist_domains.Clone()), nullptr); |
| UpdateProviderPolicy(policies); |
| EXPECT_TRUE( |
| prefs->FindPreference(prefs::kSafeBrowsingAllowlistDomains)->IsManaged()); |
| safe_browsing::GetSafeBrowsingAllowlistDomainsPref(*prefs, |
| &canonicalized_domains); |
| EXPECT_EQ(2u, canonicalized_domains.size()); |
| EXPECT_EQ("mydomain.com", canonicalized_domains[0]); |
| EXPECT_EQ("mydomain.net", canonicalized_domains[1]); |
| |
| // Invalid domains will be skipped. |
| allowlist_domains.clear(); |
| allowlist_domains.Append("%EF%BF%BDzyx.com"); |
| policies.Set(key::kSafeBrowsingAllowlistDomains, POLICY_LEVEL_MANDATORY, |
| POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, |
| base::Value(allowlist_domains.Clone()), nullptr); |
| UpdateProviderPolicy(policies); |
| EXPECT_TRUE( |
| prefs->FindPreference(prefs::kSafeBrowsingAllowlistDomains)->IsManaged()); |
| canonicalized_domains.clear(); |
| safe_browsing::GetSafeBrowsingAllowlistDomainsPref(*prefs, |
| &canonicalized_domains); |
| EXPECT_TRUE(canonicalized_domains.empty()); |
| } |
| |
| // Test that when password protection login URLs are set by policy, password |
| // protection service gets the correct value. |
| IN_PROC_BROWSER_TEST_F(SafeBrowsingPolicyTest, PasswordProtectionLoginURLs) { |
| // Without setting up the enterprise policy, |
| // |GetPasswordProtectionLoginURLsPref(..) should return empty list. |
| const PrefService* const prefs = |
| chrome_test_utils::GetProfile(this)->GetPrefs(); |
| EXPECT_FALSE( |
| prefs->FindPreference(prefs::kPasswordProtectionLoginURLs)->IsManaged()); |
| std::vector<GURL> login_urls; |
| safe_browsing::GetPasswordProtectionLoginURLsPref(*prefs, &login_urls); |
| #if BUILDFLAG(IS_CHROMEOS) |
| // ChromeOS prepopulates chrome:// URLs. |
| EXPECT_FALSE(login_urls.empty()); |
| #else |
| EXPECT_TRUE(login_urls.empty()); |
| #endif |
| // Add 2 login URLs to this enterprise policy . |
| PolicyMap policies; |
| base::Value::List login_url_values; |
| login_url_values.Append("https://login.mydomain.com"); |
| login_url_values.Append("https://mydomian.com/login.html"); |
| policies.Set(key::kPasswordProtectionLoginURLs, POLICY_LEVEL_MANDATORY, |
| POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, |
| base::Value(login_url_values.Clone()), nullptr); |
| UpdateProviderPolicy(policies); |
| EXPECT_TRUE( |
| prefs->FindPreference(prefs::kPasswordProtectionLoginURLs)->IsManaged()); |
| safe_browsing::GetPasswordProtectionLoginURLsPref(*prefs, &login_urls); |
| #if BUILDFLAG(IS_CHROMEOS) |
| EXPECT_EQ(3u, login_urls.size()); |
| EXPECT_EQ(GURL("chrome://os-settings"), login_urls[0]); |
| EXPECT_EQ(GURL("https://login.mydomain.com"), login_urls[1]); |
| EXPECT_EQ(GURL("https://mydomian.com/login.html"), login_urls[2]); |
| #else |
| EXPECT_EQ(2u, login_urls.size()); |
| EXPECT_EQ(GURL("https://login.mydomain.com"), login_urls[0]); |
| EXPECT_EQ(GURL("https://mydomian.com/login.html"), login_urls[1]); |
| #endif |
| |
| // Verify unsupported schemes, or invalid URLs will be skipped. |
| login_url_values.clear(); |
| login_url_values.Append("invalid"); |
| login_url_values.Append("ftp://login.mydomain.com"); |
| policies.Set(key::kPasswordProtectionLoginURLs, POLICY_LEVEL_MANDATORY, |
| POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, |
| base::Value(login_url_values.Clone()), nullptr); |
| UpdateProviderPolicy(policies); |
| EXPECT_TRUE( |
| prefs->FindPreference(prefs::kPasswordProtectionLoginURLs)->IsManaged()); |
| login_urls.clear(); |
| safe_browsing::GetPasswordProtectionLoginURLsPref(*prefs, &login_urls); |
| #if BUILDFLAG(IS_CHROMEOS) |
| // Prepopulated URL should be present. |
| EXPECT_FALSE(login_urls.empty()); |
| #else |
| EXPECT_TRUE(login_urls.empty()); |
| #endif |
| } |
| |
| // Test that when password protection change password URL is set by policy, |
| // password protection service gets the correct value. |
| IN_PROC_BROWSER_TEST_F(SafeBrowsingPolicyTest, |
| PasswordProtectionChangePasswordURL) { |
| // Without setting up the enterprise policy, |
| // |GetEnterpriseChangePasswordURL(..) should return default GAIA change |
| // password URL. |
| const PrefService* const prefs = |
| chrome_test_utils::GetProfile(this)->GetPrefs(); |
| const safe_browsing::ChromePasswordProtectionService* const service = |
| safe_browsing::ChromePasswordProtectionService:: |
| GetPasswordProtectionService(chrome_test_utils::GetProfile(this)); |
| EXPECT_FALSE( |
| prefs->FindPreference(prefs::kPasswordProtectionChangePasswordURL) |
| ->IsManaged()); |
| EXPECT_FALSE(prefs->HasPrefPath(prefs::kPasswordProtectionChangePasswordURL)); |
| EXPECT_TRUE(service->GetEnterpriseChangePasswordURL().DomainIs( |
| "accounts.google.com")); |
| |
| // Add change password URL to this enterprise policy . |
| PolicyMap policies; |
| policies.Set(key::kPasswordProtectionChangePasswordURL, |
| POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, |
| base::Value("https://changepassword.mydomain.com"), nullptr); |
| UpdateProviderPolicy(policies); |
| EXPECT_TRUE(prefs->FindPreference(prefs::kPasswordProtectionChangePasswordURL) |
| ->IsManaged()); |
| EXPECT_EQ(GURL("https://changepassword.mydomain.com"), |
| service->GetEnterpriseChangePasswordURL()); |
| |
| // Verify non-http/https change password URL will be skipped. |
| policies.Set(key::kPasswordProtectionChangePasswordURL, |
| POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, |
| base::Value("data:text/html,login page"), nullptr); |
| UpdateProviderPolicy(policies); |
| EXPECT_TRUE(prefs->FindPreference(prefs::kPasswordProtectionChangePasswordURL) |
| ->IsManaged()); |
| EXPECT_TRUE(service->GetEnterpriseChangePasswordURL().DomainIs( |
| "accounts.google.com")); |
| } |
| |
| class MockPasswordProtectionService |
| : public safe_browsing::ChromePasswordProtectionService { |
| public: |
| MockPasswordProtectionService(safe_browsing::SafeBrowsingService* sb_service, |
| Profile* profile) |
| : safe_browsing::ChromePasswordProtectionService(sb_service, profile) {} |
| ~MockPasswordProtectionService() override {} |
| |
| MOCK_CONST_METHOD0(IsPrimaryAccountGmail, bool()); |
| |
| AccountInfo GetAccountInfo() const override { |
| AccountInfo info; |
| info.email = "user@mycompany.com"; |
| return info; |
| } |
| }; |
| |
| // Test that when password protection warning trigger is set for users who are |
| // not signed-into Chrome, Chrome password protection service gets the correct |
| // value. |
| IN_PROC_BROWSER_TEST_F(SafeBrowsingPolicyTest, |
| PasswordProtectionWarningTriggerNotLoggedIn) { |
| MockPasswordProtectionService mock_service( |
| g_browser_process->safe_browsing_service(), |
| chrome_test_utils::GetProfile(this)); |
| |
| // If user is not signed-in, |GetPasswordProtectionWarningTriggerPref(...)| |
| // should return |PHISHING_REUSE| unless specified by policy. |
| const PrefService* const prefs = |
| chrome_test_utils::GetProfile(this)->GetPrefs(); |
| EXPECT_FALSE(prefs->FindPreference(prefs::kPasswordProtectionWarningTrigger) |
| ->IsManaged()); |
| EXPECT_EQ(safe_browsing::PHISHING_REUSE, |
| mock_service.GetPasswordProtectionWarningTriggerPref( |
| ReusedPasswordAccountType())); |
| // Sets the enterprise policy to 1 (a.k.a PASSWORD_REUSE). |
| PolicyMap policies; |
| policies.Set(key::kPasswordProtectionWarningTrigger, POLICY_LEVEL_MANDATORY, |
| POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, base::Value(1), nullptr); |
| UpdateProviderPolicy(policies); |
| EXPECT_TRUE(prefs->FindPreference(prefs::kPasswordProtectionWarningTrigger) |
| ->IsManaged()); |
| EXPECT_EQ(safe_browsing::PASSWORD_REUSE, |
| mock_service.GetPasswordProtectionWarningTriggerPref( |
| ReusedPasswordAccountType())); |
| // Sets the enterprise policy to 2 (a.k.a PHISHING_REUSE). |
| policies.Set(key::kPasswordProtectionWarningTrigger, POLICY_LEVEL_MANDATORY, |
| POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, base::Value(2), nullptr); |
| UpdateProviderPolicy(policies); |
| EXPECT_EQ(safe_browsing::PHISHING_REUSE, |
| mock_service.GetPasswordProtectionWarningTriggerPref( |
| ReusedPasswordAccountType())); |
| } |
| |
| // Test that when password protection warning trigger is set for Gmail users, |
| // Chrome password protection service gets the correct |
| // value. |
| IN_PROC_BROWSER_TEST_F(SafeBrowsingPolicyTest, |
| PasswordProtectionWarningTriggerGmail) { |
| MockPasswordProtectionService mock_service( |
| g_browser_process->safe_browsing_service(), |
| chrome_test_utils::GetProfile(this)); |
| |
| // If user is a Gmail user, |GetPasswordProtectionWarningTriggerPref(...)| |
| // should return |PHISHING_REUSE| unless specified by policy. |
| EXPECT_CALL(mock_service, IsPrimaryAccountGmail()) |
| .WillRepeatedly(Return(true)); |
| const PrefService* const prefs = |
| chrome_test_utils::GetProfile(this)->GetPrefs(); |
| EXPECT_FALSE(prefs->FindPreference(prefs::kPasswordProtectionWarningTrigger) |
| ->IsManaged()); |
| ReusedPasswordAccountType account_type; |
| account_type.set_account_type(ReusedPasswordAccountType::GMAIL); |
| account_type.set_is_account_syncing(true); |
| EXPECT_EQ(safe_browsing::PHISHING_REUSE, |
| mock_service.GetPasswordProtectionWarningTriggerPref(account_type)); |
| // Sets the enterprise policy to 1 (a.k.a PASSWORD_REUSE). Gmail accounts |
| // should always return PHISHING_REUSE if the policy is not set to 0. |
| PolicyMap policies; |
| policies.Set(key::kPasswordProtectionWarningTrigger, POLICY_LEVEL_MANDATORY, |
| POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, base::Value(1), nullptr); |
| UpdateProviderPolicy(policies); |
| EXPECT_TRUE(prefs->FindPreference(prefs::kPasswordProtectionWarningTrigger) |
| ->IsManaged()); |
| EXPECT_EQ(safe_browsing::PHISHING_REUSE, |
| mock_service.GetPasswordProtectionWarningTriggerPref(account_type)); |
| // Sets the enterprise policy to 2 (a.k.a PHISHING_REUSE). |
| policies.Set(key::kPasswordProtectionWarningTrigger, POLICY_LEVEL_MANDATORY, |
| POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, base::Value(2), nullptr); |
| UpdateProviderPolicy(policies); |
| EXPECT_EQ(safe_browsing::PHISHING_REUSE, |
| mock_service.GetPasswordProtectionWarningTriggerPref(account_type)); |
| // Sets the enterprise policy to 0 (a.k.a PASSWORD_PROTECTION_OFF). |
| policies.Set(key::kPasswordProtectionWarningTrigger, POLICY_LEVEL_MANDATORY, |
| POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, base::Value(0), nullptr); |
| UpdateProviderPolicy(policies); |
| EXPECT_EQ(safe_browsing::PASSWORD_PROTECTION_OFF, |
| mock_service.GetPasswordProtectionWarningTriggerPref(account_type)); |
| } |
| |
| // Test that when password protection warning trigger is set for GSuite users, |
| // Chrome password protection service gets the correct value. |
| IN_PROC_BROWSER_TEST_F(SafeBrowsingPolicyTest, |
| PasswordProtectionWarningTriggerGSuite) { |
| MockPasswordProtectionService mock_service( |
| g_browser_process->safe_browsing_service(), |
| chrome_test_utils::GetProfile(this)); |
| const PrefService* const prefs = |
| chrome_test_utils::GetProfile(this)->GetPrefs(); |
| PolicyMap policies; |
| |
| // If user is a GSuite user, |GetPasswordProtectionWarningTriggerPref(...)| |
| // should return |PHISHING_REUSE| unless specified by policy. |
| EXPECT_FALSE(prefs->FindPreference(prefs::kPasswordProtectionWarningTrigger) |
| ->IsManaged()); |
| EXPECT_EQ(safe_browsing::PHISHING_REUSE, |
| mock_service.GetPasswordProtectionWarningTriggerPref( |
| ReusedPasswordAccountType())); |
| // Sets the enterprise policy to 1 (a.k.a PASSWORD_REUSE). |
| policies.Set(key::kPasswordProtectionWarningTrigger, POLICY_LEVEL_MANDATORY, |
| POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, base::Value(1), nullptr); |
| UpdateProviderPolicy(policies); |
| EXPECT_TRUE(prefs->FindPreference(prefs::kPasswordProtectionWarningTrigger) |
| ->IsManaged()); |
| EXPECT_EQ(safe_browsing::PASSWORD_REUSE, |
| mock_service.GetPasswordProtectionWarningTriggerPref( |
| ReusedPasswordAccountType())); |
| // Sets the enterprise policy to 2 (a.k.a PHISHING_REUSE). |
| policies.Set(key::kPasswordProtectionWarningTrigger, POLICY_LEVEL_MANDATORY, |
| POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, base::Value(2), nullptr); |
| UpdateProviderPolicy(policies); |
| EXPECT_EQ(safe_browsing::PHISHING_REUSE, |
| mock_service.GetPasswordProtectionWarningTriggerPref( |
| ReusedPasswordAccountType())); |
| } |
| #endif // !BUILDFLAG(IS_ANDROID) |
| |
| } // namespace policy |