summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorfinnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-11 14:56:36 +0000
committerfinnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-11 14:56:36 +0000
commit306a2bd6e1bdabbe0cb5a70e17fe9a3eee08b5f9 (patch)
treed4e2239ea87c5552c19a7cd33f2af8d76473a603 /chrome
parent1bf88f540099cb145757a3572dbab90faff9bf1e (diff)
downloadchromium_src-306a2bd6e1bdabbe0cb5a70e17fe9a3eee08b5f9.zip
chromium_src-306a2bd6e1bdabbe0cb5a70e17fe9a3eee08b5f9.tar.gz
chromium_src-306a2bd6e1bdabbe0cb5a70e17fe9a3eee08b5f9.tar.bz2
Implement admin control (by policy) over which extensions the user can install and run. Currently we intercept in two locations:
1) When the user tries to install an extension (includes error message). 2) Every time the browser starts up and the currently installed extensions are loaded (silently skips the extension). I implemented a whitelist and a blacklist approach, calling it a allow/deny list to not clash with the global blacklist we have for extensions. A blacklist of '*' means all extensions are blacklisted. If an extension is on the blacklist it cannot be installed/loaded, unless it also appears on the whitelist. I also fleshed out the LIST_TYPE support for policy values, so that we don't have to use comma separated REG_SZ values for lists and can instead use ADM support for listboxes. BUG=47085 TEST=ExtensionsServiceTest.BlacklistedByPolicyWillNotInstall, ConfigurationPolicyProviderWinTest.TestExtensionInstall* Review URL: http://codereview.chromium.org/3014053 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55727 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/extensions/crx_installer.cc6
-rw-r--r--chrome/browser/extensions/extension_prefs.cc46
-rw-r--r--chrome/browser/extensions/extension_prefs.h5
-rw-r--r--chrome/browser/extensions/extensions_service.cc4
-rw-r--r--chrome/browser/extensions/extensions_service_unittest.cc31
-rw-r--r--chrome/browser/policy/configuration_policy_pref_store.cc4
-rw-r--r--chrome/browser/policy/configuration_policy_provider.cc4
-rw-r--r--chrome/browser/policy/configuration_policy_provider_win.cc105
-rw-r--r--chrome/browser/policy/configuration_policy_provider_win.h19
-rw-r--r--chrome/browser/policy/configuration_policy_provider_win_unittest.cc106
-rw-r--r--chrome/browser/policy/configuration_policy_store.h4
-rw-r--r--chrome/common/extensions/extension_constants.cc4
-rw-r--r--chrome/common/extensions/extension_constants.h3
-rw-r--r--chrome/common/policy_constants.cc2
-rw-r--r--chrome/common/policy_constants.h2
-rw-r--r--chrome/common/pref_names.cc8
-rw-r--r--chrome/common/pref_names.h4
17 files changed, 304 insertions, 53 deletions
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index ddc1404..b24a02d 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -201,6 +201,12 @@ void CrxInstaller::ConfirmInstall() {
return;
}
+ if (!frontend_->extension_prefs()->IsExtensionAllowedByPolicy(
+ extension_->id())) {
+ ReportFailureFromUIThread("This extension is blacklisted by admin policy.");
+ return;
+ }
+
GURL overlapping_url;
Extension* overlapping_extension =
frontend_->GetExtensionByOverlappingWebExtent(extension_->web_extent());
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index 1f4f3e8..f8dbc59 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -45,6 +45,13 @@ const wchar_t kExtensionDidEscalatePermissions[] = L"install_warning_on_enable";
// object read from the Preferences file, containing a list of toolstrip URLs.
const wchar_t kExtensionShelf[] = L"extensions.shelf";
+// A preference that tracks admin policy regarding which extensions the user
+// can and can not install. This preference is a list object, containing
+// strings that list extension ids. Denylist can contain "*" meaning all
+// extensions.
+const wchar_t kExtensionInstallAllowList[] = L"extensions.install.allowlist";
+const wchar_t kExtensionInstallDenyList[] = L"extensions.install.denylist";
+
// A preference that tracks browser action toolbar configuration. This is a list
// object stored in the Preferences file. The extensions are stored by ID.
const wchar_t kExtensionToolbar[] = L"extensions.toolbar";
@@ -233,6 +240,41 @@ bool ExtensionPrefs::IsExtensionBlacklisted(const std::string& extension_id) {
return ReadExtensionPrefBoolean(extension_id, kPrefBlacklist);
}
+bool ExtensionPrefs::IsExtensionAllowedByPolicy(
+ const std::string& extension_id) {
+ std::string string_value;
+
+ // Check the whitelist first.
+ const ListValue* whitelist = prefs_->GetList(kExtensionInstallAllowList);
+ if (whitelist) {
+ for (ListValue::const_iterator it = whitelist->begin();
+ it != whitelist->end(); ++it) {
+ if (!(*it)->GetAsString(&string_value))
+ LOG(WARNING) << "Failed to read whitelist string.";
+ else if (string_value == extension_id)
+ return true;
+ }
+ }
+
+ // Then check the blacklist (the admin blacklist, not the Google blacklist).
+ const ListValue* blacklist = prefs_->GetList(kExtensionInstallDenyList);
+ if (blacklist) {
+ for (ListValue::const_iterator it = blacklist->begin();
+ it != blacklist->end(); ++it) {
+ if (!(*it)->GetAsString(&string_value)) {
+ LOG(WARNING) << "Failed to read blacklist string.";
+ } else {
+ if (string_value == "*")
+ return false; // Only whitelisted extensions are allowed.
+ if (string_value == extension_id)
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
bool ExtensionPrefs::DidExtensionEscalatePermissions(
const std::string& extension_id) {
return ReadExtensionPrefBoolean(extension_id,
@@ -247,7 +289,7 @@ void ExtensionPrefs::SetDidExtensionEscalatePermissions(
}
void ExtensionPrefs::UpdateBlacklist(
- const std::set<std::string>& blacklist_set) {
+ const std::set<std::string>& blacklist_set) {
std::vector<std::string> remove_pref_ids;
std::set<std::string> used_id_set;
const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
@@ -785,4 +827,6 @@ void ExtensionPrefs::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterListPref(kExtensionToolbar);
prefs->RegisterIntegerPref(prefs::kExtensionToolbarSize, -1);
prefs->RegisterDictionaryPref(kExtensionsBlacklistUpdate);
+ prefs->RegisterListPref(kExtensionInstallAllowList);
+ prefs->RegisterListPref(kExtensionInstallDenyList);
}
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
index 3ab50ee..f61cdc1 100644
--- a/chrome/browser/extensions/extension_prefs.h
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -90,6 +90,10 @@ class ExtensionPrefs {
// Based on extension id, checks prefs to see if it is blacklisted.
bool IsExtensionBlacklisted(const std::string& id);
+ // Is the extension with |extension_id| allowed by policy (checking both
+ // whitelist and blacklist).
+ bool IsExtensionAllowedByPolicy(const std::string& extension_id);
+
// Returns the last value set via SetLastPingDay. If there isn't such a
// pref, the returned Time will return true for is_null().
base::Time LastPingDay(const std::string& extension_id) const;
@@ -149,7 +153,6 @@ class ExtensionPrefs {
PrefService* pref_service() const { return prefs_; }
private:
-
// Converts absolute paths in the pref to paths relative to the
// install_directory_.
void MakePathsRelative();
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
index dcfc481..fde71aa 100644
--- a/chrome/browser/extensions/extensions_service.cc
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -567,7 +567,9 @@ void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info,
bool write_to_prefs) {
std::string error;
Extension* extension = NULL;
- if (info.extension_manifest.get()) {
+ if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) {
+ error = errors::kDisabledByPolicy;
+ } else if (info.extension_manifest.get()) {
scoped_ptr<Extension> tmp(new Extension(info.extension_path));
bool require_key = info.extension_location != Extension::LOAD;
if (tmp->InitFromValue(*info.extension_manifest, require_key, &error))
diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc
index 08f8c22..012e8d6 100644
--- a/chrome/browser/extensions/extensions_service_unittest.cc
+++ b/chrome/browser/extensions/extensions_service_unittest.cc
@@ -1523,6 +1523,37 @@ TEST_F(ExtensionsServiceTest, WillNotLoadBlacklistedExtensionsFromDirectory) {
EXPECT_NE(std::string(good0), loaded_[1]->id());
}
+// Will not install extension blacklisted by policy.
+TEST_F(ExtensionsServiceTest, BlacklistedByPolicyWillNotInstall) {
+ InitializeEmptyExtensionsService();
+
+ ListValue* whitelist = prefs_->GetMutableList(
+ L"extensions.install.allowlist");
+ ListValue* blacklist = prefs_->GetMutableList(
+ L"extensions.install.denylist");
+ ASSERT_TRUE(whitelist != NULL && blacklist != NULL);
+
+ // Blacklist everything.
+ blacklist->Append(Value::CreateStringValue("*"));
+
+ // Blacklist prevents us from installing good_crx.
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ service_->InstallExtension(path);
+ loop_.RunAllPending();
+ EXPECT_EQ(0u, service_->extensions()->size());
+
+ // Now whitelist this particular extension.
+ whitelist->Append(Value::CreateStringValue(good_crx));
+
+ // Ensure we can now install good_crx.
+ service_->InstallExtension(path);
+ loop_.RunAllPending();
+ EXPECT_EQ(1u, service_->extensions()->size());
+}
+
// Tests disabling extensions
TEST_F(ExtensionsServiceTest, DisableExtension) {
InitializeEmptyExtensionsService();
diff --git a/chrome/browser/policy/configuration_policy_pref_store.cc b/chrome/browser/policy/configuration_policy_pref_store.cc
index b6fd1e6..744ee70 100644
--- a/chrome/browser/policy/configuration_policy_pref_store.cc
+++ b/chrome/browser/policy/configuration_policy_pref_store.cc
@@ -43,6 +43,10 @@ const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry
prefs::kMetricsReportingEnabled },
{ Value::TYPE_STRING, kPolicyApplicationLocale,
prefs::kApplicationLocale},
+ { Value::TYPE_LIST, kPolicyExtensionInstallAllowList,
+ prefs::kExtensionInstallAllowList},
+ { Value::TYPE_LIST, kPolicyExtensionInstallDenyList,
+ prefs::kExtensionInstallDenyList},
};
const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry
diff --git a/chrome/browser/policy/configuration_policy_provider.cc b/chrome/browser/policy/configuration_policy_provider.cc
index 99c61cf..748c3a2 100644
--- a/chrome/browser/policy/configuration_policy_provider.cc
+++ b/chrome/browser/policy/configuration_policy_provider.cc
@@ -50,6 +50,10 @@ const InternalPolicyValueMapEntry kPolicyValueMap[] = {
Value::TYPE_STRING, policy::key::kApplicationLocaleValue },
{ ConfigurationPolicyStore::kPolicySyncDisabled,
Value::TYPE_BOOLEAN, policy::key::kSyncDisabled },
+ { ConfigurationPolicyStore::kPolicyExtensionInstallAllowList,
+ Value::TYPE_LIST, policy::key::kExtensionInstallAllowList },
+ { ConfigurationPolicyStore::kPolicyExtensionInstallDenyList,
+ Value::TYPE_LIST, policy::key::kExtensionInstallDenyList },
};
} // namespace
diff --git a/chrome/browser/policy/configuration_policy_provider_win.cc b/chrome/browser/policy/configuration_policy_provider_win.cc
index 4085b14..eb6d92f 100644
--- a/chrome/browser/policy/configuration_policy_provider_win.cc
+++ b/chrome/browser/policy/configuration_policy_provider_win.cc
@@ -12,7 +12,9 @@
#include "base/object_watcher.h"
#include "base/registry.h"
#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
#include "base/string_piece.h"
+#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
@@ -56,53 +58,66 @@ ConfigurationPolicyProviderWin::ConfigurationPolicyProviderWin() {
}
bool ConfigurationPolicyProviderWin::GetRegistryPolicyString(
- const wchar_t* value_name, string16* result) {
+ const string16& name, int index, 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 {
+ RegKey policy_key;
+ string16 location = string16(policy::kRegistrySubKey);
+ string16 value_name = name;
+
+ if (index > 0) {
+ // This is a list value, treat |name| as a subkey.
+ location += ASCIIToUTF16("\\") + name;
+ value_name = base::IntToString16(index);
+ }
+
+ // First try the global policy.
+ if (!policy_key.Open(HKEY_LOCAL_MACHINE, location.c_str()) ||
+ !policy_key.ReadValue(value_name.c_str(), 0, &value_size, &key_type)) {
+ policy_key.Close();
+ // Fall back on user-specific policy.
+ if (!policy_key.Open(HKEY_CURRENT_USER, location.c_str()) ||
+ !policy_key.ReadValue(value_name.c_str(), 0, &value_size, &key_type)) {
return false;
}
}
+ 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 pre-fill to zeros to guarantee
+ // the 0-termination.
+ buffer.reset(new uint8[value_size + 2]);
+ memset(buffer.get(), 0, value_size + 2);
+ policy_key.ReadValue(value_name.c_str(), buffer.get(), &value_size);
result->assign(reinterpret_cast<const wchar_t*>(buffer.get()));
return true;
}
+
+bool ConfigurationPolicyProviderWin::GetRegistryPolicyStringList(
+ const string16& key, ListValue* result) {
+ int index = 0;
+ string16 policy_string;
+ while (GetRegistryPolicyString(key, ++index, &policy_string))
+ result->Append(Value::CreateStringValue(policy_string));
+ return true;
+}
+
bool ConfigurationPolicyProviderWin::GetRegistryPolicyBoolean(
- const wchar_t* value_name, bool* result) {
+ const string16& value_name, bool* result) {
DWORD value;
RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, policy::kRegistrySubKey);
- if (hkcu_policy_key.ReadValueDW(value_name, &value)) {
+ if (hkcu_policy_key.ReadValueDW(value_name.c_str(), &value)) {
*result = value != 0;
return true;
}
RegKey hklm_policy_key(HKEY_CURRENT_USER, policy::kRegistrySubKey);
- if (hklm_policy_key.ReadValueDW(value_name, &value)) {
+ if (hklm_policy_key.ReadValueDW(value_name.c_str(), &value)) {
*result = value != 0;
return true;
}
@@ -110,16 +125,16 @@ bool ConfigurationPolicyProviderWin::GetRegistryPolicyBoolean(
}
bool ConfigurationPolicyProviderWin::GetRegistryPolicyInteger(
- const wchar_t* value_name, uint32* result) {
+ const string16& value_name, uint32* result) {
DWORD value;
RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, policy::kRegistrySubKey);
- if (hkcu_policy_key.ReadValueDW(value_name, &value)) {
+ if (hkcu_policy_key.ReadValueDW(value_name.c_str(), &value)) {
*result = value;
return true;
}
RegKey hklm_policy_key(HKEY_CURRENT_USER, policy::kRegistrySubKey);
- if (hklm_policy_key.ReadValueDW(value_name, &value)) {
+ if (hklm_policy_key.ReadValueDW(value_name.c_str(), &value)) {
*result = value;
return true;
}
@@ -133,29 +148,37 @@ bool ConfigurationPolicyProviderWin::Provide(
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));
+ case Value::TYPE_STRING: {
+ std::wstring string_value;
+ if (GetRegistryPolicyString(name.c_str(), -1, &string_value)) {
+ store->Apply(current->policy_type,
+ Value::CreateStringValue(string_value));
}
break;
- case Value::TYPE_BOOLEAN:
+ }
+ case Value::TYPE_LIST: {
+ scoped_ptr<ListValue> list_value(new ListValue);
+ if (GetRegistryPolicyStringList(name.c_str(), list_value.get()))
+ store->Apply(current->policy_type, list_value.release());
+ break;
+ }
+ case Value::TYPE_BOOLEAN: {
+ bool bool_value;
if (GetRegistryPolicyBoolean(name.c_str(), &bool_value)) {
store->Apply(current->policy_type,
Value::CreateBooleanValue(bool_value));
}
break;
- case Value::TYPE_INTEGER:
+ }
+ case Value::TYPE_INTEGER: {
+ uint32 int_value;
if (GetRegistryPolicyInteger(name.c_str(), &int_value)) {
store->Apply(current->policy_type,
Value::CreateIntegerValue(int_value));
}
break;
+ }
default:
NOTREACHED();
return false;
diff --git a/chrome/browser/policy/configuration_policy_provider_win.h b/chrome/browser/policy/configuration_policy_provider_win.h
index e2ebbdb..e197e9d 100644
--- a/chrome/browser/policy/configuration_policy_provider_win.h
+++ b/chrome/browser/policy/configuration_policy_provider_win.h
@@ -51,11 +51,22 @@ class ConfigurationPolicyProviderWin : public ConfigurationPolicyProvider {
private:
scoped_ptr<GroupPolicyChangeWatcher> watcher_;
- // Methods to perfrom type-specific policy lookups in the registry.
+ // Methods to perform 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);
+
+ // Reads a string registry value |name| and puts the resulting string in
+ // |result|. If |index| > 0, |name| is the name of a subkey and the value
+ // read is named |index|. Note: A subkey is used for lists to work around
+ // a problem with the Group Policy Editor, where one list value overwrites
+ // another if they appear under the same key (even if they have different
+ // names).
+ bool GetRegistryPolicyString(const string16& name,
+ int index,
+ string16* result);
+ // Gets a list value contained under |key| one level below the policy root.
+ bool GetRegistryPolicyStringList(const string16& key, ListValue* result);
+ bool GetRegistryPolicyBoolean(const string16& value_name, bool* result);
+ bool GetRegistryPolicyInteger(const string16& 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
index 221ef83..1614a59 100644
--- a/chrome/browser/policy/configuration_policy_provider_win_unittest.cc
+++ b/chrome/browser/policy/configuration_policy_provider_win_unittest.cc
@@ -10,6 +10,7 @@
#include "base/registry.h"
#include "base/scoped_ptr.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 "chrome/browser/policy/configuration_policy_provider_win.h"
@@ -40,6 +41,8 @@ class TestConfigurationPolicyProviderWin
void SetBooleanPolicy(ConfigurationPolicyStore::PolicyType type,
HKEY hive, bool value);
void SetCookiesMode(HKEY hive, uint32 value);
+ void AllowExtension(HKEY hive, int index, const wchar_t* id);
+ void DenyExtension(HKEY hive, int index, const wchar_t* id);
typedef std::vector<PolicyValueMapEntry> PolicyValueMap;
static const PolicyValueMap* PolicyValueMapping() {
@@ -79,6 +82,26 @@ void TestConfigurationPolicyProviderWin::SetHomepageRegistryValueWrongType(
5));
}
+void TestConfigurationPolicyProviderWin::AllowExtension(HKEY hive,
+ int index,
+ const wchar_t* id) {
+ RegKey key(hive,
+ (string16(policy::kRegistrySubKey) + ASCIIToUTF16("\\") +
+ ASCIIToUTF16(policy::key::kExtensionInstallAllowList)).c_str(),
+ KEY_ALL_ACCESS);
+ EXPECT_TRUE(key.WriteValue(base::IntToString16(index).c_str(), id));
+}
+
+void TestConfigurationPolicyProviderWin::DenyExtension(HKEY hive,
+ int index,
+ const wchar_t* id) {
+ RegKey key(hive,
+ (string16(policy::kRegistrySubKey) + ASCIIToUTF16("\\") +
+ ASCIIToUTF16(policy::key::kExtensionInstallDenyList)).c_str(),
+ KEY_ALL_ACCESS);
+ EXPECT_TRUE(key.WriteValue(base::IntToString16(index).c_str(), id));
+}
+
void TestConfigurationPolicyProviderWin::SetBooleanPolicy(
ConfigurationPolicyStore::PolicyType type,
HKEY hive,
@@ -284,6 +307,89 @@ TEST_F(ConfigurationPolicyProviderWinTest,
TestBooleanPolicy(ConfigurationPolicyStore::kPolicyHomepageIsNewTabPage);
}
+TEST_F(ConfigurationPolicyProviderWinTest, TestExtensionInstallWhitelistHKCU) {
+ MockConfigurationPolicyStore store;
+ TestConfigurationPolicyProviderWin provider;
+ provider.AllowExtension(HKEY_CURRENT_USER, 1, L"abc");
+ provider.AllowExtension(HKEY_CURRENT_USER, 2, L"def");
+ provider.Provide(&store);
+
+ const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
+ MockConfigurationPolicyStore::PolicyMap::const_iterator i =
+ map.find(ConfigurationPolicyStore::kPolicyExtensionInstallAllowList);
+ ASSERT_TRUE(i != map.end());
+ ASSERT_TRUE(i->second->IsType(Value::TYPE_LIST));
+ ListValue* value = reinterpret_cast<ListValue*>(i->second);
+ std::string str_value;
+ EXPECT_EQ(2, value->GetSize());
+ EXPECT_TRUE(value->GetString(0, &str_value));
+ EXPECT_STREQ("abc", str_value.c_str());
+ EXPECT_TRUE(value->GetString(1, &str_value));
+ EXPECT_STREQ("def", str_value.c_str());
+}
+
+TEST_F(ConfigurationPolicyProviderWinTest, TestExtensionInstallWhitelistHKLM) {
+ MockConfigurationPolicyStore store;
+ TestConfigurationPolicyProviderWin provider;
+ provider.AllowExtension(HKEY_LOCAL_MACHINE, 1, L"abc");
+ provider.AllowExtension(HKEY_LOCAL_MACHINE, 2, L"def");
+ provider.Provide(&store);
+
+ const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
+ MockConfigurationPolicyStore::PolicyMap::const_iterator i =
+ map.find(ConfigurationPolicyStore::kPolicyExtensionInstallAllowList);
+ ASSERT_TRUE(i != map.end());
+ ASSERT_TRUE(i->second->IsType(Value::TYPE_LIST));
+ ListValue* value = reinterpret_cast<ListValue*>(i->second);
+ std::string str_value;
+ EXPECT_EQ(2, value->GetSize());
+ EXPECT_TRUE(value->GetString(0, &str_value));
+ EXPECT_STREQ("abc", str_value.c_str());
+ EXPECT_TRUE(value->GetString(1, &str_value));
+ EXPECT_STREQ("def", str_value.c_str());
+}
+
+TEST_F(ConfigurationPolicyProviderWinTest,
+ TestExtensionInstallWhitelistHKLMOverHKCU) {
+ MockConfigurationPolicyStore store;
+ TestConfigurationPolicyProviderWin provider;
+ provider.AllowExtension(HKEY_CURRENT_USER, 1, L"abc");
+ provider.AllowExtension(HKEY_LOCAL_MACHINE, 1, L"def");
+ provider.Provide(&store);
+
+ const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
+ MockConfigurationPolicyStore::PolicyMap::const_iterator i =
+ map.find(ConfigurationPolicyStore::kPolicyExtensionInstallAllowList);
+ ASSERT_TRUE(i != map.end());
+ ASSERT_TRUE(i->second->IsType(Value::TYPE_LIST));
+ ListValue* value = reinterpret_cast<ListValue*>(i->second);
+ std::string str_value;
+ EXPECT_EQ(1, value->GetSize());
+ EXPECT_TRUE(value->GetString(0, &str_value));
+ EXPECT_STREQ("def", str_value.c_str());
+}
+
+TEST_F(ConfigurationPolicyProviderWinTest, TestExtensionInstallBlacklistHKLM) {
+ MockConfigurationPolicyStore store;
+ TestConfigurationPolicyProviderWin provider;
+ provider.DenyExtension(HKEY_LOCAL_MACHINE, 1, L"abc");
+ provider.DenyExtension(HKEY_LOCAL_MACHINE, 2, L"def");
+ provider.Provide(&store);
+
+ const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
+ MockConfigurationPolicyStore::PolicyMap::const_iterator i =
+ map.find(ConfigurationPolicyStore::kPolicyExtensionInstallDenyList);
+ ASSERT_TRUE(i != map.end());
+ ASSERT_TRUE(i->second->IsType(Value::TYPE_LIST));
+ ListValue* value = reinterpret_cast<ListValue*>(i->second);
+ std::string str_value;
+ EXPECT_EQ(2, value->GetSize());
+ EXPECT_TRUE(value->GetString(0, &str_value));
+ EXPECT_STREQ("abc", str_value.c_str());
+ EXPECT_TRUE(value->GetString(1, &str_value));
+ EXPECT_STREQ("def", str_value.c_str());
+}
+
TEST_F(ConfigurationPolicyProviderWinTest,
TestPolicyAlternateErrorPagesEnabled) {
TestBooleanPolicy(
diff --git a/chrome/browser/policy/configuration_policy_store.h b/chrome/browser/policy/configuration_policy_store.h
index 80d9a56..4f876fe 100644
--- a/chrome/browser/policy/configuration_policy_store.h
+++ b/chrome/browser/policy/configuration_policy_store.h
@@ -32,6 +32,8 @@ class ConfigurationPolicyStore {
kPolicyPasswordManagerEnabled,
kPolicySyncDisabled,
kPolicyApplicationLocale,
+ kPolicyExtensionInstallAllowList,
+ kPolicyExtensionInstallDenyList,
// A policy for allowing administrators to forcibly disable
// specific plugins. This policy is a comma-separated list of
@@ -45,7 +47,7 @@ class ConfigurationPolicyStore {
static const int kPolicyManuallyConfiguredProxyMode = 2;
static const int kPolicyUseSystemProxyMode = 3;
- // A |ConfigurationPolicyProvider| specifes the value of a policy setting
+ // A |ConfigurationPolicyProvider| specifies 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;
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 4001c9b..ce4d74f 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -92,6 +92,8 @@ const char* kCannotScriptGallery =
"The extensions gallery cannot be scripted.";
const char* kChromeVersionTooLow =
"This extension requires * version * or greater.";
+const char* kDisabledByPolicy =
+ "This extension has been disabled by your administrator.";
const char* kDevToolsExperimental =
"You must request the 'experimental' permission in order to use the"
" DevTools API.";
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index 4cd9779..bc85b3c 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -101,6 +101,7 @@ namespace extension_manifest_errors {
extern const char* kInvalidCssList;
extern const char* kInvalidDefaultLocale;
extern const char* kInvalidDescription;
+ extern const char* kDisabledByPolicy;
extern const char* kInvalidDevToolsPage;
extern const char* kInvalidGlob;
extern const char* kInvalidGlobList;
diff --git a/chrome/common/policy_constants.cc b/chrome/common/policy_constants.cc
index 7c0b5b4..8f56108 100644
--- a/chrome/common/policy_constants.cc
+++ b/chrome/common/policy_constants.cc
@@ -31,6 +31,8 @@ const char kPasswordManagerEnabled[] = "PasswordManagerEnabled";
const char kDisabledPluginsList[] = "DisabledPluginsList";
const char kApplicationLocaleValue[] = "ApplicationLocaleValue";
const char kSyncDisabled[] = "SyncDisabled";
+const char kExtensionInstallAllowList[] = "ExtensionInstallWhitelist";
+const char kExtensionInstallDenyList[] = "ExtensionInstallBlacklist";
} // namespace key
diff --git a/chrome/common/policy_constants.h b/chrome/common/policy_constants.h
index 37107db..591a9f1 100644
--- a/chrome/common/policy_constants.h
+++ b/chrome/common/policy_constants.h
@@ -33,6 +33,8 @@ extern const char kPasswordManagerEnabled[];
extern const char kDisabledPluginsList[];
extern const char kApplicationLocaleValue[];
extern const char kSyncDisabled[];
+extern const char kExtensionInstallAllowList[];
+extern const char kExtensionInstallDenyList[];
} // namespace key
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index cd47625..4a3d79c 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -814,6 +814,14 @@ const char kShowExtensionShelf[] = "extensions.shelf.show_on_all_tabs";
const char kBrowserActionContainerWidth[] =
"extensions.browseractions.container.width";
+// A whitelist of extension the user can install. This is controlled by the
+// administrator.
+const char kExtensionInstallAllowList[] = "extensions.install.allowlist";
+// A blacklist, containing extensions the user cannot install. This is
+// controlled by the administrator. This list should not be confused with
+// the extension blacklist, which is Google controlled.
+const char kExtensionInstallDenyList[] = "extensions.install.denylist";
+
// Time of the last, and next scheduled, extensions auto-update checks.
const char kLastExtensionsUpdateCheck[] = "extensions.autoupdate.last_check";
const char kNextExtensionsUpdateCheck[] = "extensions.autoupdate.next_check";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 61e87bf..1e20e76 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -299,8 +299,8 @@ extern const char kDisableExtensions[];
extern const char kShowExtensionShelf[];
extern const char kBrowserActionContainerWidth[];
-extern const char kLastExtensionsUpdateCheck[];
-extern const char kNextExtensionsUpdateCheck[];
+extern const char kExtensionInstallAllowList[];
+extern const char kExtensionInstallDenyList[];
extern const char kExtensionBlacklistUpdateVersion[];