// 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