普通文本  |  503行  |  18.42 KB

// Copyright (c) 2011 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 <gtest/gtest.h>
#include <windows.h>

#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/stl_util-inl.h"
#include "base/string_number_conversions.h"
#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "base/win/registry.h"
#include "chrome/browser/policy/asynchronous_policy_loader.h"
#include "chrome/browser/policy/configuration_policy_pref_store.h"
#include "chrome/browser/policy/configuration_policy_provider_win.h"
#include "chrome/browser/policy/mock_configuration_policy_store.h"
#include "chrome/common/pref_names.h"
#include "content/browser/browser_thread.h"
#include "policy/policy_constants.h"
#include "testing/gtest/include/gtest/gtest.h"

using base::win::RegKey;

namespace policy {

const wchar_t kUnitTestRegistrySubKey[] = L"SOFTWARE\\Chromium Unit Tests";
const wchar_t kUnitTestMachineOverrideSubKey[] =
    L"SOFTWARE\\Chromium Unit Tests\\HKLM Override";
const wchar_t kUnitTestUserOverrideSubKey[] =
    L"SOFTWARE\\Chromium Unit Tests\\HKCU Override";

namespace {

// Holds policy type, corresponding policy name string and a valid value for use
// in parametrized value tests.
class PolicyTestParams {
 public:
  // Assumes ownership of |hklm_value| and |hkcu_value|.
  PolicyTestParams(ConfigurationPolicyType type,
                   const char* policy_name,
                   Value* hklm_value,
                   Value* hkcu_value)
      : type_(type),
        policy_name_(policy_name),
        hklm_value_(hklm_value),
        hkcu_value_(hkcu_value) {}

  // testing::TestWithParam does copy the parameters, so provide copy
  // constructor and assignment operator.
  PolicyTestParams(const PolicyTestParams& other)
      : type_(other.type_),
        policy_name_(other.policy_name_),
        hklm_value_(other.hklm_value_->DeepCopy()),
        hkcu_value_(other.hkcu_value_->DeepCopy()) {}

  const PolicyTestParams& operator=(PolicyTestParams other) {
    swap(other);
    return *this;
  }

  void swap(PolicyTestParams& other) {
    std::swap(type_, other.type_);
    std::swap(policy_name_, other.policy_name_);
    hklm_value_.swap(other.hklm_value_);
    hkcu_value_.swap(other.hkcu_value_);
  }

  ConfigurationPolicyType type() const { return type_; }
  const char* policy_name() const { return policy_name_; }
  const Value* hklm_value() const { return hklm_value_.get(); }
  const Value* hkcu_value() const { return hkcu_value_.get(); }

  // Factory methods for different value types.
  static PolicyTestParams ForStringPolicy(
      ConfigurationPolicyType type,
      const char* policy_name) {
    return PolicyTestParams(type,
                            policy_name,
                            Value::CreateStringValue("string_a"),
                            Value::CreateStringValue("string_b"));
  }
  static PolicyTestParams ForBooleanPolicy(
      ConfigurationPolicyType type,
      const char* policy_name) {
    return PolicyTestParams(type,
                            policy_name,
                            Value::CreateBooleanValue(true),
                            Value::CreateBooleanValue(false));
  }
  static PolicyTestParams ForIntegerPolicy(
      ConfigurationPolicyType type,
      const char* policy_name) {
    return PolicyTestParams(type,
                            policy_name,
                            Value::CreateIntegerValue(42),
                            Value::CreateIntegerValue(17));
  }
  static PolicyTestParams ForListPolicy(
      ConfigurationPolicyType type,
      const char* policy_name) {
    ListValue* hklm_value = new ListValue;
    hklm_value->Set(0U, Value::CreateStringValue("It's a plane!"));
    ListValue* hkcu_value = new ListValue;
    hkcu_value->Set(0U, Value::CreateStringValue("It's a bird!"));
    hkcu_value->Set(0U, Value::CreateStringValue("It's a flying carpet!"));
    return PolicyTestParams(type, policy_name, hklm_value, hkcu_value);
  }

 private:
  ConfigurationPolicyType type_;
  const char* policy_name_;
  scoped_ptr<Value> hklm_value_;
  scoped_ptr<Value> hkcu_value_;
};

}  // namespace

// This test class provides sandboxing and mocking for the parts of the
// Windows Registry implementing Group Policy. The |SetUp| method prepares
// two temporary sandbox keys in |kUnitTestRegistrySubKey|, one for HKLM and one
// for HKCU. A test's calls to the registry are redirected by Windows to these
// sandboxes, allowing the tests to manipulate and access policy as if it
// were active, but without actually changing the parts of the Registry that
// are managed by Group Policy.
class ConfigurationPolicyProviderWinTest
    : public testing::TestWithParam<PolicyTestParams> {
 public:
  ConfigurationPolicyProviderWinTest();

  // testing::Test method overrides:
  virtual void SetUp();
  virtual void TearDown();

  void ActivateOverrides();
  void DeactivateOverrides();

  // Deletes the registry key created during the tests.
  void DeleteRegistrySandbox();

  // Write a string value to the registry.
  void WriteString(HKEY hive, const char* name, const wchar_t* value);
  // Write a DWORD value to the registry.
  void WriteDWORD(HKEY hive, const char* name, DWORD value);

  // Write the given value to the registry.
  void WriteValue(HKEY hive, const char* name, const Value* value);
  // Write a value that is not compatible with the given |value|.
  void WriteInvalidValue(HKEY hive, const char* name, const Value* value);

 protected:
  scoped_ptr<MockConfigurationPolicyStore> store_;
  scoped_ptr<ConfigurationPolicyProviderWin> provider_;

  // A message loop must be declared and instantiated for these tests,
  // because Windows policy provider create WaitableEvents and
  // ObjectWatchers that require the tests to have a MessageLoop associated
  // with the thread executing the tests.
  MessageLoop loop_;

 private:
  BrowserThread ui_thread_;
  BrowserThread file_thread_;

  // Keys are created for the lifetime of a test to contain
  // the sandboxed HKCU and HKLM hives, respectively.
  RegKey temp_hkcu_hive_key_;
  RegKey temp_hklm_hive_key_;
};

ConfigurationPolicyProviderWinTest::ConfigurationPolicyProviderWinTest()
    : ui_thread_(BrowserThread::UI, &loop_),
      file_thread_(BrowserThread::FILE, &loop_),
      temp_hklm_hive_key_(HKEY_CURRENT_USER, kUnitTestMachineOverrideSubKey,
                          KEY_READ),
      temp_hkcu_hive_key_(HKEY_CURRENT_USER, kUnitTestUserOverrideSubKey,
                          KEY_READ) {
}

void ConfigurationPolicyProviderWinTest::SetUp() {
  // Cleanup any remnants of previous tests.
  DeleteRegistrySandbox();

  // Create the subkeys to hold the overridden HKLM and HKCU
  // policy settings.
  temp_hklm_hive_key_.Create(HKEY_CURRENT_USER,
                             kUnitTestMachineOverrideSubKey,
                             KEY_ALL_ACCESS);
  temp_hkcu_hive_key_.Create(HKEY_CURRENT_USER,
                             kUnitTestUserOverrideSubKey,
                             KEY_ALL_ACCESS);

  ActivateOverrides();

  store_.reset(new MockConfigurationPolicyStore);
  provider_.reset(new ConfigurationPolicyProviderWin(
      ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList()));
}

void ConfigurationPolicyProviderWinTest::TearDown() {
  DeactivateOverrides();
  DeleteRegistrySandbox();
  loop_.RunAllPending();
}

void ConfigurationPolicyProviderWinTest::ActivateOverrides() {
  HRESULT result = RegOverridePredefKey(HKEY_LOCAL_MACHINE,
                                        temp_hklm_hive_key_.Handle());
  EXPECT_EQ(ERROR_SUCCESS, result);
  result = RegOverridePredefKey(HKEY_CURRENT_USER,
                                temp_hkcu_hive_key_.Handle());
  EXPECT_EQ(ERROR_SUCCESS, result);
}

void ConfigurationPolicyProviderWinTest::DeactivateOverrides() {
  uint32 result = RegOverridePredefKey(HKEY_LOCAL_MACHINE, 0);
  EXPECT_EQ(ERROR_SUCCESS, result);
  result = RegOverridePredefKey(HKEY_CURRENT_USER, 0);
  EXPECT_EQ(ERROR_SUCCESS, result);
}

void ConfigurationPolicyProviderWinTest::DeleteRegistrySandbox() {
  temp_hklm_hive_key_.Close();
  temp_hkcu_hive_key_.Close();
  RegKey key(HKEY_CURRENT_USER, kUnitTestRegistrySubKey, KEY_ALL_ACCESS);
  key.DeleteKey(L"");
}

void ConfigurationPolicyProviderWinTest::WriteString(HKEY hive,
                                                     const char* name,
                                                     const wchar_t* value) {
  RegKey key(hive, policy::kRegistrySubKey, KEY_ALL_ACCESS);
  key.WriteValue(UTF8ToUTF16(name).c_str(), value);
}

void ConfigurationPolicyProviderWinTest::WriteDWORD(HKEY hive,
                                                    const char* name,
                                                    DWORD value) {
  RegKey key(hive, policy::kRegistrySubKey, KEY_ALL_ACCESS);
  key.WriteValue(UTF8ToUTF16(name).c_str(), value);
}

void ConfigurationPolicyProviderWinTest::WriteValue(HKEY hive,
                                                    const char* name,
                                                    const Value* value) {
  switch (value->GetType()) {
    case Value::TYPE_BOOLEAN: {
      bool v;
      ASSERT_TRUE(value->GetAsBoolean(&v));
      WriteDWORD(hive, name, v);
      break;
    }
    case Value::TYPE_INTEGER: {
      int v;
      ASSERT_TRUE(value->GetAsInteger(&v));
      WriteDWORD(hive, name, v);
      break;
    }
    case Value::TYPE_STRING: {
      std::string v;
      ASSERT_TRUE(value->GetAsString(&v));
      WriteString(hive, name, UTF8ToUTF16(v).c_str());
      break;
    }
    case Value::TYPE_LIST: {
      const ListValue* list = static_cast<const ListValue*>(value);
      RegKey key(hive,
                 (string16(policy::kRegistrySubKey) + ASCIIToUTF16("\\") +
                  UTF8ToUTF16(name)).c_str(),
                 KEY_ALL_ACCESS);
      int index = 1;
      for (ListValue::const_iterator element(list->begin());
           element != list->end(); ++element) {
        ASSERT_TRUE((*element)->IsType(Value::TYPE_STRING));
        std::string element_value;
        ASSERT_TRUE((*element)->GetAsString(&element_value));
        key.WriteValue(base::IntToString16(index++).c_str(),
                       UTF8ToUTF16(element_value).c_str());
      }
      break;
    }
    default:
      FAIL() << "Unsupported value type " << value->GetType();
      break;
  }
}

void ConfigurationPolicyProviderWinTest::WriteInvalidValue(HKEY hive,
                                                           const char* name,
                                                           const Value* value) {
  if (value->IsType(Value::TYPE_STRING))
    WriteDWORD(hive, name, -1);
  else
    WriteString(hive, name, L"bad value");
}

TEST_P(ConfigurationPolicyProviderWinTest, Default) {
  provider_->Provide(store_.get());
  EXPECT_TRUE(store_->policy_map().empty());
}

TEST_P(ConfigurationPolicyProviderWinTest, InvalidValue) {
  WriteInvalidValue(HKEY_LOCAL_MACHINE,
                    GetParam().policy_name(),
                    GetParam().hklm_value());
  WriteInvalidValue(HKEY_CURRENT_USER,
                    GetParam().policy_name(),
                    GetParam().hkcu_value());
  provider_->loader()->Reload();
  loop_.RunAllPending();
  provider_->Provide(store_.get());
  EXPECT_TRUE(store_->policy_map().empty());
}

TEST_P(ConfigurationPolicyProviderWinTest, HKLM) {
  WriteValue(HKEY_LOCAL_MACHINE,
             GetParam().policy_name(),
             GetParam().hklm_value());
  provider_->loader()->Reload();
  loop_.RunAllPending();
  provider_->Provide(store_.get());
  const Value* value = store_->Get(GetParam().type());
  ASSERT_TRUE(value);
  EXPECT_TRUE(value->Equals(GetParam().hklm_value()));
}

TEST_P(ConfigurationPolicyProviderWinTest, HKCU) {
  WriteValue(HKEY_CURRENT_USER,
             GetParam().policy_name(),
             GetParam().hkcu_value());
  provider_->loader()->Reload();
  loop_.RunAllPending();
  provider_->Provide(store_.get());
  const Value* value = store_->Get(GetParam().type());
  ASSERT_TRUE(value);
  EXPECT_TRUE(value->Equals(GetParam().hkcu_value()));
}

TEST_P(ConfigurationPolicyProviderWinTest, HKLMOverHKCU) {
  WriteValue(HKEY_LOCAL_MACHINE,
             GetParam().policy_name(),
             GetParam().hklm_value());
  WriteValue(HKEY_CURRENT_USER,
             GetParam().policy_name(),
             GetParam().hkcu_value());
  provider_->loader()->Reload();
  loop_.RunAllPending();
  provider_->Provide(store_.get());
  const Value* value = store_->Get(GetParam().type());
  ASSERT_TRUE(value);
  EXPECT_TRUE(value->Equals(GetParam().hklm_value()));
}

// Instantiate the test case for all supported policies.
INSTANTIATE_TEST_CASE_P(
    ConfigurationPolicyProviderWinTestInstance,
    ConfigurationPolicyProviderWinTest,
    testing::Values(
        PolicyTestParams::ForStringPolicy(
            kPolicyHomepageLocation,
            key::kHomepageLocation),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyHomepageIsNewTabPage,
            key::kHomepageIsNewTabPage),
        PolicyTestParams::ForIntegerPolicy(
            kPolicyRestoreOnStartup,
            key::kRestoreOnStartup),
        PolicyTestParams::ForListPolicy(
            kPolicyRestoreOnStartupURLs,
            key::kRestoreOnStartupURLs),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyDefaultSearchProviderEnabled,
            key::kDefaultSearchProviderEnabled),
        PolicyTestParams::ForStringPolicy(
            kPolicyDefaultSearchProviderName,
            key::kDefaultSearchProviderName),
        PolicyTestParams::ForStringPolicy(
            kPolicyDefaultSearchProviderKeyword,
            key::kDefaultSearchProviderKeyword),
        PolicyTestParams::ForStringPolicy(
            kPolicyDefaultSearchProviderSearchURL,
            key::kDefaultSearchProviderSearchURL),
        PolicyTestParams::ForStringPolicy(
            kPolicyDefaultSearchProviderSuggestURL,
            key::kDefaultSearchProviderSuggestURL),
        PolicyTestParams::ForStringPolicy(
            kPolicyDefaultSearchProviderInstantURL,
            key::kDefaultSearchProviderInstantURL),
        PolicyTestParams::ForStringPolicy(
            kPolicyDefaultSearchProviderIconURL,
            key::kDefaultSearchProviderIconURL),
        PolicyTestParams::ForStringPolicy(
            kPolicyDefaultSearchProviderEncodings,
            key::kDefaultSearchProviderEncodings),
        PolicyTestParams::ForStringPolicy(
            kPolicyProxyMode,
            key::kProxyMode),
        PolicyTestParams::ForIntegerPolicy(
            kPolicyProxyServerMode,
            key::kProxyServerMode),
        PolicyTestParams::ForStringPolicy(
            kPolicyProxyServer,
            key::kProxyServer),
        PolicyTestParams::ForStringPolicy(
            kPolicyProxyPacUrl,
            key::kProxyPacUrl),
        PolicyTestParams::ForStringPolicy(
            kPolicyProxyBypassList,
            key::kProxyBypassList),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyAlternateErrorPagesEnabled,
            key::kAlternateErrorPagesEnabled),
        PolicyTestParams::ForBooleanPolicy(
            kPolicySearchSuggestEnabled,
            key::kSearchSuggestEnabled),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyDnsPrefetchingEnabled,
            key::kDnsPrefetchingEnabled),
        PolicyTestParams::ForBooleanPolicy(
            kPolicySafeBrowsingEnabled,
            key::kSafeBrowsingEnabled),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyMetricsReportingEnabled,
            key::kMetricsReportingEnabled),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyPasswordManagerEnabled,
            key::kPasswordManagerEnabled),
        PolicyTestParams::ForListPolicy(
            kPolicyDisabledPlugins,
            key::kDisabledPlugins),
        PolicyTestParams::ForListPolicy(
            kPolicyDisabledPluginsExceptions,
            key::kDisabledPluginsExceptions),
        PolicyTestParams::ForListPolicy(
            kPolicyEnabledPlugins,
            key::kEnabledPlugins),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyAutoFillEnabled,
            key::kAutoFillEnabled),
        PolicyTestParams::ForBooleanPolicy(
            kPolicySyncDisabled,
            key::kSyncDisabled),
        PolicyTestParams::ForStringPolicy(
            kPolicyApplicationLocaleValue,
            key::kApplicationLocaleValue),
        PolicyTestParams::ForListPolicy(
            kPolicyExtensionInstallWhitelist,
            key::kExtensionInstallWhitelist),
        PolicyTestParams::ForListPolicy(
            kPolicyExtensionInstallBlacklist,
            key::kExtensionInstallBlacklist),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyShowHomeButton,
            key::kShowHomeButton),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyPrintingEnabled,
            key::kPrintingEnabled),
        PolicyTestParams::ForIntegerPolicy(
            kPolicyPolicyRefreshRate,
            key::kPolicyRefreshRate),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyInstantEnabled,
            key::kInstantEnabled),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyIncognitoEnabled,
            key::kIncognitoEnabled),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyDisablePluginFinder,
            key::kDisablePluginFinder),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyClearSiteDataOnExit,
            key::kClearSiteDataOnExit),
        PolicyTestParams::ForStringPolicy(
            kPolicyDownloadDirectory,
            key::kDownloadDirectory),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyDefaultBrowserSettingEnabled,
            key::kDefaultBrowserSettingEnabled),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyCloudPrintProxyEnabled,
            key::kCloudPrintProxyEnabled),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyTranslateEnabled,
            key::kTranslateEnabled),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyAllowOutdatedPlugins,
            key::kAllowOutdatedPlugins),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyBookmarkBarEnabled,
            key::kBookmarkBarEnabled),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyEditBookmarksEnabled,
            key::kEditBookmarksEnabled),
        PolicyTestParams::ForBooleanPolicy(
            kPolicyAllowFileSelectionDialogs,
            key::kAllowFileSelectionDialogs),
        PolicyTestParams::ForListPolicy(
            kPolicyDisabledSchemes,
            key::kDisabledSchemes)));

}  // namespace policy