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
3 // found in the LICENSE file.
5 #include "components/policy/core/common/policy_loader_win.h"
16 #include "base/base_paths.h"
17 #include "base/callback.h"
18 #include "base/files/file_path.h"
19 #include "base/files/file_util.h"
20 #include "base/files/scoped_temp_dir.h"
21 #include "base/json/json_writer.h"
22 #include "base/path_service.h"
23 #include "base/process/process.h"
24 #include "base/strings/string16.h"
25 #include "base/strings/string_number_conversions.h"
26 #include "base/strings/string_util.h"
27 #include "base/strings/stringprintf.h"
28 #include "base/strings/utf_string_conversions.h"
29 #include "base/sys_byteorder.h"
30 #include "base/win/registry.h"
31 #include "base/win/win_util.h"
32 #include "components/policy/core/common/async_policy_provider.h"
33 #include "components/policy/core/common/configuration_policy_provider_test.h"
34 #include "components/policy/core/common/external_data_fetcher.h"
35 #include "components/policy/core/common/policy_bundle.h"
36 #include "components/policy/core/common/policy_map.h"
37 #include "components/policy/core/common/preg_parser_win.h"
38 #include "components/policy/core/common/schema_map.h"
39 #include "testing/gtest/include/gtest/gtest.h"
41 using base::UTF8ToUTF16;
42 using base::UTF16ToUTF8;
43 using base::win::RegKey;
49 // Constants for registry key names.
50 const wchar_t kPathSep[] = L"\\";
51 const wchar_t kThirdParty[] = L"3rdparty";
52 const wchar_t kMandatory[] = L"policy";
53 const wchar_t kRecommended[] = L"recommended";
54 const char kSchema[] = "schema";
55 const wchar_t kTestPolicyKey[] = L"chrome.policy.key";
57 // Installs |value| in the given registry |path| and |hive|, under the key
58 // |name|. Returns false on errors.
59 // Some of the possible Value types are stored after a conversion (e.g. doubles
60 // are stored as strings), and can only be retrieved if a corresponding schema
62 bool InstallValue(const base::Value& value,
64 const base::string16& path,
65 const base::string16& name) {
66 // KEY_ALL_ACCESS causes the ctor to create the key if it does not exist yet.
67 RegKey key(hive, path.c_str(), KEY_ALL_ACCESS);
68 EXPECT_TRUE(key.Valid());
69 switch (value.GetType()) {
70 case base::Value::TYPE_NULL:
71 return key.WriteValue(name.c_str(), L"") == ERROR_SUCCESS;
73 case base::Value::TYPE_BOOLEAN: {
75 if (!value.GetAsBoolean(&bool_value))
77 return key.WriteValue(name.c_str(), bool_value ? 1 : 0) == ERROR_SUCCESS;
80 case base::Value::TYPE_INTEGER: {
82 if (!value.GetAsInteger(&int_value))
84 return key.WriteValue(name.c_str(), int_value) == ERROR_SUCCESS;
87 case base::Value::TYPE_DOUBLE: {
89 if (!value.GetAsDouble(&double_value))
91 base::string16 str_value =
92 UTF8ToUTF16(base::DoubleToString(double_value));
93 return key.WriteValue(name.c_str(), str_value.c_str()) == ERROR_SUCCESS;
96 case base::Value::TYPE_STRING: {
97 base::string16 str_value;
98 if (!value.GetAsString(&str_value))
100 return key.WriteValue(name.c_str(), str_value.c_str()) == ERROR_SUCCESS;
103 case base::Value::TYPE_DICTIONARY: {
104 const base::DictionaryValue* sub_dict = NULL;
105 if (!value.GetAsDictionary(&sub_dict))
107 for (base::DictionaryValue::Iterator it(*sub_dict);
108 !it.IsAtEnd(); it.Advance()) {
109 if (!InstallValue(it.value(), hive, path + kPathSep + name,
110 UTF8ToUTF16(it.key()))) {
117 case base::Value::TYPE_LIST: {
118 const base::ListValue* list = NULL;
119 if (!value.GetAsList(&list))
121 for (size_t i = 0; i < list->GetSize(); ++i) {
122 const base::Value* item;
123 if (!list->Get(i, &item))
125 if (!InstallValue(*item, hive, path + kPathSep + name,
126 base::UintToString16(i + 1))) {
133 case base::Value::TYPE_BINARY:
140 // This class provides sandboxing and mocking for the parts of the Windows
141 // Registry implementing Group Policy. It prepares two temporary sandbox keys,
142 // one for HKLM and one for HKCU. A test's calls to the registry are redirected
143 // by Windows to these sandboxes, allowing the tests to manipulate and access
144 // policy as if it were active, but without actually changing the parts of the
145 // Registry that are managed by Group Policy.
146 class ScopedGroupPolicyRegistrySandbox {
148 ScopedGroupPolicyRegistrySandbox();
149 ~ScopedGroupPolicyRegistrySandbox();
152 void ActivateOverrides();
153 void RemoveOverrides();
155 // Deletes the sandbox keys.
158 std::wstring key_name_;
160 // Keys are created for the lifetime of a test to contain
161 // the sandboxed HKCU and HKLM hives, respectively.
162 RegKey temp_hkcu_hive_key_;
163 RegKey temp_hklm_hive_key_;
165 DISALLOW_COPY_AND_ASSIGN(ScopedGroupPolicyRegistrySandbox);
168 // A test harness that feeds policy via the Chrome GPO registry subtree.
169 class RegistryTestHarness : public PolicyProviderTestHarness,
170 public AppliedGPOListProvider {
172 RegistryTestHarness(HKEY hive, PolicyScope scope);
173 virtual ~RegistryTestHarness();
175 // PolicyProviderTestHarness:
176 virtual void SetUp() OVERRIDE;
178 virtual ConfigurationPolicyProvider* CreateProvider(
179 SchemaRegistry* registry,
180 scoped_refptr<base::SequencedTaskRunner> task_runner) OVERRIDE;
182 virtual void InstallEmptyPolicy() OVERRIDE;
183 virtual void InstallStringPolicy(const std::string& policy_name,
184 const std::string& policy_value) OVERRIDE;
185 virtual void InstallIntegerPolicy(const std::string& policy_name,
186 int policy_value) OVERRIDE;
187 virtual void InstallBooleanPolicy(const std::string& policy_name,
188 bool policy_value) OVERRIDE;
189 virtual void InstallStringListPolicy(
190 const std::string& policy_name,
191 const base::ListValue* policy_value) OVERRIDE;
192 virtual void InstallDictionaryPolicy(
193 const std::string& policy_name,
194 const base::DictionaryValue* policy_value) OVERRIDE;
195 virtual void Install3rdPartyPolicy(
196 const base::DictionaryValue* policies) OVERRIDE;
198 // AppliedGPOListProvider:
199 virtual DWORD GetAppliedGPOList(DWORD flags,
200 LPCTSTR machine_name,
202 GUID* extension_guid,
203 PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE;
204 virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE;
206 // Creates a harness instance that will install policy in HKCU or HKLM,
208 static PolicyProviderTestHarness* CreateHKCU();
209 static PolicyProviderTestHarness* CreateHKLM();
214 ScopedGroupPolicyRegistrySandbox registry_sandbox_;
216 DISALLOW_COPY_AND_ASSIGN(RegistryTestHarness);
219 // A test harness that generates PReg files for the provider to read.
220 class PRegTestHarness : public PolicyProviderTestHarness,
221 public AppliedGPOListProvider {
224 virtual ~PRegTestHarness();
226 // PolicyProviderTestHarness:
227 virtual void SetUp() OVERRIDE;
229 virtual ConfigurationPolicyProvider* CreateProvider(
230 SchemaRegistry* registry,
231 scoped_refptr<base::SequencedTaskRunner> task_runner) OVERRIDE;
233 virtual void InstallEmptyPolicy() OVERRIDE;
234 virtual void InstallStringPolicy(const std::string& policy_name,
235 const std::string& policy_value) OVERRIDE;
236 virtual void InstallIntegerPolicy(const std::string& policy_name,
237 int policy_value) OVERRIDE;
238 virtual void InstallBooleanPolicy(const std::string& policy_name,
239 bool policy_value) OVERRIDE;
240 virtual void InstallStringListPolicy(
241 const std::string& policy_name,
242 const base::ListValue* policy_value) OVERRIDE;
243 virtual void InstallDictionaryPolicy(
244 const std::string& policy_name,
245 const base::DictionaryValue* policy_value) OVERRIDE;
246 virtual void Install3rdPartyPolicy(
247 const base::DictionaryValue* policies) OVERRIDE;
249 // AppliedGPOListProvider:
250 virtual DWORD GetAppliedGPOList(DWORD flags,
251 LPCTSTR machine_name,
253 GUID* extension_guid,
254 PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE;
255 virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE;
257 // Creates a harness instance.
258 static PolicyProviderTestHarness* Create();
261 // Helper to append a base::string16 to an uint8 buffer.
262 static void AppendChars(std::vector<uint8>* buffer,
263 const base::string16& chars);
265 // Appends a record with the given fields to the PReg file.
266 void AppendRecordToPRegFile(const base::string16& path,
267 const std::string& key,
272 // Appends the given DWORD |value| for |path| + |key| to the PReg file.
273 void AppendDWORDToPRegFile(const base::string16& path,
274 const std::string& key,
277 // Appends the given string |value| for |path| + |key| to the PReg file.
278 void AppendStringToPRegFile(const base::string16& path,
279 const std::string& key,
280 const std::string& value);
282 // Appends the given policy |value| for |path| + |key| to the PReg file,
283 // converting and recursing as necessary.
284 void AppendPolicyToPRegFile(const base::string16& path,
285 const std::string& key,
286 const base::Value* value);
288 base::ScopedTempDir temp_dir_;
289 base::FilePath preg_file_path_;
290 GROUP_POLICY_OBJECT gpo_;
292 DISALLOW_COPY_AND_ASSIGN(PRegTestHarness);
295 ScopedGroupPolicyRegistrySandbox::ScopedGroupPolicyRegistrySandbox() {
296 // Generate a unique registry key for the override for each test. This
297 // makes sure that tests executing in parallel won't delete each other's
298 // key, at DeleteKeys().
299 key_name_ = base::ASCIIToWide(base::StringPrintf(
300 "SOFTWARE\\chromium unittest %d",
301 base::Process::Current().pid()));
302 std::wstring hklm_key_name = key_name_ + L"\\HKLM";
303 std::wstring hkcu_key_name = key_name_ + L"\\HKCU";
305 // Create the subkeys to hold the overridden HKLM and HKCU
307 temp_hklm_hive_key_.Create(HKEY_CURRENT_USER,
308 hklm_key_name.c_str(),
310 temp_hkcu_hive_key_.Create(HKEY_CURRENT_USER,
311 hkcu_key_name.c_str(),
317 ScopedGroupPolicyRegistrySandbox::~ScopedGroupPolicyRegistrySandbox() {
322 void ScopedGroupPolicyRegistrySandbox::ActivateOverrides() {
323 ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_LOCAL_MACHINE,
324 temp_hklm_hive_key_.Handle()));
325 ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_CURRENT_USER,
326 temp_hkcu_hive_key_.Handle()));
329 void ScopedGroupPolicyRegistrySandbox::RemoveOverrides() {
330 ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_LOCAL_MACHINE, 0));
331 ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_CURRENT_USER, 0));
334 void ScopedGroupPolicyRegistrySandbox::DeleteKeys() {
335 RegKey key(HKEY_CURRENT_USER, key_name_.c_str(), KEY_ALL_ACCESS);
336 ASSERT_TRUE(key.Valid());
340 RegistryTestHarness::RegistryTestHarness(HKEY hive, PolicyScope scope)
341 : PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY, scope), hive_(hive) {}
343 RegistryTestHarness::~RegistryTestHarness() {}
345 void RegistryTestHarness::SetUp() {}
347 ConfigurationPolicyProvider* RegistryTestHarness::CreateProvider(
348 SchemaRegistry* registry,
349 scoped_refptr<base::SequencedTaskRunner> task_runner) {
350 base::win::SetDomainStateForTesting(true);
351 scoped_ptr<AsyncPolicyLoader> loader(
352 new PolicyLoaderWin(task_runner, kTestPolicyKey, this));
353 return new AsyncPolicyProvider(registry, loader.Pass());
356 void RegistryTestHarness::InstallEmptyPolicy() {}
358 void RegistryTestHarness::InstallStringPolicy(
359 const std::string& policy_name,
360 const std::string& policy_value) {
361 RegKey key(hive_, kTestPolicyKey, KEY_ALL_ACCESS);
362 ASSERT_TRUE(key.Valid());
363 ASSERT_HRESULT_SUCCEEDED(key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
364 UTF8ToUTF16(policy_value).c_str()));
367 void RegistryTestHarness::InstallIntegerPolicy(
368 const std::string& policy_name,
370 RegKey key(hive_, kTestPolicyKey, KEY_ALL_ACCESS);
371 ASSERT_TRUE(key.Valid());
372 key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
373 static_cast<DWORD>(policy_value));
376 void RegistryTestHarness::InstallBooleanPolicy(
377 const std::string& policy_name,
379 RegKey key(hive_, kTestPolicyKey, KEY_ALL_ACCESS);
380 ASSERT_TRUE(key.Valid());
381 key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
382 static_cast<DWORD>(policy_value));
385 void RegistryTestHarness::InstallStringListPolicy(
386 const std::string& policy_name,
387 const base::ListValue* policy_value) {
389 (base::string16(kTestPolicyKey) + base::ASCIIToUTF16("\\") +
390 UTF8ToUTF16(policy_name)).c_str(),
392 ASSERT_TRUE(key.Valid());
394 for (base::ListValue::const_iterator element(policy_value->begin());
395 element != policy_value->end();
397 std::string element_value;
398 if (!(*element)->GetAsString(&element_value))
400 std::string name(base::IntToString(index++));
401 key.WriteValue(UTF8ToUTF16(name).c_str(),
402 UTF8ToUTF16(element_value).c_str());
406 void RegistryTestHarness::InstallDictionaryPolicy(
407 const std::string& policy_name,
408 const base::DictionaryValue* policy_value) {
410 base::JSONWriter::Write(policy_value, &json);
411 RegKey key(hive_, kTestPolicyKey, KEY_ALL_ACCESS);
412 ASSERT_TRUE(key.Valid());
413 key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
414 UTF8ToUTF16(json).c_str());
417 void RegistryTestHarness::Install3rdPartyPolicy(
418 const base::DictionaryValue* policies) {
419 // The first level entries are domains, and the second level entries map
420 // components to their policy.
421 const base::string16 kPathPrefix =
422 base::string16(kTestPolicyKey) + kPathSep + kThirdParty + kPathSep;
423 for (base::DictionaryValue::Iterator domain(*policies);
424 !domain.IsAtEnd(); domain.Advance()) {
425 const base::DictionaryValue* components = NULL;
426 if (!domain.value().GetAsDictionary(&components)) {
430 for (base::DictionaryValue::Iterator component(*components);
431 !component.IsAtEnd(); component.Advance()) {
432 const base::string16 path = kPathPrefix +
433 UTF8ToUTF16(domain.key()) + kPathSep + UTF8ToUTF16(component.key());
434 InstallValue(component.value(), hive_, path, kMandatory);
439 DWORD RegistryTestHarness::GetAppliedGPOList(DWORD flags,
440 LPCTSTR machine_name,
442 GUID* extension_guid,
443 PGROUP_POLICY_OBJECT* gpo_list) {
445 return ERROR_ACCESS_DENIED;
448 BOOL RegistryTestHarness::FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) {
453 PolicyProviderTestHarness* RegistryTestHarness::CreateHKCU() {
454 return new RegistryTestHarness(HKEY_CURRENT_USER, POLICY_SCOPE_USER);
458 PolicyProviderTestHarness* RegistryTestHarness::CreateHKLM() {
459 return new RegistryTestHarness(HKEY_LOCAL_MACHINE, POLICY_SCOPE_MACHINE);
462 PRegTestHarness::PRegTestHarness()
463 : PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE) {}
465 PRegTestHarness::~PRegTestHarness() {}
467 void PRegTestHarness::SetUp() {
468 base::win::SetDomainStateForTesting(false);
469 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
470 preg_file_path_ = temp_dir_.path().Append(PolicyLoaderWin::kPRegFileName);
471 ASSERT_TRUE(base::WriteFile(preg_file_path_,
472 preg_parser::kPRegFileHeader,
473 arraysize(preg_parser::kPRegFileHeader)));
475 memset(&gpo_, 0, sizeof(GROUP_POLICY_OBJECT));
476 gpo_.lpFileSysPath = const_cast<wchar_t*>(temp_dir_.path().value().c_str());
479 ConfigurationPolicyProvider* PRegTestHarness::CreateProvider(
480 SchemaRegistry* registry,
481 scoped_refptr<base::SequencedTaskRunner> task_runner) {
482 scoped_ptr<AsyncPolicyLoader> loader(
483 new PolicyLoaderWin(task_runner, kTestPolicyKey, this));
484 return new AsyncPolicyProvider(registry, loader.Pass());
487 void PRegTestHarness::InstallEmptyPolicy() {}
489 void PRegTestHarness::InstallStringPolicy(const std::string& policy_name,
490 const std::string& policy_value) {
491 AppendStringToPRegFile(kTestPolicyKey, policy_name, policy_value);
494 void PRegTestHarness::InstallIntegerPolicy(const std::string& policy_name,
496 AppendDWORDToPRegFile(kTestPolicyKey, policy_name, policy_value);
499 void PRegTestHarness::InstallBooleanPolicy(const std::string& policy_name,
501 AppendDWORDToPRegFile(kTestPolicyKey, policy_name, policy_value);
504 void PRegTestHarness::InstallStringListPolicy(
505 const std::string& policy_name,
506 const base::ListValue* policy_value) {
507 AppendPolicyToPRegFile(kTestPolicyKey, policy_name, policy_value);
510 void PRegTestHarness::InstallDictionaryPolicy(
511 const std::string& policy_name,
512 const base::DictionaryValue* policy_value) {
514 base::JSONWriter::Write(policy_value, &json);
515 AppendStringToPRegFile(kTestPolicyKey, policy_name, json);
518 void PRegTestHarness::Install3rdPartyPolicy(
519 const base::DictionaryValue* policies) {
520 // The first level entries are domains, and the second level entries map
521 // components to their policy.
522 const base::string16 kPathPrefix =
523 base::string16(kTestPolicyKey) + kPathSep + kThirdParty + kPathSep;
524 for (base::DictionaryValue::Iterator domain(*policies);
525 !domain.IsAtEnd(); domain.Advance()) {
526 const base::DictionaryValue* components = NULL;
527 if (!domain.value().GetAsDictionary(&components)) {
531 const base::string16 domain_path = kPathPrefix + UTF8ToUTF16(domain.key());
532 for (base::DictionaryValue::Iterator component(*components);
533 !component.IsAtEnd(); component.Advance()) {
534 const base::string16 component_path =
535 domain_path + kPathSep + UTF8ToUTF16(component.key());
536 AppendPolicyToPRegFile(component_path, UTF16ToUTF8(kMandatory),
542 DWORD PRegTestHarness::GetAppliedGPOList(DWORD flags,
543 LPCTSTR machine_name,
545 GUID* extension_guid,
546 PGROUP_POLICY_OBJECT* gpo_list) {
547 *gpo_list = flags & GPO_LIST_FLAG_MACHINE ? &gpo_ : NULL;
548 return ERROR_SUCCESS;
551 BOOL PRegTestHarness::FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) {
556 PolicyProviderTestHarness* PRegTestHarness::Create() {
557 return new PRegTestHarness();
561 void PRegTestHarness::AppendChars(std::vector<uint8>* buffer,
562 const base::string16& chars) {
563 for (base::string16::const_iterator c(chars.begin()); c != chars.end(); ++c) {
564 buffer->push_back(*c & 0xff);
565 buffer->push_back((*c >> 8) & 0xff);
569 void PRegTestHarness::AppendRecordToPRegFile(const base::string16& path,
570 const std::string& key,
574 std::vector<uint8> buffer;
575 AppendChars(&buffer, L"[");
576 AppendChars(&buffer, path);
577 AppendChars(&buffer, base::string16(L"\0;", 2));
578 AppendChars(&buffer, UTF8ToUTF16(key));
579 AppendChars(&buffer, base::string16(L"\0;", 2));
580 type = base::ByteSwapToLE32(type);
581 uint8* type_data = reinterpret_cast<uint8*>(&type);
582 buffer.insert(buffer.end(), type_data, type_data + sizeof(DWORD));
583 AppendChars(&buffer, L";");
584 size = base::ByteSwapToLE32(size);
585 uint8* size_data = reinterpret_cast<uint8*>(&size);
586 buffer.insert(buffer.end(), size_data, size_data + sizeof(DWORD));
587 AppendChars(&buffer, L";");
588 buffer.insert(buffer.end(), data, data + size);
589 AppendChars(&buffer, L"]");
591 ASSERT_EQ(buffer.size(),
594 reinterpret_cast<const char*>(vector_as_array(&buffer)),
598 void PRegTestHarness::AppendDWORDToPRegFile(const base::string16& path,
599 const std::string& key,
601 value = base::ByteSwapToLE32(value);
602 AppendRecordToPRegFile(path, key, REG_DWORD, sizeof(DWORD),
603 reinterpret_cast<uint8*>(&value));
606 void PRegTestHarness::AppendStringToPRegFile(const base::string16& path,
607 const std::string& key,
608 const std::string& value) {
609 base::string16 string16_value(UTF8ToUTF16(value));
610 std::vector<base::char16> data;
611 std::transform(string16_value.begin(), string16_value.end(),
612 std::back_inserter(data), std::ptr_fun(base::ByteSwapToLE16));
613 data.push_back(base::ByteSwapToLE16(L'\0'));
615 AppendRecordToPRegFile(path, key, REG_SZ, data.size() * sizeof(base::char16),
616 reinterpret_cast<uint8*>(vector_as_array(&data)));
619 void PRegTestHarness::AppendPolicyToPRegFile(const base::string16& path,
620 const std::string& key,
621 const base::Value* value) {
622 switch (value->GetType()) {
623 case base::Value::TYPE_BOOLEAN: {
624 bool boolean_value = false;
625 ASSERT_TRUE(value->GetAsBoolean(&boolean_value));
626 AppendDWORDToPRegFile(path, key, boolean_value);
629 case base::Value::TYPE_INTEGER: {
631 ASSERT_TRUE(value->GetAsInteger(&int_value));
632 AppendDWORDToPRegFile(path, key, int_value);
635 case base::Value::TYPE_DOUBLE: {
636 double double_value = 0;
637 ASSERT_TRUE(value->GetAsDouble(&double_value));
638 AppendStringToPRegFile(path, key, base::DoubleToString(double_value));
641 case base::Value::TYPE_STRING: {
642 std::string string_value;
643 ASSERT_TRUE(value->GetAsString(&string_value));
644 AppendStringToPRegFile(path, key, string_value);
647 case base::Value::TYPE_DICTIONARY: {
648 base::string16 subpath = path + kPathSep + UTF8ToUTF16(key);
649 const base::DictionaryValue* dict = NULL;
650 ASSERT_TRUE(value->GetAsDictionary(&dict));
651 for (base::DictionaryValue::Iterator entry(*dict); !entry.IsAtEnd();
653 AppendPolicyToPRegFile(subpath, entry.key(), &entry.value());
657 case base::Value::TYPE_LIST: {
658 base::string16 subpath = path + kPathSep + UTF8ToUTF16(key);
659 const base::ListValue* list = NULL;
660 ASSERT_TRUE(value->GetAsList(&list));
661 for (size_t i = 0; i < list->GetSize(); ++i) {
662 const base::Value* entry = NULL;
663 ASSERT_TRUE(list->Get(i, &entry));
664 AppendPolicyToPRegFile(subpath, base::IntToString(i + 1), entry);
668 case base::Value::TYPE_BINARY:
669 case base::Value::TYPE_NULL: {
678 // Instantiate abstract test case for basic policy reading tests.
679 INSTANTIATE_TEST_CASE_P(
680 PolicyProviderWinTest,
681 ConfigurationPolicyProviderTest,
682 testing::Values(RegistryTestHarness::CreateHKCU,
683 RegistryTestHarness::CreateHKLM,
684 PRegTestHarness::Create));
686 // Instantiate abstract test case for 3rd party policy reading tests.
687 INSTANTIATE_TEST_CASE_P(
688 ThirdPartyPolicyProviderWinTest,
689 Configuration3rdPartyPolicyProviderTest,
690 testing::Values(RegistryTestHarness::CreateHKCU,
691 RegistryTestHarness::CreateHKLM,
692 PRegTestHarness::Create));
694 // Test cases for windows policy provider specific functionality.
695 class PolicyLoaderWinTest : public PolicyTestBase,
696 public AppliedGPOListProvider {
698 // The policy key this tests places data under. This must match the data
699 // files in chrome/test/data/policy/gpo.
700 static const base::char16 kTestPolicyKey[];
702 PolicyLoaderWinTest()
704 gpo_list_status_(ERROR_ACCESS_DENIED) {}
705 virtual ~PolicyLoaderWinTest() {}
707 virtual void SetUp() OVERRIDE {
708 base::win::SetDomainStateForTesting(false);
709 PolicyTestBase::SetUp();
711 ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir_));
712 test_data_dir_ = test_data_dir_.AppendASCII("chrome")
715 .AppendASCII("policy")
719 // AppliedGPOListProvider:
720 virtual DWORD GetAppliedGPOList(DWORD flags,
721 LPCTSTR machine_name,
723 GUID* extension_guid,
724 PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE {
725 *gpo_list = gpo_list_;
726 return gpo_list_status_;
728 virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE {
732 void InitGPO(GROUP_POLICY_OBJECT* gpo,
734 const base::FilePath& path,
735 GROUP_POLICY_OBJECT* next,
736 GROUP_POLICY_OBJECT* prev) {
737 memset(gpo, 0, sizeof(GROUP_POLICY_OBJECT));
738 gpo->dwOptions = options;
739 gpo->lpFileSysPath = const_cast<wchar_t*>(path.value().c_str());
744 bool Matches(const PolicyBundle& expected) {
745 PolicyLoaderWin loader(loop_.message_loop_proxy(), kTestPolicyKey, this);
746 scoped_ptr<PolicyBundle> loaded(
747 loader.InitialLoad(schema_registry_.schema_map()));
748 return loaded->Equals(expected);
751 void InstallRegistrySentinel() {
752 RegKey hklm_key(HKEY_CURRENT_USER, kTestPolicyKey, KEY_ALL_ACCESS);
753 ASSERT_TRUE(hklm_key.Valid());
755 UTF8ToUTF16(test_keys::kKeyString).c_str(),
756 UTF8ToUTF16("registry").c_str());
759 bool MatchesRegistrySentinel() {
760 base::DictionaryValue expected_policy;
761 expected_policy.SetString(test_keys::kKeyString, "registry");
762 PolicyBundle expected;
763 expected.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
764 .LoadFrom(&expected_policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
765 return Matches(expected);
768 bool MatchesTestBundle() {
769 base::DictionaryValue expected_policy;
770 expected_policy.SetBoolean(test_keys::kKeyBoolean, true);
771 expected_policy.SetString(test_keys::kKeyString, "GPO");
772 expected_policy.SetInteger(test_keys::kKeyInteger, 42);
773 scoped_ptr<base::ListValue> list(new base::ListValue());
774 list->AppendString("GPO 1");
775 list->AppendString("GPO 2");
776 expected_policy.Set(test_keys::kKeyStringList, list.release());
777 PolicyBundle expected;
778 expected.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
779 .LoadFrom(&expected_policy, POLICY_LEVEL_MANDATORY,
780 POLICY_SCOPE_MACHINE);
781 return Matches(expected);
784 ScopedGroupPolicyRegistrySandbox registry_sandbox_;
785 PGROUP_POLICY_OBJECT gpo_list_;
786 DWORD gpo_list_status_;
787 base::FilePath test_data_dir_;
790 const base::char16 PolicyLoaderWinTest::kTestPolicyKey[] =
791 L"SOFTWARE\\Policies\\Chromium";
793 TEST_F(PolicyLoaderWinTest, HKLMOverHKCU) {
794 RegKey hklm_key(HKEY_LOCAL_MACHINE, kTestPolicyKey, KEY_ALL_ACCESS);
795 ASSERT_TRUE(hklm_key.Valid());
796 hklm_key.WriteValue(UTF8ToUTF16(test_keys::kKeyString).c_str(),
797 UTF8ToUTF16("hklm").c_str());
798 RegKey hkcu_key(HKEY_CURRENT_USER, kTestPolicyKey, KEY_ALL_ACCESS);
799 ASSERT_TRUE(hkcu_key.Valid());
800 hkcu_key.WriteValue(UTF8ToUTF16(test_keys::kKeyString).c_str(),
801 UTF8ToUTF16("hkcu").c_str());
803 PolicyBundle expected;
804 expected.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
805 .Set(test_keys::kKeyString,
806 POLICY_LEVEL_MANDATORY,
807 POLICY_SCOPE_MACHINE,
808 new base::StringValue("hklm"),
810 EXPECT_TRUE(Matches(expected));
813 TEST_F(PolicyLoaderWinTest, Merge3rdPartyPolicies) {
814 // Policy for the same extension will be provided at the 4 level/scope
815 // combinations, to verify that they overlap as expected.
816 const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "merge");
817 ASSERT_TRUE(RegisterSchema(
820 " \"type\": \"object\","
822 " \"a\": { \"type\": \"string\" },"
823 " \"b\": { \"type\": \"string\" },"
824 " \"c\": { \"type\": \"string\" },"
825 " \"d\": { \"type\": \"string\" }"
829 const base::string16 kPathSuffix =
830 kTestPolicyKey + base::ASCIIToUTF16("\\3rdparty\\extensions\\merge");
832 const char kUserMandatory[] = "user-mandatory";
833 const char kUserRecommended[] = "user-recommended";
834 const char kMachineMandatory[] = "machine-mandatory";
835 const char kMachineRecommended[] = "machine-recommended";
837 base::DictionaryValue policy;
838 policy.SetString("a", kMachineMandatory);
839 EXPECT_TRUE(InstallValue(policy, HKEY_LOCAL_MACHINE,
840 kPathSuffix, kMandatory));
841 policy.SetString("a", kUserMandatory);
842 policy.SetString("b", kUserMandatory);
843 EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER,
844 kPathSuffix, kMandatory));
845 policy.SetString("a", kMachineRecommended);
846 policy.SetString("b", kMachineRecommended);
847 policy.SetString("c", kMachineRecommended);
848 EXPECT_TRUE(InstallValue(policy, HKEY_LOCAL_MACHINE,
849 kPathSuffix, kRecommended));
850 policy.SetString("a", kUserRecommended);
851 policy.SetString("b", kUserRecommended);
852 policy.SetString("c", kUserRecommended);
853 policy.SetString("d", kUserRecommended);
854 EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER,
855 kPathSuffix, kRecommended));
857 PolicyBundle expected;
858 PolicyMap& expected_policy = expected.Get(ns);
859 expected_policy.Set("a",
860 POLICY_LEVEL_MANDATORY,
861 POLICY_SCOPE_MACHINE,
862 new base::StringValue(kMachineMandatory),
864 expected_policy.Set("b",
865 POLICY_LEVEL_MANDATORY,
867 new base::StringValue(kUserMandatory),
869 expected_policy.Set("c",
870 POLICY_LEVEL_RECOMMENDED,
871 POLICY_SCOPE_MACHINE,
872 new base::StringValue(kMachineRecommended),
874 expected_policy.Set("d",
875 POLICY_LEVEL_RECOMMENDED,
877 new base::StringValue(kUserRecommended),
879 EXPECT_TRUE(Matches(expected));
882 TEST_F(PolicyLoaderWinTest, LoadStringEncodedValues) {
883 // Create a dictionary with all the types that can be stored encoded in a
885 const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "string");
886 ASSERT_TRUE(RegisterSchema(
889 " \"type\": \"object\","
890 " \"id\": \"MainType\","
892 " \"null\": { \"type\": \"null\" },"
893 " \"bool\": { \"type\": \"boolean\" },"
894 " \"int\": { \"type\": \"integer\" },"
895 " \"double\": { \"type\": \"number\" },"
897 " \"type\": \"array\","
898 " \"items\": { \"$ref\": \"MainType\" }"
900 " \"dict\": { \"$ref\": \"MainType\" }"
904 base::DictionaryValue policy;
905 policy.Set("null", base::Value::CreateNullValue());
906 policy.SetBoolean("bool", true);
907 policy.SetInteger("int", -123);
908 policy.SetDouble("double", 456.78e9);
909 base::ListValue list;
910 list.Append(policy.DeepCopy());
911 list.Append(policy.DeepCopy());
912 policy.Set("list", list.DeepCopy());
913 // Encode |policy| before adding the "dict" entry.
914 std::string encoded_dict;
915 base::JSONWriter::Write(&policy, &encoded_dict);
916 ASSERT_FALSE(encoded_dict.empty());
917 policy.Set("dict", policy.DeepCopy());
918 std::string encoded_list;
919 base::JSONWriter::Write(&list, &encoded_list);
920 ASSERT_FALSE(encoded_list.empty());
921 base::DictionaryValue encoded_policy;
922 encoded_policy.SetString("null", "");
923 encoded_policy.SetString("bool", "1");
924 encoded_policy.SetString("int", "-123");
925 encoded_policy.SetString("double", "456.78e9");
926 encoded_policy.SetString("list", encoded_list);
927 encoded_policy.SetString("dict", encoded_dict);
929 const base::string16 kPathSuffix =
930 kTestPolicyKey + base::ASCIIToUTF16("\\3rdparty\\extensions\\string");
932 InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
934 PolicyBundle expected;
935 expected.Get(ns).LoadFrom(&policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
936 EXPECT_TRUE(Matches(expected));
939 TEST_F(PolicyLoaderWinTest, LoadIntegerEncodedValues) {
940 const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "int");
941 ASSERT_TRUE(RegisterSchema(
944 " \"type\": \"object\","
946 " \"bool\": { \"type\": \"boolean\" },"
947 " \"int\": { \"type\": \"integer\" },"
948 " \"double\": { \"type\": \"number\" }"
952 base::DictionaryValue encoded_policy;
953 encoded_policy.SetInteger("bool", 1);
954 encoded_policy.SetInteger("int", 123);
955 encoded_policy.SetInteger("double", 456);
957 const base::string16 kPathSuffix =
958 kTestPolicyKey + base::ASCIIToUTF16("\\3rdparty\\extensions\\int");
960 InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
962 base::DictionaryValue policy;
963 policy.SetBoolean("bool", true);
964 policy.SetInteger("int", 123);
965 policy.SetDouble("double", 456.0);
966 PolicyBundle expected;
967 expected.Get(ns).LoadFrom(&policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
968 EXPECT_TRUE(Matches(expected));
971 TEST_F(PolicyLoaderWinTest, DefaultPropertySchemaType) {
972 // Build a schema for an "object" with a default schema for its properties.
973 // Note that the top-level object can't have "additionalProperties", so
974 // a "policy" property is used instead.
975 const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "test");
976 ASSERT_TRUE(RegisterSchema(
979 " \"type\": \"object\","
982 " \"type\": \"object\","
984 " \"special-int1\": { \"type\": \"integer\" },"
985 " \"special-int2\": { \"type\": \"integer\" }"
987 " \"additionalProperties\": { \"type\": \"number\" }"
992 // Write some test values.
993 base::DictionaryValue policy;
994 // These special values have a specific schema for them.
995 policy.SetInteger("special-int1", 123);
996 policy.SetString("special-int2", "-456");
997 // Other values default to be loaded as doubles.
998 policy.SetInteger("double1", 789.0);
999 policy.SetString("double2", "123.456e7");
1000 policy.SetString("invalid", "omg");
1001 base::DictionaryValue all_policies;
1002 all_policies.Set("policy", policy.DeepCopy());
1004 const base::string16 kPathSuffix =
1005 kTestPolicyKey + base::ASCIIToUTF16("\\3rdparty\\extensions\\test");
1007 InstallValue(all_policies, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
1009 base::DictionaryValue expected_policy;
1010 expected_policy.SetInteger("special-int1", 123);
1011 expected_policy.SetInteger("special-int2", -456);
1012 expected_policy.SetDouble("double1", 789.0);
1013 expected_policy.SetDouble("double2", 123.456e7);
1014 base::DictionaryValue expected_policies;
1015 expected_policies.Set("policy", expected_policy.DeepCopy());
1016 PolicyBundle expected;
1017 expected.Get(ns).LoadFrom(
1018 &expected_policies, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
1019 EXPECT_TRUE(Matches(expected));
1022 TEST_F(PolicyLoaderWinTest, AppliedPolicyNotPresent) {
1023 InstallRegistrySentinel();
1025 gpo_list_status_ = ERROR_SUCCESS;
1028 EXPECT_TRUE(Matches(empty));
1031 TEST_F(PolicyLoaderWinTest, AppliedPolicyEmpty) {
1032 InstallRegistrySentinel();
1033 base::FilePath gpo_dir(test_data_dir_.AppendASCII("empty"));
1034 GROUP_POLICY_OBJECT gpo;
1035 InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1037 gpo_list_status_ = ERROR_SUCCESS;
1040 EXPECT_TRUE(Matches(empty));
1043 TEST_F(PolicyLoaderWinTest, AppliedPolicyInDomain) {
1044 base::win::SetDomainStateForTesting(true);
1045 InstallRegistrySentinel();
1046 base::FilePath gpo_dir(test_data_dir_.AppendASCII("empty"));
1047 GROUP_POLICY_OBJECT gpo;
1048 InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1050 gpo_list_status_ = ERROR_SUCCESS;
1053 EXPECT_TRUE(MatchesRegistrySentinel());
1056 TEST_F(PolicyLoaderWinTest, AppliedPolicyNonExistingFile) {
1057 InstallRegistrySentinel();
1058 GROUP_POLICY_OBJECT gpo;
1059 InitGPO(&gpo, 0, test_data_dir_, NULL, NULL);
1061 gpo_list_status_ = ERROR_SUCCESS;
1063 EXPECT_TRUE(MatchesRegistrySentinel());
1066 TEST_F(PolicyLoaderWinTest, AppliedPolicyBadPath) {
1067 InstallRegistrySentinel();
1068 base::FilePath gpo_dir(test_data_dir_.AppendASCII("bad"));
1069 GROUP_POLICY_OBJECT gpo;
1070 InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1072 gpo_list_status_ = ERROR_SUCCESS;
1074 EXPECT_TRUE(MatchesRegistrySentinel());
1077 TEST_F(PolicyLoaderWinTest, AppliedPolicyPresent) {
1078 InstallRegistrySentinel();
1079 base::FilePath gpo_dir(test_data_dir_.AppendASCII("test1"));
1080 GROUP_POLICY_OBJECT gpo;
1081 InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1083 gpo_list_status_ = ERROR_SUCCESS;
1085 EXPECT_TRUE(MatchesTestBundle());
1088 TEST_F(PolicyLoaderWinTest, AppliedPolicyMerged) {
1089 InstallRegistrySentinel();
1090 base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test2"));
1091 base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test1"));
1092 GROUP_POLICY_OBJECT gpo1;
1093 GROUP_POLICY_OBJECT gpo2;
1094 InitGPO(&gpo1, 0, gpo1_dir, &gpo2, NULL);
1095 InitGPO(&gpo2, 0, gpo2_dir, NULL, &gpo1);
1097 gpo_list_status_ = ERROR_SUCCESS;
1099 EXPECT_TRUE(MatchesTestBundle());
1102 TEST_F(PolicyLoaderWinTest, AppliedPolicyDisabled) {
1103 InstallRegistrySentinel();
1104 base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test1"));
1105 base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test2"));
1106 GROUP_POLICY_OBJECT gpo1;
1107 GROUP_POLICY_OBJECT gpo2;
1108 InitGPO(&gpo1, 0, gpo1_dir, &gpo2, NULL);
1109 InitGPO(&gpo2, GPO_FLAG_DISABLE, gpo2_dir, NULL, &gpo1);
1111 gpo_list_status_ = ERROR_SUCCESS;
1113 EXPECT_TRUE(MatchesTestBundle());
1116 TEST_F(PolicyLoaderWinTest, AppliedPolicyForcedPolicy) {
1117 InstallRegistrySentinel();
1118 base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test1"));
1119 base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test2"));
1120 GROUP_POLICY_OBJECT gpo1;
1121 GROUP_POLICY_OBJECT gpo2;
1122 InitGPO(&gpo1, GPO_FLAG_FORCE, gpo1_dir, &gpo2, NULL);
1123 InitGPO(&gpo2, 0, gpo2_dir, NULL, &gpo1);
1125 gpo_list_status_ = ERROR_SUCCESS;
1127 EXPECT_TRUE(MatchesTestBundle());
1130 TEST_F(PolicyLoaderWinTest, AppliedPolicyUNCPath) {
1131 InstallRegistrySentinel();
1132 base::FilePath gpo_dir(test_data_dir_.AppendASCII("test1"));
1133 base::FilePath unc_path(L"\\\\some_share\\GPO");
1134 GROUP_POLICY_OBJECT gpo1;
1135 GROUP_POLICY_OBJECT gpo2;
1136 InitGPO(&gpo1, 0, gpo_dir, &gpo2, NULL);
1137 InitGPO(&gpo2, 0, unc_path, NULL, &gpo1);
1139 gpo_list_status_ = ERROR_SUCCESS;
1141 EXPECT_TRUE(MatchesRegistrySentinel());
1144 TEST_F(PolicyLoaderWinTest, LoadExtensionPolicyAlternativeSpelling) {
1145 base::FilePath gpo_dir(
1146 test_data_dir_.AppendASCII("extension_alternative_spelling"));
1147 GROUP_POLICY_OBJECT gpo;
1148 InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1150 gpo_list_status_ = ERROR_SUCCESS;
1152 const char kTestSchema[] =
1154 " \"type\": \"object\","
1155 " \"properties\": {"
1156 " \"policy 1\": { \"type\": \"integer\" },"
1157 " \"policy 2\": { \"type\": \"integer\" }"
1160 const PolicyNamespace ns_a(
1161 POLICY_DOMAIN_EXTENSIONS, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
1162 const PolicyNamespace ns_b(
1163 POLICY_DOMAIN_EXTENSIONS, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
1164 ASSERT_TRUE(RegisterSchema(ns_a, kTestSchema));
1165 ASSERT_TRUE(RegisterSchema(ns_b, kTestSchema));
1167 PolicyBundle expected;
1168 base::DictionaryValue expected_a;
1169 expected_a.SetInteger("policy 1", 3);
1170 expected_a.SetInteger("policy 2", 3);
1171 expected.Get(ns_a).LoadFrom(
1172 &expected_a, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
1173 base::DictionaryValue expected_b;
1174 expected_b.SetInteger("policy 1", 2);
1175 expected.Get(ns_b).LoadFrom(
1176 &expected_b, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
1177 EXPECT_TRUE(Matches(expected));
1180 TEST_F(PolicyLoaderWinTest, LBSSupport) {
1181 const PolicyNamespace ns(
1182 POLICY_DOMAIN_EXTENSIONS, "heildphpnddilhkemkielfhnkaagiabh");
1183 schema_registry_.RegisterComponent(ns, Schema());
1185 const char kIncompleteSchema[] =
1187 " \"type\": \"object\","
1188 " \"properties\": {"
1189 " \"url_list\": { \"type\": \"array\" },"
1190 " \"url_greylist\": { \"type\": \"array\" }"
1194 const base::string16 kPathSuffix =
1195 kTestPolicyKey + base::ASCIIToUTF16("\\3rdparty\\extensions");
1197 base::ListValue list;
1198 list.AppendString("youtube.com");
1199 base::DictionaryValue policy;
1200 policy.Set("url_list", list.DeepCopy());
1201 policy.SetString("alternative_browser_path", "c:\\legacy\\browser.exe");
1202 base::DictionaryValue root;
1203 root.Set(base::UTF16ToUTF8(kMandatory), policy.DeepCopy());
1204 root.SetString(kSchema, kIncompleteSchema);
1205 EXPECT_TRUE(InstallValue(root, HKEY_LOCAL_MACHINE,
1206 kPathSuffix, base::ASCIIToUTF16(ns.component_id)));
1208 PolicyBundle expected;
1209 PolicyMap& expected_policy = expected.Get(ns);
1210 expected_policy.Set("alternative_browser_path",
1211 POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
1212 new base::StringValue("c:\\legacy\\browser.exe"), NULL);
1213 expected_policy.Set("url_list", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
1214 list.DeepCopy(), NULL);
1215 EXPECT_TRUE(Matches(expected));
1218 } // namespace policy