Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/policy/policy_loader_win.h" | 5 #include "chrome/browser/policy/policy_loader_win.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 | 8 |
| 9 #include "base/json/json_writer.h" | 9 #include "base/json/json_writer.h" |
| 10 #include "base/string16.h" | 10 #include "base/string16.h" |
| 11 #include "base/string_number_conversions.h" | 11 #include "base/string_number_conversions.h" |
| 12 #include "base/string_util.h" | |
| 12 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
| 13 #include "base/win/registry.h" | 14 #include "base/win/registry.h" |
| 14 #include "chrome/browser/policy/async_policy_provider.h" | 15 #include "chrome/browser/policy/async_policy_provider.h" |
| 15 #include "chrome/browser/policy/configuration_policy_provider_test.h" | 16 #include "chrome/browser/policy/configuration_policy_provider_test.h" |
| 16 #include "chrome/browser/policy/policy_bundle.h" | 17 #include "chrome/browser/policy/policy_bundle.h" |
| 17 #include "chrome/browser/policy/policy_map.h" | 18 #include "chrome/browser/policy/policy_map.h" |
| 18 #include "policy/policy_constants.h" | 19 #include "policy/policy_constants.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
| 20 | 21 |
| 21 using base::win::RegKey; | 22 using base::win::RegKey; |
| 22 | 23 |
| 23 namespace policy { | 24 namespace policy { |
| 24 | 25 |
| 25 namespace { | 26 namespace { |
| 26 | 27 |
| 27 const wchar_t kUnitTestRegistrySubKey[] = L"SOFTWARE\\Chromium Unit Tests"; | 28 const wchar_t kUnitTestRegistrySubKey[] = L"SOFTWARE\\Chromium Unit Tests"; |
| 28 const wchar_t kUnitTestMachineOverrideSubKey[] = | 29 const wchar_t kUnitTestMachineOverrideSubKey[] = |
| 29 L"SOFTWARE\\Chromium Unit Tests\\HKLM Override"; | 30 L"SOFTWARE\\Chromium Unit Tests\\HKLM Override"; |
| 30 const wchar_t kUnitTestUserOverrideSubKey[] = | 31 const wchar_t kUnitTestUserOverrideSubKey[] = |
| 31 L"SOFTWARE\\Chromium Unit Tests\\HKCU Override"; | 32 L"SOFTWARE\\Chromium Unit Tests\\HKCU Override"; |
| 32 | 33 |
| 33 // Installs |dict| at the given |path|, in the given |hive|. Currently only | 34 const wchar_t kPathSep[] = L"\\"; |
| 34 // string, int and dictionary types are converted; other types cause a failure. | 35 |
| 35 // Returns false if there was any failure, and true if |dict| was successfully | 36 // Registry key where 3rd party policy is stored. |
| 36 // written. | 37 const wchar_t kThirdParty[] = L"3rdparty"; |
| 37 // TODO(joaodasilva): generate a schema for |dict| too, so that all types can | 38 |
| 38 // be retrieved. | 39 // Keys for mandatory and recommended policy and schema under the registry key |
| 39 bool InstallDictionary(const base::DictionaryValue& dict, | 40 // for a component. |
| 40 HKEY hive, | 41 const wchar_t kMandatory[] = L"policy"; |
| 41 const string16& path) { | 42 const wchar_t kRecommended[] = L"recommended"; |
| 43 const wchar_t kSchema[] = L"schema"; | |
| 44 | |
| 45 // JSON-schema key that indicates an entry's type. | |
| 46 const char kType[] = "type"; | |
| 47 // JSON-schema key that indicates an object entry's properties. | |
| 48 const char kProperties[] = "properties"; | |
| 49 // JSON-schema key that indicates an object entry's default schema. | |
| 50 const char kAdditionalProperties[] = "additionalProperties"; | |
| 51 // JSON-schema key that indicates the schema for the items of an array entry. | |
| 52 const char kItems[] = "items"; | |
|
Mattias Nissler (ping if slow)
2012/06/27 14:52:10
nit: You could convert these to static members in
Joao da Silva
2012/06/27 16:55:28
I've added them to a namespace within ::policy, so
Mattias Nissler (ping if slow)
2012/06/28 10:00:28
I think that's a fair solution. I'm not sure wheth
| |
| 53 | |
| 54 // Installs |value| in the given registry |path| and |hive|, under the key | |
| 55 // |name|. Returns false on errors. | |
| 56 // Some of the possible Value types are stored after a conversion (e.g. doubles | |
| 57 // are stored as strings), and can only be retrieved if a corresponding schema | |
| 58 // is written. | |
| 59 bool InstallValue(const base::Value& value, | |
| 60 HKEY hive, | |
| 61 const string16& path, | |
| 62 const string16& name) { | |
| 42 // KEY_ALL_ACCESS causes the ctor to create the key if it does not exist yet. | 63 // KEY_ALL_ACCESS causes the ctor to create the key if it does not exist yet. |
| 43 RegKey key(hive, path.c_str(), KEY_ALL_ACCESS); | 64 RegKey key(hive, path.c_str(), KEY_ALL_ACCESS); |
| 44 const string16 kPathSep = ASCIIToUTF16("\\"); | 65 switch (value.GetType()) { |
| 66 case base::Value::TYPE_NULL: | |
| 67 return key.WriteValue(name.c_str(), L"") == ERROR_SUCCESS; | |
| 45 | 68 |
| 46 for (base::DictionaryValue::Iterator it(dict); it.HasNext(); it.Advance()) { | 69 case base::Value::TYPE_BOOLEAN: { |
| 47 string16 name(UTF8ToUTF16(it.key())); | 70 bool bool_value; |
| 48 switch (it.value().GetType()) { | 71 if (!value.GetAsBoolean(&bool_value)) |
| 49 case base::Value::TYPE_STRING: { | 72 return false; |
| 50 string16 value; | 73 return key.WriteValue(name.c_str(), bool_value ? 1 : 0) == ERROR_SUCCESS; |
| 51 if (!it.value().GetAsString(&value)) | 74 } |
| 75 | |
| 76 case base::Value::TYPE_INTEGER: { | |
| 77 int int_value; | |
| 78 if (!value.GetAsInteger(&int_value)) | |
| 79 return false; | |
| 80 return key.WriteValue(name.c_str(), int_value) == ERROR_SUCCESS; | |
| 81 } | |
| 82 | |
| 83 case base::Value::TYPE_DOUBLE: { | |
| 84 double double_value; | |
| 85 if (!value.GetAsDouble(&double_value)) | |
| 86 return false; | |
| 87 string16 str_value = UTF8ToUTF16(base::DoubleToString(double_value)); | |
| 88 return key.WriteValue(name.c_str(), str_value.c_str()) == ERROR_SUCCESS; | |
| 89 } | |
| 90 | |
| 91 case base::Value::TYPE_STRING: { | |
| 92 string16 str_value; | |
| 93 if (!value.GetAsString(&str_value)) | |
| 94 return false; | |
| 95 return key.WriteValue(name.c_str(), str_value.c_str()) == ERROR_SUCCESS; | |
| 96 } | |
| 97 | |
| 98 case base::Value::TYPE_DICTIONARY: { | |
| 99 const base::DictionaryValue* sub_dict = NULL; | |
| 100 if (!value.GetAsDictionary(&sub_dict)) | |
| 101 return false; | |
| 102 for (base::DictionaryValue::Iterator it(*sub_dict); | |
| 103 it.HasNext(); it.Advance()) { | |
| 104 if (!InstallValue(it.value(), hive, path + kPathSep + name, | |
| 105 UTF8ToUTF16(it.key()))) { | |
| 52 return false; | 106 return false; |
| 53 if (key.WriteValue(name.c_str(), value.c_str()) != ERROR_SUCCESS) | 107 } |
| 108 } | |
| 109 return true; | |
| 110 } | |
| 111 | |
| 112 case base::Value::TYPE_LIST: { | |
| 113 const base::ListValue* list = NULL; | |
| 114 if (!value.GetAsList(&list)) | |
| 115 return false; | |
| 116 for (size_t i = 0; i < list->GetSize(); ++i) { | |
| 117 base::Value* item; | |
| 118 if (!list->Get(i, &item)) | |
| 54 return false; | 119 return false; |
| 55 break; | 120 if (!InstallValue(*item, hive, path + kPathSep + name, |
| 121 base::UintToString16(i + 1))) { | |
| 122 return false; | |
| 123 } | |
| 56 } | 124 } |
| 125 return true; | |
| 126 } | |
| 57 | 127 |
| 58 case base::Value::TYPE_INTEGER: { | 128 case base::Value::TYPE_BINARY: |
| 59 int value; | 129 return false; |
| 60 if (!it.value().GetAsInteger(&value)) | 130 } |
| 61 return false; | 131 NOTREACHED(); |
| 62 if (key.WriteValue(name.c_str(), value) != ERROR_SUCCESS) | 132 return false; |
| 63 return false; | 133 } |
| 64 break; | 134 |
| 135 // Builds a JSON schema that represents the types contained in |value|. | |
| 136 // Ownership is transferred to the caller. | |
| 137 base::DictionaryValue* BuildSchema(const base::Value& value) { | |
| 138 base::DictionaryValue* schema = new base::DictionaryValue(); | |
| 139 switch (value.GetType()) { | |
| 140 case base::Value::TYPE_NULL: | |
| 141 schema->SetString(kType, "null"); | |
| 142 break; | |
| 143 case base::Value::TYPE_BOOLEAN: | |
| 144 schema->SetString(kType, "boolean"); | |
| 145 break; | |
| 146 case base::Value::TYPE_INTEGER: | |
| 147 schema->SetString(kType, "integer"); | |
| 148 break; | |
| 149 case base::Value::TYPE_DOUBLE: | |
| 150 schema->SetString(kType, "number"); | |
| 151 break; | |
| 152 case base::Value::TYPE_STRING: | |
| 153 schema->SetString(kType, "string"); | |
| 154 break; | |
| 155 | |
| 156 case base::Value::TYPE_LIST: { | |
| 157 // Assumes every list element has the same type. | |
| 158 const base::ListValue* list = NULL; | |
| 159 if (value.GetAsList(&list) && !list->empty()) { | |
| 160 schema->SetString(kType, "array"); | |
| 161 schema->Set(kItems, BuildSchema(**list->begin())); | |
| 65 } | 162 } |
| 163 break; | |
| 164 } | |
| 66 | 165 |
| 67 case base::Value::TYPE_DICTIONARY: { | 166 case base::Value::TYPE_DICTIONARY: { |
| 68 const base::DictionaryValue* sub_dict = NULL; | 167 const base::DictionaryValue* dict = NULL; |
| 69 if (!it.value().GetAsDictionary(&sub_dict)) | 168 if (value.GetAsDictionary(&dict)) { |
| 70 return false; | 169 base::DictionaryValue* properties = new base::DictionaryValue(); |
| 71 if (!InstallDictionary(*sub_dict, hive, path + kPathSep + name)) | 170 for (base::DictionaryValue::Iterator it(*dict); |
| 72 return false; | 171 it.HasNext(); it.Advance()) { |
| 73 break; | 172 properties->Set(it.key(), BuildSchema(it.value())); |
| 173 } | |
| 174 schema->SetString(kType, "object"); | |
| 175 schema->Set(kProperties, properties); | |
| 74 } | 176 } |
| 177 break; | |
| 178 } | |
| 75 | 179 |
| 76 default: | 180 case base::Value::TYPE_BINARY: |
| 77 return false; | 181 break; |
| 78 } | |
| 79 } | 182 } |
| 80 return true; | 183 return schema; |
| 184 } | |
| 185 | |
| 186 // Writes a JSON |schema| at the registry entry |name| at |path| | |
| 187 // in the given |hive|. Returns false on failure. | |
| 188 bool WriteSchema(const base::DictionaryValue& schema, | |
| 189 HKEY hive, | |
| 190 const string16& path, | |
| 191 const string16& name) { | |
| 192 std::string encoded; | |
| 193 base::JSONWriter::Write(&schema, &encoded); | |
| 194 if (encoded.empty()) | |
| 195 return false; | |
| 196 string16 encoded16 = UTF8ToUTF16(encoded); | |
| 197 // KEY_ALL_ACCESS causes the ctor to create the key if it does not exist yet. | |
| 198 RegKey key(hive, path.c_str(), KEY_ALL_ACCESS); | |
| 199 return key.WriteValue(name.c_str(), encoded16.c_str()) == ERROR_SUCCESS; | |
| 200 } | |
| 201 | |
| 202 // Builds a JSON schema for |value| and writes it at the registry entry |name| | |
| 203 // at |path| in the given |hive|. Returns false on failure. | |
| 204 bool InstallSchema(const base::Value& value, | |
| 205 HKEY hive, | |
| 206 const string16& path, | |
| 207 const string16& name) { | |
| 208 scoped_ptr<base::DictionaryValue> schema_dict(BuildSchema(value)); | |
| 209 return WriteSchema(*schema_dict, hive, path, name); | |
| 81 } | 210 } |
| 82 | 211 |
| 83 // This class provides sandboxing and mocking for the parts of the Windows | 212 // This class provides sandboxing and mocking for the parts of the Windows |
| 84 // Registry implementing Group Policy. It prepares two temporary sandbox keys | 213 // Registry implementing Group Policy. It prepares two temporary sandbox keys |
| 85 // in |kUnitTestRegistrySubKey|, one for HKLM and one for HKCU. A test's calls | 214 // in |kUnitTestRegistrySubKey|, one for HKLM and one for HKCU. A test's calls |
| 86 // to the registry are redirected by Windows to these sandboxes, allowing the | 215 // to the registry are redirected by Windows to these sandboxes, allowing the |
| 87 // tests to manipulate and access policy as if it were active, but without | 216 // tests to manipulate and access policy as if it were active, but without |
| 88 // actually changing the parts of the Registry that are managed by Group | 217 // actually changing the parts of the Registry that are managed by Group |
| 89 // Policy. | 218 // Policy. |
| 90 class ScopedGroupPolicyRegistrySandbox { | 219 class ScopedGroupPolicyRegistrySandbox { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 123 virtual void InstallIntegerPolicy(const std::string& policy_name, | 252 virtual void InstallIntegerPolicy(const std::string& policy_name, |
| 124 int policy_value) OVERRIDE; | 253 int policy_value) OVERRIDE; |
| 125 virtual void InstallBooleanPolicy(const std::string& policy_name, | 254 virtual void InstallBooleanPolicy(const std::string& policy_name, |
| 126 bool policy_value) OVERRIDE; | 255 bool policy_value) OVERRIDE; |
| 127 virtual void InstallStringListPolicy( | 256 virtual void InstallStringListPolicy( |
| 128 const std::string& policy_name, | 257 const std::string& policy_name, |
| 129 const base::ListValue* policy_value) OVERRIDE; | 258 const base::ListValue* policy_value) OVERRIDE; |
| 130 virtual void InstallDictionaryPolicy( | 259 virtual void InstallDictionaryPolicy( |
| 131 const std::string& policy_name, | 260 const std::string& policy_name, |
| 132 const base::DictionaryValue* policy_value) OVERRIDE; | 261 const base::DictionaryValue* policy_value) OVERRIDE; |
| 262 virtual void Install3rdPartyPolicy( | |
| 263 const base::DictionaryValue* policies) OVERRIDE; | |
| 133 | 264 |
| 134 // Creates a harness instance that will install policy in HKCU or HKLM, | 265 // Creates a harness instance that will install policy in HKCU or HKLM, |
| 135 // respectively. | 266 // respectively. |
| 136 static PolicyProviderTestHarness* CreateHKCU(); | 267 static PolicyProviderTestHarness* CreateHKCU(); |
| 137 static PolicyProviderTestHarness* CreateHKLM(); | 268 static PolicyProviderTestHarness* CreateHKLM(); |
| 138 | 269 |
| 139 private: | 270 private: |
| 140 HKEY hive_; | 271 HKEY hive_; |
| 141 | 272 |
| 142 ScopedGroupPolicyRegistrySandbox registry_sandbox_; | 273 ScopedGroupPolicyRegistrySandbox registry_sandbox_; |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 240 void TestHarness::InstallDictionaryPolicy( | 371 void TestHarness::InstallDictionaryPolicy( |
| 241 const std::string& policy_name, | 372 const std::string& policy_name, |
| 242 const base::DictionaryValue* policy_value) { | 373 const base::DictionaryValue* policy_value) { |
| 243 std::string json; | 374 std::string json; |
| 244 base::JSONWriter::Write(policy_value, &json); | 375 base::JSONWriter::Write(policy_value, &json); |
| 245 RegKey key(hive_, kRegistryMandatorySubKey, KEY_ALL_ACCESS); | 376 RegKey key(hive_, kRegistryMandatorySubKey, KEY_ALL_ACCESS); |
| 246 key.WriteValue(UTF8ToUTF16(policy_name).c_str(), | 377 key.WriteValue(UTF8ToUTF16(policy_name).c_str(), |
| 247 UTF8ToUTF16(json).c_str()); | 378 UTF8ToUTF16(json).c_str()); |
| 248 } | 379 } |
| 249 | 380 |
| 381 void TestHarness::Install3rdPartyPolicy(const base::DictionaryValue* policies) { | |
| 382 // The first level entries are domains, and the second level entries map | |
| 383 // components to their policy. | |
| 384 const string16 kPathPrefix = string16(kRegistryMandatorySubKey) + kPathSep + | |
| 385 kThirdParty + kPathSep; | |
| 386 for (base::DictionaryValue::Iterator domain(*policies); | |
| 387 domain.HasNext(); domain.Advance()) { | |
| 388 const base::DictionaryValue* components = NULL; | |
| 389 if (!domain.value().GetAsDictionary(&components)) { | |
| 390 ADD_FAILURE(); | |
| 391 continue; | |
| 392 } | |
| 393 for (base::DictionaryValue::Iterator component(*components); | |
| 394 component.HasNext(); component.Advance()) { | |
| 395 const string16 path = string16(kRegistryMandatorySubKey) + kPathSep + | |
| 396 kThirdParty + kPathSep + | |
| 397 UTF8ToUTF16(domain.key()) + kPathSep + | |
| 398 UTF8ToUTF16(component.key()); | |
| 399 InstallValue(component.value(), hive_, path, kMandatory); | |
| 400 EXPECT_TRUE(InstallSchema(component.value(), hive_, path, kSchema)); | |
| 401 } | |
| 402 } | |
| 403 } | |
| 404 | |
| 250 // static | 405 // static |
| 251 PolicyProviderTestHarness* TestHarness::CreateHKCU() { | 406 PolicyProviderTestHarness* TestHarness::CreateHKCU() { |
| 252 return new TestHarness(HKEY_CURRENT_USER, POLICY_SCOPE_USER); | 407 return new TestHarness(HKEY_CURRENT_USER, POLICY_SCOPE_USER); |
| 253 } | 408 } |
| 254 | 409 |
| 255 // static | 410 // static |
| 256 PolicyProviderTestHarness* TestHarness::CreateHKLM() { | 411 PolicyProviderTestHarness* TestHarness::CreateHKLM() { |
| 257 return new TestHarness(HKEY_LOCAL_MACHINE, POLICY_SCOPE_MACHINE); | 412 return new TestHarness(HKEY_LOCAL_MACHINE, POLICY_SCOPE_MACHINE); |
| 258 } | 413 } |
| 259 | 414 |
| 260 } // namespace | 415 } // namespace |
| 261 | 416 |
| 262 // Instantiate abstract test case for basic policy reading tests. | 417 // Instantiate abstract test case for basic policy reading tests. |
| 263 INSTANTIATE_TEST_CASE_P( | 418 INSTANTIATE_TEST_CASE_P( |
| 264 PolicyProviderWinTest, | 419 PolicyProviderWinTest, |
| 265 ConfigurationPolicyProviderTest, | 420 ConfigurationPolicyProviderTest, |
| 266 testing::Values(TestHarness::CreateHKCU, TestHarness::CreateHKLM)); | 421 testing::Values(TestHarness::CreateHKCU, TestHarness::CreateHKLM)); |
| 267 | 422 |
| 423 // Instantiate abstract test case for 3rd party policy reading tests. | |
| 424 INSTANTIATE_TEST_CASE_P( | |
| 425 ThirdPartyPolicyProviderWinTest, | |
| 426 Configuration3rdPartyPolicyProviderTest, | |
| 427 testing::Values(TestHarness::CreateHKCU, TestHarness::CreateHKLM)); | |
| 428 | |
| 268 // Test cases for windows policy provider specific functionality. | 429 // Test cases for windows policy provider specific functionality. |
| 269 class PolicyLoaderWinTest : public PolicyTestBase { | 430 class PolicyLoaderWinTest : public PolicyTestBase { |
| 270 protected: | 431 protected: |
| 271 PolicyLoaderWinTest() {} | 432 PolicyLoaderWinTest() {} |
| 272 virtual ~PolicyLoaderWinTest() {} | 433 virtual ~PolicyLoaderWinTest() {} |
| 273 | 434 |
| 435 bool Matches(const PolicyBundle& expected) { | |
| 436 PolicyLoaderWin loader(&test_policy_definitions::kList); | |
| 437 scoped_ptr<PolicyBundle> loaded(loader.Load()); | |
| 438 return loaded->Equals(expected); | |
| 439 } | |
| 440 | |
| 274 ScopedGroupPolicyRegistrySandbox registry_sandbox_; | 441 ScopedGroupPolicyRegistrySandbox registry_sandbox_; |
| 275 }; | 442 }; |
| 276 | 443 |
| 277 TEST_F(PolicyLoaderWinTest, HKLMOverHKCU) { | 444 TEST_F(PolicyLoaderWinTest, HKLMOverHKCU) { |
| 278 RegKey hklm_key(HKEY_LOCAL_MACHINE, kRegistryMandatorySubKey, KEY_ALL_ACCESS); | 445 RegKey hklm_key(HKEY_LOCAL_MACHINE, kRegistryMandatorySubKey, KEY_ALL_ACCESS); |
| 279 hklm_key.WriteValue(UTF8ToUTF16(test_policy_definitions::kKeyString).c_str(), | 446 hklm_key.WriteValue(UTF8ToUTF16(test_policy_definitions::kKeyString).c_str(), |
| 280 UTF8ToUTF16("hklm").c_str()); | 447 UTF8ToUTF16("hklm").c_str()); |
| 281 RegKey hkcu_key(HKEY_CURRENT_USER, kRegistryMandatorySubKey, KEY_ALL_ACCESS); | 448 RegKey hkcu_key(HKEY_CURRENT_USER, kRegistryMandatorySubKey, KEY_ALL_ACCESS); |
| 282 hkcu_key.WriteValue(UTF8ToUTF16(test_policy_definitions::kKeyString).c_str(), | 449 hkcu_key.WriteValue(UTF8ToUTF16(test_policy_definitions::kKeyString).c_str(), |
| 283 UTF8ToUTF16("hkcu").c_str()); | 450 UTF8ToUTF16("hkcu").c_str()); |
| 284 | 451 |
| 285 PolicyLoaderWin loader(&test_policy_definitions::kList); | 452 PolicyBundle expected; |
| 286 scoped_ptr<PolicyBundle> bundle(loader.Load()); | 453 expected.Get(POLICY_DOMAIN_CHROME, "") |
| 287 | |
| 288 PolicyBundle expected_bundle; | |
| 289 expected_bundle.Get(POLICY_DOMAIN_CHROME, "") | |
| 290 .Set(test_policy_definitions::kKeyString, | 454 .Set(test_policy_definitions::kKeyString, |
| 291 POLICY_LEVEL_MANDATORY, | 455 POLICY_LEVEL_MANDATORY, |
| 292 POLICY_SCOPE_MACHINE, | 456 POLICY_SCOPE_MACHINE, |
| 293 base::Value::CreateStringValue("hklm")); | 457 base::Value::CreateStringValue("hklm")); |
| 294 EXPECT_TRUE(bundle->Equals(expected_bundle)); | 458 EXPECT_TRUE(Matches(expected)); |
| 295 } | 459 } |
| 296 | 460 |
| 297 // TODO(joaodasilva): share tests for 3rd party policy with | 461 TEST_F(PolicyLoaderWinTest, Load3rdPartyWithoutSchema) { |
| 298 // ConfigDirPolicyProvider once PolicyLoaderWin is able to load all types. | |
| 299 TEST_F(PolicyLoaderWinTest, Load3rdParty) { | |
| 300 base::DictionaryValue dict; | 462 base::DictionaryValue dict; |
| 301 dict.SetString("str", "string value"); | 463 dict.SetString("str", "string value"); |
| 302 dict.SetInteger("int", 123); | 464 dict.SetInteger("int", 123); |
| 303 dict.Set("subdict", dict.DeepCopy()); | 465 dict.Set("subdict", dict.DeepCopy()); |
| 304 dict.Set("subsubdict", dict.DeepCopy()); | 466 dict.Set("subsubdict", dict.DeepCopy()); |
| 305 dict.Set("subsubsubdict", dict.DeepCopy()); | 467 dict.Set("subsubsubdict", dict.DeepCopy()); |
| 306 | 468 |
| 307 base::DictionaryValue policy_dict; | 469 base::DictionaryValue policy_dict; |
| 308 policy_dict.Set("3rdparty.extensions.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.policy", | 470 policy_dict.Set("extensions.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.policy", |
| 309 dict.DeepCopy()); | 471 dict.DeepCopy()); |
| 310 policy_dict.Set("3rdparty.extensions.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.policy", | 472 policy_dict.Set("extensions.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.policy", |
| 311 dict.DeepCopy()); | 473 dict.DeepCopy()); |
| 312 EXPECT_TRUE(InstallDictionary(policy_dict, HKEY_LOCAL_MACHINE, | 474 EXPECT_TRUE(InstallValue(policy_dict, HKEY_LOCAL_MACHINE, |
| 313 kRegistryMandatorySubKey)); | 475 kRegistryMandatorySubKey, kThirdParty)); |
| 314 | 476 |
| 315 PolicyBundle expected; | 477 PolicyBundle expected; |
| 316 expected.Get(POLICY_DOMAIN_EXTENSIONS, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") | 478 expected.Get(POLICY_DOMAIN_EXTENSIONS, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") |
| 317 .LoadFrom(&dict, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE); | 479 .LoadFrom(&dict, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE); |
| 318 expected.Get(POLICY_DOMAIN_EXTENSIONS, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") | 480 expected.Get(POLICY_DOMAIN_EXTENSIONS, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") |
| 319 .LoadFrom(&dict, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE); | 481 .LoadFrom(&dict, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE); |
| 320 | 482 EXPECT_TRUE(Matches(expected)); |
| 321 PolicyLoaderWin loader(&test_policy_definitions::kList); | |
| 322 scoped_ptr<PolicyBundle> loaded(loader.Load()); | |
| 323 EXPECT_TRUE(loaded->Equals(expected)); | |
| 324 } | 483 } |
| 325 | 484 |
| 326 TEST_F(PolicyLoaderWinTest, Merge3rdPartyPolicies) { | 485 TEST_F(PolicyLoaderWinTest, Merge3rdPartyPolicies) { |
| 327 // Policy for the same extension will be provided at the 4 level/scope | 486 // Policy for the same extension will be provided at the 4 level/scope |
| 328 // combinations, to verify that they overlap as expected. | 487 // combinations, to verify that they overlap as expected. |
| 329 | 488 |
| 330 const string16 kPathSuffix = | 489 const string16 kPathSuffix = |
| 331 kRegistryMandatorySubKey + ASCIIToUTF16("\\3rdparty\\extensions\\merge"); | 490 kRegistryMandatorySubKey + ASCIIToUTF16("\\3rdparty\\extensions\\merge"); |
| 332 const string16 kMandatoryPath = kPathSuffix + ASCIIToUTF16("\\policy"); | |
| 333 const string16 kRecommendedPath = kPathSuffix + ASCIIToUTF16("\\recommended"); | |
| 334 | 491 |
| 335 const char kUserMandatory[] = "user-mandatory"; | 492 const char kUserMandatory[] = "user-mandatory"; |
| 336 const char kUserRecommended[] = "user-recommended"; | 493 const char kUserRecommended[] = "user-recommended"; |
| 337 const char kMachineMandatory[] = "machine-mandatory"; | 494 const char kMachineMandatory[] = "machine-mandatory"; |
| 338 const char kMachineRecommended[] = "machine-recommended"; | 495 const char kMachineRecommended[] = "machine-recommended"; |
| 339 | 496 |
| 340 base::DictionaryValue policy; | 497 base::DictionaryValue policy; |
| 341 policy.SetString("a", kMachineMandatory); | 498 policy.SetString("a", kMachineMandatory); |
| 342 EXPECT_TRUE(InstallDictionary(policy, HKEY_LOCAL_MACHINE, kMandatoryPath)); | 499 EXPECT_TRUE(InstallValue(policy, HKEY_LOCAL_MACHINE, |
| 500 kPathSuffix, kMandatory)); | |
| 343 policy.SetString("a", kUserMandatory); | 501 policy.SetString("a", kUserMandatory); |
| 344 policy.SetString("b", kUserMandatory); | 502 policy.SetString("b", kUserMandatory); |
| 345 EXPECT_TRUE(InstallDictionary(policy, HKEY_CURRENT_USER, kMandatoryPath)); | 503 EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER, |
| 504 kPathSuffix, kMandatory)); | |
| 346 policy.SetString("a", kMachineRecommended); | 505 policy.SetString("a", kMachineRecommended); |
| 347 policy.SetString("b", kMachineRecommended); | 506 policy.SetString("b", kMachineRecommended); |
| 348 policy.SetString("c", kMachineRecommended); | 507 policy.SetString("c", kMachineRecommended); |
| 349 EXPECT_TRUE(InstallDictionary(policy, HKEY_LOCAL_MACHINE, kRecommendedPath)); | 508 EXPECT_TRUE(InstallValue(policy, HKEY_LOCAL_MACHINE, |
| 509 kPathSuffix, kRecommended)); | |
| 350 policy.SetString("a", kUserRecommended); | 510 policy.SetString("a", kUserRecommended); |
| 351 policy.SetString("b", kUserRecommended); | 511 policy.SetString("b", kUserRecommended); |
| 352 policy.SetString("c", kUserRecommended); | 512 policy.SetString("c", kUserRecommended); |
| 353 policy.SetString("d", kUserRecommended); | 513 policy.SetString("d", kUserRecommended); |
| 354 EXPECT_TRUE(InstallDictionary(policy, HKEY_CURRENT_USER, kRecommendedPath)); | 514 EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER, |
| 515 kPathSuffix, kRecommended)); | |
| 355 | 516 |
| 356 PolicyBundle expected; | 517 PolicyBundle expected; |
| 357 PolicyMap& expected_policy = expected.Get(POLICY_DOMAIN_EXTENSIONS, "merge"); | 518 PolicyMap& expected_policy = expected.Get(POLICY_DOMAIN_EXTENSIONS, "merge"); |
| 358 expected_policy.Set("a", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, | 519 expected_policy.Set("a", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, |
| 359 base::Value::CreateStringValue(kMachineMandatory)); | 520 base::Value::CreateStringValue(kMachineMandatory)); |
| 360 expected_policy.Set("b", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, | 521 expected_policy.Set("b", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, |
| 361 base::Value::CreateStringValue(kUserMandatory)); | 522 base::Value::CreateStringValue(kUserMandatory)); |
| 362 expected_policy.Set("c", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, | 523 expected_policy.Set("c", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, |
| 363 base::Value::CreateStringValue(kMachineRecommended)); | 524 base::Value::CreateStringValue(kMachineRecommended)); |
| 364 expected_policy.Set("d", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER, | 525 expected_policy.Set("d", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER, |
| 365 base::Value::CreateStringValue(kUserRecommended)); | 526 base::Value::CreateStringValue(kUserRecommended)); |
| 527 EXPECT_TRUE(Matches(expected)); | |
| 528 } | |
| 366 | 529 |
| 367 PolicyLoaderWin loader(&test_policy_definitions::kList); | 530 TEST_F(PolicyLoaderWinTest, LoadStringEncodedValues) { |
| 368 scoped_ptr<PolicyBundle> loaded(loader.Load()); | 531 // Create a dictionary with all the types that can be stored encoded in a |
| 369 EXPECT_TRUE(loaded->Equals(expected)); | 532 // string, to pass to InstallSchema(). Also build an equivalent dictionary |
| 533 // with the encoded values, to pass to InstallValue(). | |
| 534 base::DictionaryValue policy; | |
| 535 policy.Set("null", base::Value::CreateNullValue()); | |
| 536 policy.SetBoolean("bool", true); | |
| 537 policy.SetInteger("int", -123); | |
| 538 policy.SetDouble("double", 456.78e9); | |
| 539 base::ListValue list; | |
| 540 list.Append(policy.DeepCopy()); | |
| 541 list.Append(policy.DeepCopy()); | |
| 542 policy.Set("list", list.DeepCopy()); | |
| 543 // Encode |policy| before adding the "dict" entry. | |
| 544 std::string encoded_dict; | |
| 545 base::JSONWriter::Write(&policy, &encoded_dict); | |
| 546 ASSERT_FALSE(encoded_dict.empty()); | |
| 547 policy.Set("dict", policy.DeepCopy()); | |
| 548 | |
| 549 std::string encoded_list; | |
| 550 base::JSONWriter::Write(&list, &encoded_list); | |
| 551 ASSERT_FALSE(encoded_list.empty()); | |
| 552 base::DictionaryValue encoded_policy; | |
| 553 encoded_policy.SetString("null", ""); | |
| 554 encoded_policy.SetString("bool", "1"); | |
| 555 encoded_policy.SetString("int", "-123"); | |
| 556 encoded_policy.SetString("double", "456.78e9"); | |
| 557 encoded_policy.SetString("list", encoded_list); | |
| 558 encoded_policy.SetString("dict", encoded_dict); | |
| 559 | |
| 560 const string16 kPathSuffix = | |
| 561 kRegistryMandatorySubKey + ASCIIToUTF16("\\3rdparty\\extensions\\string"); | |
| 562 EXPECT_TRUE(InstallSchema(policy, HKEY_CURRENT_USER, kPathSuffix, kSchema)); | |
| 563 EXPECT_TRUE( | |
| 564 InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory)); | |
| 565 | |
| 566 PolicyBundle expected; | |
| 567 expected.Get(POLICY_DOMAIN_EXTENSIONS, "string") | |
| 568 .LoadFrom(&policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER); | |
| 569 EXPECT_TRUE(Matches(expected)); | |
| 570 } | |
| 571 | |
| 572 TEST_F(PolicyLoaderWinTest, LoadIntegerEncodedValues) { | |
| 573 base::DictionaryValue policy; | |
| 574 policy.SetBoolean("bool", true); | |
| 575 policy.SetInteger("int", 123); | |
| 576 policy.SetDouble("double", 456.0); | |
| 577 | |
| 578 base::DictionaryValue encoded_policy; | |
| 579 encoded_policy.SetInteger("bool", 1); | |
| 580 encoded_policy.SetInteger("int", 123); | |
| 581 encoded_policy.SetInteger("double", 456); | |
| 582 | |
| 583 const string16 kPathSuffix = | |
| 584 kRegistryMandatorySubKey + ASCIIToUTF16("\\3rdparty\\extensions\\int"); | |
| 585 EXPECT_TRUE(InstallSchema(policy, HKEY_CURRENT_USER, kPathSuffix, kSchema)); | |
| 586 EXPECT_TRUE( | |
| 587 InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory)); | |
| 588 | |
| 589 PolicyBundle expected; | |
| 590 expected.Get(POLICY_DOMAIN_EXTENSIONS, "int") | |
| 591 .LoadFrom(&policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER); | |
| 592 EXPECT_TRUE(Matches(expected)); | |
| 593 } | |
| 594 | |
| 595 TEST_F(PolicyLoaderWinTest, DefaultPropertySchemaType) { | |
| 596 // Build a schema for an "object" with a default schema for its properties. | |
| 597 base::DictionaryValue default_schema; | |
| 598 default_schema.SetString(kType, "number"); | |
| 599 base::DictionaryValue integer_schema; | |
| 600 integer_schema.SetString(kType, "integer"); | |
| 601 base::DictionaryValue properties; | |
| 602 properties.Set("special-int1", integer_schema.DeepCopy()); | |
| 603 properties.Set("special-int2", integer_schema.DeepCopy()); | |
| 604 base::DictionaryValue schema; | |
| 605 schema.SetString(kType, "object"); | |
| 606 schema.Set(kProperties, properties.DeepCopy()); | |
| 607 schema.Set(kAdditionalProperties, default_schema.DeepCopy()); | |
| 608 | |
| 609 const string16 kPathSuffix = | |
| 610 kRegistryMandatorySubKey + ASCIIToUTF16("\\3rdparty\\extensions\\test"); | |
| 611 EXPECT_TRUE(WriteSchema(schema, HKEY_CURRENT_USER, kPathSuffix, kSchema)); | |
| 612 | |
| 613 // Write some test values. | |
| 614 base::DictionaryValue policy; | |
| 615 // These special values have a specific schema for them. | |
| 616 policy.SetInteger("special-int1", 123); | |
| 617 policy.SetString("special-int2", "-456"); | |
| 618 // Other values default to be loaded as doubles. | |
| 619 policy.SetInteger("double1", 789.0); | |
| 620 policy.SetString("double2", "123.456e7"); | |
| 621 policy.SetString("invalid", "omg"); | |
| 622 EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory)); | |
| 623 | |
| 624 base::DictionaryValue expected_policy; | |
| 625 expected_policy.SetInteger("special-int1", 123); | |
| 626 expected_policy.SetInteger("special-int2", -456); | |
| 627 expected_policy.SetDouble("double1", 789.0); | |
| 628 expected_policy.SetDouble("double2", 123.456e7); | |
| 629 PolicyBundle expected; | |
| 630 expected.Get(POLICY_DOMAIN_EXTENSIONS, "test") | |
| 631 .LoadFrom(&expected_policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER); | |
| 632 EXPECT_TRUE(Matches(expected)); | |
| 370 } | 633 } |
| 371 | 634 |
| 372 } // namespace policy | 635 } // namespace policy |
| OLD | NEW |