|  | // Copyright 2012 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "chrome/browser/ash/settings/session_manager_operation.h" | 
|  |  | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <memory> | 
|  | #include <string> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/functional/bind.h" | 
|  | #include "base/functional/callback.h" | 
|  | #include "base/functional/callback_helpers.h" | 
|  | #include "base/memory/ptr_util.h" | 
|  | #include "base/memory/raw_ptr.h" | 
|  | #include "base/memory/ref_counted.h" | 
|  | #include "base/task/single_thread_task_runner.h" | 
|  | #include "base/time/time.h" | 
|  | #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" | 
|  | #include "chrome/browser/ash/ownership/owner_settings_service_ash.h" | 
|  | #include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h" | 
|  | #include "chrome/browser/ash/settings/device_settings_test_helper.h" | 
|  | #include "chrome/test/base/testing_profile.h" | 
|  | #include "chromeos/ash/components/policy/device_policy/device_policy_builder.h" | 
|  | #include "components/ownership/mock_owner_key_util.h" | 
|  | #include "components/policy/core/common/cloud/cloud_policy_constants.h" | 
|  | #include "components/policy/core/common/cloud/cloud_policy_validator.h" | 
|  | #include "components/policy/core/common/cloud/test/policy_builder.h" | 
|  | #include "components/policy/proto/chrome_device_policy.pb.h" | 
|  | #include "components/policy/proto/device_management_backend.pb.h" | 
|  | #include "components/user_manager/fake_user_manager.h" | 
|  | #include "components/user_manager/scoped_user_manager.h" | 
|  | #include "content/public/test/browser_task_environment.h" | 
|  | #include "content/public/test/test_utils.h" | 
|  | #include "testing/gmock/include/gmock/gmock.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace em = enterprise_management; | 
|  |  | 
|  | using testing::_; | 
|  | using testing::Mock; | 
|  |  | 
|  | namespace ash { | 
|  | namespace { | 
|  |  | 
|  | class ObservableFakeSessionManagerClient : public FakeSessionManagerClient { | 
|  | public: | 
|  | void SetOnRetrievePolicyCalled(const base::RepeatingClosure& closure) { | 
|  | on_retrieve_policy_called_ = closure; | 
|  | } | 
|  |  | 
|  | // SessionManagerClient override: | 
|  | void RetrievePolicy(const login_manager::PolicyDescriptor& descriptor, | 
|  | RetrievePolicyCallback callback) override { | 
|  | FakeSessionManagerClient::RetrievePolicy(descriptor, std::move(callback)); | 
|  |  | 
|  | // Run the task just after the |callback| is invoked. | 
|  | if (!on_retrieve_policy_called_.is_null()) { | 
|  | base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
|  | FROM_HERE, on_retrieve_policy_called_); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | base::RepeatingClosure on_retrieve_policy_called_; | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | class SessionManagerOperationTest : public testing::Test { | 
|  | public: | 
|  | SessionManagerOperationTest() | 
|  | : owner_key_util_(new ownership::MockOwnerKeyUtil()), | 
|  | validated_(false) { | 
|  | OwnerSettingsServiceAshFactory::GetInstance()->SetOwnerKeyUtilForTesting( | 
|  | owner_key_util_); | 
|  | } | 
|  |  | 
|  | SessionManagerOperationTest(const SessionManagerOperationTest&) = delete; | 
|  | SessionManagerOperationTest& operator=(const SessionManagerOperationTest&) = | 
|  | delete; | 
|  |  | 
|  | void SetUp() override { | 
|  | policy_.payload().mutable_user_allowlist()->add_user_allowlist( | 
|  | "fake-allowlist"); | 
|  | policy_.Build(); | 
|  |  | 
|  | profile_ = std::make_unique<TestingProfile>(); | 
|  | service_ = | 
|  | OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_.get()); | 
|  | } | 
|  |  | 
|  | MOCK_METHOD2(OnOperationCompleted, | 
|  | void(SessionManagerOperation*, DeviceSettingsService::Status)); | 
|  |  | 
|  | void CheckSuccessfulValidation( | 
|  | policy::DeviceCloudPolicyValidator* validator) { | 
|  | EXPECT_TRUE(validator->success()); | 
|  | EXPECT_TRUE(validator->payload().get()); | 
|  | EXPECT_EQ(validator->payload()->SerializeAsString(), | 
|  | policy_.payload().SerializeAsString()); | 
|  | validated_ = true; | 
|  | } | 
|  |  | 
|  | void CheckPublicKeyLoaded(SessionManagerOperation* op) { | 
|  | ASSERT_TRUE(op->public_key().get()); | 
|  | ASSERT_FALSE(op->public_key()->is_empty()); | 
|  | std::vector<uint8_t> public_key = | 
|  | policy_.GetSigningKey()->ToSubjectPublicKeyInfo(); | 
|  | EXPECT_EQ(public_key, op->public_key()->data()); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | content::BrowserTaskEnvironment task_environment_; | 
|  |  | 
|  | policy::DevicePolicyBuilder policy_; | 
|  | ObservableFakeSessionManagerClient session_manager_client_; | 
|  | scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util_; | 
|  |  | 
|  | user_manager::TypedScopedUserManager<FakeChromeUserManager> user_manager_{ | 
|  | std::make_unique<FakeChromeUserManager>()}; | 
|  |  | 
|  | std::unique_ptr<TestingProfile> profile_; | 
|  | raw_ptr<OwnerSettingsServiceAsh> service_; | 
|  |  | 
|  | bool validated_; | 
|  | }; | 
|  |  | 
|  | TEST_F(SessionManagerOperationTest, LoadNoPolicyNoKey) { | 
|  | LoadSettingsOperation op( | 
|  | false /* force_key_load */, false /* force_immediate_load */, | 
|  | base::BindOnce(&SessionManagerOperationTest::OnOperationCompleted, | 
|  | base::Unretained(this))); | 
|  |  | 
|  | EXPECT_CALL(*this, OnOperationCompleted( | 
|  | &op, DeviceSettingsService::STORE_KEY_UNAVAILABLE)); | 
|  | op.Start(&session_manager_client_, owner_key_util_, nullptr); | 
|  | content::RunAllTasksUntilIdle(); | 
|  | Mock::VerifyAndClearExpectations(this); | 
|  |  | 
|  | EXPECT_FALSE(op.policy_data().get()); | 
|  | EXPECT_FALSE(op.device_settings().get()); | 
|  | ASSERT_TRUE(op.public_key().get()); | 
|  | EXPECT_TRUE(op.public_key()->is_empty()); | 
|  | } | 
|  |  | 
|  | TEST_F(SessionManagerOperationTest, LoadOwnerKey) { | 
|  | owner_key_util_->SetPublicKeyFromPrivateKey(*policy_.GetSigningKey()); | 
|  | LoadSettingsOperation op( | 
|  | false /* force_key_load */, false /* force_immediate_load */, | 
|  | base::BindOnce(&SessionManagerOperationTest::OnOperationCompleted, | 
|  | base::Unretained(this))); | 
|  |  | 
|  | EXPECT_CALL( | 
|  | *this, OnOperationCompleted(&op, DeviceSettingsService::STORE_NO_POLICY)); | 
|  | op.Start(&session_manager_client_, owner_key_util_, nullptr); | 
|  | content::RunAllTasksUntilIdle(); | 
|  | Mock::VerifyAndClearExpectations(this); | 
|  |  | 
|  | CheckPublicKeyLoaded(&op); | 
|  | } | 
|  |  | 
|  | TEST_F(SessionManagerOperationTest, LoadPolicy) { | 
|  | owner_key_util_->SetPublicKeyFromPrivateKey(*policy_.GetSigningKey()); | 
|  | session_manager_client_.set_device_policy(policy_.GetBlob()); | 
|  | LoadSettingsOperation op( | 
|  | false /* force_key_load */, false /* force_immediate_load */, | 
|  | base::BindOnce(&SessionManagerOperationTest::OnOperationCompleted, | 
|  | base::Unretained(this))); | 
|  |  | 
|  | EXPECT_CALL(*this, | 
|  | OnOperationCompleted(&op, DeviceSettingsService::STORE_SUCCESS)); | 
|  | op.Start(&session_manager_client_, owner_key_util_, nullptr); | 
|  | content::RunAllTasksUntilIdle(); | 
|  | Mock::VerifyAndClearExpectations(this); | 
|  |  | 
|  | ASSERT_TRUE(op.policy_data().get()); | 
|  | EXPECT_EQ(policy_.policy_data().SerializeAsString(), | 
|  | op.policy_data()->SerializeAsString()); | 
|  | ASSERT_TRUE(op.device_settings().get()); | 
|  | EXPECT_EQ(policy_.payload().SerializeAsString(), | 
|  | op.device_settings()->SerializeAsString()); | 
|  | } | 
|  |  | 
|  | TEST_F(SessionManagerOperationTest, LoadImmediately) { | 
|  | owner_key_util_->SetPublicKeyFromPrivateKey(*policy_.GetSigningKey()); | 
|  | session_manager_client_.set_device_policy(policy_.GetBlob()); | 
|  | LoadSettingsOperation op( | 
|  | false /* force_key_load */, true /* force_immediate_load */, | 
|  | base::BindOnce(&SessionManagerOperationTest::OnOperationCompleted, | 
|  | base::Unretained(this))); | 
|  |  | 
|  | EXPECT_CALL(*this, | 
|  | OnOperationCompleted(&op, DeviceSettingsService::STORE_SUCCESS)); | 
|  | op.Start(&session_manager_client_, owner_key_util_, nullptr); | 
|  | content::RunAllTasksUntilIdle(); | 
|  | Mock::VerifyAndClearExpectations(this); | 
|  |  | 
|  | ASSERT_TRUE(op.policy_data().get()); | 
|  | EXPECT_EQ(policy_.policy_data().SerializeAsString(), | 
|  | op.policy_data()->SerializeAsString()); | 
|  | ASSERT_TRUE(op.device_settings().get()); | 
|  | EXPECT_EQ(policy_.payload().SerializeAsString(), | 
|  | op.device_settings()->SerializeAsString()); | 
|  | } | 
|  |  | 
|  | TEST_F(SessionManagerOperationTest, RestartLoad) { | 
|  | owner_key_util_->ImportPrivateKeyAndSetPublicKey(*policy_.GetSigningKey()); | 
|  | session_manager_client_.set_device_policy(policy_.GetBlob()); | 
|  | LoadSettingsOperation op( | 
|  | false /* force_key_load */, false /* force_immediate_load */, | 
|  | base::BindOnce(&SessionManagerOperationTest::OnOperationCompleted, | 
|  | base::Unretained(this))); | 
|  |  | 
|  | // Just after the first RetrievePolicy() completion, | 
|  | // verify the state, install a different key, then RestartLoad(). | 
|  | session_manager_client_.SetOnRetrievePolicyCalled(base::BindRepeating( | 
|  | [](SessionManagerOperationTest* test, policy::DevicePolicyBuilder* policy, | 
|  | ObservableFakeSessionManagerClient* session_manager_client, | 
|  | scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util, | 
|  | LoadSettingsOperation* op) { | 
|  | // Reset this callback to avoid infinite loop. | 
|  | session_manager_client->SetOnRetrievePolicyCalled( | 
|  | base::RepeatingClosure()); | 
|  |  | 
|  | // Verify the public_key() is properly set, but the callback is | 
|  | // not yet called. | 
|  | EXPECT_TRUE(op->public_key().get()); | 
|  | EXPECT_FALSE(op->public_key()->is_empty()); | 
|  | Mock::VerifyAndClearExpectations(test); | 
|  |  | 
|  | // Now install a different key and policy. | 
|  | policy->SetSigningKey( | 
|  | policy::PolicyBuilder::CreateTestOtherSigningKey()); | 
|  | policy->payload().mutable_metrics_enabled()->set_metrics_enabled(true); | 
|  | policy->Build(); | 
|  | session_manager_client->set_device_policy(policy->GetBlob()); | 
|  | owner_key_util->ImportPrivateKeyAndSetPublicKey( | 
|  | *policy->GetSigningKey()); | 
|  |  | 
|  | // And restart the operation. | 
|  | EXPECT_CALL(*test, OnOperationCompleted( | 
|  | op, DeviceSettingsService::STORE_SUCCESS)); | 
|  | op->RestartLoad(true); | 
|  | }, | 
|  | this, &policy_, &session_manager_client_, owner_key_util_, &op)); | 
|  |  | 
|  | EXPECT_CALL(*this, OnOperationCompleted(&op, _)).Times(0); | 
|  | op.Start(&session_manager_client_, owner_key_util_, nullptr); | 
|  | content::RunAllTasksUntilIdle(); | 
|  | Mock::VerifyAndClearExpectations(this); | 
|  |  | 
|  | // Check that the new keys have been loaded. | 
|  | CheckPublicKeyLoaded(&op); | 
|  |  | 
|  | // Verify the new policy. | 
|  | ASSERT_TRUE(op.policy_data().get()); | 
|  | EXPECT_EQ(policy_.policy_data().SerializeAsString(), | 
|  | op.policy_data()->SerializeAsString()); | 
|  | ASSERT_TRUE(op.device_settings().get()); | 
|  | EXPECT_EQ(policy_.payload().SerializeAsString(), | 
|  | op.device_settings()->SerializeAsString()); | 
|  | } | 
|  |  | 
|  | TEST_F(SessionManagerOperationTest, StoreSettings) { | 
|  | owner_key_util_->SetPublicKeyFromPrivateKey(*policy_.GetSigningKey()); | 
|  | StoreSettingsOperation op( | 
|  | base::BindOnce(&SessionManagerOperationTest::OnOperationCompleted, | 
|  | base::Unretained(this)), | 
|  | policy_.GetCopy()); | 
|  |  | 
|  | EXPECT_CALL(*this, | 
|  | OnOperationCompleted(&op, DeviceSettingsService::STORE_SUCCESS)); | 
|  | op.Start(&session_manager_client_, owner_key_util_, nullptr); | 
|  | content::RunAllTasksUntilIdle(); | 
|  | Mock::VerifyAndClearExpectations(this); | 
|  |  | 
|  | EXPECT_EQ(session_manager_client_.device_policy(), policy_.GetBlob()); | 
|  | ASSERT_TRUE(op.policy_data().get()); | 
|  | EXPECT_EQ(policy_.policy_data().SerializeAsString(), | 
|  | op.policy_data()->SerializeAsString()); | 
|  | ASSERT_TRUE(op.device_settings().get()); | 
|  | EXPECT_EQ(policy_.payload().SerializeAsString(), | 
|  | op.device_settings()->SerializeAsString()); | 
|  | } | 
|  |  | 
|  | }  // namespace ash |