chromium/chrome/browser/ash/settings/session_manager_operation_unittest.cc

// 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/policy/core/device_policy_builder.h"
#include "chrome/browser/ash/settings/device_settings_test_helper.h"
#include "chrome/test/base/testing_profile.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 "crypto/rsa_private_key.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;
    ASSERT_TRUE(policy_.GetSigningKey()->ExportPublicKey(&public_key));
    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