blob: ef45a93417c923db30f05bd3bd43bbbf8d322322 [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/policy/policy_test_utils.h"
#include "base/callback_helpers.h"
#include "base/optional.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/current_thread.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/extensions/chrome_test_extension_loader.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/ash/chrome_screenshot_grabber.h"
#include "chrome/browser/ui/ash/chrome_screenshot_grabber_test_observer.h"
#include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/location_bar/location_bar.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/net/safe_search_util.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/omnibox/browser/omnibox_edit_model.h"
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/policy_constants.h"
#include "components/security_interstitials/content/security_interstitial_page.h"
#include "components/security_interstitials/content/security_interstitial_tab_helper.h"
#include "components/variations/variations_params_manager.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/network_service_util.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/dns/mock_host_resolver.h"
#include "net/http/transport_security_state.h"
#include "services/network/public/mojom/network_service_test.mojom.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/snapshot/screenshot_grabber.h"
#endif
using content::BrowserThread;
using testing::_;
using testing::Return;
namespace policy {
const base::FilePath::CharType kTestExtensionsDir[] =
FILE_PATH_LITERAL("extensions");
void GetTestDataDirectory(base::FilePath* test_data_directory) {
ASSERT_TRUE(
base::PathService::Get(chrome::DIR_TEST_DATA, test_data_directory));
}
PolicyTest::PolicyTest() = default;
PolicyTest::~PolicyTest() = default;
void PolicyTest::SetUp() {
InProcessBrowserTest::SetUp();
}
void PolicyTest::CheckURLIsBlockedInWebContents(
content::WebContents* web_contents,
const GURL& url) {
EXPECT_EQ(url, web_contents->GetURL());
std::u16string blocked_page_title;
if (url.has_host()) {
blocked_page_title = base::UTF8ToUTF16(url.host());
} else {
// Local file paths show the full URL.
blocked_page_title = base::UTF8ToUTF16(url.spec());
}
EXPECT_EQ(blocked_page_title, web_contents->GetTitle());
// Verify that the expected error page is being displayed.
bool result = false;
EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
web_contents,
"var textContent = document.body.textContent;"
"var hasError = textContent.indexOf('ERR_BLOCKED_BY_ADMINISTRATOR') >= 0;"
"domAutomationController.send(hasError);",
&result));
EXPECT_TRUE(result);
}
void PolicyTest::CheckURLIsBlocked(Browser* browser, const std::string& spec) {
GURL url(spec);
ui_test_utils::NavigateToURL(browser, url);
content::WebContents* contents =
browser->tab_strip_model()->GetActiveWebContents();
PolicyTest::CheckURLIsBlockedInWebContents(contents, url);
}
void PolicyTest::SetUpInProcessBrowserTestFixture() {
base::CommandLine::ForCurrentProcess()->AppendSwitch("noerrdialogs");
EXPECT_CALL(provider_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider_, IsFirstPolicyLoadComplete(_))
.WillRepeatedly(Return(true));
BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
}
void PolicyTest::SetUpOnMainThread() {
host_resolver()->AddRule("*", "127.0.0.1");
}
void PolicyTest::SetUpCommandLine(base::CommandLine* command_line) {
variations::testing::VariationParamsManager::AppendVariationParams(
"ReportCertificateErrors", "ShowAndPossiblySend",
{{"sendingThreshold", "1.0"}}, command_line);
}
void PolicyTest::SetScreenshotPolicy(bool enabled) {
PolicyMap policies;
policies.Set(key::kDisableScreenshots, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, base::Value(!enabled),
nullptr);
UpdateProviderPolicy(policies);
}
void PolicyTest::SetRequireCTForTesting(bool required) {
if (content::IsOutOfProcessNetworkService()) {
mojo::Remote<network::mojom::NetworkServiceTest> network_service_test;
content::GetNetworkService()->BindTestInterface(
network_service_test.BindNewPipeAndPassReceiver());
network::mojom::NetworkServiceTest::RequireCT required_ct =
required ? network::mojom::NetworkServiceTest::RequireCT::REQUIRE
: network::mojom::NetworkServiceTest::RequireCT::DEFAULT;
mojo::ScopedAllowSyncCallForTesting allow_sync_call;
network_service_test->SetRequireCT(required_ct);
return;
}
content::GetIOThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&net::TransportSecurityState::SetRequireCTForTesting,
required));
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
class QuitMessageLoopAfterScreenshot
: public ChromeScreenshotGrabberTestObserver {
public:
explicit QuitMessageLoopAfterScreenshot(base::OnceClosure done)
: done_(std::move(done)) {}
void OnScreenshotCompleted(ui::ScreenshotResult screenshot_result,
const base::FilePath& screenshot_path) override {
content::GetIOThreadTaskRunner({})->PostTaskAndReply(
FROM_HERE, base::DoNothing(), std::move(done_));
}
~QuitMessageLoopAfterScreenshot() override {}
private:
base::OnceClosure done_;
};
void PolicyTest::TestScreenshotFile(bool enabled) {
base::RunLoop run_loop;
QuitMessageLoopAfterScreenshot observer_(run_loop.QuitClosure());
ChromeScreenshotGrabber* grabber = ChromeScreenshotGrabber::Get();
grabber->test_observer_ = &observer_;
SetScreenshotPolicy(enabled);
grabber->HandleTakeScreenshotForAllRootWindows();
run_loop.Run();
grabber->test_observer_ = nullptr;
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
scoped_refptr<const extensions::Extension> PolicyTest::LoadUnpackedExtension(
const base::FilePath::StringType& name) {
base::FilePath extension_path(ui_test_utils::GetTestFilePath(
base::FilePath(kTestExtensionsDir), base::FilePath(name)));
extensions::ChromeTestExtensionLoader loader(browser()->profile());
return loader.LoadExtension(extension_path);
}
void PolicyTest::UpdateProviderPolicy(const PolicyMap& policy) {
PolicyMap policy_with_defaults = policy.Clone();
#if BUILDFLAG(IS_CHROMEOS_ASH)
SetEnterpriseUsersDefaults(&policy_with_defaults);
#endif
provider_.UpdateChromePolicy(policy_with_defaults);
DCHECK(base::CurrentThread::Get());
base::RunLoop loop;
loop.RunUntilIdle();
}
void PolicyTest::PerformClick(int x, int y) {
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
blink::WebMouseEvent click_event(
blink::WebInputEvent::Type::kMouseDown,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
click_event.button = blink::WebMouseEvent::Button::kLeft;
click_event.click_count = 1;
click_event.SetPositionInWidget(x, y);
contents->GetMainFrame()->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
click_event);
click_event.SetType(blink::WebInputEvent::Type::kMouseUp);
contents->GetMainFrame()->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
click_event);
}
// static
void PolicyTest::SetPolicy(PolicyMap* policies,
const char* key,
base::Optional<base::Value> value) {
policies->Set(key, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, std::move(value), nullptr);
}
void PolicyTest::ApplySafeSearchPolicy(
base::Optional<base::Value> legacy_safe_search,
base::Optional<base::Value> google_safe_search,
base::Optional<base::Value> legacy_youtube,
base::Optional<base::Value> youtube_restrict) {
PolicyMap policies;
SetPolicy(&policies, key::kForceSafeSearch, std::move(legacy_safe_search));
SetPolicy(&policies, key::kForceGoogleSafeSearch,
std::move(google_safe_search));
SetPolicy(&policies, key::kForceYouTubeSafetyMode, std::move(legacy_youtube));
SetPolicy(&policies, key::kForceYouTubeRestrict, std::move(youtube_restrict));
UpdateProviderPolicy(policies);
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
void PolicyTest::SetEnableFlag(const keyboard::KeyboardEnableFlag& flag) {
auto* keyboard_client = ChromeKeyboardControllerClient::Get();
keyboard_client->SetEnableFlag(flag);
}
void PolicyTest::ClearEnableFlag(const keyboard::KeyboardEnableFlag& flag) {
auto* keyboard_client = ChromeKeyboardControllerClient::Get();
keyboard_client->ClearEnableFlag(flag);
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// static
GURL PolicyTest::GetExpectedSearchURL(bool expect_safe_search) {
std::string expected_url("http://google.com/");
if (expect_safe_search) {
expected_url += "?" +
std::string(safe_search_util::kSafeSearchSafeParameter) +
"&" + safe_search_util::kSafeSearchSsuiParameter;
}
return GURL(expected_url);
}
// static
void PolicyTest::CheckSafeSearch(Browser* browser,
bool expect_safe_search,
const std::string& url) {
content::WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
content::TestNavigationObserver observer(web_contents);
ui_test_utils::SendToOmniboxAndSubmit(browser, url);
observer.Wait();
OmniboxEditModel* model =
browser->window()->GetLocationBar()->GetOmniboxView()->model();
EXPECT_TRUE(model->CurrentMatch(nullptr).destination_url.is_valid());
EXPECT_EQ(GetExpectedSearchURL(expect_safe_search), web_contents->GetURL());
}
// static
void PolicyTest::CheckYouTubeRestricted(
int youtube_restrict_mode,
const net::HttpRequestHeaders& headers) {
std::string header;
headers.GetHeader(safe_search_util::kYouTubeRestrictHeaderName, &header);
if (youtube_restrict_mode == safe_search_util::YOUTUBE_RESTRICT_OFF) {
EXPECT_TRUE(header.empty());
} else if (youtube_restrict_mode ==
safe_search_util::YOUTUBE_RESTRICT_MODERATE) {
EXPECT_EQ(header, safe_search_util::kYouTubeRestrictHeaderValueModerate);
} else if (youtube_restrict_mode ==
safe_search_util::YOUTUBE_RESTRICT_STRICT) {
EXPECT_EQ(header, safe_search_util::kYouTubeRestrictHeaderValueStrict);
}
}
// static
void PolicyTest::CheckAllowedDomainsHeader(
const std::string& allowed_domain,
const net::HttpRequestHeaders& headers) {
if (allowed_domain.empty()) {
EXPECT_TRUE(
!headers.HasHeader(safe_search_util::kGoogleAppsAllowedDomains));
return;
}
std::string header;
headers.GetHeader(safe_search_util::kGoogleAppsAllowedDomains, &header);
EXPECT_EQ(header, allowed_domain);
}
// static
bool PolicyTest::FetchSubresource(content::WebContents* web_contents,
const GURL& url) {
std::string script(
"var xhr = new XMLHttpRequest();"
"xhr.open('GET', '");
script += url.spec() +
"', true);"
"xhr.onload = function (e) {"
" if (xhr.readyState === 4) {"
" window.domAutomationController.send(xhr.status === 200);"
" }"
"};"
"xhr.onerror = function () {"
" window.domAutomationController.send(false);"
"};"
"xhr.send(null)";
bool xhr_result = false;
bool execute_result =
content::ExecuteScriptAndExtractBool(web_contents, script, &xhr_result);
return xhr_result && execute_result;
}
bool PolicyTest::IsShowingInterstitial(content::WebContents* tab) {
security_interstitials::SecurityInterstitialTabHelper* helper =
security_interstitials::SecurityInterstitialTabHelper::FromWebContents(
tab);
if (!helper) {
return false;
}
return helper->GetBlockingPageForCurrentlyCommittedNavigationForTesting() !=
nullptr;
}
void PolicyTest::WaitForInterstitial(content::WebContents* tab) {
ASSERT_TRUE(IsShowingInterstitial(tab));
ASSERT_TRUE(WaitForRenderFrameReady(tab->GetMainFrame()));
}
void PolicyTest::SendInterstitialCommand(
content::WebContents* tab,
security_interstitials::SecurityInterstitialCommand command) {
security_interstitials::SecurityInterstitialTabHelper* helper =
security_interstitials::SecurityInterstitialTabHelper::FromWebContents(
tab);
helper->GetBlockingPageForCurrentlyCommittedNavigationForTesting()
->CommandReceived(base::NumberToString(command));
return;
}
void PolicyTest::FlushBlacklistPolicy() {
// Updates of the URLBlacklist are done on IO, after building the blacklist
// on the blocking pool, which is initiated from IO.
content::RunAllPendingInMessageLoop(BrowserThread::IO);
content::RunAllTasksUntilIdle();
content::RunAllPendingInMessageLoop(BrowserThread::IO);
}
} // namespace policy