chromium/chrome/browser/ash/system/device_disabling_manager_unittest.cc

// Copyright 2014 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/system/device_disabling_manager.h"

#include <memory>

#include "ash/constants/ash_switches.h"
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/ash/policy/core/device_cloud_policy_manager_ash.h"
#include "chrome/browser/ash/policy/core/device_policy_builder.h"
#include "chrome/browser/ash/policy/server_backed_state/server_backed_device_state.h"
#include "chrome/browser/ash/settings/device_settings_service.h"
#include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
#include "chrome/browser/browser_process_platform_part.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
#include "chromeos/ash/components/system/fake_statistics_provider.h"
#include "components/ownership/mock_owner_key_util.h"
#include "components/policy/core/common/cloud/cloud_policy_constants.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/prefs/testing_pref_service.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"

using testing::_;
using testing::Mock;

namespace ash {
namespace system {

namespace {

const char kTestUser[] = "[email protected]";
const char kEnrollmentDomain[] = "example.com";
const char kDeviceId[] = "fake-id";
const char kDisabledMessage1[] = "Device disabled 1.";
const char kDisabledMessage2[] = "Device disabled 2.";

}  // namespace

class DeviceDisablingManagerTestBase : public testing::Test,
                                       public DeviceDisablingManager::Delegate {
 public:
  DeviceDisablingManagerTestBase();

  DeviceDisablingManagerTestBase(const DeviceDisablingManagerTestBase&) =
      delete;
  DeviceDisablingManagerTestBase& operator=(
      const DeviceDisablingManagerTestBase&) = delete;

  // testing::Test:
  void TearDown() override;

  virtual void CreateDeviceDisablingManager();
  virtual void DestroyDeviceDisablingManager();
  void LogIn();

  // DeviceDisablingManager::Delegate:
  MOCK_METHOD0(RestartToLoginScreen, void());
  MOCK_METHOD0(ShowDeviceDisabledScreen, void());

  DeviceDisablingManager* GetDeviceDisablingManager() {
    return device_disabling_manager_.get();
  }

  // Configure install attributes.
  void SetUnowned();
  void SetEnterpriseOwned();
  void SetConsumerOwned();

 private:
  content::BrowserTaskEnvironment task_environment_;
  ScopedCrosSettingsTestHelper cros_settings_test_helper_;
  FakeChromeUserManager fake_user_manager_;
  std::unique_ptr<DeviceDisablingManager> device_disabling_manager_;
  FakeStatisticsProvider statistics_provider_;
};

DeviceDisablingManagerTestBase::DeviceDisablingManagerTestBase() {
  StatisticsProvider::SetTestProvider(&statistics_provider_);
}

void DeviceDisablingManagerTestBase::TearDown() {
  DestroyDeviceDisablingManager();
}

void DeviceDisablingManagerTestBase::CreateDeviceDisablingManager() {
  device_disabling_manager_ = std::make_unique<DeviceDisablingManager>(
      this, CrosSettings::Get(), &fake_user_manager_);
  device_disabling_manager_->Init();
}

void DeviceDisablingManagerTestBase::DestroyDeviceDisablingManager() {
  device_disabling_manager_.reset();
}

void DeviceDisablingManagerTestBase::LogIn() {
  fake_user_manager_.AddUser(AccountId::FromUserEmail(kTestUser));
}

void DeviceDisablingManagerTestBase::SetUnowned() {
  cros_settings_test_helper_.InstallAttributes()->Clear();
}

void DeviceDisablingManagerTestBase::SetEnterpriseOwned() {
  cros_settings_test_helper_.InstallAttributes()->SetCloudManaged(
      kEnrollmentDomain, kDeviceId);
}

void DeviceDisablingManagerTestBase::SetConsumerOwned() {
  cros_settings_test_helper_.InstallAttributes()->SetConsumerOwned();
}

// Base class for tests that verify device disabling behavior during OOBE, when
// the device is not owned yet.
class DeviceDisablingManagerOOBETest : public DeviceDisablingManagerTestBase {
 public:
  DeviceDisablingManagerOOBETest();

  DeviceDisablingManagerOOBETest(const DeviceDisablingManagerOOBETest&) =
      delete;
  DeviceDisablingManagerOOBETest& operator=(
      const DeviceDisablingManagerOOBETest&) = delete;

  // DeviceDisablingManagerTestBase:
  void SetUp() override;
  void TearDown() override;

  bool device_disabled() const { return device_disabled_; }

  void CheckWhetherDeviceDisabledDuringOOBE();

  void SetDeviceDisabled(bool disabled);

 private:
  void OnDeviceDisabledChecked(bool device_disabled);

  TestingPrefServiceSimple local_state_;
  FakeStatisticsProvider statistics_provider_;

  base::RunLoop run_loop_;
  bool device_disabled_ = false;
};

DeviceDisablingManagerOOBETest::DeviceDisablingManagerOOBETest() {
  EXPECT_CALL(*this, RestartToLoginScreen()).Times(0);
  EXPECT_CALL(*this, ShowDeviceDisabledScreen()).Times(0);
}

void DeviceDisablingManagerOOBETest::SetUp() {
  TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_);
  policy::DeviceCloudPolicyManagerAsh::RegisterPrefs(local_state_.registry());
  CreateDeviceDisablingManager();
  StatisticsProvider::SetTestProvider(&statistics_provider_);
}

void DeviceDisablingManagerOOBETest::TearDown() {
  DeviceDisablingManagerTestBase::TearDown();
  TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
}

void DeviceDisablingManagerOOBETest::CheckWhetherDeviceDisabledDuringOOBE() {
  GetDeviceDisablingManager()->CheckWhetherDeviceDisabledDuringOOBE(
      base::BindOnce(&DeviceDisablingManagerOOBETest::OnDeviceDisabledChecked,
                     base::Unretained(this)));
  run_loop_.Run();
}

void DeviceDisablingManagerOOBETest::SetDeviceDisabled(bool disabled) {
  ScopedDictPrefUpdate dict(&local_state_, prefs::kServerBackedDeviceState);
  if (disabled) {
    dict->Set(policy::kDeviceStateMode, policy::kDeviceStateModeDisabled);
  } else {
    dict->Remove(policy::kDeviceStateMode);
  }
  dict->Set(policy::kDeviceStateManagementDomain, kEnrollmentDomain);
  dict->Set(policy::kDeviceStateDisabledMessage, kDisabledMessage1);
}

void DeviceDisablingManagerOOBETest::OnDeviceDisabledChecked(
    bool device_disabled) {
  device_disabled_ = device_disabled;
  run_loop_.Quit();
}

// Verifies that the device is not considered disabled during OOBE by default.
TEST_F(DeviceDisablingManagerOOBETest, NotDisabledByDefault) {
  CheckWhetherDeviceDisabledDuringOOBE();
  EXPECT_FALSE(device_disabled());
}

// Verifies that the device is not considered disabled during OOBE when it is
// explicitly marked as not disabled.
TEST_F(DeviceDisablingManagerOOBETest, NotDisabledWhenExplicitlyNotDisabled) {
  SetDeviceDisabled(false);
  CheckWhetherDeviceDisabledDuringOOBE();
  EXPECT_FALSE(device_disabled());
}

// Verifies that the device is not considered disabled during OOBE when device
// disabling is turned off by switch, even if the device is marked as disabled.
TEST_F(DeviceDisablingManagerOOBETest, NotDisabledWhenTurnedOffBySwitch) {
  base::CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kDisableDeviceDisabling);
  SetDeviceDisabled(true);
  CheckWhetherDeviceDisabledDuringOOBE();
  EXPECT_FALSE(device_disabled());
}

// Verifies that the device is not considered disabled during OOBE when it is
// already enterprise enrolled, even if the device is marked as disabled.
TEST_F(DeviceDisablingManagerOOBETest, NotDisabledWhenEnterpriseOwned) {
  SetEnterpriseOwned();
  SetDeviceDisabled(true);
  CheckWhetherDeviceDisabledDuringOOBE();
  EXPECT_FALSE(device_disabled());
}

// Verifies that the device is not considered disabled during OOBE when it is
// already owned by a consumer, even if the device is marked as disabled.
TEST_F(DeviceDisablingManagerOOBETest, NotDisabledWhenConsumerOwned) {
  SetConsumerOwned();
  SetDeviceDisabled(true);
  CheckWhetherDeviceDisabledDuringOOBE();
  EXPECT_FALSE(device_disabled());
}

// Verifies that the device is considered disabled during OOBE when it is marked
// as disabled, device disabling is not turned off by flag and the device is not
// owned yet.
TEST_F(DeviceDisablingManagerOOBETest, ShowWhenDisabledAndNotOwned) {
  SetUnowned();
  SetDeviceDisabled(true);
  CheckWhetherDeviceDisabledDuringOOBE();
  EXPECT_TRUE(device_disabled());
  EXPECT_EQ(kEnrollmentDomain,
            GetDeviceDisablingManager()->enrollment_domain());
  EXPECT_EQ(kDisabledMessage1, GetDeviceDisablingManager()->disabled_message());
}

// Base class for tests that verify device disabling behavior once the device is
// owned.
class DeviceDisablingManagerTest : public DeviceDisablingManagerTestBase,
                                   public DeviceDisablingManager::Observer {
 public:
  DeviceDisablingManagerTest();

  DeviceDisablingManagerTest(const DeviceDisablingManagerTest&) = delete;
  DeviceDisablingManagerTest& operator=(const DeviceDisablingManagerTest&) =
      delete;

  // DeviceDisablingManagerTestBase:
  void TearDown() override;
  void CreateDeviceDisablingManager() override;
  void DestroyDeviceDisablingManager() override;

  // DeviceDisablingManager::Observer:
  MOCK_METHOD1(OnDisabledMessageChanged, void(const std::string&));

  void MakeCrosSettingsTrusted();

  void SetDeviceDisabled(bool disabled);
  void SetDisabledMessage(const std::string& disabled_message);

 private:
  void SimulatePolicyFetch();

  FakeSessionManagerClient session_manager_client_;
  policy::DevicePolicyBuilder device_policy_;
};

DeviceDisablingManagerTest::DeviceDisablingManagerTest() = default;

void DeviceDisablingManagerTest::TearDown() {
  DeviceSettingsService::Get()->UnsetSessionManager();
  DeviceDisablingManagerTestBase::TearDown();
}

void DeviceDisablingManagerTest::CreateDeviceDisablingManager() {
  DeviceDisablingManagerTestBase::CreateDeviceDisablingManager();
  GetDeviceDisablingManager()->AddObserver(this);
}

void DeviceDisablingManagerTest::DestroyDeviceDisablingManager() {
  if (GetDeviceDisablingManager())
    GetDeviceDisablingManager()->RemoveObserver(this);
  DeviceDisablingManagerTestBase::DestroyDeviceDisablingManager();
}

void DeviceDisablingManagerTest::MakeCrosSettingsTrusted() {
  scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util(
      new ownership::MockOwnerKeyUtil);
  owner_key_util->SetPublicKeyFromPrivateKey(*device_policy_.GetSigningKey());
  DeviceSettingsService::Get()->SetSessionManager(&session_manager_client_,
                                                  owner_key_util);
  SimulatePolicyFetch();
}

void DeviceDisablingManagerTest::SetDeviceDisabled(bool disabled) {
  if (disabled) {
    device_policy_.policy_data().mutable_device_state()->set_device_mode(
        enterprise_management::DeviceState::DEVICE_MODE_DISABLED);
  } else {
    device_policy_.policy_data().mutable_device_state()->clear_device_mode();
  }
  SimulatePolicyFetch();
}

void DeviceDisablingManagerTest::SetDisabledMessage(
    const std::string& disabled_message) {
  device_policy_.policy_data()
      .mutable_device_state()
      ->mutable_disabled_state()
      ->set_message(disabled_message);
  SimulatePolicyFetch();
}

void DeviceDisablingManagerTest::SimulatePolicyFetch() {
  device_policy_.Build();
  session_manager_client_.set_device_policy(device_policy_.GetBlob());
  DeviceSettingsService::Get()->OwnerKeySet(true);
  content::RunAllTasksUntilIdle();
}

// Verifies that the device is not considered disabled by default when it is
// enrolled for enterprise management.
TEST_F(DeviceDisablingManagerTest, NotDisabledByDefault) {
  SetEnterpriseOwned();
  MakeCrosSettingsTrusted();

  EXPECT_CALL(*this, RestartToLoginScreen()).Times(0);
  EXPECT_CALL(*this, ShowDeviceDisabledScreen()).Times(0);
  EXPECT_CALL(*this, OnDisabledMessageChanged(_)).Times(0);
  CreateDeviceDisablingManager();
}

// Verifies that the device is not considered disabled when it is explicitly
// marked as not disabled.
TEST_F(DeviceDisablingManagerTest, NotDisabledWhenExplicitlyNotDisabled) {
  SetEnterpriseOwned();
  MakeCrosSettingsTrusted();
  SetDeviceDisabled(false);

  EXPECT_CALL(*this, RestartToLoginScreen()).Times(0);
  EXPECT_CALL(*this, ShowDeviceDisabledScreen()).Times(0);
  EXPECT_CALL(*this, OnDisabledMessageChanged(_)).Times(0);
  CreateDeviceDisablingManager();
}

// Verifies that the device is not considered disabled when device disabling is
// turned off by switch, even if the device is marked as disabled.
TEST_F(DeviceDisablingManagerTest,
       NotDisabledWhenTurnedOffBySwitchEnterpriseManaged) {
  base::CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kDisableDeviceDisabling);
  SetEnterpriseOwned();
  MakeCrosSettingsTrusted();
  SetDeviceDisabled(true);

  EXPECT_CALL(*this, RestartToLoginScreen()).Times(0);
  EXPECT_CALL(*this, ShowDeviceDisabledScreen()).Times(0);
  EXPECT_CALL(*this, OnDisabledMessageChanged(_)).Times(0);
  CreateDeviceDisablingManager();
}

// Verifies that the device is not considered disabled when it is owned by a
// consumer, even if the device is marked as disabled.
TEST_F(DeviceDisablingManagerTest, NotDisabledWhenConsumerOwned) {
  SetConsumerOwned();
  MakeCrosSettingsTrusted();
  SetDeviceDisabled(true);

  EXPECT_CALL(*this, RestartToLoginScreen()).Times(0);
  EXPECT_CALL(*this, ShowDeviceDisabledScreen()).Times(0);
  EXPECT_CALL(*this, OnDisabledMessageChanged(_)).Times(0);
  CreateDeviceDisablingManager();
}

// Verifies that the device disabled screen is shown immediately when the device
// is already marked as disabled on start-up.
TEST_F(DeviceDisablingManagerTest, DisabledOnLoginScreen) {
  SetEnterpriseOwned();
  MakeCrosSettingsTrusted();
  SetDisabledMessage(kDisabledMessage1);
  SetDeviceDisabled(true);

  EXPECT_CALL(*this, RestartToLoginScreen()).Times(0);
  EXPECT_CALL(*this, ShowDeviceDisabledScreen()).Times(1);
  EXPECT_CALL(*this, OnDisabledMessageChanged(_)).Times(0);
  CreateDeviceDisablingManager();
  EXPECT_EQ(kEnrollmentDomain,
            GetDeviceDisablingManager()->enrollment_domain());
  EXPECT_EQ(kDisabledMessage1, GetDeviceDisablingManager()->disabled_message());
}

// Verifies that the device disabled screen is shown immediately when the device
// becomes disabled while the login screen is showing. Also verifies that Chrome
// restarts when the device becomes enabled again.
TEST_F(DeviceDisablingManagerTest, DisableAndReEnableOnLoginScreen) {
  SetEnterpriseOwned();
  MakeCrosSettingsTrusted();
  SetDisabledMessage(kDisabledMessage1);

  // Verify that initially, the disabled screen is not shown and Chrome does not
  // restart.
  EXPECT_CALL(*this, RestartToLoginScreen()).Times(0);
  EXPECT_CALL(*this, ShowDeviceDisabledScreen()).Times(0);
  EXPECT_CALL(*this, OnDisabledMessageChanged(_)).Times(0);
  CreateDeviceDisablingManager();
  Mock::VerifyAndClearExpectations(this);

  // Mark the device as disabled. Verify that the device disabled screen is
  // shown.
  EXPECT_CALL(*this, RestartToLoginScreen()).Times(0);
  EXPECT_CALL(*this, ShowDeviceDisabledScreen()).Times(1);
  EXPECT_CALL(*this, OnDisabledMessageChanged(_)).Times(0);
  EXPECT_CALL(*this, OnDisabledMessageChanged(kDisabledMessage1)).Times(1);
  SetDeviceDisabled(true);
  Mock::VerifyAndClearExpectations(this);
  EXPECT_EQ(kEnrollmentDomain,
            GetDeviceDisablingManager()->enrollment_domain());
  EXPECT_EQ(kDisabledMessage1, GetDeviceDisablingManager()->disabled_message());

  // Update the disabled message. Verify that the device disabled screen is
  // updated.
  EXPECT_CALL(*this, RestartToLoginScreen()).Times(0);
  EXPECT_CALL(*this, ShowDeviceDisabledScreen()).Times(0);
  EXPECT_CALL(*this, OnDisabledMessageChanged(_)).Times(0);
  EXPECT_CALL(*this, OnDisabledMessageChanged(kDisabledMessage2)).Times(1);
  SetDisabledMessage(kDisabledMessage2);
  Mock::VerifyAndClearExpectations(this);
  EXPECT_EQ(kDisabledMessage2, GetDeviceDisablingManager()->disabled_message());

  // Mark the device as enabled again. Verify that Chrome restarts.
  EXPECT_CALL(*this, RestartToLoginScreen()).Times(1);
  EXPECT_CALL(*this, ShowDeviceDisabledScreen()).Times(0);
  EXPECT_CALL(*this, OnDisabledMessageChanged(_)).Times(0);
  SetDeviceDisabled(false);
}

// Verifies that Chrome restarts when the device becomes disabled while a
// session is in progress.
TEST_F(DeviceDisablingManagerTest, DisableDuringSession) {
  SetEnterpriseOwned();
  MakeCrosSettingsTrusted();
  SetDisabledMessage(kDisabledMessage1);
  LogIn();

  // Verify that initially, the disabled screen is not shown and Chrome does not
  // restart.
  EXPECT_CALL(*this, RestartToLoginScreen()).Times(0);
  EXPECT_CALL(*this, ShowDeviceDisabledScreen()).Times(0);
  EXPECT_CALL(*this, OnDisabledMessageChanged(_)).Times(0);
  CreateDeviceDisablingManager();
  Mock::VerifyAndClearExpectations(this);

  // Mark the device as disabled. Verify that Chrome restarts.
  EXPECT_CALL(*this, RestartToLoginScreen()).Times(1);
  EXPECT_CALL(*this, ShowDeviceDisabledScreen()).Times(0);
  EXPECT_CALL(*this, OnDisabledMessageChanged(_)).Times(0);
  EXPECT_CALL(*this, OnDisabledMessageChanged(kDisabledMessage1)).Times(1);
  SetDeviceDisabled(true);
}

// Verifies that the HonorDeviceDisablingDuringNormalOperation() method returns
// true iff the device is enterprise enrolled and device disabling is not turned
// off by switch.
TEST_F(DeviceDisablingManagerTest, HonorDeviceDisablingDuringNormalOperation) {
  // Not enterprise owned, not disabled by switch.
  EXPECT_FALSE(
      DeviceDisablingManager::HonorDeviceDisablingDuringNormalOperation());

  // Enterprise owned, not disabled by switch.
  SetEnterpriseOwned();
  EXPECT_TRUE(
      DeviceDisablingManager::HonorDeviceDisablingDuringNormalOperation());

  // Enterprise owned, disabled by switch.
  base::CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kDisableDeviceDisabling);
  EXPECT_FALSE(
      DeviceDisablingManager::HonorDeviceDisablingDuringNormalOperation());

  // Not enterprise owned, disabled by switch.
  SetUnowned();
  EXPECT_FALSE(
      DeviceDisablingManager::HonorDeviceDisablingDuringNormalOperation());
}

// Tests the IsDeviceDisabledDuringNormalOperation() method, when device
// disabling is turned off by switch.
TEST_F(DeviceDisablingManagerTest, IsDeviceDisabledWhenTurnedOffBySwitch) {
  base::CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kDisableDeviceDisabling);
  MakeCrosSettingsTrusted();
  SetDeviceDisabled(true);

  // Not enterprise owned.
  SetConsumerOwned();
  EXPECT_FALSE(DeviceDisablingManager::IsDeviceDisabledDuringNormalOperation());

  // Enterprise owned.
  SetEnterpriseOwned();
  EXPECT_FALSE(DeviceDisablingManager::IsDeviceDisabledDuringNormalOperation());
}

// Tests the IsDeviceDisabledDuringNormalOperation() method, when device
// is not enterprise owned.
TEST_F(DeviceDisablingManagerTest, IsDeviceDisabledNotEnterpriseOwned) {
  SetConsumerOwned();
  MakeCrosSettingsTrusted();
  SetDeviceDisabled(true);

  EXPECT_FALSE(DeviceDisablingManager::IsDeviceDisabledDuringNormalOperation());
}

// Tests the IsDeviceDisabledDuringNormalOperation() method, when device is
// enterprise owned.
TEST_F(DeviceDisablingManagerTest, IsDeviceDisabledEnterpriseOwned) {
  SetEnterpriseOwned();
  MakeCrosSettingsTrusted();
  SetDeviceDisabled(false);

  EXPECT_FALSE(DeviceDisablingManager::IsDeviceDisabledDuringNormalOperation());

  SetDeviceDisabled(true);

  EXPECT_TRUE(DeviceDisablingManager::IsDeviceDisabledDuringNormalOperation());
}

}  // namespace system
}  // namespace ash