policy_loader_win_unittest.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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.
4
5#include "components/policy/core/common/policy_loader_win.h"
6
7#include <windows.h>
8#include <userenv.h>
9
10#include <algorithm>
11#include <cstring>
12#include <functional>
13#include <iterator>
14#include <vector>
15
16#include "base/base_paths.h"
17#include "base/callback.h"
18#include "base/file_util.h"
19#include "base/files/file_path.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 "components/policy/core/common/async_policy_provider.h"
32#include "components/policy/core/common/configuration_policy_provider_test.h"
33#include "components/policy/core/common/external_data_fetcher.h"
34#include "components/policy/core/common/policy_bundle.h"
35#include "components/policy/core/common/policy_map.h"
36#include "components/policy/core/common/preg_parser_win.h"
37#include "components/policy/core/common/schema_map.h"
38#include "testing/gtest/include/gtest/gtest.h"
39
40using base::win::RegKey;
41
42namespace policy {
43
44namespace {
45
46// Constants for registry key names.
47const wchar_t kPathSep[] = L"\\";
48const wchar_t kThirdParty[] = L"3rdparty";
49const wchar_t kMandatory[] = L"policy";
50const wchar_t kRecommended[] = L"recommended";
51const char kSchema[] = "schema";
52const wchar_t kTestPolicyKey[] = L"chrome.policy.key";
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.
59bool InstallValue(const base::Value& value,
60                  HKEY hive,
61                  const string16& path,
62                  const string16& name) {
63  // KEY_ALL_ACCESS causes the ctor to create the key if it does not exist yet.
64  RegKey key(hive, path.c_str(), KEY_ALL_ACCESS);
65  EXPECT_TRUE(key.Valid());
66  switch (value.GetType()) {
67    case base::Value::TYPE_NULL:
68      return key.WriteValue(name.c_str(), L"") == ERROR_SUCCESS;
69
70    case base::Value::TYPE_BOOLEAN: {
71      bool bool_value;
72      if (!value.GetAsBoolean(&bool_value))
73        return false;
74      return key.WriteValue(name.c_str(), bool_value ? 1 : 0) == ERROR_SUCCESS;
75    }
76
77    case base::Value::TYPE_INTEGER: {
78      int int_value;
79      if (!value.GetAsInteger(&int_value))
80        return false;
81      return key.WriteValue(name.c_str(), int_value) == ERROR_SUCCESS;
82    }
83
84    case base::Value::TYPE_DOUBLE: {
85      double double_value;
86      if (!value.GetAsDouble(&double_value))
87        return false;
88      string16 str_value = UTF8ToUTF16(base::DoubleToString(double_value));
89      return key.WriteValue(name.c_str(), str_value.c_str()) == ERROR_SUCCESS;
90    }
91
92    case base::Value::TYPE_STRING: {
93      string16 str_value;
94      if (!value.GetAsString(&str_value))
95        return false;
96      return key.WriteValue(name.c_str(), str_value.c_str()) == ERROR_SUCCESS;
97    }
98
99    case base::Value::TYPE_DICTIONARY: {
100      const base::DictionaryValue* sub_dict = NULL;
101      if (!value.GetAsDictionary(&sub_dict))
102        return false;
103      for (base::DictionaryValue::Iterator it(*sub_dict);
104           !it.IsAtEnd(); it.Advance()) {
105        if (!InstallValue(it.value(), hive, path + kPathSep + name,
106                          UTF8ToUTF16(it.key()))) {
107          return false;
108        }
109      }
110      return true;
111    }
112
113    case base::Value::TYPE_LIST: {
114      const base::ListValue* list = NULL;
115      if (!value.GetAsList(&list))
116        return false;
117      for (size_t i = 0; i < list->GetSize(); ++i) {
118        const base::Value* item;
119        if (!list->Get(i, &item))
120          return false;
121        if (!InstallValue(*item, hive, path + kPathSep + name,
122                          base::UintToString16(i + 1))) {
123          return false;
124        }
125      }
126      return true;
127    }
128
129    case base::Value::TYPE_BINARY:
130      return false;
131  }
132  NOTREACHED();
133  return false;
134}
135
136// This class provides sandboxing and mocking for the parts of the Windows
137// Registry implementing Group Policy. It prepares two temporary sandbox keys,
138// one for HKLM and one for HKCU. A test's calls to the registry are redirected
139// by Windows to these sandboxes, allowing the tests to manipulate and access
140// policy as if it were active, but without actually changing the parts of the
141// Registry that are managed by Group Policy.
142class ScopedGroupPolicyRegistrySandbox {
143 public:
144  ScopedGroupPolicyRegistrySandbox();
145  ~ScopedGroupPolicyRegistrySandbox();
146
147 private:
148  void ActivateOverrides();
149  void RemoveOverrides();
150
151  // Deletes the sandbox keys.
152  void DeleteKeys();
153
154  std::wstring key_name_;
155
156  // Keys are created for the lifetime of a test to contain
157  // the sandboxed HKCU and HKLM hives, respectively.
158  RegKey temp_hkcu_hive_key_;
159  RegKey temp_hklm_hive_key_;
160
161  DISALLOW_COPY_AND_ASSIGN(ScopedGroupPolicyRegistrySandbox);
162};
163
164// A test harness that feeds policy via the Chrome GPO registry subtree.
165class RegistryTestHarness : public PolicyProviderTestHarness,
166                            public AppliedGPOListProvider {
167 public:
168  RegistryTestHarness(HKEY hive, PolicyScope scope);
169  virtual ~RegistryTestHarness();
170
171  // PolicyProviderTestHarness:
172  virtual void SetUp() OVERRIDE;
173
174  virtual ConfigurationPolicyProvider* CreateProvider(
175      SchemaRegistry* registry,
176      scoped_refptr<base::SequencedTaskRunner> task_runner) OVERRIDE;
177
178  virtual void InstallEmptyPolicy() OVERRIDE;
179  virtual void InstallStringPolicy(const std::string& policy_name,
180                                   const std::string& policy_value) OVERRIDE;
181  virtual void InstallIntegerPolicy(const std::string& policy_name,
182                                    int policy_value) OVERRIDE;
183  virtual void InstallBooleanPolicy(const std::string& policy_name,
184                                    bool policy_value) OVERRIDE;
185  virtual void InstallStringListPolicy(
186      const std::string& policy_name,
187      const base::ListValue* policy_value) OVERRIDE;
188  virtual void InstallDictionaryPolicy(
189      const std::string& policy_name,
190      const base::DictionaryValue* policy_value) OVERRIDE;
191  virtual void Install3rdPartyPolicy(
192      const base::DictionaryValue* policies) OVERRIDE;
193
194  // AppliedGPOListProvider:
195  virtual DWORD GetAppliedGPOList(DWORD flags,
196                                  LPCTSTR machine_name,
197                                  PSID sid_user,
198                                  GUID* extension_guid,
199                                  PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE;
200  virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE;
201
202  // Creates a harness instance that will install policy in HKCU or HKLM,
203  // respectively.
204  static PolicyProviderTestHarness* CreateHKCU();
205  static PolicyProviderTestHarness* CreateHKLM();
206
207 private:
208  HKEY hive_;
209
210  ScopedGroupPolicyRegistrySandbox registry_sandbox_;
211
212  DISALLOW_COPY_AND_ASSIGN(RegistryTestHarness);
213};
214
215// A test harness that generates PReg files for the provider to read.
216class PRegTestHarness : public PolicyProviderTestHarness,
217                        public AppliedGPOListProvider {
218 public:
219  PRegTestHarness();
220  virtual ~PRegTestHarness();
221
222  // PolicyProviderTestHarness:
223  virtual void SetUp() OVERRIDE;
224
225  virtual ConfigurationPolicyProvider* CreateProvider(
226      SchemaRegistry* registry,
227      scoped_refptr<base::SequencedTaskRunner> task_runner) OVERRIDE;
228
229  virtual void InstallEmptyPolicy() OVERRIDE;
230  virtual void InstallStringPolicy(const std::string& policy_name,
231                                   const std::string& policy_value) OVERRIDE;
232  virtual void InstallIntegerPolicy(const std::string& policy_name,
233                                    int policy_value) OVERRIDE;
234  virtual void InstallBooleanPolicy(const std::string& policy_name,
235                                    bool policy_value) OVERRIDE;
236  virtual void InstallStringListPolicy(
237      const std::string& policy_name,
238      const base::ListValue* policy_value) OVERRIDE;
239  virtual void InstallDictionaryPolicy(
240      const std::string& policy_name,
241      const base::DictionaryValue* policy_value) OVERRIDE;
242  virtual void Install3rdPartyPolicy(
243      const base::DictionaryValue* policies) OVERRIDE;
244
245  // AppliedGPOListProvider:
246  virtual DWORD GetAppliedGPOList(DWORD flags,
247                                  LPCTSTR machine_name,
248                                  PSID sid_user,
249                                  GUID* extension_guid,
250                                  PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE;
251  virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE;
252
253  // Creates a harness instance.
254  static PolicyProviderTestHarness* Create();
255
256 private:
257  // Helper to append a string16 to an uint8 buffer.
258  static void AppendChars(std::vector<uint8>* buffer, const string16& chars);
259
260  // Appends a record with the given fields to the PReg file.
261  void AppendRecordToPRegFile(const string16& path,
262                              const std::string& key,
263                              DWORD type,
264                              DWORD size,
265                              uint8* data);
266
267  // Appends the given DWORD |value| for |path| + |key| to the PReg file.
268  void AppendDWORDToPRegFile(const string16& path,
269                             const std::string& key,
270                             DWORD value);
271
272  // Appends the given string |value| for |path| + |key| to the PReg file.
273  void AppendStringToPRegFile(const string16& path,
274                              const std::string& key,
275                              const std::string& value);
276
277  // Appends the given policy |value| for |path| + |key| to the PReg file,
278  // converting and recursing as necessary.
279  void AppendPolicyToPRegFile(const string16& path,
280                              const std::string& key,
281                              const base::Value* value);
282
283  base::ScopedTempDir temp_dir_;
284  base::FilePath preg_file_path_;
285  GROUP_POLICY_OBJECT gpo_;
286
287  DISALLOW_COPY_AND_ASSIGN(PRegTestHarness);
288};
289
290ScopedGroupPolicyRegistrySandbox::ScopedGroupPolicyRegistrySandbox() {
291  // Generate a unique registry key for the override for each test. This
292  // makes sure that tests executing in parallel won't delete each other's
293  // key, at DeleteKeys().
294  key_name_ = ASCIIToWide(base::StringPrintf(
295        "SOFTWARE\\chromium unittest %d",
296        base::Process::Current().pid()));
297  std::wstring hklm_key_name = key_name_ + L"\\HKLM";
298  std::wstring hkcu_key_name = key_name_ + L"\\HKCU";
299
300  // Create the subkeys to hold the overridden HKLM and HKCU
301  // policy settings.
302  temp_hklm_hive_key_.Create(HKEY_CURRENT_USER,
303                             hklm_key_name.c_str(),
304                             KEY_ALL_ACCESS);
305  temp_hkcu_hive_key_.Create(HKEY_CURRENT_USER,
306                             hkcu_key_name.c_str(),
307                             KEY_ALL_ACCESS);
308
309  ActivateOverrides();
310}
311
312ScopedGroupPolicyRegistrySandbox::~ScopedGroupPolicyRegistrySandbox() {
313  RemoveOverrides();
314  DeleteKeys();
315}
316
317void ScopedGroupPolicyRegistrySandbox::ActivateOverrides() {
318  ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_LOCAL_MACHINE,
319                                                temp_hklm_hive_key_.Handle()));
320  ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_CURRENT_USER,
321                                                temp_hkcu_hive_key_.Handle()));
322}
323
324void ScopedGroupPolicyRegistrySandbox::RemoveOverrides() {
325  ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_LOCAL_MACHINE, 0));
326  ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_CURRENT_USER, 0));
327}
328
329void ScopedGroupPolicyRegistrySandbox::DeleteKeys() {
330  RegKey key(HKEY_CURRENT_USER, key_name_.c_str(), KEY_ALL_ACCESS);
331  ASSERT_TRUE(key.Valid());
332  key.DeleteKey(L"");
333}
334
335RegistryTestHarness::RegistryTestHarness(HKEY hive, PolicyScope scope)
336    : PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY, scope), hive_(hive) {}
337
338RegistryTestHarness::~RegistryTestHarness() {}
339
340void RegistryTestHarness::SetUp() {}
341
342ConfigurationPolicyProvider* RegistryTestHarness::CreateProvider(
343    SchemaRegistry* registry,
344    scoped_refptr<base::SequencedTaskRunner> task_runner) {
345  scoped_ptr<AsyncPolicyLoader> loader(
346      new PolicyLoaderWin(task_runner, kTestPolicyKey, this));
347  return new AsyncPolicyProvider(registry, loader.Pass());
348}
349
350void RegistryTestHarness::InstallEmptyPolicy() {}
351
352void RegistryTestHarness::InstallStringPolicy(
353    const std::string& policy_name,
354    const std::string& policy_value) {
355  RegKey key(hive_, kTestPolicyKey, KEY_ALL_ACCESS);
356  ASSERT_TRUE(key.Valid());
357  ASSERT_HRESULT_SUCCEEDED(key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
358                                          UTF8ToUTF16(policy_value).c_str()));
359}
360
361void RegistryTestHarness::InstallIntegerPolicy(
362    const std::string& policy_name,
363    int policy_value) {
364  RegKey key(hive_, kTestPolicyKey, KEY_ALL_ACCESS);
365  ASSERT_TRUE(key.Valid());
366  key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
367                 static_cast<DWORD>(policy_value));
368}
369
370void RegistryTestHarness::InstallBooleanPolicy(
371    const std::string& policy_name,
372    bool policy_value) {
373  RegKey key(hive_, kTestPolicyKey, KEY_ALL_ACCESS);
374  ASSERT_TRUE(key.Valid());
375  key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
376                 static_cast<DWORD>(policy_value));
377}
378
379void RegistryTestHarness::InstallStringListPolicy(
380    const std::string& policy_name,
381    const base::ListValue* policy_value) {
382  RegKey key(hive_,
383             (string16(kTestPolicyKey) + ASCIIToUTF16("\\") +
384              UTF8ToUTF16(policy_name)).c_str(),
385             KEY_ALL_ACCESS);
386  ASSERT_TRUE(key.Valid());
387  int index = 1;
388  for (base::ListValue::const_iterator element(policy_value->begin());
389       element != policy_value->end();
390       ++element) {
391    std::string element_value;
392    if (!(*element)->GetAsString(&element_value))
393      continue;
394    std::string name(base::IntToString(index++));
395    key.WriteValue(UTF8ToUTF16(name).c_str(),
396                   UTF8ToUTF16(element_value).c_str());
397  }
398}
399
400void RegistryTestHarness::InstallDictionaryPolicy(
401    const std::string& policy_name,
402    const base::DictionaryValue* policy_value) {
403  std::string json;
404  base::JSONWriter::Write(policy_value, &json);
405  RegKey key(hive_, kTestPolicyKey, KEY_ALL_ACCESS);
406  ASSERT_TRUE(key.Valid());
407  key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
408                 UTF8ToUTF16(json).c_str());
409}
410
411void RegistryTestHarness::Install3rdPartyPolicy(
412    const base::DictionaryValue* policies) {
413  // The first level entries are domains, and the second level entries map
414  // components to their policy.
415  const string16 kPathPrefix = string16(kTestPolicyKey) + kPathSep +
416                               kThirdParty + kPathSep;
417  for (base::DictionaryValue::Iterator domain(*policies);
418       !domain.IsAtEnd(); domain.Advance()) {
419    const base::DictionaryValue* components = NULL;
420    if (!domain.value().GetAsDictionary(&components)) {
421      ADD_FAILURE();
422      continue;
423    }
424    for (base::DictionaryValue::Iterator component(*components);
425         !component.IsAtEnd(); component.Advance()) {
426      const string16 path = kPathPrefix +
427                            UTF8ToUTF16(domain.key()) + kPathSep +
428                            UTF8ToUTF16(component.key());
429      InstallValue(component.value(), hive_, path, kMandatory);
430    }
431  }
432}
433
434DWORD RegistryTestHarness::GetAppliedGPOList(DWORD flags,
435                                             LPCTSTR machine_name,
436                                             PSID sid_user,
437                                             GUID* extension_guid,
438                                             PGROUP_POLICY_OBJECT* gpo_list) {
439  *gpo_list = NULL;
440  return ERROR_ACCESS_DENIED;
441}
442
443BOOL RegistryTestHarness::FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) {
444  return TRUE;
445}
446
447// static
448PolicyProviderTestHarness* RegistryTestHarness::CreateHKCU() {
449  return new RegistryTestHarness(HKEY_CURRENT_USER, POLICY_SCOPE_USER);
450}
451
452// static
453PolicyProviderTestHarness* RegistryTestHarness::CreateHKLM() {
454  return new RegistryTestHarness(HKEY_LOCAL_MACHINE, POLICY_SCOPE_MACHINE);
455}
456
457PRegTestHarness::PRegTestHarness()
458    : PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE) {}
459
460PRegTestHarness::~PRegTestHarness() {}
461
462void PRegTestHarness::SetUp() {
463  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
464  preg_file_path_ = temp_dir_.path().Append(PolicyLoaderWin::kPRegFileName);
465  ASSERT_TRUE(file_util::WriteFile(preg_file_path_,
466                                   preg_parser::kPRegFileHeader,
467                                   arraysize(preg_parser::kPRegFileHeader)));
468
469  memset(&gpo_, 0, sizeof(GROUP_POLICY_OBJECT));
470  gpo_.lpFileSysPath = const_cast<wchar_t*>(temp_dir_.path().value().c_str());
471}
472
473ConfigurationPolicyProvider* PRegTestHarness::CreateProvider(
474    SchemaRegistry* registry,
475    scoped_refptr<base::SequencedTaskRunner> task_runner) {
476  scoped_ptr<AsyncPolicyLoader> loader(
477      new PolicyLoaderWin(task_runner, kTestPolicyKey, this));
478  return new AsyncPolicyProvider(registry, loader.Pass());
479}
480
481void PRegTestHarness::InstallEmptyPolicy() {}
482
483void PRegTestHarness::InstallStringPolicy(const std::string& policy_name,
484                                          const std::string& policy_value) {
485  AppendStringToPRegFile(kTestPolicyKey, policy_name, policy_value);
486}
487
488void PRegTestHarness::InstallIntegerPolicy(const std::string& policy_name,
489                                           int policy_value) {
490  AppendDWORDToPRegFile(kTestPolicyKey, policy_name, policy_value);
491}
492
493void PRegTestHarness::InstallBooleanPolicy(const std::string& policy_name,
494                                           bool policy_value) {
495  AppendDWORDToPRegFile(kTestPolicyKey, policy_name, policy_value);
496}
497
498void PRegTestHarness::InstallStringListPolicy(
499    const std::string& policy_name,
500    const base::ListValue* policy_value) {
501  AppendPolicyToPRegFile(kTestPolicyKey, policy_name, policy_value);
502}
503
504void PRegTestHarness::InstallDictionaryPolicy(
505    const std::string& policy_name,
506    const base::DictionaryValue* policy_value) {
507  std::string json;
508  base::JSONWriter::Write(policy_value, &json);
509  AppendStringToPRegFile(kTestPolicyKey, policy_name, json);
510}
511
512void PRegTestHarness::Install3rdPartyPolicy(
513    const base::DictionaryValue* policies) {
514  // The first level entries are domains, and the second level entries map
515  // components to their policy.
516  const string16 kPathPrefix = string16(kTestPolicyKey) + kPathSep +
517                               kThirdParty + kPathSep;
518  for (base::DictionaryValue::Iterator domain(*policies);
519       !domain.IsAtEnd(); domain.Advance()) {
520    const base::DictionaryValue* components = NULL;
521    if (!domain.value().GetAsDictionary(&components)) {
522      ADD_FAILURE();
523      continue;
524    }
525    const string16 domain_path = kPathPrefix + UTF8ToUTF16(domain.key());
526    for (base::DictionaryValue::Iterator component(*components);
527         !component.IsAtEnd(); component.Advance()) {
528      const string16 component_path =
529          domain_path + kPathSep + UTF8ToUTF16(component.key());
530      AppendPolicyToPRegFile(component_path, UTF16ToUTF8(kMandatory),
531                             &component.value());
532    }
533  }
534}
535
536DWORD PRegTestHarness::GetAppliedGPOList(DWORD flags,
537                                         LPCTSTR machine_name,
538                                         PSID sid_user,
539                                         GUID* extension_guid,
540                                         PGROUP_POLICY_OBJECT* gpo_list) {
541  *gpo_list = flags & GPO_LIST_FLAG_MACHINE ? &gpo_ : NULL;
542  return ERROR_SUCCESS;
543}
544
545BOOL PRegTestHarness::FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) {
546  return TRUE;
547}
548
549// static
550PolicyProviderTestHarness* PRegTestHarness::Create() {
551  return new PRegTestHarness();
552}
553
554// static
555void PRegTestHarness::AppendChars(std::vector<uint8>* buffer,
556                                  const string16& chars) {
557  for (string16::const_iterator c(chars.begin()); c != chars.end(); ++c) {
558    buffer->push_back(*c & 0xff);
559    buffer->push_back((*c >> 8) & 0xff);
560  }
561}
562
563void PRegTestHarness::AppendRecordToPRegFile(const string16& path,
564                                             const std::string& key,
565                                             DWORD type,
566                                             DWORD size,
567                                             uint8* data) {
568  std::vector<uint8> buffer;
569  AppendChars(&buffer, L"[");
570  AppendChars(&buffer, path);
571  AppendChars(&buffer, string16(L"\0;", 2));
572  AppendChars(&buffer, UTF8ToUTF16(key));
573  AppendChars(&buffer, string16(L"\0;", 2));
574  type = base::ByteSwapToLE32(type);
575  uint8* type_data = reinterpret_cast<uint8*>(&type);
576  buffer.insert(buffer.end(), type_data, type_data + sizeof(DWORD));
577  AppendChars(&buffer, L";");
578  size = base::ByteSwapToLE32(size);
579  uint8* size_data = reinterpret_cast<uint8*>(&size);
580  buffer.insert(buffer.end(), size_data, size_data + sizeof(DWORD));
581  AppendChars(&buffer, L";");
582  buffer.insert(buffer.end(), data, data + size);
583  AppendChars(&buffer, L"]");
584
585  ASSERT_EQ(buffer.size(),
586            file_util::AppendToFile(
587                preg_file_path_,
588                reinterpret_cast<const char*>(vector_as_array(&buffer)),
589                buffer.size()));
590}
591
592void PRegTestHarness::AppendDWORDToPRegFile(const string16& path,
593                                            const std::string& key,
594                                            DWORD value) {
595  value = base::ByteSwapToLE32(value);
596  AppendRecordToPRegFile(path, key, REG_DWORD, sizeof(DWORD),
597                         reinterpret_cast<uint8*>(&value));
598}
599
600void PRegTestHarness::AppendStringToPRegFile(const string16& path,
601                                             const std::string& key,
602                                             const std::string& value) {
603  string16 string16_value(UTF8ToUTF16(value));
604  std::vector<char16> data;
605  std::transform(string16_value.begin(), string16_value.end(),
606                 std::back_inserter(data), std::ptr_fun(base::ByteSwapToLE16));
607  data.push_back(base::ByteSwapToLE16(L'\0'));
608
609  AppendRecordToPRegFile(path, key, REG_SZ, data.size() * sizeof(char16),
610                         reinterpret_cast<uint8*>(vector_as_array(&data)));
611}
612
613void PRegTestHarness::AppendPolicyToPRegFile(const string16& path,
614                                             const std::string& key,
615                                             const base::Value* value) {
616  switch (value->GetType()) {
617    case base::Value::TYPE_BOOLEAN: {
618      bool boolean_value = false;
619      ASSERT_TRUE(value->GetAsBoolean(&boolean_value));
620      AppendDWORDToPRegFile(path, key, boolean_value);
621      break;
622    }
623    case base::Value::TYPE_INTEGER: {
624      int int_value = 0;
625      ASSERT_TRUE(value->GetAsInteger(&int_value));
626      AppendDWORDToPRegFile(path, key, int_value);
627      break;
628    }
629    case base::Value::TYPE_DOUBLE: {
630      double double_value = 0;
631      ASSERT_TRUE(value->GetAsDouble(&double_value));
632      AppendStringToPRegFile(path, key, base::DoubleToString(double_value));
633      break;
634    }
635    case base::Value::TYPE_STRING: {
636      std::string string_value;
637      ASSERT_TRUE(value->GetAsString(&string_value));
638      AppendStringToPRegFile(path, key, string_value);
639      break;
640    }
641    case base::Value::TYPE_DICTIONARY: {
642      string16 subpath = path + kPathSep + UTF8ToUTF16(key);
643      const base::DictionaryValue* dict = NULL;
644      ASSERT_TRUE(value->GetAsDictionary(&dict));
645      for (base::DictionaryValue::Iterator entry(*dict); !entry.IsAtEnd();
646           entry.Advance()) {
647        AppendPolicyToPRegFile(subpath, entry.key(), &entry.value());
648      }
649      break;
650    }
651    case base::Value::TYPE_LIST: {
652      string16 subpath = path + kPathSep + UTF8ToUTF16(key);
653      const base::ListValue* list = NULL;
654      ASSERT_TRUE(value->GetAsList(&list));
655      for (size_t i = 0; i < list->GetSize(); ++i) {
656        const base::Value* entry = NULL;
657        ASSERT_TRUE(list->Get(i, &entry));
658        AppendPolicyToPRegFile(subpath, base::IntToString(i + 1), entry);
659      }
660      break;
661    }
662    case base::Value::TYPE_BINARY:
663    case base::Value::TYPE_NULL: {
664      ADD_FAILURE();
665      break;
666    }
667  }
668}
669
670}  // namespace
671
672// Instantiate abstract test case for basic policy reading tests.
673INSTANTIATE_TEST_CASE_P(
674    PolicyProviderWinTest,
675    ConfigurationPolicyProviderTest,
676    testing::Values(RegistryTestHarness::CreateHKCU,
677                    RegistryTestHarness::CreateHKLM,
678                    PRegTestHarness::Create));
679
680// Instantiate abstract test case for 3rd party policy reading tests.
681INSTANTIATE_TEST_CASE_P(
682    ThirdPartyPolicyProviderWinTest,
683    Configuration3rdPartyPolicyProviderTest,
684    testing::Values(RegistryTestHarness::CreateHKCU,
685                    RegistryTestHarness::CreateHKLM,
686                    PRegTestHarness::Create));
687
688// Test cases for windows policy provider specific functionality.
689class PolicyLoaderWinTest : public PolicyTestBase,
690                            public AppliedGPOListProvider {
691 protected:
692  // The policy key this tests places data under. This must match the data
693  // files in chrome/test/data/policy/gpo.
694  static const char16 kTestPolicyKey[];
695
696  PolicyLoaderWinTest()
697      : gpo_list_(NULL),
698        gpo_list_status_(ERROR_ACCESS_DENIED) {}
699  virtual ~PolicyLoaderWinTest() {}
700
701  virtual void SetUp() OVERRIDE {
702    PolicyTestBase::SetUp();
703
704    ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir_));
705    test_data_dir_ = test_data_dir_.AppendASCII("chrome")
706                                   .AppendASCII("test")
707                                   .AppendASCII("data")
708                                   .AppendASCII("policy")
709                                   .AppendASCII("gpo");
710  }
711
712  // AppliedGPOListProvider:
713  virtual DWORD GetAppliedGPOList(DWORD flags,
714                                  LPCTSTR machine_name,
715                                  PSID sid_user,
716                                  GUID* extension_guid,
717                                  PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE {
718    *gpo_list = gpo_list_;
719    return gpo_list_status_;
720  }
721  virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE {
722    return TRUE;
723  }
724
725  void InitGPO(GROUP_POLICY_OBJECT* gpo,
726               DWORD options,
727               const base::FilePath& path,
728               GROUP_POLICY_OBJECT* next,
729               GROUP_POLICY_OBJECT* prev) {
730    memset(gpo, 0, sizeof(GROUP_POLICY_OBJECT));
731    gpo->dwOptions = options;
732    gpo->lpFileSysPath = const_cast<wchar_t*>(path.value().c_str());
733    gpo->pNext = next;
734    gpo->pPrev = prev;
735  }
736
737  bool Matches(const PolicyBundle& expected) {
738    PolicyLoaderWin loader(loop_.message_loop_proxy(), kTestPolicyKey, this);
739    scoped_ptr<PolicyBundle> loaded(
740        loader.InitialLoad(schema_registry_.schema_map()));
741    return loaded->Equals(expected);
742  }
743
744  void InstallRegistrySentinel() {
745    RegKey hklm_key(HKEY_CURRENT_USER, kTestPolicyKey, KEY_ALL_ACCESS);
746    ASSERT_TRUE(hklm_key.Valid());
747    hklm_key.WriteValue(
748        UTF8ToUTF16(test_keys::kKeyString).c_str(),
749        UTF8ToUTF16("registry").c_str());
750  }
751
752  bool MatchesRegistrySentinel() {
753    base::DictionaryValue expected_policy;
754    expected_policy.SetString(test_keys::kKeyString, "registry");
755    PolicyBundle expected;
756    expected.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
757        .LoadFrom(&expected_policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
758    return Matches(expected);
759  }
760
761  bool MatchesTestBundle() {
762    base::DictionaryValue expected_policy;
763    expected_policy.SetBoolean(test_keys::kKeyBoolean, true);
764    expected_policy.SetString(test_keys::kKeyString, "GPO");
765    expected_policy.SetInteger(test_keys::kKeyInteger, 42);
766    scoped_ptr<base::ListValue> list(new base::ListValue());
767    list->AppendString("GPO 1");
768    list->AppendString("GPO 2");
769    expected_policy.Set(test_keys::kKeyStringList, list.release());
770    PolicyBundle expected;
771    expected.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
772        .LoadFrom(&expected_policy, POLICY_LEVEL_MANDATORY,
773                  POLICY_SCOPE_MACHINE);
774    return Matches(expected);
775  }
776
777  ScopedGroupPolicyRegistrySandbox registry_sandbox_;
778  PGROUP_POLICY_OBJECT gpo_list_;
779  DWORD gpo_list_status_;
780  base::FilePath test_data_dir_;
781};
782
783const char16 PolicyLoaderWinTest::kTestPolicyKey[] =
784    L"SOFTWARE\\Policies\\Chromium";
785
786TEST_F(PolicyLoaderWinTest, HKLMOverHKCU) {
787  RegKey hklm_key(HKEY_LOCAL_MACHINE, kTestPolicyKey, KEY_ALL_ACCESS);
788  ASSERT_TRUE(hklm_key.Valid());
789  hklm_key.WriteValue(UTF8ToUTF16(test_keys::kKeyString).c_str(),
790                      UTF8ToUTF16("hklm").c_str());
791  RegKey hkcu_key(HKEY_CURRENT_USER, kTestPolicyKey, KEY_ALL_ACCESS);
792  ASSERT_TRUE(hkcu_key.Valid());
793  hkcu_key.WriteValue(UTF8ToUTF16(test_keys::kKeyString).c_str(),
794                      UTF8ToUTF16("hkcu").c_str());
795
796  PolicyBundle expected;
797  expected.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
798      .Set(test_keys::kKeyString,
799           POLICY_LEVEL_MANDATORY,
800           POLICY_SCOPE_MACHINE,
801           base::Value::CreateStringValue("hklm"), NULL);
802  EXPECT_TRUE(Matches(expected));
803}
804
805TEST_F(PolicyLoaderWinTest, Merge3rdPartyPolicies) {
806  // Policy for the same extension will be provided at the 4 level/scope
807  // combinations, to verify that they overlap as expected.
808  const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "merge");
809  ASSERT_TRUE(RegisterSchema(
810      ns,
811      "{"
812      "  \"type\": \"object\","
813      "  \"properties\": {"
814      "    \"a\": { \"type\": \"string\" },"
815      "    \"b\": { \"type\": \"string\" },"
816      "    \"c\": { \"type\": \"string\" },"
817      "    \"d\": { \"type\": \"string\" }"
818      "  }"
819      "}"));
820
821  const string16 kPathSuffix =
822      kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\merge");
823
824  const char kUserMandatory[] = "user-mandatory";
825  const char kUserRecommended[] = "user-recommended";
826  const char kMachineMandatory[] = "machine-mandatory";
827  const char kMachineRecommended[] = "machine-recommended";
828
829  base::DictionaryValue policy;
830  policy.SetString("a", kMachineMandatory);
831  EXPECT_TRUE(InstallValue(policy, HKEY_LOCAL_MACHINE,
832                           kPathSuffix, kMandatory));
833  policy.SetString("a", kUserMandatory);
834  policy.SetString("b", kUserMandatory);
835  EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER,
836                           kPathSuffix, kMandatory));
837  policy.SetString("a", kMachineRecommended);
838  policy.SetString("b", kMachineRecommended);
839  policy.SetString("c", kMachineRecommended);
840  EXPECT_TRUE(InstallValue(policy, HKEY_LOCAL_MACHINE,
841                           kPathSuffix, kRecommended));
842  policy.SetString("a", kUserRecommended);
843  policy.SetString("b", kUserRecommended);
844  policy.SetString("c", kUserRecommended);
845  policy.SetString("d", kUserRecommended);
846  EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER,
847                           kPathSuffix, kRecommended));
848
849  PolicyBundle expected;
850  PolicyMap& expected_policy = expected.Get(ns);
851  expected_policy.Set("a", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
852                      base::Value::CreateStringValue(kMachineMandatory), NULL);
853  expected_policy.Set("b", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
854                      base::Value::CreateStringValue(kUserMandatory), NULL);
855  expected_policy.Set("c", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE,
856                      base::Value::CreateStringValue(kMachineRecommended),
857                      NULL);
858  expected_policy.Set("d", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER,
859                      base::Value::CreateStringValue(kUserRecommended), NULL);
860  EXPECT_TRUE(Matches(expected));
861}
862
863TEST_F(PolicyLoaderWinTest, LoadStringEncodedValues) {
864  // Create a dictionary with all the types that can be stored encoded in a
865  // string.
866  const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "string");
867  ASSERT_TRUE(RegisterSchema(
868      ns,
869      "{"
870      "  \"type\": \"object\","
871      "  \"id\": \"MainType\","
872      "  \"properties\": {"
873      "    \"null\": { \"type\": \"null\" },"
874      "    \"bool\": { \"type\": \"boolean\" },"
875      "    \"int\": { \"type\": \"integer\" },"
876      "    \"double\": { \"type\": \"number\" },"
877      "    \"list\": {"
878      "      \"type\": \"array\","
879      "      \"items\": { \"$ref\": \"MainType\" }"
880      "    },"
881      "    \"dict\": { \"$ref\": \"MainType\" }"
882      "  }"
883      "}"));
884
885  base::DictionaryValue policy;
886  policy.Set("null", base::Value::CreateNullValue());
887  policy.SetBoolean("bool", true);
888  policy.SetInteger("int", -123);
889  policy.SetDouble("double", 456.78e9);
890  base::ListValue list;
891  list.Append(policy.DeepCopy());
892  list.Append(policy.DeepCopy());
893  policy.Set("list", list.DeepCopy());
894  // Encode |policy| before adding the "dict" entry.
895  std::string encoded_dict;
896  base::JSONWriter::Write(&policy, &encoded_dict);
897  ASSERT_FALSE(encoded_dict.empty());
898  policy.Set("dict", policy.DeepCopy());
899  std::string encoded_list;
900  base::JSONWriter::Write(&list, &encoded_list);
901  ASSERT_FALSE(encoded_list.empty());
902  base::DictionaryValue encoded_policy;
903  encoded_policy.SetString("null", "");
904  encoded_policy.SetString("bool", "1");
905  encoded_policy.SetString("int", "-123");
906  encoded_policy.SetString("double", "456.78e9");
907  encoded_policy.SetString("list", encoded_list);
908  encoded_policy.SetString("dict", encoded_dict);
909
910  const string16 kPathSuffix =
911      kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\string");
912  EXPECT_TRUE(
913      InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
914
915  PolicyBundle expected;
916  expected.Get(ns).LoadFrom(&policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
917  EXPECT_TRUE(Matches(expected));
918}
919
920TEST_F(PolicyLoaderWinTest, LoadIntegerEncodedValues) {
921  const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "int");
922  ASSERT_TRUE(RegisterSchema(
923      ns,
924      "{"
925      "  \"type\": \"object\","
926      "  \"properties\": {"
927      "    \"bool\": { \"type\": \"boolean\" },"
928      "    \"int\": { \"type\": \"integer\" },"
929      "    \"double\": { \"type\": \"number\" }"
930      "  }"
931      "}"));
932
933  base::DictionaryValue encoded_policy;
934  encoded_policy.SetInteger("bool", 1);
935  encoded_policy.SetInteger("int", 123);
936  encoded_policy.SetInteger("double", 456);
937
938  const string16 kPathSuffix =
939      kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\int");
940  EXPECT_TRUE(
941      InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
942
943  base::DictionaryValue policy;
944  policy.SetBoolean("bool", true);
945  policy.SetInteger("int", 123);
946  policy.SetDouble("double", 456.0);
947  PolicyBundle expected;
948  expected.Get(ns).LoadFrom(&policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
949  EXPECT_TRUE(Matches(expected));
950}
951
952TEST_F(PolicyLoaderWinTest, DefaultPropertySchemaType) {
953  // Build a schema for an "object" with a default schema for its properties.
954  // Note that the top-level object can't have "additionalProperties", so
955  // a "policy" property is used instead.
956  const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "test");
957  ASSERT_TRUE(RegisterSchema(
958      ns,
959      "{"
960      "  \"type\": \"object\","
961      "  \"properties\": {"
962      "    \"policy\": {"
963      "      \"type\": \"object\","
964      "      \"properties\": {"
965      "        \"special-int1\": { \"type\": \"integer\" },"
966      "        \"special-int2\": { \"type\": \"integer\" }"
967      "      },"
968      "      \"additionalProperties\": { \"type\": \"number\" }"
969      "    }"
970      "  }"
971      "}"));
972
973  // Write some test values.
974  base::DictionaryValue policy;
975  // These special values have a specific schema for them.
976  policy.SetInteger("special-int1", 123);
977  policy.SetString("special-int2", "-456");
978  // Other values default to be loaded as doubles.
979  policy.SetInteger("double1", 789.0);
980  policy.SetString("double2", "123.456e7");
981  policy.SetString("invalid", "omg");
982  base::DictionaryValue all_policies;
983  all_policies.Set("policy", policy.DeepCopy());
984
985  const string16 kPathSuffix =
986      kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\test");
987  EXPECT_TRUE(
988      InstallValue(all_policies, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
989
990  base::DictionaryValue expected_policy;
991  expected_policy.SetInteger("special-int1", 123);
992  expected_policy.SetInteger("special-int2", -456);
993  expected_policy.SetDouble("double1", 789.0);
994  expected_policy.SetDouble("double2", 123.456e7);
995  base::DictionaryValue expected_policies;
996  expected_policies.Set("policy", expected_policy.DeepCopy());
997  PolicyBundle expected;
998  expected.Get(ns).LoadFrom(
999      &expected_policies, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
1000  EXPECT_TRUE(Matches(expected));
1001}
1002
1003TEST_F(PolicyLoaderWinTest, AppliedPolicyNotPresent) {
1004  InstallRegistrySentinel();
1005  gpo_list_ = NULL;
1006  gpo_list_status_ = ERROR_SUCCESS;
1007
1008  PolicyBundle empty;
1009  EXPECT_TRUE(Matches(empty));
1010}
1011
1012TEST_F(PolicyLoaderWinTest, AppliedPolicyEmpty) {
1013  InstallRegistrySentinel();
1014  base::FilePath gpo_dir(test_data_dir_.AppendASCII("empty"));
1015  GROUP_POLICY_OBJECT gpo;
1016  InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1017  gpo_list_ = &gpo;
1018  gpo_list_status_ = ERROR_SUCCESS;
1019
1020  PolicyBundle empty;
1021  EXPECT_TRUE(Matches(empty));
1022}
1023
1024TEST_F(PolicyLoaderWinTest, AppliedPolicyNonExistingFile) {
1025  InstallRegistrySentinel();
1026  GROUP_POLICY_OBJECT gpo;
1027  InitGPO(&gpo, 0, test_data_dir_, NULL, NULL);
1028  gpo_list_ = &gpo;
1029  gpo_list_status_ = ERROR_SUCCESS;
1030
1031  EXPECT_TRUE(MatchesRegistrySentinel());
1032}
1033
1034TEST_F(PolicyLoaderWinTest, AppliedPolicyBadPath) {
1035  InstallRegistrySentinel();
1036  base::FilePath gpo_dir(test_data_dir_.AppendASCII("bad"));
1037  GROUP_POLICY_OBJECT gpo;
1038  InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1039  gpo_list_ = &gpo;
1040  gpo_list_status_ = ERROR_SUCCESS;
1041
1042  EXPECT_TRUE(MatchesRegistrySentinel());
1043}
1044
1045TEST_F(PolicyLoaderWinTest, AppliedPolicyPresent) {
1046  InstallRegistrySentinel();
1047  base::FilePath gpo_dir(test_data_dir_.AppendASCII("test1"));
1048  GROUP_POLICY_OBJECT gpo;
1049  InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1050  gpo_list_ = &gpo;
1051  gpo_list_status_ = ERROR_SUCCESS;
1052
1053  EXPECT_TRUE(MatchesTestBundle());
1054}
1055
1056TEST_F(PolicyLoaderWinTest, AppliedPolicyMerged) {
1057  InstallRegistrySentinel();
1058  base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test2"));
1059  base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test1"));
1060  GROUP_POLICY_OBJECT gpo1;
1061  GROUP_POLICY_OBJECT gpo2;
1062  InitGPO(&gpo1, 0, gpo1_dir, &gpo2, NULL);
1063  InitGPO(&gpo2, 0, gpo2_dir, NULL, &gpo1);
1064  gpo_list_ = &gpo1;
1065  gpo_list_status_ = ERROR_SUCCESS;
1066
1067  EXPECT_TRUE(MatchesTestBundle());
1068}
1069
1070TEST_F(PolicyLoaderWinTest, AppliedPolicyDisabled) {
1071  InstallRegistrySentinel();
1072  base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test1"));
1073  base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test2"));
1074  GROUP_POLICY_OBJECT gpo1;
1075  GROUP_POLICY_OBJECT gpo2;
1076  InitGPO(&gpo1, 0, gpo1_dir, &gpo2, NULL);
1077  InitGPO(&gpo2, GPO_FLAG_DISABLE, gpo2_dir, NULL, &gpo1);
1078  gpo_list_ = &gpo1;
1079  gpo_list_status_ = ERROR_SUCCESS;
1080
1081  EXPECT_TRUE(MatchesTestBundle());
1082}
1083
1084TEST_F(PolicyLoaderWinTest, AppliedPolicyForcedPolicy) {
1085  InstallRegistrySentinel();
1086  base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test1"));
1087  base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test2"));
1088  GROUP_POLICY_OBJECT gpo1;
1089  GROUP_POLICY_OBJECT gpo2;
1090  InitGPO(&gpo1, GPO_FLAG_FORCE, gpo1_dir, &gpo2, NULL);
1091  InitGPO(&gpo2, 0, gpo2_dir, NULL, &gpo1);
1092  gpo_list_ = &gpo1;
1093  gpo_list_status_ = ERROR_SUCCESS;
1094
1095  EXPECT_TRUE(MatchesTestBundle());
1096}
1097
1098TEST_F(PolicyLoaderWinTest, AppliedPolicyUNCPath) {
1099  InstallRegistrySentinel();
1100  base::FilePath gpo_dir(test_data_dir_.AppendASCII("test1"));
1101  base::FilePath unc_path(L"\\\\some_share\\GPO");
1102  GROUP_POLICY_OBJECT gpo1;
1103  GROUP_POLICY_OBJECT gpo2;
1104  InitGPO(&gpo1, 0, gpo_dir, &gpo2, NULL);
1105  InitGPO(&gpo2, 0, unc_path, NULL, &gpo1);
1106  gpo_list_ = &gpo1;
1107  gpo_list_status_ = ERROR_SUCCESS;
1108
1109  EXPECT_TRUE(MatchesRegistrySentinel());
1110}
1111
1112TEST_F(PolicyLoaderWinTest, LoadExtensionPolicyAlternativeSpelling) {
1113  base::FilePath gpo_dir(
1114      test_data_dir_.AppendASCII("extension_alternative_spelling"));
1115  GROUP_POLICY_OBJECT gpo;
1116  InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1117  gpo_list_ = &gpo;
1118  gpo_list_status_ = ERROR_SUCCESS;
1119
1120  const char kTestSchema[] =
1121      "{"
1122      "  \"type\": \"object\","
1123      "  \"properties\": {"
1124      "    \"policy 1\": { \"type\": \"integer\" },"
1125      "    \"policy 2\": { \"type\": \"integer\" }"
1126      "  }"
1127      "}";
1128  const PolicyNamespace ns_a(
1129      POLICY_DOMAIN_EXTENSIONS, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
1130  const PolicyNamespace ns_b(
1131      POLICY_DOMAIN_EXTENSIONS, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
1132  ASSERT_TRUE(RegisterSchema(ns_a, kTestSchema));
1133  ASSERT_TRUE(RegisterSchema(ns_b, kTestSchema));
1134
1135  PolicyBundle expected;
1136  base::DictionaryValue expected_a;
1137  expected_a.SetInteger("policy 1", 3);
1138  expected_a.SetInteger("policy 2", 3);
1139  expected.Get(ns_a).LoadFrom(
1140      &expected_a, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
1141  base::DictionaryValue expected_b;
1142  expected_b.SetInteger("policy 1", 2);
1143  expected.Get(ns_b).LoadFrom(
1144      &expected_b, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
1145  EXPECT_TRUE(Matches(expected));
1146}
1147
1148TEST_F(PolicyLoaderWinTest, LBSSupport) {
1149  const PolicyNamespace ns(
1150      POLICY_DOMAIN_EXTENSIONS, "heildphpnddilhkemkielfhnkaagiabh");
1151  schema_registry_.RegisterComponent(ns, Schema());
1152
1153  const char kIncompleteSchema[] =
1154      "{"
1155       "  \"type\": \"object\","
1156       "  \"properties\": {"
1157       "    \"url_list\": { \"type\": \"array\" },"
1158       "    \"url_greylist\": { \"type\": \"array\" }"
1159       "  }"
1160      "}";
1161
1162  const string16 kPathSuffix =
1163      kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions");
1164
1165  base::ListValue list;
1166  list.AppendString("youtube.com");
1167  base::DictionaryValue policy;
1168  policy.Set("url_list", list.DeepCopy());
1169  policy.SetString("alternative_browser_path", "c:\\legacy\\browser.exe");
1170  base::DictionaryValue root;
1171  root.Set(UTF16ToUTF8(kMandatory), policy.DeepCopy());
1172  root.SetString(kSchema, kIncompleteSchema);
1173  EXPECT_TRUE(InstallValue(root, HKEY_LOCAL_MACHINE,
1174                           kPathSuffix, ASCIIToUTF16(ns.component_id)));
1175
1176  PolicyBundle expected;
1177  PolicyMap& expected_policy = expected.Get(ns);
1178  expected_policy.Set("alternative_browser_path",
1179                      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
1180                      new base::StringValue("c:\\legacy\\browser.exe"), NULL);
1181  expected_policy.Set("url_list", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
1182                      list.DeepCopy(), NULL);
1183  EXPECT_TRUE(Matches(expected));
1184}
1185
1186}  // namespace policy
1187