diff options
author | evan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-09 23:36:04 +0000 |
---|---|---|
committer | evan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-09 23:36:04 +0000 |
commit | 99178111dddd6c8770cc021870f2bca48b218565 (patch) | |
tree | 7bf0089e70dedfb3afbf49b8a0a6762d0ab8cce3 /chrome/browser/policy | |
parent | 537436d7d0ef6690f31de8854886597dddfa1117 (diff) | |
download | chromium_src-99178111dddd6c8770cc021870f2bca48b218565.zip chromium_src-99178111dddd6c8770cc021870f2bca48b218565.tar.gz chromium_src-99178111dddd6c8770cc021870f2bca48b218565.tar.bz2 |
Move a bunch of chrome/browser/ files into a policy/ subdir.
BUG=50548
TEST=compiles
Review URL: http://codereview.chromium.org/3110002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55503 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/policy')
18 files changed, 2243 insertions, 0 deletions
diff --git a/chrome/browser/policy/config_dir_policy_provider.cc b/chrome/browser/policy/config_dir_policy_provider.cc new file mode 100644 index 0000000..92e9714 --- /dev/null +++ b/chrome/browser/policy/config_dir_policy_provider.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2010 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 "chrome/browser/policy/config_dir_policy_provider.h" + +#include <set> + +#include "base/file_util.h" +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/common/json_value_serializer.h" + +ConfigDirPolicyProvider::ConfigDirPolicyProvider(const FilePath& config_dir) + : config_dir_(config_dir) { +} + +bool ConfigDirPolicyProvider::Provide(ConfigurationPolicyStore* store) { + scoped_ptr<DictionaryValue> policy(ReadPolicies()); + DecodePolicyValueTree(policy.get(), store); + return true; +} + +DictionaryValue* ConfigDirPolicyProvider::ReadPolicies() { + // Enumerate the files and sort them lexicographically. + std::set<FilePath> files; + file_util::FileEnumerator file_enumerator(config_dir_, false, + file_util::FileEnumerator::FILES); + for (FilePath config_file_path = file_enumerator.Next(); + !config_file_path.empty(); config_file_path = file_enumerator.Next()) + files.insert(config_file_path); + + // Start with an empty dictionary and merge the files' contents. + DictionaryValue* policy = new DictionaryValue; + for (std::set<FilePath>::iterator config_file_iter = files.begin(); + config_file_iter != files.end(); ++config_file_iter) { + JSONFileValueSerializer deserializer(*config_file_iter); + int error_code = 0; + std::string error_msg; + scoped_ptr<Value> value(deserializer.Deserialize(&error_code, &error_msg)); + if (!value.get()) { + LOG(WARNING) << "Failed to read configuration file " + << config_file_iter->value() << ": " << error_msg; + continue; + } + if (!value->IsType(Value::TYPE_DICTIONARY)) { + LOG(WARNING) << "Expected JSON dictionary in configuration file " + << config_file_iter->value(); + continue; + } + policy->MergeDictionary(static_cast<DictionaryValue*>(value.get())); + } + + return policy; +} + +void ConfigDirPolicyProvider::DecodePolicyValueTree( + DictionaryValue* policies, + ConfigurationPolicyStore* store) { + const PolicyValueMap* mapping = PolicyValueMapping(); + for (PolicyValueMap::const_iterator i = mapping->begin(); + i != mapping->end(); ++i) { + const PolicyValueMapEntry& entry(*i); + Value* value; + if (policies->Get(UTF8ToWide(entry.name), &value) && + value->IsType(entry.value_type)) + store->Apply(entry.policy_type, value->DeepCopy()); + } + + // TODO(mnissler): Handle preference overrides once |ConfigurationPolicyStore| + // supports it. +} + diff --git a/chrome/browser/policy/config_dir_policy_provider.h b/chrome/browser/policy/config_dir_policy_provider.h new file mode 100644 index 0000000..9412ff2 --- /dev/null +++ b/chrome/browser/policy/config_dir_policy_provider.h @@ -0,0 +1,43 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_POLICY_CONFIG_DIR_POLICY_PROVIDER_H_ +#define CHROME_BROWSER_POLICY_CONFIG_DIR_POLICY_PROVIDER_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "chrome/browser/policy/configuration_policy_provider.h" + +class DictionaryValue; + +// A policy provider implementation backed by a set of files in a given +// directory. The files should contain JSON-formatted policy settings. They are +// merged together and the result is returned via the +// ConfigurationPolicyProvider interface. The files are consulted in +// lexicographic file name order, so the last value read takes precedence in +// case of preference key collisions. +class ConfigDirPolicyProvider : public ConfigurationPolicyProvider { + public: + explicit ConfigDirPolicyProvider(const FilePath& config_dir); + virtual ~ConfigDirPolicyProvider() { } + + // ConfigurationPolicyProvider implementation. + virtual bool Provide(ConfigurationPolicyStore* store); + + private: + // Read and merge the files from the configuration directory. + DictionaryValue* ReadPolicies(); + + // Decodes the value tree and writes the configuration to the given |store|. + void DecodePolicyValueTree(DictionaryValue* policies, + ConfigurationPolicyStore* store); + + // The directory in which we look for configuration files. + const FilePath config_dir_; + + DISALLOW_COPY_AND_ASSIGN(ConfigDirPolicyProvider); +}; + +#endif // CHROME_BROWSER_POLICY_CONFIG_DIR_POLICY_PROVIDER_H_ diff --git a/chrome/browser/policy/config_dir_policy_provider_unittest.cc b/chrome/browser/policy/config_dir_policy_provider_unittest.cc new file mode 100644 index 0000000..987a50b --- /dev/null +++ b/chrome/browser/policy/config_dir_policy_provider_unittest.cc @@ -0,0 +1,115 @@ +// Copyright (c) 2010 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 "base/file_util.h" +#include "base/path_service.h" +#include "base/string_number_conversions.h" +#include "chrome/browser/policy/config_dir_policy_provider.h" +#include "chrome/browser/policy/mock_configuration_policy_store.h" +#include "chrome/common/json_value_serializer.h" +#include "testing/gtest/include/gtest/gtest.h" + +class ConfigDirPolicyProviderTest : public testing::Test { + protected: + virtual void SetUp() { + // Determine the directory to use for testing. + ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_)); + test_dir_ = + test_dir_.Append(FILE_PATH_LITERAL("ConfigDirPolicyProviderTest")); + + // Make sure the directory is fresh. + file_util::Delete(test_dir_, true); + file_util::CreateDirectory(test_dir_); + ASSERT_TRUE(file_util::DirectoryExists(test_dir_)); + + // Create a fresh policy store mock. + policy_store_.reset(new MockConfigurationPolicyStore()); + } + + virtual void TearDown() { + // Clean up test directory. + ASSERT_TRUE(file_util::Delete(test_dir_, true)); + ASSERT_FALSE(file_util::PathExists(test_dir_)); + } + + // JSON-encode a dictionary and write it to a file. + void WriteConfigFile(const DictionaryValue& dict, + const std::string& file_name) { + std::string data; + JSONStringValueSerializer serializer(&data); + serializer.Serialize(dict); + FilePath file_path(test_dir_.AppendASCII(file_name)); + file_util::WriteFile(file_path, data.c_str(), data.size()); + } + + FilePath test_dir_; + scoped_ptr<MockConfigurationPolicyStore> policy_store_; +}; + +// The preferences dictionary is expected to be empty when there are no files to +// load. +TEST_F(ConfigDirPolicyProviderTest, ReadPrefsEmpty) { + ConfigDirPolicyProvider provider(test_dir_); + EXPECT_TRUE(provider.Provide(policy_store_.get())); + EXPECT_TRUE(policy_store_->policy_map().empty()); +} + +// Reading from a non-existent directory should result in an empty preferences +// dictionary. +TEST_F(ConfigDirPolicyProviderTest, ReadPrefsNonExistentDirectory) { + FilePath non_existent_dir(test_dir_.Append(FILE_PATH_LITERAL("not_there"))); + ConfigDirPolicyProvider provider(non_existent_dir); + EXPECT_TRUE(provider.Provide(policy_store_.get())); + EXPECT_TRUE(policy_store_->policy_map().empty()); +} + +// Test reading back a single preference value. +TEST_F(ConfigDirPolicyProviderTest, ReadPrefsSinglePref) { + DictionaryValue test_dict; + test_dict.SetString(L"HomepageLocation", L"http://www.google.com"); + WriteConfigFile(test_dict, "config_file"); + ConfigDirPolicyProvider provider(test_dir_); + + EXPECT_TRUE(provider.Provide(policy_store_.get())); + const MockConfigurationPolicyStore::PolicyMap& policy_map( + policy_store_->policy_map()); + EXPECT_EQ(1U, policy_map.size()); + MockConfigurationPolicyStore::PolicyMap::const_iterator entry = + policy_map.find(ConfigurationPolicyStore::kPolicyHomePage); + ASSERT_TRUE(entry != policy_map.end()); + + std::wstring str_value; + EXPECT_TRUE(entry->second->GetAsString(&str_value)); + EXPECT_EQ(L"http://www.google.com", str_value); +} + +// Test merging values from different files. +TEST_F(ConfigDirPolicyProviderTest, ReadPrefsMergePrefs) { + // Write a bunch of data files in order to increase the chance to detect the + // provider not respecting lexicographic ordering when reading them. Since the + // filesystem may return files in arbitrary order, there is no way to be sure, + // but this is better than nothing. + DictionaryValue test_dict_bar; + test_dict_bar.SetString(L"HomepageLocation", L"http://bar.com"); + for (unsigned int i = 1; i <= 4; ++i) + WriteConfigFile(test_dict_bar, base::IntToString(i)); + DictionaryValue test_dict_foo; + test_dict_foo.SetString(L"HomepageLocation", L"http://foo.com"); + WriteConfigFile(test_dict_foo, "9"); + for (unsigned int i = 5; i <= 8; ++i) + WriteConfigFile(test_dict_bar, base::IntToString(i)); + ConfigDirPolicyProvider provider(test_dir_); + + EXPECT_TRUE(provider.Provide(policy_store_.get())); + const MockConfigurationPolicyStore::PolicyMap& policy_map( + policy_store_->policy_map()); + EXPECT_EQ(1U, policy_map.size()); + MockConfigurationPolicyStore::PolicyMap::const_iterator entry = + policy_map.find(ConfigurationPolicyStore::kPolicyHomePage); + ASSERT_TRUE(entry != policy_map.end()); + + std::wstring str_value; + EXPECT_TRUE(entry->second->GetAsString(&str_value)); + EXPECT_EQ(L"http://foo.com", str_value); +} diff --git a/chrome/browser/policy/configuration_policy_pref_store.cc b/chrome/browser/policy/configuration_policy_pref_store.cc new file mode 100644 index 0000000..b6fd1e6 --- /dev/null +++ b/chrome/browser/policy/configuration_policy_pref_store.cc @@ -0,0 +1,365 @@ +// Copyright (c) 2010 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 "chrome/browser/policy/configuration_policy_pref_store.h" + +#include "base/command_line.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/string16.h" +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/policy/configuration_policy_provider.h" +#if defined(OS_WIN) +#include "chrome/browser/policy/configuration_policy_provider_win.h" +#elif defined(OS_MACOSX) +#include "chrome/browser/policy/configuration_policy_provider_mac.h" +#elif defined(OS_POSIX) +#include "chrome/browser/policy/config_dir_policy_provider.h" +#endif +#include "chrome/browser/policy/dummy_configuration_policy_provider.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" + +const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry + ConfigurationPolicyPrefStore::simple_policy_map_[] = { + { Value::TYPE_STRING, kPolicyHomePage, prefs::kHomePage }, + { Value::TYPE_BOOLEAN, kPolicyHomepageIsNewTabPage, + prefs::kHomePageIsNewTabPage }, + { Value::TYPE_BOOLEAN, kPolicyAlternateErrorPagesEnabled, + prefs::kAlternateErrorPagesEnabled }, + { Value::TYPE_BOOLEAN, kPolicySearchSuggestEnabled, + prefs::kSearchSuggestEnabled }, + { Value::TYPE_BOOLEAN, kPolicyDnsPrefetchingEnabled, + prefs::kDnsPrefetchingEnabled }, + { Value::TYPE_BOOLEAN, kPolicySafeBrowsingEnabled, + prefs::kSafeBrowsingEnabled }, + { Value::TYPE_BOOLEAN, kPolicyPasswordManagerEnabled, + prefs::kPasswordManagerEnabled }, + { Value::TYPE_BOOLEAN, kPolicyMetricsReportingEnabled, + prefs::kMetricsReportingEnabled }, + { Value::TYPE_STRING, kPolicyApplicationLocale, + prefs::kApplicationLocale}, +}; + +const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry + ConfigurationPolicyPrefStore::proxy_policy_map_[] = { + { Value::TYPE_STRING, kPolicyProxyServer, prefs::kProxyServer }, + { Value::TYPE_STRING, kPolicyProxyPacUrl, prefs::kProxyPacUrl }, + { Value::TYPE_STRING, kPolicyProxyBypassList, prefs::kProxyBypassList } +}; + +ConfigurationPolicyPrefStore::ConfigurationPolicyPrefStore( + const CommandLine* command_line, + ConfigurationPolicyProvider* provider) + : command_line_(command_line), + provider_(provider), + prefs_(new DictionaryValue()), + command_line_proxy_settings_cleared_(false), + proxy_disabled_(false), + proxy_configuration_specified_(false), + use_system_proxy_(false) { +} + +void ConfigurationPolicyPrefStore::ApplyProxySwitches() { + bool proxy_disabled = command_line_->HasSwitch(switches::kNoProxyServer); + if (proxy_disabled) { + prefs_->Set(prefs::kNoProxyServer, Value::CreateBooleanValue(true)); + } + bool has_explicit_proxy_config = false; + if (command_line_->HasSwitch(switches::kProxyAutoDetect)) { + has_explicit_proxy_config = true; + prefs_->Set(prefs::kProxyAutoDetect, Value::CreateBooleanValue(true)); + } + if (command_line_->HasSwitch(switches::kProxyServer)) { + has_explicit_proxy_config = true; + prefs_->Set(prefs::kProxyServer, Value::CreateStringValue( + command_line_->GetSwitchValueASCII(switches::kProxyServer))); + } + if (command_line_->HasSwitch(switches::kProxyPacUrl)) { + has_explicit_proxy_config = true; + prefs_->Set(prefs::kProxyPacUrl, Value::CreateStringValue( + command_line_->GetSwitchValueASCII(switches::kProxyPacUrl))); + } + if (command_line_->HasSwitch(switches::kProxyBypassList)) { + has_explicit_proxy_config = true; + prefs_->Set(prefs::kProxyBypassList, Value::CreateStringValue( + command_line_->GetSwitchValueASCII(switches::kProxyBypassList))); + } + + // Warn about all the other proxy config switches we get if + // the --no-proxy-server command-line argument is present. + if (proxy_disabled && has_explicit_proxy_config) { + LOG(WARNING) << "Additional command-line proxy switches specified when --" + << switches::kNoProxyServer << " was also specified."; + } +} + +PrefStore::PrefReadError ConfigurationPolicyPrefStore::ReadPrefs() { + // Initialize proxy preference values from command-line switches. This is done + // before calling Provide to allow the provider to overwrite proxy-related + // preferences that are specified by line settings. + ApplyProxySwitches(); + + proxy_disabled_ = false; + proxy_configuration_specified_ = false; + command_line_proxy_settings_cleared_ = false; + + return (provider_.get() == NULL || provider_->Provide(this)) ? + PrefStore::PREF_READ_ERROR_NONE : PrefStore::PREF_READ_ERROR_OTHER; +} + +// static +ConfigurationPolicyPrefStore* +ConfigurationPolicyPrefStore::CreateManagedPolicyPrefStore() { + ConfigurationPolicyProvider* provider; +#if defined(OS_WIN) + provider = new ConfigurationPolicyProviderWin(); +#elif defined(OS_MACOSX) + provider = new ConfigurationPolicyProviderMac(); +#elif defined(OS_POSIX) + FilePath config_dir_path; + if (PathService::Get(chrome::DIR_POLICY_FILES, &config_dir_path)) + provider = new ConfigDirPolicyProvider( + config_dir_path.Append(FILE_PATH_LITERAL("managed"))); + else + provider = new DummyConfigurationPolicyProvider(); +#else + provider = new DummyConfigurationPolicyProvider(); +#endif + + return new ConfigurationPolicyPrefStore(CommandLine::ForCurrentProcess(), + provider); +} + +// static +ConfigurationPolicyPrefStore* +ConfigurationPolicyPrefStore::CreateRecommendedPolicyPrefStore() { + ConfigurationPolicyProvider* provider; +#if defined(OS_POSIX) && !defined(OS_MACOSX) + FilePath config_dir_path; + if (PathService::Get(chrome::DIR_POLICY_FILES, &config_dir_path)) + provider = new ConfigDirPolicyProvider( + config_dir_path.Append(FILE_PATH_LITERAL("recommended"))); + else + provider = new DummyConfigurationPolicyProvider(); +#else + provider = new DummyConfigurationPolicyProvider(); +#endif + + return new ConfigurationPolicyPrefStore(CommandLine::ForCurrentProcess(), + provider); +} + +bool ConfigurationPolicyPrefStore::ApplyProxyPolicy(PolicyType policy, + Value* value) { + bool result = false; + bool warn_about_proxy_disable_config = false; + bool warn_about_proxy_system_config = false; + + const PolicyToPreferenceMapEntry* match_entry_ = NULL; + for (const PolicyToPreferenceMapEntry* current = proxy_policy_map_; + current != proxy_policy_map_ + arraysize(proxy_policy_map_); ++current) { + if (current->policy_type == policy) { + match_entry_ = current; + } + } + + // When the first proxy-related policy is applied, ALL proxy-related + // preferences that have been set by command-line switches must be + // removed. Otherwise it's possible for a user to interfere with proxy + // policy by using proxy-related switches that are related to, but not + // identical, to the ones set through policy. + if ((match_entry_ || + policy == ConfigurationPolicyPrefStore::kPolicyProxyServerMode) && + !command_line_proxy_settings_cleared_) { + for (const PolicyToPreferenceMapEntry* i = proxy_policy_map_; + i != proxy_policy_map_ + arraysize(proxy_policy_map_); ++i) { + if (prefs_->Get(i->preference_path, NULL)) { + LOG(WARNING) << "proxy configuration options were specified on the" + << " command-line but will be ignored because an" + << " explicit proxy configuration has been specified" + << " through a centrally-administered policy."; + break; + } + } + + // Now actually do the preference removal. + for (const PolicyToPreferenceMapEntry* current = proxy_policy_map_; + current != proxy_policy_map_ + arraysize(proxy_policy_map_); ++current) + prefs_->Remove(current->preference_path, NULL); + prefs_->Remove(prefs::kNoProxyServer, NULL); + prefs_->Remove(prefs::kProxyAutoDetect, NULL); + + command_line_proxy_settings_cleared_ = true; + } + + // Translate the proxy policy into preferences. + if (policy == ConfigurationPolicyStore::kPolicyProxyServerMode) { + int int_value; + bool proxy_auto_detect = false; + if (value->GetAsInteger(&int_value)) { + result = true; + switch (int_value) { + case ConfigurationPolicyStore::kPolicyNoProxyServerMode: + if (!proxy_disabled_) { + if (proxy_configuration_specified_) + warn_about_proxy_disable_config = true; + proxy_disabled_ = true; + } + break; + case ConfigurationPolicyStore::kPolicyAutoDetectProxyMode: + proxy_auto_detect = true; + break; + case ConfigurationPolicyStore::kPolicyManuallyConfiguredProxyMode: + break; + case ConfigurationPolicyStore::kPolicyUseSystemProxyMode: + if (!use_system_proxy_) { + if (proxy_configuration_specified_) + warn_about_proxy_system_config = true; + use_system_proxy_ = true; + } + break; + default: + // Not a valid policy, don't assume ownership of |value| + result = false; + break; + } + + if (int_value != kPolicyUseSystemProxyMode) { + prefs_->Set(prefs::kNoProxyServer, + Value::CreateBooleanValue(proxy_disabled_)); + prefs_->Set(prefs::kProxyAutoDetect, + Value::CreateBooleanValue(proxy_auto_detect)); + } + + // No proxy and system proxy mode should ensure that no other + // proxy preferences are set. + if (int_value == ConfigurationPolicyStore::kPolicyNoProxyServerMode || + int_value == kPolicyUseSystemProxyMode) { + for (const PolicyToPreferenceMapEntry* current = proxy_policy_map_; + current != proxy_policy_map_ + arraysize(proxy_policy_map_); + ++current) + prefs_->Remove(current->preference_path, NULL); + } + } + } else if (match_entry_) { + // Determine if the applied proxy policy settings conflict and issue + // a corresponding warning if they do. + if (!proxy_configuration_specified_) { + if (proxy_disabled_) + warn_about_proxy_disable_config = true; + if (use_system_proxy_) + warn_about_proxy_system_config = true; + proxy_configuration_specified_ = true; + } + if (!use_system_proxy_ && !proxy_disabled_) { + prefs_->Set(match_entry_->preference_path, value); + // The ownership of value has been passed on to |prefs_|, + // don't clean it up later. + value = NULL; + } + result = true; + } + + if (warn_about_proxy_disable_config) { + LOG(WARNING) << "A centrally-administered policy disables the use of" + << " a proxy but also specifies an explicit proxy" + << " configuration."; + } + + if (warn_about_proxy_system_config) { + LOG(WARNING) << "A centrally-administered policy dictates that the" + << " system proxy settings should be used but also specifies" + << " an explicit proxy configuration."; + } + + // If the policy was a proxy policy, cleanup |value|. + if (result && value) + delete value; + return result; +} + +bool ConfigurationPolicyPrefStore::ApplyPluginPolicy(PolicyType policy, + Value* value) { + if (policy == kPolicyDisabledPlugins) { + string16 plugin_list; + if (value->GetAsString(&plugin_list)) { + std::vector<string16> plugin_names; + // Change commas into tabs so that we can change escaped + // tabs back into commas, leaving non-escaped commas as tabs + // that can be used for splitting the string. Note that plugin + // names must not contain backslashes, since a trailing backslash + // in a plugin name before a comma would get swallowed during the + // splitting. + std::replace(plugin_list.begin(), plugin_list.end(), L',', L'\t'); + ReplaceSubstringsAfterOffset(&plugin_list, 0, + ASCIIToUTF16("\\\t"), ASCIIToUTF16(",")); + SplitString(plugin_list, L'\t', &plugin_names); + bool added_plugin = false; + scoped_ptr<ListValue> list(new ListValue()); + for (std::vector<string16>::const_iterator i(plugin_names.begin()); + i != plugin_names.end(); ++i) { + if (!i->empty()) { + list->Append(Value::CreateStringValue(*i)); + added_plugin = true; + } + } + if (added_plugin) { + prefs_->Set(prefs::kPluginsPluginsBlacklist, list.release()); + delete value; + return true; + } + } + } + return false; +} + +bool ConfigurationPolicyPrefStore::ApplySyncPolicy(PolicyType policy, + Value* value) { + if (policy == ConfigurationPolicyStore::kPolicySyncDisabled) { + bool disable_sync; + if (value->GetAsBoolean(&disable_sync) && disable_sync) + prefs_->Set(prefs::kSyncManaged, value); + else + delete value; + return true; + } + return false; +} + +bool ConfigurationPolicyPrefStore::ApplyPolicyFromMap(PolicyType policy, + Value* value, const PolicyToPreferenceMapEntry map[], int size) { + const PolicyToPreferenceMapEntry* end = map + size; + for (const PolicyToPreferenceMapEntry* current = map; + current != end; ++current) { + if (current->policy_type == policy) { + DCHECK(current->value_type == value->GetType()); + prefs_->Set(current->preference_path, value); + return true; + } + } + return false; +} + +void ConfigurationPolicyPrefStore::Apply(PolicyType policy, Value* value) { + if (ApplyProxyPolicy(policy, value)) + return; + + if (ApplyPluginPolicy(policy, value)) + return; + + if (ApplySyncPolicy(policy, value)) + return; + + if (ApplyPolicyFromMap(policy, value, simple_policy_map_, + arraysize(simple_policy_map_))) + return; + + // Other policy implementations go here. + NOTIMPLEMENTED(); + delete value; +} diff --git a/chrome/browser/policy/configuration_policy_pref_store.h b/chrome/browser/policy/configuration_policy_pref_store.h new file mode 100644 index 0000000..df35238 --- /dev/null +++ b/chrome/browser/policy/configuration_policy_pref_store.h @@ -0,0 +1,107 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PREF_STORE_H_ +#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PREF_STORE_H_ +#pragma once + +#include <string> + +#include "base/basictypes.h" +#include "base/gtest_prod_util.h" +#include "base/scoped_ptr.h" +#include "base/values.h" +#include "chrome/browser/policy/configuration_policy_provider.h" +#include "chrome/browser/policy/configuration_policy_store.h" +#include "chrome/common/pref_store.h" + +class CommandLine; + +// An implementation of the |PrefStore| that holds a Dictionary +// created through applied policy. +class ConfigurationPolicyPrefStore : public PrefStore, + public ConfigurationPolicyStore { + public: + // The ConfigurationPolicyPrefStore takes the ownership of the passed + // |provider|. + ConfigurationPolicyPrefStore(const CommandLine* command_line, + ConfigurationPolicyProvider* provider); + virtual ~ConfigurationPolicyPrefStore() { } + + // PrefStore methods: + virtual PrefReadError ReadPrefs(); + virtual DictionaryValue* prefs() { return prefs_.get(); } + + // Creates a ConfigurationPolicyPrefStore that reads managed policy. + static ConfigurationPolicyPrefStore* CreateManagedPolicyPrefStore(); + + // Creates a ConfigurationPolicyPrefStore that reads recommended policy. + static ConfigurationPolicyPrefStore* CreateRecommendedPolicyPrefStore(); + + private: + // For unit tests. + friend class ConfigurationPolicyPrefStoreTest; + + // Policies that map to a single preference are handled + // by an automated converter. Each one of these policies + // has an entry in |simple_policy_map_| with the following type. + struct PolicyToPreferenceMapEntry { + Value::ValueType value_type; + PolicyType policy_type; + const wchar_t* preference_path; // A DictionaryValue path, not a file path. + }; + + static const PolicyToPreferenceMapEntry simple_policy_map_[]; + static const PolicyToPreferenceMapEntry proxy_policy_map_[]; + + const CommandLine* command_line_; + scoped_ptr<ConfigurationPolicyProvider> provider_; + scoped_ptr<DictionaryValue> prefs_; + + // Set to false until the first proxy-relevant policy is applied. Allows + // the Apply method to erase all switch-specified proxy configuration before + // applying proxy policy configuration; + bool command_line_proxy_settings_cleared_; + + // The following are used to track what proxy-relevant policy has been applied + // accross calls to Apply to provide a warning if a policy specifies a + // contradictory proxy configuration. |proxy_disabled_| is set to true if and + // only if the kPolicyNoProxyServer has been applied, + // |proxy_configuration_specified_| is set to true if and only if any other + // proxy policy other than kPolicyNoProxyServer has been applied. + bool proxy_disabled_; + bool proxy_configuration_specified_; + + // Set to true if a the proxy mode policy has been set to force Chrome + // to use the system proxy. + bool use_system_proxy_; + + // ConfigurationPolicyStore methods: + virtual void Apply(PolicyType setting, Value* value); + + // Initializes default preference values from proxy-related command-line + // switches in |command_line_|. + void ApplyProxySwitches(); + + bool ApplyPolicyFromMap(PolicyType policy, Value* value, + const PolicyToPreferenceMapEntry map[], int size); + + // Processes proxy-specific policies. Returns true if the specified policy + // is a proxy-related policy. ApplyProxyPolicy assumes the ownership + // of |value| in the case that the policy is proxy-specific. + bool ApplyProxyPolicy(PolicyType policy, Value* value); + + // Processes plugin policies. Returns true if the specified policy + // is a plugin-related policy. ApplyPluginPolicy assumes the ownership + // of |value| in the case that the policy is plugin-specific. + bool ApplyPluginPolicy(PolicyType policy, Value* value); + + // Handles sync-related policies. Returns true if the policy was handled. + // Assumes ownership of |value| in that case. + bool ApplySyncPolicy(PolicyType policy, Value* value); + + DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyPrefStore); +}; + +#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PREF_STORE_H_ diff --git a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc new file mode 100644 index 0000000..fa63845 --- /dev/null +++ b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc @@ -0,0 +1,470 @@ +// Copyright (c) 2010 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 "base/command_line.h" +#include "base/file_path.h" +#include "chrome/browser/policy/configuration_policy_pref_store.h" +#include "chrome/browser/policy/mock_configuration_policy_provider.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/chrome_switches.h" + +class ConfigurationPolicyPrefStoreTest : public testing::Test { + public: + // Applies a policy that has a string value. + void ApplyStringPolicyValue( + ConfigurationPolicyPrefStore* store, + ConfigurationPolicyStore::PolicyType type, + const wchar_t* policy_value); + + // The following three methods test a policy which controls a string + // preference. + // Checks that by default, it's an empty string. + void TestStringPolicyGetDefault(const wchar_t* pref_name); + // Checks that values can be set. + void TestStringPolicySetValue(const wchar_t* pref_name, + ConfigurationPolicyStore::PolicyType type); + // A wrapper that calls the above two methods. + void TestStringPolicy(const wchar_t* pref_name, + ConfigurationPolicyStore::PolicyType type); + + // The following three methods test a policy which controls a boolean + // preference. + // Checks that there's no deafult. + void TestBooleanPolicyGetDefault(const wchar_t* pref_name); + // Checks that values can be set. + void TestBooleanPolicySetValue(const wchar_t* pref_name, + ConfigurationPolicyStore::PolicyType type); + // A wrapper that calls the above two methods. + void TestBooleanPolicy(const wchar_t* pref_name, + ConfigurationPolicyStore::PolicyType type); + + // The following three methods test a policy which controls an integer + // preference. + // Checks that by default, it's 0. + void TestIntegerPolicyGetDefault(const wchar_t* pref_name); + // Checks that values can be set. + void TestIntegerPolicySetValue(const wchar_t* pref_name, + ConfigurationPolicyStore::PolicyType type); + // A wrapper that calls the above two methods. + void TestIntegerPolicy(const wchar_t* pref_name, + ConfigurationPolicyStore::PolicyType type); +}; + +void ConfigurationPolicyPrefStoreTest::ApplyStringPolicyValue( + ConfigurationPolicyPrefStore* store, + ConfigurationPolicyStore::PolicyType type, + const wchar_t* policy_value) { + store->Apply(type, Value::CreateStringValue(policy_value)); +} + +void ConfigurationPolicyPrefStoreTest::TestStringPolicyGetDefault( + const wchar_t* pref_name) { + ConfigurationPolicyPrefStore store(NULL, NULL); + std::wstring result; + store.prefs()->GetString(pref_name, &result); + EXPECT_EQ(result, L""); +} + +void ConfigurationPolicyPrefStoreTest::TestStringPolicySetValue( + const wchar_t* pref_name, ConfigurationPolicyStore::PolicyType type) { + ConfigurationPolicyPrefStore store(NULL, NULL); + ApplyStringPolicyValue(&store, type, L"http://chromium.org"); + std::wstring result; + store.prefs()->GetString(pref_name, &result); + EXPECT_EQ(result, L"http://chromium.org"); +} + +void ConfigurationPolicyPrefStoreTest::TestStringPolicy( + const wchar_t* pref_name, ConfigurationPolicyStore::PolicyType type) { + TestStringPolicyGetDefault(pref_name); + TestStringPolicySetValue(pref_name, type); +} + +void ConfigurationPolicyPrefStoreTest::TestBooleanPolicyGetDefault( + const wchar_t* pref_name) { + ConfigurationPolicyPrefStore store(NULL, NULL); + bool result = false; + store.prefs()->GetBoolean(pref_name, &result); + EXPECT_FALSE(result); + result = true; + store.prefs()->GetBoolean(pref_name, &result); + EXPECT_TRUE(result); +} + +void ConfigurationPolicyPrefStoreTest::TestBooleanPolicySetValue( + const wchar_t* pref_name, ConfigurationPolicyStore::PolicyType type) { + ConfigurationPolicyPrefStore store(NULL, NULL); + store.Apply(type, Value::CreateBooleanValue(false)); + bool result = true; + store.prefs()->GetBoolean(pref_name, &result); + EXPECT_FALSE(result); + + store.Apply(type, Value::CreateBooleanValue(true)); + result = false; + store.prefs()->GetBoolean(pref_name, &result); + EXPECT_TRUE(result); +} + +void ConfigurationPolicyPrefStoreTest::TestBooleanPolicy( + const wchar_t* pref_name, ConfigurationPolicyStore::PolicyType type) { + TestBooleanPolicyGetDefault(pref_name); + TestBooleanPolicySetValue(pref_name, type); +} + +void ConfigurationPolicyPrefStoreTest::TestIntegerPolicyGetDefault( + const wchar_t* pref_name) { + ConfigurationPolicyPrefStore store(NULL, NULL); + int result = 0; + store.prefs()->GetInteger(pref_name, &result); + EXPECT_EQ(result, 0); +} + +void ConfigurationPolicyPrefStoreTest::TestIntegerPolicySetValue( + const wchar_t* pref_name, ConfigurationPolicyStore::PolicyType type) { + ConfigurationPolicyPrefStore store(NULL, NULL); + store.Apply(type, Value::CreateIntegerValue(2)); + int result = 0; + store.prefs()->GetInteger(pref_name, &result); + EXPECT_EQ(result, 2); +} + +void ConfigurationPolicyPrefStoreTest::TestIntegerPolicy( + const wchar_t* pref_name, ConfigurationPolicyStore::PolicyType type) { + TestIntegerPolicyGetDefault(pref_name); + TestIntegerPolicySetValue(pref_name, type); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestSettingHomePageDefault) { + TestStringPolicy(prefs::kHomePage, + ConfigurationPolicyPrefStore::kPolicyHomePage); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyHomepageIsNewTabPage) { + TestBooleanPolicy(prefs::kHomePageIsNewTabPage, + ConfigurationPolicyPrefStore::kPolicyHomepageIsNewTabPage); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyAlternateErrorPagesEnabled) { + TestBooleanPolicy(prefs::kAlternateErrorPagesEnabled, + ConfigurationPolicyStore::kPolicyAlternateErrorPagesEnabled); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicySearchSuggestEnabled) { + TestBooleanPolicy(prefs::kSearchSuggestEnabled, + ConfigurationPolicyStore::kPolicySearchSuggestEnabled); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyDnsPrefetchingEnabled) { + TestBooleanPolicy(prefs::kDnsPrefetchingEnabled, + ConfigurationPolicyStore::kPolicyDnsPrefetchingEnabled); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicySafeBrowsingEnabled) { + TestBooleanPolicy(prefs::kSafeBrowsingEnabled, + ConfigurationPolicyStore::kPolicySafeBrowsingEnabled); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyMetricsReportingEnabled) { + TestBooleanPolicy(prefs::kMetricsReportingEnabled, + ConfigurationPolicyStore::kPolicyMetricsReportingEnabled); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyPasswordManagerEnabled) { + TestBooleanPolicy(prefs::kPasswordManagerEnabled, + ConfigurationPolicyStore::kPolicyPasswordManagerEnabled); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestSettingProxyServer) { + TestStringPolicy(prefs::kProxyServer, + ConfigurationPolicyPrefStore::kPolicyProxyServer); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestSettingProxyPacUrl) { + TestStringPolicy(prefs::kProxyPacUrl, + ConfigurationPolicyPrefStore::kPolicyProxyPacUrl); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestSettingProxyBypassList) { + TestStringPolicy(prefs::kProxyBypassList, + ConfigurationPolicyPrefStore::kPolicyProxyBypassList); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestSettingsProxyConfig) { + FilePath unused_path(FILE_PATH_LITERAL("foo.exe")); + CommandLine command_line(unused_path); + command_line.AppendSwitch(switches::kNoProxyServer); + command_line.AppendSwitch(switches::kProxyAutoDetect); + command_line.AppendSwitchASCII(switches::kProxyPacUrl, + "http://chromium.org/test.pac"); + command_line.AppendSwitchASCII(switches::kProxyServer, + "http://chromium2.org"); + command_line.AppendSwitchASCII(switches::kProxyBypassList, + "http://chromium3.org"); + + ConfigurationPolicyPrefStore store(&command_line, NULL); + EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); + + // Ensure that all traces of the command-line specified proxy + // switches have been overriden. + std::wstring string_result; + EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyBypassList, + &string_result)); + EXPECT_EQ(string_result, L"http://chromium3.org"); + + EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result)); + EXPECT_EQ(string_result, L"http://chromium.org/test.pac"); + EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyServer, &string_result)); + EXPECT_EQ(string_result, L"http://chromium2.org"); + bool bool_result; + EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result)); + EXPECT_TRUE(bool_result); + EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, + &bool_result)); + EXPECT_TRUE(bool_result); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyProxyConfigManualOverride) { + FilePath unused_path(FILE_PATH_LITERAL("foo.exe")); + CommandLine command_line(unused_path); + command_line.AppendSwitch(switches::kNoProxyServer); + command_line.AppendSwitch(switches::kProxyAutoDetect); + command_line.AppendSwitchASCII(switches::kProxyPacUrl, + "http://chromium.org/test.pac"); + command_line.AppendSwitchASCII(switches::kProxyServer, + "http://chromium.org"); + command_line.AppendSwitchASCII(switches::kProxyBypassList, + "http://chromium.org"); + + scoped_ptr<MockConfigurationPolicyProvider> provider( + new MockConfigurationPolicyProvider()); + provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyServerMode, + Value::CreateIntegerValue( + ConfigurationPolicyStore::kPolicyManuallyConfiguredProxyMode)); + provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyBypassList, + Value::CreateStringValue(L"http://chromium.org/override")); + + ConfigurationPolicyPrefStore store(&command_line, + provider.release()); + EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); + + // Ensure that all traces of the command-line specified proxy + // switches have been overriden. + std::wstring string_result; + EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyBypassList, + &string_result)); + EXPECT_EQ(string_result, L"http://chromium.org/override"); + + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result)); + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result)); + bool bool_result; + EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result)); + EXPECT_FALSE(bool_result); + EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, + &bool_result)); + EXPECT_FALSE(bool_result); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyProxyConfigNoProxy) { + FilePath unused_path(FILE_PATH_LITERAL("foo.exe")); + CommandLine command_line(unused_path); + scoped_ptr<MockConfigurationPolicyProvider> provider( + new MockConfigurationPolicyProvider()); + provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyBypassList, + Value::CreateStringValue(L"http://chromium.org/override")); + provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyServerMode, + Value::CreateIntegerValue( + ConfigurationPolicyStore::kPolicyNoProxyServerMode)); + + ConfigurationPolicyPrefStore store(&command_line, provider.release()); + EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); + + std::wstring string_result; + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList, + &string_result)); + + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result)); + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result)); + bool bool_result; + EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result)); + EXPECT_TRUE(bool_result); + EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, + &bool_result)); + EXPECT_FALSE(bool_result); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, + TestPolicyProxyConfigNoProxyReversedApplyOrder) { + FilePath unused_path(FILE_PATH_LITERAL("foo.exe")); + CommandLine command_line(unused_path); + scoped_ptr<MockConfigurationPolicyProvider> provider( + new MockConfigurationPolicyProvider()); + provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyServerMode, + Value::CreateIntegerValue( + ConfigurationPolicyStore::kPolicyNoProxyServerMode)); + provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyBypassList, + Value::CreateStringValue(L"http://chromium.org/override")); + + ConfigurationPolicyPrefStore store(&command_line, provider.release()); + EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); + + std::wstring string_result; + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList, + &string_result)); + + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result)); + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result)); + bool bool_result; + EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result)); + EXPECT_TRUE(bool_result); + EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, + &bool_result)); + EXPECT_FALSE(bool_result); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyProxyConfigAutoDetect) { + FilePath unused_path(FILE_PATH_LITERAL("foo.exe")); + CommandLine command_line(unused_path); + scoped_ptr<MockConfigurationPolicyProvider> provider( + new MockConfigurationPolicyProvider()); + provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyBypassList, + Value::CreateStringValue(L"http://chromium.org/override")); + provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyServerMode, + Value::CreateIntegerValue( + ConfigurationPolicyStore::kPolicyAutoDetectProxyMode)); + + ConfigurationPolicyPrefStore store(&command_line, provider.release()); + EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); + + // Ensure that all traces of the command-line specified proxy + // switches have been overriden. + std::wstring string_result; + EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyBypassList, + &string_result)); + EXPECT_EQ(string_result, L"http://chromium.org/override"); + + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result)); + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result)); + bool bool_result; + EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result)); + EXPECT_FALSE(bool_result); + EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, + &bool_result)); + EXPECT_TRUE(bool_result); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyProxyConfiguseSystem) { + FilePath unused_path(FILE_PATH_LITERAL("foo.exe")); + CommandLine command_line(unused_path); + scoped_ptr<MockConfigurationPolicyProvider> provider( + new MockConfigurationPolicyProvider()); + provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyBypassList, + Value::CreateStringValue(L"http://chromium.org/override")); + provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyServerMode, + Value::CreateIntegerValue( + ConfigurationPolicyStore::kPolicyUseSystemProxyMode)); + + ConfigurationPolicyPrefStore store(&command_line, provider.release()); + EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); + + std::wstring string_result; + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList, + &string_result)); + EXPECT_EQ(string_result, L""); + + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result)); + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result)); + bool bool_result; + EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result)); + EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, + &bool_result)); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, + TestPolicyProxyConfiguseSystemReversedApplyOrder) { + FilePath unused_path(FILE_PATH_LITERAL("foo.exe")); + CommandLine command_line(unused_path); + scoped_ptr<MockConfigurationPolicyProvider> provider( + new MockConfigurationPolicyProvider()); + provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyServerMode, + Value::CreateIntegerValue( + ConfigurationPolicyStore::kPolicyUseSystemProxyMode)); + provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyBypassList, + Value::CreateStringValue(L"http://chromium.org/override")); + + ConfigurationPolicyPrefStore store(&command_line, provider.release()); + EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); + + std::wstring string_result; + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList, + &string_result)); + EXPECT_EQ(string_result, L""); + + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result)); + EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result)); + bool bool_result; + EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result)); + EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, + &bool_result)); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, + TestPolicyProxyDisabledPlugin) { + FilePath unused_path(FILE_PATH_LITERAL("foo.exe")); + CommandLine command_line(unused_path); + scoped_ptr<MockConfigurationPolicyProvider> provider( + new MockConfigurationPolicyProvider()); + + ConfigurationPolicyPrefStore store(&command_line, provider.release()); + ApplyStringPolicyValue(&store, + ConfigurationPolicyStore::kPolicyDisabledPlugins, + L"plugin1"); + EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); + + ListValue* plugin_blacklist = NULL; + EXPECT_TRUE(store.prefs()->GetList(prefs::kPluginsPluginsBlacklist, + &plugin_blacklist)); + + ListValue::const_iterator current(plugin_blacklist->begin()); + ListValue::const_iterator end(plugin_blacklist->end()); + + ASSERT_TRUE(current != end); + std::string plugin_name; + (*current)->GetAsString(&plugin_name); + EXPECT_EQ("plugin1", plugin_name); + ++current; + EXPECT_TRUE(current == end); +} + +TEST_F(ConfigurationPolicyPrefStoreTest, + TestPolicyProxyDisabledPluginEscapedComma) { + FilePath unused_path(FILE_PATH_LITERAL("foo.exe")); + CommandLine command_line(unused_path); + scoped_ptr<MockConfigurationPolicyProvider> provider( + new MockConfigurationPolicyProvider()); + + ConfigurationPolicyPrefStore store(&command_line, provider.release()); + ApplyStringPolicyValue(&store, + ConfigurationPolicyStore::kPolicyDisabledPlugins, + L"plugin1,plugin2\\,"); + EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); + + ListValue* plugin_blacklist = NULL; + EXPECT_TRUE(store.prefs()->GetList(prefs::kPluginsPluginsBlacklist, + &plugin_blacklist)); + ListValue::const_iterator current(plugin_blacklist->begin()); + ListValue::const_iterator end(plugin_blacklist->end()); + ASSERT_TRUE(current != end); + std::string plugin_name; + (*current)->GetAsString(&plugin_name); + EXPECT_EQ("plugin1", plugin_name); + ++current; + ASSERT_TRUE(current != end); + (*current)->GetAsString(&plugin_name); + EXPECT_EQ("plugin2,", plugin_name); + ++current; + EXPECT_TRUE(current == end); +} + diff --git a/chrome/browser/policy/configuration_policy_provider.cc b/chrome/browser/policy/configuration_policy_provider.cc new file mode 100644 index 0000000..99c61cf --- /dev/null +++ b/chrome/browser/policy/configuration_policy_provider.cc @@ -0,0 +1,81 @@ +// Copyright (c) 2010 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 "chrome/browser/policy/configuration_policy_provider.h" + +#include "base/values.h" +#include "chrome/common/policy_constants.h" +#include "chrome/common/notification_service.h" + +namespace { + +// TODO(avi): Use this mapping to auto-generate MCX manifests and Windows +// ADM/ADMX files. http://crbug.com/49316 + +struct InternalPolicyValueMapEntry { + ConfigurationPolicyStore::PolicyType policy_type; + Value::ValueType value_type; + const char* name; +}; + +const InternalPolicyValueMapEntry kPolicyValueMap[] = { + { ConfigurationPolicyStore::kPolicyHomePage, + Value::TYPE_STRING, policy::key::kHomepageLocation }, + { ConfigurationPolicyStore::kPolicyHomepageIsNewTabPage, + Value::TYPE_BOOLEAN, policy::key::kHomepageIsNewTabPage }, + { ConfigurationPolicyStore::kPolicyProxyServerMode, + Value::TYPE_INTEGER, policy::key::kProxyServerMode }, + { ConfigurationPolicyStore::kPolicyProxyServer, + Value::TYPE_STRING, policy::key::kProxyServer }, + { ConfigurationPolicyStore::kPolicyProxyPacUrl, + Value::TYPE_STRING, policy::key::kProxyPacUrl }, + { ConfigurationPolicyStore::kPolicyProxyBypassList, + Value::TYPE_STRING, policy::key::kProxyBypassList }, + { ConfigurationPolicyStore::kPolicyAlternateErrorPagesEnabled, + Value::TYPE_BOOLEAN, policy::key::kAlternateErrorPagesEnabled }, + { ConfigurationPolicyStore::kPolicySearchSuggestEnabled, + Value::TYPE_BOOLEAN, policy::key::kSearchSuggestEnabled }, + { ConfigurationPolicyStore::kPolicyDnsPrefetchingEnabled, + Value::TYPE_BOOLEAN, policy::key::kDnsPrefetchingEnabled }, + { ConfigurationPolicyStore::kPolicySafeBrowsingEnabled, + Value::TYPE_BOOLEAN, policy::key::kSafeBrowsingEnabled }, + { ConfigurationPolicyStore::kPolicyMetricsReportingEnabled, + Value::TYPE_BOOLEAN, policy::key::kMetricsReportingEnabled }, + { ConfigurationPolicyStore::kPolicyPasswordManagerEnabled, + Value::TYPE_BOOLEAN, policy::key::kPasswordManagerEnabled }, + { ConfigurationPolicyStore::kPolicyDisabledPlugins, + Value::TYPE_STRING, policy::key::kDisabledPluginsList }, + { ConfigurationPolicyStore::kPolicyApplicationLocale, + Value::TYPE_STRING, policy::key::kApplicationLocaleValue }, + { ConfigurationPolicyStore::kPolicySyncDisabled, + Value::TYPE_BOOLEAN, policy::key::kSyncDisabled }, +}; + +} // namespace + +/* static */ +const ConfigurationPolicyProvider::PolicyValueMap* + ConfigurationPolicyProvider::PolicyValueMapping() { + static PolicyValueMap* mapping; + if (!mapping) { + mapping = new PolicyValueMap(); + for (size_t i = 0; i < arraysize(kPolicyValueMap); ++i) { + const InternalPolicyValueMapEntry& internal_entry = kPolicyValueMap[i]; + PolicyValueMapEntry entry; + entry.policy_type = internal_entry.policy_type; + entry.value_type = internal_entry.value_type; + entry.name = std::string(internal_entry.name); + mapping->push_back(entry); + } + } + return mapping; +} + +void ConfigurationPolicyProvider::NotifyStoreOfPolicyChange() { + NotificationService::current()->Notify( + NotificationType::POLICY_CHANGED, + Source<ConfigurationPolicyProvider>(this), + NotificationService::NoDetails()); +} + diff --git a/chrome/browser/policy/configuration_policy_provider.h b/chrome/browser/policy/configuration_policy_provider.h new file mode 100644 index 0000000..a0802e8 --- /dev/null +++ b/chrome/browser/policy/configuration_policy_provider.h @@ -0,0 +1,54 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_H_ +#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_H_ +#pragma once + +#include <vector> + +#include "base/basictypes.h" +#include "base/values.h" +#include "chrome/browser/policy/configuration_policy_store.h" + +// A mostly-abstract super class for platform-specific policy providers. +// Platform-specific policy providers (Windows Group Policy, gconf, +// etc.) should implement a subclass of this class. +class ConfigurationPolicyProvider { + public: + ConfigurationPolicyProvider() {} + virtual ~ConfigurationPolicyProvider() {} + + // Must be implemented by provider subclasses to specify the + // provider-specific policy decisions. The preference service + // invokes this |Provide| method when it needs a policy + // provider to specify its policy choices. In |Provide|, + // the |ConfigurationPolicyProvider| must make calls to the + // |Apply| method of |store| to apply specific policies. + // Returns true if the policy could be provided, otherwise false. + virtual bool Provide(ConfigurationPolicyStore* store) = 0; + + // Called by the subclass provider at any time to indicate that the currently + // applied policy is not longer current. A policy refresh will be initiated as + // soon as possible. + virtual void NotifyStoreOfPolicyChange(); + + protected: + // A structure mapping policies to their implementations by providers. + struct PolicyValueMapEntry { + ConfigurationPolicyStore::PolicyType policy_type; + Value::ValueType value_type; + std::string name; + }; + typedef std::vector<PolicyValueMapEntry> PolicyValueMap; + + // Returns the mapping from policy values to the actual names used by + // implementations. + static const PolicyValueMap* PolicyValueMapping(); + + private: + DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProvider); +}; + +#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_H_ diff --git a/chrome/browser/policy/configuration_policy_provider_mac.cc b/chrome/browser/policy/configuration_policy_provider_mac.cc new file mode 100644 index 0000000..77e3a4c --- /dev/null +++ b/chrome/browser/policy/configuration_policy_provider_mac.cc @@ -0,0 +1,78 @@ +// Copyright (c) 2010 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 "chrome/browser/policy/configuration_policy_provider_mac.h" + +#include "base/logging.h" +#include "base/scoped_cftyperef.h" +#include "base/sys_string_conversions.h" + +ConfigurationPolicyProviderMac::ConfigurationPolicyProviderMac() + : preferences_(new MacPreferences()) { +} + +ConfigurationPolicyProviderMac::ConfigurationPolicyProviderMac( + MacPreferences* preferences) : preferences_(preferences) { +} + +bool ConfigurationPolicyProviderMac::Provide(ConfigurationPolicyStore* store) { + bool success = true; + const PolicyValueMap* mapping = PolicyValueMapping(); + + for (PolicyValueMap::const_iterator current = mapping->begin(); + current != mapping->end(); ++current) { + scoped_cftyperef<CFStringRef> name( + base::SysUTF8ToCFStringRef(current->name)); + scoped_cftyperef<CFPropertyListRef> value( + preferences_->CopyAppValue(name, kCFPreferencesCurrentApplication)); + if (!value.get()) + continue; + if (!preferences_->AppValueIsForced(name, kCFPreferencesCurrentApplication)) + continue; + + switch (current->value_type) { + case Value::TYPE_STRING: + if (CFGetTypeID(value) == CFStringGetTypeID()) { + std::string string_value = + base::SysCFStringRefToUTF8((CFStringRef)value.get()); + store->Apply( + current->policy_type, + Value::CreateStringValue(string_value)); + } else { + success = false; + } + break; + case Value::TYPE_BOOLEAN: + if (CFGetTypeID(value) == CFBooleanGetTypeID()) { + bool bool_value = CFBooleanGetValue((CFBooleanRef)value.get()); + store->Apply(current->policy_type, + Value::CreateBooleanValue(bool_value)); + } else { + success = false; + } + break; + case Value::TYPE_INTEGER: + if (CFGetTypeID(value) == CFNumberGetTypeID()) { + int int_value; + bool cast = CFNumberGetValue((CFNumberRef)value.get(), + kCFNumberIntType, + &int_value); + if (cast) + store->Apply(current->policy_type, + Value::CreateIntegerValue(int_value)); + else + success = false; + } else { + success = false; + } + break; + default: + NOTREACHED(); + return false; + } + } + + return success; +} + diff --git a/chrome/browser/policy/configuration_policy_provider_mac.h b/chrome/browser/policy/configuration_policy_provider_mac.h new file mode 100644 index 0000000..ab24473 --- /dev/null +++ b/chrome/browser/policy/configuration_policy_provider_mac.h @@ -0,0 +1,31 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_MAC_H_ +#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_MAC_H_ +#pragma once + +#include "base/scoped_ptr.h" +#include "chrome/browser/policy/configuration_policy_store.h" +#include "chrome/browser/policy/configuration_policy_provider.h" +#include "chrome/browser/preferences_mac.h" + +// An implementation of |ConfigurationPolicyProvider| using the mechanism +// provided by Mac OS X's managed preferences. +class ConfigurationPolicyProviderMac : public ConfigurationPolicyProvider { + public: + ConfigurationPolicyProviderMac(); + // For testing; takes ownership of |preferences|. + explicit ConfigurationPolicyProviderMac(MacPreferences* preferences); + virtual ~ConfigurationPolicyProviderMac() { } + + // ConfigurationPolicyProvider method overrides: + virtual bool Provide(ConfigurationPolicyStore* store); + + protected: + scoped_ptr<MacPreferences> preferences_; +}; + +#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_MAC_H_ + diff --git a/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc b/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc new file mode 100644 index 0000000..23f01b7 --- /dev/null +++ b/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc @@ -0,0 +1,119 @@ +// Copyright (c) 2010 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 "base/stl_util-inl.h" +#include "base/sys_string_conversions.h" +#include "chrome/browser/policy/configuration_policy_provider_mac.h" +#include "chrome/browser/policy/mock_configuration_policy_store.h" +#include "chrome/browser/preferences_mock_mac.h" + +// A subclass of |ConfigurationPolicyProviderMac| providing access to various +// internal things without an orgy of FRIEND_TESTS. +class TestConfigurationPolicyProviderMac + : public ConfigurationPolicyProviderMac { + public: + TestConfigurationPolicyProviderMac() : + ConfigurationPolicyProviderMac(new MockPreferences()) { } + virtual ~TestConfigurationPolicyProviderMac() { } + + void AddTestItem(ConfigurationPolicyStore::PolicyType policy, + CFPropertyListRef value, + bool is_forced); + + typedef std::vector<PolicyValueMapEntry> PolicyValueMap; + static const PolicyValueMap* PolicyValueMapping() { + return ConfigurationPolicyProvider::PolicyValueMapping(); + } +}; + +void TestConfigurationPolicyProviderMac::AddTestItem( + ConfigurationPolicyStore::PolicyType policy, + CFPropertyListRef value, + bool is_forced) { + const PolicyValueMap* mapping = PolicyValueMapping(); + for (PolicyValueMap::const_iterator current = mapping->begin(); + current != mapping->end(); ++current) { + if (current->policy_type == policy) { + scoped_cftyperef<CFStringRef> name( + base::SysUTF8ToCFStringRef(current->name)); + static_cast<MockPreferences*>(preferences_.get())-> + AddTestItem(name, value, is_forced); + } + } +} + +TEST(ConfigurationPolicyProviderMacTest, TestPolicyDefault) { + MockConfigurationPolicyStore store; + TestConfigurationPolicyProviderMac provider; + + provider.Provide(&store); + + const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map()); + EXPECT_FALSE(ContainsKey(map, ConfigurationPolicyStore::kPolicyHomePage)); +} + +TEST(ConfigurationPolicyProviderMacTest, TestHomePagePolicy) { + MockConfigurationPolicyStore store; + TestConfigurationPolicyProviderMac provider; + provider.AddTestItem(ConfigurationPolicyStore::kPolicyHomePage, + CFSTR("http://chromium.org"), + true); + + provider.Provide(&store); + + const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map()); + MockConfigurationPolicyStore::PolicyMap::const_iterator i = + map.find(ConfigurationPolicyStore::kPolicyHomePage); + ASSERT_TRUE(i != map.end()); + std::string value; + i->second->GetAsString(&value); + EXPECT_EQ("http://chromium.org", value); +} + +TEST(ConfigurationPolicyProviderMacTest, TestHomePagePolicyUnforced) { + MockConfigurationPolicyStore store; + TestConfigurationPolicyProviderMac provider; + provider.AddTestItem(ConfigurationPolicyStore::kPolicyHomePage, + CFSTR("http://chromium.org"), + false); + + provider.Provide(&store); + + const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map()); + EXPECT_FALSE(ContainsKey(map, ConfigurationPolicyStore::kPolicyHomePage)); +} + +TEST(ConfigurationPolicyProviderMacTest, TestHomePagePolicyWrongType) { + MockConfigurationPolicyStore store; + TestConfigurationPolicyProviderMac provider; + provider.AddTestItem(ConfigurationPolicyStore::kPolicyHomePage, + kCFBooleanTrue, + true); + + provider.Provide(&store); + + const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map()); + EXPECT_FALSE(ContainsKey(map, ConfigurationPolicyStore::kPolicyHomePage)); +} + +TEST(ConfigurationPolicyProviderMacTest, TestHomepageIsNewTabPagePolicy) { + MockConfigurationPolicyStore store; + TestConfigurationPolicyProviderMac provider; + provider.AddTestItem(ConfigurationPolicyStore::kPolicyHomepageIsNewTabPage, + kCFBooleanTrue, + true); + + provider.Provide(&store); + + const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map()); + MockConfigurationPolicyStore::PolicyMap::const_iterator i = + map.find(ConfigurationPolicyStore::kPolicyHomepageIsNewTabPage); + ASSERT_TRUE(i != map.end()); + bool value = false; + i->second->GetAsBoolean(&value); + EXPECT_EQ(true, value); +} + diff --git a/chrome/browser/policy/configuration_policy_provider_win.cc b/chrome/browser/policy/configuration_policy_provider_win.cc new file mode 100644 index 0000000..4085b14 --- /dev/null +++ b/chrome/browser/policy/configuration_policy_provider_win.cc @@ -0,0 +1,166 @@ +// Copyright (c) 2010 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 "chrome/browser/policy/configuration_policy_provider_win.h" + +#include <userenv.h> + +#include <algorithm> + +#include "base/logging.h" +#include "base/object_watcher.h" +#include "base/registry.h" +#include "base/scoped_ptr.h" +#include "base/string_piece.h" +#include "base/sys_string_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/common/policy_constants.h" + +ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher:: + GroupPolicyChangeWatcher(ConfigurationPolicyProvider* provider) + : provider_(provider), + user_policy_changed_event_(false, false), + machine_policy_changed_event_(false, false) { + CHECK(RegisterGPNotification(user_policy_changed_event_.handle(), false)); + CHECK(RegisterGPNotification(machine_policy_changed_event_.handle(), true)); + user_policy_watcher_.StartWatching( + user_policy_changed_event_.handle(), + this); + machine_policy_watcher_.StartWatching( + machine_policy_changed_event_.handle(), + this); +} + +void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher:: + OnObjectSignaled(HANDLE object) { + provider_->NotifyStoreOfPolicyChange(); + if (object == user_policy_changed_event_.handle()) { + user_policy_watcher_.StartWatching( + user_policy_changed_event_.handle(), + this); + } else if (object == machine_policy_changed_event_.handle()) { + machine_policy_watcher_.StartWatching( + machine_policy_changed_event_.handle(), + this); + } else { + // This method should only be called as a result of signals + // to the user- and machine-policy handle watchers. + NOTREACHED(); + } +} + +ConfigurationPolicyProviderWin::ConfigurationPolicyProviderWin() { + watcher_.reset(new GroupPolicyChangeWatcher(this)); +} + +bool ConfigurationPolicyProviderWin::GetRegistryPolicyString( + const wchar_t* value_name, string16* result) { + DWORD value_size = 0; + DWORD key_type = 0; + scoped_array<uint8> buffer; + RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, policy::kRegistrySubKey); + if (hkcu_policy_key.ReadValue(value_name, 0, &value_size, &key_type)) { + if (key_type != REG_SZ) + return false; + // According to the Microsoft documentation, the string + // buffer may not be explicitly 0-terminated. Allocate a + // slightly larger buffer and prefill to zeros to guarantee + // the 0-termination. + buffer.reset(new uint8[value_size + 2]); + memset(buffer.get(), 0, value_size + 2); + hkcu_policy_key.ReadValue(value_name, buffer.get(), &value_size); + } else { + RegKey hklm_policy_key(HKEY_CURRENT_USER, policy::kRegistrySubKey); + if (hklm_policy_key.ReadValue(value_name, 0, &value_size, &key_type)) { + if (key_type != REG_SZ) + return false; + // According to the Microsoft documentation, the string + // buffer may not be explicitly 0-terminated. Allocate a + // slightly larger buffer and prefill to zeros to guarantee + // the 0-termination. + buffer.reset(new uint8[value_size + 2]); + memset(buffer.get(), 0, value_size + 2); + hklm_policy_key.ReadValue(value_name, buffer.get(), &value_size); + } else { + return false; + } + } + + result->assign(reinterpret_cast<const wchar_t*>(buffer.get())); + return true; +} + +bool ConfigurationPolicyProviderWin::GetRegistryPolicyBoolean( + const wchar_t* value_name, bool* result) { + DWORD value; + RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, policy::kRegistrySubKey); + if (hkcu_policy_key.ReadValueDW(value_name, &value)) { + *result = value != 0; + return true; + } + + RegKey hklm_policy_key(HKEY_CURRENT_USER, policy::kRegistrySubKey); + if (hklm_policy_key.ReadValueDW(value_name, &value)) { + *result = value != 0; + return true; + } + return false; +} + +bool ConfigurationPolicyProviderWin::GetRegistryPolicyInteger( + const wchar_t* value_name, uint32* result) { + DWORD value; + RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, policy::kRegistrySubKey); + if (hkcu_policy_key.ReadValueDW(value_name, &value)) { + *result = value; + return true; + } + + RegKey hklm_policy_key(HKEY_CURRENT_USER, policy::kRegistrySubKey); + if (hklm_policy_key.ReadValueDW(value_name, &value)) { + *result = value; + return true; + } + return false; +} + +bool ConfigurationPolicyProviderWin::Provide( + ConfigurationPolicyStore* store) { + const PolicyValueMap* mapping = PolicyValueMapping(); + + for (PolicyValueMap::const_iterator current = mapping->begin(); + current != mapping->end(); ++current) { + std::wstring name = UTF8ToWide(current->name); + std::wstring string_value; + uint32 int_value; + bool bool_value; + switch (current->value_type) { + case Value::TYPE_STRING: + if (GetRegistryPolicyString(name.c_str(), &string_value)) { + store->Apply( + current->policy_type, + Value::CreateStringValue(string_value)); + } + break; + case Value::TYPE_BOOLEAN: + if (GetRegistryPolicyBoolean(name.c_str(), &bool_value)) { + store->Apply(current->policy_type, + Value::CreateBooleanValue(bool_value)); + } + break; + case Value::TYPE_INTEGER: + if (GetRegistryPolicyInteger(name.c_str(), &int_value)) { + store->Apply(current->policy_type, + Value::CreateIntegerValue(int_value)); + } + break; + default: + NOTREACHED(); + return false; + } + } + + return true; +} diff --git a/chrome/browser/policy/configuration_policy_provider_win.h b/chrome/browser/policy/configuration_policy_provider_win.h new file mode 100644 index 0000000..e2ebbdb --- /dev/null +++ b/chrome/browser/policy/configuration_policy_provider_win.h @@ -0,0 +1,62 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_WIN_H_ +#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_WIN_H_ +#pragma once + +#include "base/object_watcher.h" +#include "base/scoped_ptr.h" +#include "base/waitable_event.h" +#include "chrome/browser/policy/configuration_policy_store.h" +#include "chrome/browser/policy/configuration_policy_provider.h" + +// An implementation of |ConfigurationPolicyProvider| using the +// mechanism provided by Windows Groups Policy. Policy decisions are +// stored as values in a special section of the Windows Registry. +// On a managed machine in a domain, this portion of the registry is +// periodically updated by the Windows Group Policy machinery to contain +// the latest version of the policy set by administrators. +class ConfigurationPolicyProviderWin : public ConfigurationPolicyProvider { + public: + // Keeps watch on Windows Group Policy notification event to trigger + // a policy reload when Group Policy changes. + class GroupPolicyChangeWatcher : public base::ObjectWatcher::Delegate { + public: + explicit GroupPolicyChangeWatcher(ConfigurationPolicyProvider* provider); + virtual ~GroupPolicyChangeWatcher() {} + + virtual void OnObjectSignaled(HANDLE object); + + private: + ConfigurationPolicyProvider* provider_; + base::WaitableEvent user_policy_changed_event_; + base::WaitableEvent machine_policy_changed_event_; + base::ObjectWatcher user_policy_watcher_; + base::ObjectWatcher machine_policy_watcher_; + }; + + ConfigurationPolicyProviderWin(); + virtual ~ConfigurationPolicyProviderWin() { } + + // ConfigurationPolicyProvider method overrides: + virtual bool Provide(ConfigurationPolicyStore* store); + + protected: + // The sub key path for Chromium's Group Policy information in the + // Windows registry. + static const wchar_t kPolicyRegistrySubKey[]; + + private: + scoped_ptr<GroupPolicyChangeWatcher> watcher_; + + // Methods to perfrom type-specific policy lookups in the registry. + // HKLM is checked first, then HKCU. + bool GetRegistryPolicyString(const wchar_t* value_name, string16* result); + bool GetRegistryPolicyBoolean(const wchar_t* value_name, bool* result); + bool GetRegistryPolicyInteger(const wchar_t* value_name, uint32* result); +}; + +#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_WIN_H_ + diff --git a/chrome/browser/policy/configuration_policy_provider_win_unittest.cc b/chrome/browser/policy/configuration_policy_provider_win_unittest.cc new file mode 100644 index 0000000..221ef83 --- /dev/null +++ b/chrome/browser/policy/configuration_policy_provider_win_unittest.cc @@ -0,0 +1,316 @@ +// Copyright (c) 2010 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/logging.h" +#include "base/registry.h" +#include "base/scoped_ptr.h" +#include "base/stl_util-inl.h" +#include "base/string_piece.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/policy/configuration_policy_provider_win.h" +#include "chrome/browser/policy/mock_configuration_policy_store.h" +#include "chrome/common/policy_constants.h" +#include "chrome/common/pref_names.h" + +namespace { + +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 + +// A subclass of |ConfigurationPolicyProviderWin| providing access to +// internal protected constants without an orgy of FRIEND_TESTS. +class TestConfigurationPolicyProviderWin + : public ConfigurationPolicyProviderWin { + public: + TestConfigurationPolicyProviderWin() : ConfigurationPolicyProviderWin() { } + virtual ~TestConfigurationPolicyProviderWin() { } + + void SetHomepageRegistryValue(HKEY hive, const wchar_t* value); + void SetHomepageRegistryValueWrongType(HKEY hive); + void SetBooleanPolicy(ConfigurationPolicyStore::PolicyType type, + HKEY hive, bool value); + void SetCookiesMode(HKEY hive, uint32 value); + + typedef std::vector<PolicyValueMapEntry> PolicyValueMap; + static const PolicyValueMap* PolicyValueMapping() { + return ConfigurationPolicyProvider::PolicyValueMapping(); + } +}; + +namespace { + +std::wstring NameForPolicy(ConfigurationPolicyStore::PolicyType policy) { + const TestConfigurationPolicyProviderWin::PolicyValueMap* mapping = + TestConfigurationPolicyProviderWin::PolicyValueMapping(); + for (TestConfigurationPolicyProviderWin::PolicyValueMap::const_iterator + current = mapping->begin(); current != mapping->end(); ++current) { + if (current->policy_type == policy) + return UTF8ToWide(current->name); + } + return NULL; +} + +} // namespace + +void TestConfigurationPolicyProviderWin::SetHomepageRegistryValue( + HKEY hive, + const wchar_t* value) { + RegKey key(hive, policy::kRegistrySubKey, KEY_ALL_ACCESS); + EXPECT_TRUE(key.WriteValue( + NameForPolicy(ConfigurationPolicyStore::kPolicyHomePage).c_str(), + value)); +} + +void TestConfigurationPolicyProviderWin::SetHomepageRegistryValueWrongType( + HKEY hive) { + RegKey key(hive, policy::kRegistrySubKey, KEY_ALL_ACCESS); + EXPECT_TRUE(key.WriteValue( + NameForPolicy(ConfigurationPolicyStore::kPolicyHomePage).c_str(), + 5)); +} + +void TestConfigurationPolicyProviderWin::SetBooleanPolicy( + ConfigurationPolicyStore::PolicyType type, + HKEY hive, + bool value) { + RegKey key(hive, policy::kRegistrySubKey, KEY_ALL_ACCESS); + EXPECT_TRUE(key.WriteValue(NameForPolicy(type).c_str(), value)); +} + +// 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::Test { + 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(); + + void TestBooleanPolicyDefault(ConfigurationPolicyStore::PolicyType type); + void TestBooleanPolicyHKLM(ConfigurationPolicyStore::PolicyType type); + void TestBooleanPolicy(ConfigurationPolicyStore::PolicyType type); + + private: + // 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_; + + // 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() + : temp_hklm_hive_key_(HKEY_CURRENT_USER, kUnitTestMachineOverrideSubKey), + temp_hkcu_hive_key_(HKEY_CURRENT_USER, kUnitTestUserOverrideSubKey) { +} + +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(); +} + +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::TearDown() { + DeactivateOverrides(); + DeleteRegistrySandbox(); +} + +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::TestBooleanPolicyDefault( + ConfigurationPolicyStore::PolicyType type) { + MockConfigurationPolicyStore store; + TestConfigurationPolicyProviderWin provider; + provider.Provide(&store); + + const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map()); + EXPECT_FALSE(ContainsKey(map, type)); +} + +void ConfigurationPolicyProviderWinTest::TestBooleanPolicyHKLM( + ConfigurationPolicyStore::PolicyType type) { + MockConfigurationPolicyStore store; + TestConfigurationPolicyProviderWin provider; + provider.SetBooleanPolicy(type, HKEY_LOCAL_MACHINE, true); + provider.Provide(&store); + + const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map()); + MockConfigurationPolicyStore::PolicyMap::const_iterator i = map.find(type); + ASSERT_TRUE(i != map.end()); + bool value = false; + i->second->GetAsBoolean(&value); + EXPECT_EQ(true, value); +} + +void ConfigurationPolicyProviderWinTest::TestBooleanPolicy( + ConfigurationPolicyStore::PolicyType type) { + TestBooleanPolicyDefault(type); + TestBooleanPolicyHKLM(type); +} + +TEST_F(ConfigurationPolicyProviderWinTest, TestHomePagePolicyDefault) { + MockConfigurationPolicyStore store; + TestConfigurationPolicyProviderWin provider; + + provider.Provide(&store); + + const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map()); + EXPECT_FALSE(ContainsKey(map, ConfigurationPolicyStore::kPolicyHomePage)); +} + +TEST_F(ConfigurationPolicyProviderWinTest, TestHomePagePolicyHKCU) { + MockConfigurationPolicyStore store; + TestConfigurationPolicyProviderWin provider; + provider.SetHomepageRegistryValue(HKEY_CURRENT_USER, + L"http://chromium.org"); + + provider.Provide(&store); + + const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map()); + MockConfigurationPolicyStore::PolicyMap::const_iterator i = + map.find(ConfigurationPolicyStore::kPolicyHomePage); + ASSERT_TRUE(i != map.end()); + string16 value; + i->second->GetAsString(&value); + EXPECT_EQ(L"http://chromium.org", value); +} + +TEST_F(ConfigurationPolicyProviderWinTest, TestHomePagePolicyHKCUWrongType) { + MockConfigurationPolicyStore store; + TestConfigurationPolicyProviderWin provider; + provider.SetHomepageRegistryValueWrongType(HKEY_CURRENT_USER); + + provider.Provide(&store); + + const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map()); + EXPECT_FALSE(ContainsKey(map, ConfigurationPolicyStore::kPolicyHomePage)); +} + +TEST_F(ConfigurationPolicyProviderWinTest, TestHomePagePolicyHKLM) { + MockConfigurationPolicyStore store; + TestConfigurationPolicyProviderWin provider; + provider.SetHomepageRegistryValue(HKEY_LOCAL_MACHINE, + L"http://chromium.org"); + + provider.Provide(&store); + + const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map()); + MockConfigurationPolicyStore::PolicyMap::const_iterator i = + map.find(ConfigurationPolicyStore::kPolicyHomePage); + ASSERT_TRUE(i != map.end()); + string16 value; + i->second->GetAsString(&value); + EXPECT_EQ(L"http://chromium.org", value); +} + +TEST_F(ConfigurationPolicyProviderWinTest, TestHomePagePolicyHKLMOverHKCU) { + MockConfigurationPolicyStore store; + TestConfigurationPolicyProviderWin provider; + provider.SetHomepageRegistryValue(HKEY_CURRENT_USER, + L"http://chromium.org"); + provider.SetHomepageRegistryValue(HKEY_LOCAL_MACHINE, + L"http://crbug.com"); + + provider.Provide(&store); + + const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map()); + MockConfigurationPolicyStore::PolicyMap::const_iterator i = + map.find(ConfigurationPolicyStore::kPolicyHomePage); + ASSERT_TRUE(i != map.end()); + string16 value; + i->second->GetAsString(&value); + EXPECT_EQ(L"http://crbug.com", value); +} + +TEST_F(ConfigurationPolicyProviderWinTest, + TestHomepageIsNewTabPagePolicy) { + TestBooleanPolicy(ConfigurationPolicyStore::kPolicyHomepageIsNewTabPage); +} + +TEST_F(ConfigurationPolicyProviderWinTest, + TestPolicyAlternateErrorPagesEnabled) { + TestBooleanPolicy( + ConfigurationPolicyStore::kPolicyAlternateErrorPagesEnabled); +} + +TEST_F(ConfigurationPolicyProviderWinTest, + TestPolicySearchSuggestEnabled) { + TestBooleanPolicy(ConfigurationPolicyStore::kPolicySearchSuggestEnabled); +} + +TEST_F(ConfigurationPolicyProviderWinTest, + TestPolicyDnsPrefetchingEnabled) { + TestBooleanPolicy(ConfigurationPolicyStore::kPolicyDnsPrefetchingEnabled); +} + +TEST_F(ConfigurationPolicyProviderWinTest, + TestPolicySafeBrowsingEnabled) { + TestBooleanPolicy(ConfigurationPolicyStore::kPolicySafeBrowsingEnabled); +} + +TEST_F(ConfigurationPolicyProviderWinTest, + TestPolicyMetricsReportingEnabled) { + TestBooleanPolicy(ConfigurationPolicyStore::kPolicyMetricsReportingEnabled); +} + +TEST_F(ConfigurationPolicyProviderWinTest, + TestPolicyPasswordManagerEnabled) { + TestBooleanPolicy(ConfigurationPolicyStore::kPolicyPasswordManagerEnabled); +} diff --git a/chrome/browser/policy/configuration_policy_store.h b/chrome/browser/policy/configuration_policy_store.h new file mode 100644 index 0000000..80d9a56 --- /dev/null +++ b/chrome/browser/policy/configuration_policy_store.h @@ -0,0 +1,57 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_STORE_H_ +#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_STORE_H_ +#pragma once + +#include "base/basictypes.h" + +class Value; + +// An abstract super class for policy stores that provides a method that can be +// called by a |ConfigurationPolicyProvider| to specify a policy. +class ConfigurationPolicyStore { + public: + ConfigurationPolicyStore() {} + virtual ~ConfigurationPolicyStore() {} + + enum PolicyType { + kPolicyHomePage, + kPolicyHomepageIsNewTabPage, + kPolicyProxyServerMode, + kPolicyProxyServer, + kPolicyProxyPacUrl, + kPolicyProxyBypassList, + kPolicyAlternateErrorPagesEnabled, + kPolicySearchSuggestEnabled, + kPolicyDnsPrefetchingEnabled, + kPolicySafeBrowsingEnabled, + kPolicyMetricsReportingEnabled, + kPolicyPasswordManagerEnabled, + kPolicySyncDisabled, + kPolicyApplicationLocale, + + // A policy for allowing administrators to forcibly disable + // specific plugins. This policy is a comma-separated list of + // plugin names. Plugin names must not include the backslash + // character. + kPolicyDisabledPlugins + }; + + static const int kPolicyNoProxyServerMode = 0; + static const int kPolicyAutoDetectProxyMode = 1; + static const int kPolicyManuallyConfiguredProxyMode = 2; + static const int kPolicyUseSystemProxyMode = 3; + + // A |ConfigurationPolicyProvider| specifes the value of a policy setting + // through a call to |Apply|. + // The configuration policy pref store takes over the ownership of |value|. + virtual void Apply(PolicyType policy, Value* value) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyStore); +}; + +#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_STORE_H_ diff --git a/chrome/browser/policy/dummy_configuration_policy_provider.h b/chrome/browser/policy/dummy_configuration_policy_provider.h new file mode 100644 index 0000000..9309c00 --- /dev/null +++ b/chrome/browser/policy/dummy_configuration_policy_provider.h @@ -0,0 +1,26 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_POLICY_DUMMY_CONFIGURATION_POLICY_PROVIDER_H_ +#define CHROME_BROWSER_POLICY_DUMMY_CONFIGURATION_POLICY_PROVIDER_H_ +#pragma once + +#include "chrome/browser/policy/configuration_policy_store.h" +#include "chrome/browser/policy/configuration_policy_provider.h" + +class DummyConfigurationPolicyProvider : public ConfigurationPolicyProvider { + public: + DummyConfigurationPolicyProvider() {} + virtual ~DummyConfigurationPolicyProvider() {} + + virtual bool Provide(ConfigurationPolicyStore* store) { + return true; + } + + private: + DISALLOW_COPY_AND_ASSIGN(DummyConfigurationPolicyProvider); +}; + +#endif // CHROME_BROWSER_POLICY_DUMMY_CONFIGURATION_POLICY_PROVIDER_H_ + diff --git a/chrome/browser/policy/mock_configuration_policy_provider.h b/chrome/browser/policy/mock_configuration_policy_provider.h new file mode 100644 index 0000000..2d727467 --- /dev/null +++ b/chrome/browser/policy/mock_configuration_policy_provider.h @@ -0,0 +1,43 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_POLICY_MOCK_CONFIGURATION_POLICY_PROVIDER_H_ +#define CHROME_BROWSER_POLICY_MOCK_CONFIGURATION_POLICY_PROVIDER_H_ +#pragma once + +#include <map> + +#include "base/stl_util-inl.h" +#include "chrome/browser/policy/configuration_policy_provider.h" + +// Mock ConfigurationPolicyProvider implementation that supplies canned +// values for polices. +class MockConfigurationPolicyProvider : public ConfigurationPolicyProvider { + public: + MockConfigurationPolicyProvider() {} + ~MockConfigurationPolicyProvider() { + STLDeleteValues(&policy_map_); + } + + typedef std::map<ConfigurationPolicyStore::PolicyType, Value*> PolicyMap; + + void AddPolicy(ConfigurationPolicyStore::PolicyType policy, Value* value) { + policy_map_[policy] = value; + } + + // ConfigurationPolicyProvider method overrides. + virtual bool Provide(ConfigurationPolicyStore* store) { + for (PolicyMap::const_iterator current = policy_map_.begin(); + current != policy_map_.end(); ++current) { + store->Apply(current->first, current->second->DeepCopy()); + } + return true; + } + + private: + PolicyMap policy_map_; +}; + +#endif // CHROME_BROWSER_POLICY_MOCK_CONFIGURATION_POLICY_PROVIDER_H_ + diff --git a/chrome/browser/policy/mock_configuration_policy_store.h b/chrome/browser/policy/mock_configuration_policy_store.h new file mode 100644 index 0000000..c1ab12d --- /dev/null +++ b/chrome/browser/policy/mock_configuration_policy_store.h @@ -0,0 +1,35 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_POLICY_MOCK_CONFIGURATION_POLICY_STORE_H_ +#define CHROME_BROWSER_POLICY_MOCK_CONFIGURATION_POLICY_STORE_H_ +#pragma once + +#include <map> + +#include "base/stl_util-inl.h" +#include "chrome/browser/policy/configuration_policy_store.h" + +// Mock ConfigurationPolicyStore implementation that records values for policy +// settings as they get set. +class MockConfigurationPolicyStore : public ConfigurationPolicyStore { + public: + MockConfigurationPolicyStore() {} + ~MockConfigurationPolicyStore() { + STLDeleteValues(&policy_map_); + } + + typedef std::map<ConfigurationPolicyStore::PolicyType, Value*> PolicyMap; + const PolicyMap& policy_map() { return policy_map_; } + + // ConfigurationPolicyStore implementation. + virtual void Apply(PolicyType policy, Value* value) { + policy_map_[policy] = value; + } + + private: + PolicyMap policy_map_; +}; + +#endif // CHROME_BROWSER_POLICY_MOCK_CONFIGURATION_POLICY_STORE_H_ |