| // 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 "base/command_line.h" |
| #include "base/json/json_reader.h" |
| #include "base/memory/ptr_util.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/component_updater/chrome_component_updater_configurator.h" |
| #include "chrome/browser/policy/policy_test_utils.h" |
| #include "components/component_updater/component_updater_service.h" |
| #include "components/component_updater/component_updater_switches.h" |
| #include "components/policy/core/common/policy_map.h" |
| #include "components/policy/policy_constants.h" |
| #include "components/update_client/net/url_loader_post_interceptor.h" |
| #include "components/update_client/update_client.h" |
| #include "components/update_client/update_client_errors.h" |
| #include "content/public/browser/browser_task_traits.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/test/browser_test.h" |
| #include "url/gurl.h" |
| |
| namespace policy { |
| |
| // Tests the ComponentUpdater's EnabledComponentUpdates group policy by |
| // calling the OnDemand interface. It uses the network interceptor to inspect |
| // the presence of the updatedisabled="true" attribute in the update check |
| // request. The update check request is expected to fail, since CUP fails. |
| class ComponentUpdaterPolicyTest : public PolicyTest { |
| public: |
| ComponentUpdaterPolicyTest(); |
| ~ComponentUpdaterPolicyTest() override; |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override; |
| void SetUpOnMainThread() override; |
| |
| protected: |
| using TestCaseAction = void (ComponentUpdaterPolicyTest::*)(); |
| using TestCase = std::pair<TestCaseAction, TestCaseAction>; |
| |
| // These test scenarios run as part of one test case by using the |
| // CallAsync helper, which calls OnDemand, then chains up to the next |
| // scenario when the OnDemandComplete callback fires. |
| void DefaultPolicy_GroupPolicySupported(); |
| void FinishDefaultPolicy_GroupPolicySupported(); |
| |
| void DefaultPolicy_GroupPolicyNotSupported(); |
| void FinishDefaultPolicy_GroupPolicyNotSupported(); |
| |
| void EnabledPolicy_GroupPolicySupported(); |
| void FinishEnabledPolicy_GroupPolicySupported(); |
| |
| void EnabledPolicy_GroupPolicyNotSupported(); |
| void FinishEnabledPolicy_GroupPolicyNotSupported(); |
| |
| void DisabledPolicy_GroupPolicySupported(); |
| void FinishDisabled_PolicyGroupPolicySupported(); |
| |
| void DisabledPolicy_GroupPolicyNotSupported(); |
| void FinishDisabledPolicy_GroupPolicyNotSupported(); |
| |
| void BeginTest(); |
| void EndTest(); |
| |
| void UpdateComponent(const update_client::CrxComponent& crx_component); |
| void CallAsync(TestCaseAction action); |
| void VerifyExpectations(bool update_disabled); |
| |
| void SetEnableComponentUpdates(bool enable_component_updates); |
| |
| static update_client::CrxComponent MakeCrxComponent( |
| bool supports_group_policy_enable_component_updates); |
| |
| TestCase cur_test_case_; |
| base::RepeatingClosure quit_closure_; |
| |
| static const char component_id_[]; |
| |
| static const bool kUpdateDisabled = true; |
| |
| private: |
| void OnDemandComplete(update_client::Error error); |
| |
| std::unique_ptr<update_client::URLLoaderPostInterceptor> post_interceptor_; |
| |
| // This member is owned by g_browser_process; |
| component_updater::ComponentUpdateService* cus_ = nullptr; |
| |
| net::EmbeddedTestServer https_server_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComponentUpdaterPolicyTest); |
| }; |
| |
| const char ComponentUpdaterPolicyTest::component_id_[] = |
| "jebgalgnebhfojomionfpkfelancnnkf"; |
| |
| ComponentUpdaterPolicyTest::ComponentUpdaterPolicyTest() |
| : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {} |
| |
| ComponentUpdaterPolicyTest::~ComponentUpdaterPolicyTest() {} |
| |
| void ComponentUpdaterPolicyTest::SetUpCommandLine( |
| base::CommandLine* command_line) { |
| // Set up the mock server, for the network requests. |
| ASSERT_TRUE(https_server_.InitializeAndListen()); |
| const std::string val = base::StringPrintf( |
| "url-source=%s", https_server_.GetURL("/service/update2").spec().c_str()); |
| command_line->AppendSwitchASCII(switches::kComponentUpdater, val.c_str()); |
| PolicyTest::SetUpCommandLine(command_line); |
| } |
| |
| void ComponentUpdaterPolicyTest::SetUpOnMainThread() { |
| const auto config = component_updater::MakeChromeComponentUpdaterConfigurator( |
| base::CommandLine::ForCurrentProcess(), g_browser_process->local_state()); |
| const auto urls = config->UpdateUrl(); |
| ASSERT_EQ(1u, urls.size()); |
| post_interceptor_ = std::make_unique<update_client::URLLoaderPostInterceptor>( |
| urls, &https_server_); |
| |
| https_server_.StartAcceptingConnections(); |
| PolicyTest::SetUpOnMainThread(); |
| } |
| |
| void ComponentUpdaterPolicyTest::SetEnableComponentUpdates( |
| bool enable_component_updates) { |
| PolicyMap policies; |
| policies.Set(key::kComponentUpdatesEnabled, POLICY_LEVEL_MANDATORY, |
| POLICY_SCOPE_MACHINE, POLICY_SOURCE_ENTERPRISE_DEFAULT, |
| base::Value(enable_component_updates), nullptr); |
| UpdateProviderPolicy(policies); |
| } |
| |
| update_client::CrxComponent ComponentUpdaterPolicyTest::MakeCrxComponent( |
| bool supports_group_policy_enable_component_updates) { |
| class MockInstaller : public update_client::CrxInstaller { |
| public: |
| MockInstaller() {} |
| |
| void Install(const base::FilePath& unpack_path, |
| const std::string& public_key, |
| std::unique_ptr<InstallParams> /*install_params*/, |
| ProgressCallback /*progress_callback*/, |
| Callback callback) override { |
| DoInstall(unpack_path, public_key, std::move(callback)); |
| } |
| |
| MOCK_METHOD1(OnUpdateError, void(int error)); |
| MOCK_METHOD3(DoInstall, |
| void(const base::FilePath& unpack_path, |
| const std::string& public_key, |
| const Callback& callback)); |
| MOCK_METHOD2(GetInstalledFile, |
| bool(const std::string& file, base::FilePath* installed_file)); |
| MOCK_METHOD0(Uninstall, bool()); |
| |
| private: |
| ~MockInstaller() override {} |
| }; |
| |
| // component id "jebgalgnebhfojomionfpkfelancnnkf". |
| static const uint8_t jebg_hash[] = { |
| 0x94, 0x16, 0x0b, 0x6d, 0x41, 0x75, 0xe9, 0xec, 0x8e, 0xd5, 0xfa, |
| 0x54, 0xb0, 0xd2, 0xdd, 0xa5, 0x6e, 0x05, 0x6b, 0xe8, 0x73, 0x47, |
| 0xf6, 0xc4, 0x11, 0x9f, 0xbc, 0xb3, 0x09, 0xb3, 0x5b, 0x40}; |
| |
| // The component uses HTTPS only for network interception purposes. |
| update_client::CrxComponent crx_component; |
| crx_component.pk_hash.assign(std::begin(jebg_hash), std::end(jebg_hash)); |
| crx_component.app_id = "jebgalgnebhfojomionfpkfelancnnkf"; |
| crx_component.version = base::Version("0.9"); |
| crx_component.installer = scoped_refptr<MockInstaller>(new MockInstaller()); |
| crx_component.requires_network_encryption = true; |
| crx_component.supports_group_policy_enable_component_updates = |
| supports_group_policy_enable_component_updates; |
| |
| return crx_component; |
| } |
| |
| void ComponentUpdaterPolicyTest::UpdateComponent( |
| const update_client::CrxComponent& crx_component) { |
| post_interceptor_->Reset(); |
| EXPECT_TRUE(post_interceptor_->ExpectRequest( |
| std::make_unique<update_client::PartialMatch>("updatecheck"))); |
| EXPECT_TRUE(cus_->RegisterComponent(crx_component)); |
| cus_->GetOnDemandUpdater().OnDemandUpdate( |
| component_id_, component_updater::OnDemandUpdater::Priority::FOREGROUND, |
| base::BindOnce(&ComponentUpdaterPolicyTest::OnDemandComplete, |
| base::Unretained(this))); |
| } |
| |
| void ComponentUpdaterPolicyTest::CallAsync(TestCaseAction action) { |
| content::GetUIThreadTaskRunner({})->PostTask( |
| FROM_HERE, base::BindOnce(action, base::Unretained(this))); |
| } |
| |
| void ComponentUpdaterPolicyTest::OnDemandComplete(update_client::Error error) { |
| CallAsync(cur_test_case_.second); |
| } |
| |
| void ComponentUpdaterPolicyTest::BeginTest() { |
| cus_ = g_browser_process->component_updater(); |
| |
| const auto config = component_updater::MakeChromeComponentUpdaterConfigurator( |
| base::CommandLine::ForCurrentProcess(), g_browser_process->local_state()); |
| const auto urls = config->UpdateUrl(); |
| ASSERT_TRUE(urls.size()); |
| const GURL url = urls.front(); |
| |
| cur_test_case_ = std::make_pair( |
| &ComponentUpdaterPolicyTest::DefaultPolicy_GroupPolicySupported, |
| &ComponentUpdaterPolicyTest::FinishDefaultPolicy_GroupPolicySupported); |
| |
| CallAsync(cur_test_case_.first); |
| } |
| |
| void ComponentUpdaterPolicyTest::EndTest() { |
| post_interceptor_.reset(); |
| cus_ = nullptr; |
| quit_closure_.Run(); |
| } |
| |
| void ComponentUpdaterPolicyTest::VerifyExpectations(bool update_disabled) { |
| EXPECT_EQ(1, post_interceptor_->GetHitCount()) |
| << post_interceptor_->GetRequestsAsString(); |
| ASSERT_EQ(1, post_interceptor_->GetCount()) |
| << post_interceptor_->GetRequestsAsString(); |
| |
| const auto& request = post_interceptor_->GetRequestBody(0); |
| |
| // Handle XML and JSON protocols. |
| if (base::StartsWith(request, "<?xml", base::CompareCase::SENSITIVE)) { |
| EXPECT_NE(std::string::npos, |
| request.find(base::StringPrintf( |
| "<updatecheck%s/>", |
| update_disabled ? " updatedisabled=\"true\"" : ""))); |
| } else if (base::StartsWith(request, R"({"request":{)", |
| base::CompareCase::SENSITIVE)) { |
| const auto root = base::JSONReader::Read(request); |
| ASSERT_TRUE(root); |
| const auto* update_check = |
| root->FindKey("request")->FindKey("app")->GetList()[0].FindKey( |
| "updatecheck"); |
| ASSERT_TRUE(update_check); |
| if (update_disabled) { |
| EXPECT_EQ(true, update_check->FindKey("updatedisabled")->GetBool()); |
| } else { |
| EXPECT_FALSE(update_check->FindKey("updatedisabled")); |
| } |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| void ComponentUpdaterPolicyTest::DefaultPolicy_GroupPolicySupported() { |
| UpdateComponent(MakeCrxComponent(true)); |
| } |
| |
| void ComponentUpdaterPolicyTest::FinishDefaultPolicy_GroupPolicySupported() { |
| // Default policy && policy support -> updates are enabled. |
| VerifyExpectations(!kUpdateDisabled); |
| |
| cur_test_case_ = std::make_pair( |
| &ComponentUpdaterPolicyTest::DefaultPolicy_GroupPolicyNotSupported, |
| &ComponentUpdaterPolicyTest::FinishDefaultPolicy_GroupPolicyNotSupported); |
| CallAsync(cur_test_case_.first); |
| } |
| |
| void ComponentUpdaterPolicyTest::DefaultPolicy_GroupPolicyNotSupported() { |
| UpdateComponent(MakeCrxComponent(false)); |
| } |
| |
| void ComponentUpdaterPolicyTest::FinishDefaultPolicy_GroupPolicyNotSupported() { |
| // Default policy && no policy support -> updates are enabled. |
| VerifyExpectations(!kUpdateDisabled); |
| |
| cur_test_case_ = std::make_pair( |
| &ComponentUpdaterPolicyTest::EnabledPolicy_GroupPolicySupported, |
| &ComponentUpdaterPolicyTest::FinishEnabledPolicy_GroupPolicySupported); |
| CallAsync(cur_test_case_.first); |
| } |
| |
| void ComponentUpdaterPolicyTest::EnabledPolicy_GroupPolicySupported() { |
| SetEnableComponentUpdates(true); |
| UpdateComponent(MakeCrxComponent(true)); |
| } |
| |
| void ComponentUpdaterPolicyTest::FinishEnabledPolicy_GroupPolicySupported() { |
| // Updates enabled policy && policy support -> updates are enabled. |
| VerifyExpectations(!kUpdateDisabled); |
| |
| cur_test_case_ = std::make_pair( |
| &ComponentUpdaterPolicyTest::EnabledPolicy_GroupPolicyNotSupported, |
| &ComponentUpdaterPolicyTest::FinishEnabledPolicy_GroupPolicyNotSupported); |
| CallAsync(cur_test_case_.first); |
| } |
| |
| void ComponentUpdaterPolicyTest::EnabledPolicy_GroupPolicyNotSupported() { |
| SetEnableComponentUpdates(true); |
| UpdateComponent(MakeCrxComponent(false)); |
| } |
| |
| void ComponentUpdaterPolicyTest::FinishEnabledPolicy_GroupPolicyNotSupported() { |
| // Updates enabled policy && no policy support -> updates are enabled. |
| VerifyExpectations(!kUpdateDisabled); |
| |
| cur_test_case_ = std::make_pair( |
| &ComponentUpdaterPolicyTest::DisabledPolicy_GroupPolicySupported, |
| &ComponentUpdaterPolicyTest::FinishDisabled_PolicyGroupPolicySupported); |
| CallAsync(cur_test_case_.first); |
| } |
| |
| void ComponentUpdaterPolicyTest::DisabledPolicy_GroupPolicySupported() { |
| SetEnableComponentUpdates(false); |
| UpdateComponent(MakeCrxComponent(true)); |
| } |
| |
| void ComponentUpdaterPolicyTest::FinishDisabled_PolicyGroupPolicySupported() { |
| // Updates enabled policy && policy support -> updates are disabled. |
| VerifyExpectations(kUpdateDisabled); |
| |
| cur_test_case_ = std::make_pair( |
| &ComponentUpdaterPolicyTest::DisabledPolicy_GroupPolicyNotSupported, |
| &ComponentUpdaterPolicyTest:: |
| FinishDisabledPolicy_GroupPolicyNotSupported); |
| CallAsync(cur_test_case_.first); |
| } |
| |
| void ComponentUpdaterPolicyTest::DisabledPolicy_GroupPolicyNotSupported() { |
| SetEnableComponentUpdates(false); |
| UpdateComponent(MakeCrxComponent(false)); |
| } |
| |
| void ComponentUpdaterPolicyTest:: |
| FinishDisabledPolicy_GroupPolicyNotSupported() { |
| // Updates enabled policy && no policy support -> updates are enabled. |
| VerifyExpectations(!kUpdateDisabled); |
| |
| cur_test_case_ = TestCase(); |
| CallAsync(&ComponentUpdaterPolicyTest::EndTest); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ComponentUpdaterPolicyTest, EnabledComponentUpdates) { |
| BeginTest(); |
| base::RunLoop loop; |
| quit_closure_ = loop.QuitWhenIdleClosure(); |
| loop.Run(); |
| } |
| |
| } // namespace policy |