policy_loader_win_unittest.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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 "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"
40
41using base::UTF8ToUTF16;
42using base::UTF16ToUTF8;
43using base::win::RegKey;
44
45namespace policy {
46
47namespace {
48
49// Constants for registry key names.
50const wchar_t kPathSep[] = L"\\";
51const wchar_t kThirdParty[] = L"3rdparty";
52const wchar_t kMandatory[] = L"policy";
53const wchar_t kRecommended[] = L"recommended";
54const char kSchema[] = "schema";
55const wchar_t kTestPolicyKey[] = L"chrome.policy.key";
56
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
61// is written.
62bool InstallValue(const base::Value& value,
63                  HKEY hive,
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;
72
73    case base::Value::TYPE_BOOLEAN: {
74      bool bool_value;
75      if (!value.GetAsBoolean(&bool_value))
76        return false;
77      return key.WriteValue(name.c_str(), bool_value ? 1 : 0) == ERROR_SUCCESS;
78    }
79
80    case base::Value::TYPE_INTEGER: {
81      int int_value;
82      if (!value.GetAsInteger(&int_value))
83        return false;
84      return key.WriteValue(name.c_str(), int_value) == ERROR_SUCCESS;
85    }
86
87    case base::Value::TYPE_DOUBLE: {
88      double double_value;
89      if (!value.GetAsDouble(&double_value))
90        return false;
91      base::string16 str_value =
92          UTF8ToUTF16(base::DoubleToString(double_value));
93      return key.WriteValue(name.c_str(), str_value.c_str()) == ERROR_SUCCESS;
94    }
95
96    case base::Value::TYPE_STRING: {
97      base::string16 str_value;
98      if (!value.GetAsString(&str_value))
99        return false;
100      return key.WriteValue(name.c_str(), str_value.c_str()) == ERROR_SUCCESS;
101    }
102
103    case base::Value::TYPE_DICTIONARY: {
104      const base::DictionaryValue* sub_dict = NULL;
105      if (!value.GetAsDictionary(&sub_dict))
106        return false;
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()))) {
111          return false;
112        }
113      }
114      return true;
115    }
116
117    case base::Value::TYPE_LIST: {
118      const base::ListValue* list = NULL;
119      if (!value.GetAsList(&list))
120        return false;
121      for (size_t i = 0; i < list->GetSize(); ++i) {
122        const base::Value* item;
123        if (!list->Get(i, &item))
124          return false;
125        if (!InstallValue(*item, hive, path + kPathSep + name,
126                          base::UintToString16(i + 1))) {
127          return false;
128        }
129      }
130      return true;
131    }
132
133    case base::Value::TYPE_BINARY:
134      return false;
135  }
136  NOTREACHED();
137  return false;
138}
139
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.
146class ScopedGroupPolicyRegistrySandbox {
147 public:
148  ScopedGroupPolicyRegistrySandbox();
149  ~ScopedGroupPolicyRegistrySandbox();
150
151 private:
152  void ActivateOverrides();
153  void RemoveOverrides();
154
155  // Deletes the sandbox keys.
156  void DeleteKeys();
157
158  std::wstring key_name_;
159
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_;
164
165  DISALLOW_COPY_AND_ASSIGN(ScopedGroupPolicyRegistrySandbox);
166};
167
168// A test harness that feeds policy via the Chrome GPO registry subtree.
169class RegistryTestHarness : public PolicyProviderTestHarness,
170                            public AppliedGPOListProvider {
171 public:
172  RegistryTestHarness(HKEY hive, PolicyScope scope);
173  virtual ~RegistryTestHarness();
174
175  // PolicyProviderTestHarness:
176  virtual void SetUp() OVERRIDE;
177
178  virtual ConfigurationPolicyProvider* CreateProvider(
179      SchemaRegistry* registry,
180      scoped_refptr<base::SequencedTaskRunner> task_runner) OVERRIDE;
181
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;
197
198  // AppliedGPOListProvider:
199  virtual DWORD GetAppliedGPOList(DWORD flags,
200                                  LPCTSTR machine_name,
201                                  PSID sid_user,
202                                  GUID* extension_guid,
203                                  PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE;
204  virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE;
205
206  // Creates a harness instance that will install policy in HKCU or HKLM,
207  // respectively.
208  static PolicyProviderTestHarness* CreateHKCU();
209  static PolicyProviderTestHarness* CreateHKLM();
210
211 private:
212  HKEY hive_;
213
214  ScopedGroupPolicyRegistrySandbox registry_sandbox_;
215
216  DISALLOW_COPY_AND_ASSIGN(RegistryTestHarness);
217};
218
219// A test harness that generates PReg files for the provider to read.
220class PRegTestHarness : public PolicyProviderTestHarness,
221                        public AppliedGPOListProvider {
222 public:
223  PRegTestHarness();
224  virtual ~PRegTestHarness();
225
226  // PolicyProviderTestHarness:
227  virtual void SetUp() OVERRIDE;
228
229  virtual ConfigurationPolicyProvider* CreateProvider(
230      SchemaRegistry* registry,
231      scoped_refptr<base::SequencedTaskRunner> task_runner) OVERRIDE;
232
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;
248
249  // AppliedGPOListProvider:
250  virtual DWORD GetAppliedGPOList(DWORD flags,
251                                  LPCTSTR machine_name,
252                                  PSID sid_user,
253                                  GUID* extension_guid,
254                                  PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE;
255  virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE;
256
257  // Creates a harness instance.
258  static PolicyProviderTestHarness* Create();
259
260 private:
261  // Helper to append a base::string16 to an uint8 buffer.
262  static void AppendChars(std::vector<uint8>* buffer,
263                          const base::string16& chars);
264
265  // Appends a record with the given fields to the PReg file.
266  void AppendRecordToPRegFile(const base::string16& path,
267                              const std::string& key,
268                              DWORD type,
269                              DWORD size,
270                              uint8* data);
271
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,
275                             DWORD value);
276
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);
281
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);
287
288  base::ScopedTempDir temp_dir_;
289  base::FilePath preg_file_path_;
290  GROUP_POLICY_OBJECT gpo_;
291
292  DISALLOW_COPY_AND_ASSIGN(PRegTestHarness);
293};
294
295ScopedGroupPolicyRegistrySandbox::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";
304
305  // Create the subkeys to hold the overridden HKLM and HKCU
306  // policy settings.
307  temp_hklm_hive_key_.Create(HKEY_CURRENT_USER,
308                             hklm_key_name.c_str(),
309                             KEY_ALL_ACCESS);
310  temp_hkcu_hive_key_.Create(HKEY_CURRENT_USER,
311                             hkcu_key_name.c_str(),
312                             KEY_ALL_ACCESS);
313
314  ActivateOverrides();
315}
316
317ScopedGroupPolicyRegistrySandbox::~ScopedGroupPolicyRegistrySandbox() {
318  RemoveOverrides();
319  DeleteKeys();
320}
321
322void 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()));
327}
328
329void ScopedGroupPolicyRegistrySandbox::RemoveOverrides() {
330  ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_LOCAL_MACHINE, 0));
331  ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_CURRENT_USER, 0));
332}
333
334void ScopedGroupPolicyRegistrySandbox::DeleteKeys() {
335  RegKey key(HKEY_CURRENT_USER, key_name_.c_str(), KEY_ALL_ACCESS);
336  ASSERT_TRUE(key.Valid());
337  key.DeleteKey(L"");
338}
339
340RegistryTestHarness::RegistryTestHarness(HKEY hive, PolicyScope scope)
341    : PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY, scope), hive_(hive) {}
342
343RegistryTestHarness::~RegistryTestHarness() {}
344
345void RegistryTestHarness::SetUp() {}
346
347ConfigurationPolicyProvider* 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());
354}
355
356void RegistryTestHarness::InstallEmptyPolicy() {}
357
358void 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()));
365}
366
367void RegistryTestHarness::InstallIntegerPolicy(
368    const std::string& policy_name,
369    int policy_value) {
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));
374}
375
376void RegistryTestHarness::InstallBooleanPolicy(
377    const std::string& policy_name,
378    bool policy_value) {
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));
383}
384
385void RegistryTestHarness::InstallStringListPolicy(
386    const std::string& policy_name,
387    const base::ListValue* policy_value) {
388  RegKey key(hive_,
389             (base::string16(kTestPolicyKey) + base::ASCIIToUTF16("\\") +
390              UTF8ToUTF16(policy_name)).c_str(),
391             KEY_ALL_ACCESS);
392  ASSERT_TRUE(key.Valid());
393  int index = 1;
394  for (base::ListValue::const_iterator element(policy_value->begin());
395       element != policy_value->end();
396       ++element) {
397    std::string element_value;
398    if (!(*element)->GetAsString(&element_value))
399      continue;
400    std::string name(base::IntToString(index++));
401    key.WriteValue(UTF8ToUTF16(name).c_str(),
402                   UTF8ToUTF16(element_value).c_str());
403  }
404}
405
406void RegistryTestHarness::InstallDictionaryPolicy(
407    const std::string& policy_name,
408    const base::DictionaryValue* policy_value) {
409  std::string json;
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());
415}
416
417void 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)) {
427      ADD_FAILURE();
428      continue;
429    }
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);
435    }
436  }
437}
438
439DWORD RegistryTestHarness::GetAppliedGPOList(DWORD flags,
440                                             LPCTSTR machine_name,
441                                             PSID sid_user,
442                                             GUID* extension_guid,
443                                             PGROUP_POLICY_OBJECT* gpo_list) {
444  *gpo_list = NULL;
445  return ERROR_ACCESS_DENIED;
446}
447
448BOOL RegistryTestHarness::FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) {
449  return TRUE;
450}
451
452// static
453PolicyProviderTestHarness* RegistryTestHarness::CreateHKCU() {
454  return new RegistryTestHarness(HKEY_CURRENT_USER, POLICY_SCOPE_USER);
455}
456
457// static
458PolicyProviderTestHarness* RegistryTestHarness::CreateHKLM() {
459  return new RegistryTestHarness(HKEY_LOCAL_MACHINE, POLICY_SCOPE_MACHINE);
460}
461
462PRegTestHarness::PRegTestHarness()
463    : PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE) {}
464
465PRegTestHarness::~PRegTestHarness() {}
466
467void 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)));
474
475  memset(&gpo_, 0, sizeof(GROUP_POLICY_OBJECT));
476  gpo_.lpFileSysPath = const_cast<wchar_t*>(temp_dir_.path().value().c_str());
477}
478
479ConfigurationPolicyProvider* 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());
485}
486
487void PRegTestHarness::InstallEmptyPolicy() {}
488
489void PRegTestHarness::InstallStringPolicy(const std::string& policy_name,
490                                          const std::string& policy_value) {
491  AppendStringToPRegFile(kTestPolicyKey, policy_name, policy_value);
492}
493
494void PRegTestHarness::InstallIntegerPolicy(const std::string& policy_name,
495                                           int policy_value) {
496  AppendDWORDToPRegFile(kTestPolicyKey, policy_name, policy_value);
497}
498
499void PRegTestHarness::InstallBooleanPolicy(const std::string& policy_name,
500                                           bool policy_value) {
501  AppendDWORDToPRegFile(kTestPolicyKey, policy_name, policy_value);
502}
503
504void PRegTestHarness::InstallStringListPolicy(
505    const std::string& policy_name,
506    const base::ListValue* policy_value) {
507  AppendPolicyToPRegFile(kTestPolicyKey, policy_name, policy_value);
508}
509
510void PRegTestHarness::InstallDictionaryPolicy(
511    const std::string& policy_name,
512    const base::DictionaryValue* policy_value) {
513  std::string json;
514  base::JSONWriter::Write(policy_value, &json);
515  AppendStringToPRegFile(kTestPolicyKey, policy_name, json);
516}
517
518void 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)) {
528      ADD_FAILURE();
529      continue;
530    }
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),
537                             &component.value());
538    }
539  }
540}
541
542DWORD PRegTestHarness::GetAppliedGPOList(DWORD flags,
543                                         LPCTSTR machine_name,
544                                         PSID sid_user,
545                                         GUID* extension_guid,
546                                         PGROUP_POLICY_OBJECT* gpo_list) {
547  *gpo_list = flags & GPO_LIST_FLAG_MACHINE ? &gpo_ : NULL;
548  return ERROR_SUCCESS;
549}
550
551BOOL PRegTestHarness::FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) {
552  return TRUE;
553}
554
555// static
556PolicyProviderTestHarness* PRegTestHarness::Create() {
557  return new PRegTestHarness();
558}
559
560// static
561void 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);
566  }
567}
568
569void PRegTestHarness::AppendRecordToPRegFile(const base::string16& path,
570                                             const std::string& key,
571                                             DWORD type,
572                                             DWORD size,
573                                             uint8* data) {
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"]");
590
591  ASSERT_EQ(buffer.size(),
592            base::AppendToFile(
593                preg_file_path_,
594                reinterpret_cast<const char*>(vector_as_array(&buffer)),
595                buffer.size()));
596}
597
598void PRegTestHarness::AppendDWORDToPRegFile(const base::string16& path,
599                                            const std::string& key,
600                                            DWORD value) {
601  value = base::ByteSwapToLE32(value);
602  AppendRecordToPRegFile(path, key, REG_DWORD, sizeof(DWORD),
603                         reinterpret_cast<uint8*>(&value));
604}
605
606void 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'));
614
615  AppendRecordToPRegFile(path, key, REG_SZ, data.size() * sizeof(base::char16),
616                         reinterpret_cast<uint8*>(vector_as_array(&data)));
617}
618
619void 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);
627      break;
628    }
629    case base::Value::TYPE_INTEGER: {
630      int int_value = 0;
631      ASSERT_TRUE(value->GetAsInteger(&int_value));
632      AppendDWORDToPRegFile(path, key, int_value);
633      break;
634    }
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));
639      break;
640    }
641    case base::Value::TYPE_STRING: {
642      std::string string_value;
643      ASSERT_TRUE(value->GetAsString(&string_value));
644      AppendStringToPRegFile(path, key, string_value);
645      break;
646    }
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();
652           entry.Advance()) {
653        AppendPolicyToPRegFile(subpath, entry.key(), &entry.value());
654      }
655      break;
656    }
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);
665      }
666      break;
667    }
668    case base::Value::TYPE_BINARY:
669    case base::Value::TYPE_NULL: {
670      ADD_FAILURE();
671      break;
672    }
673  }
674}
675
676}  // namespace
677
678// Instantiate abstract test case for basic policy reading tests.
679INSTANTIATE_TEST_CASE_P(
680    PolicyProviderWinTest,
681    ConfigurationPolicyProviderTest,
682    testing::Values(RegistryTestHarness::CreateHKCU,
683                    RegistryTestHarness::CreateHKLM,
684                    PRegTestHarness::Create));
685
686// Instantiate abstract test case for 3rd party policy reading tests.
687INSTANTIATE_TEST_CASE_P(
688    ThirdPartyPolicyProviderWinTest,
689    Configuration3rdPartyPolicyProviderTest,
690    testing::Values(RegistryTestHarness::CreateHKCU,
691                    RegistryTestHarness::CreateHKLM,
692                    PRegTestHarness::Create));
693
694// Test cases for windows policy provider specific functionality.
695class PolicyLoaderWinTest : public PolicyTestBase,
696                            public AppliedGPOListProvider {
697 protected:
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[];
701
702  PolicyLoaderWinTest()
703      : gpo_list_(NULL),
704        gpo_list_status_(ERROR_ACCESS_DENIED) {}
705  virtual ~PolicyLoaderWinTest() {}
706
707  virtual void SetUp() OVERRIDE {
708    base::win::SetDomainStateForTesting(false);
709    PolicyTestBase::SetUp();
710
711    ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir_));
712    test_data_dir_ = test_data_dir_.AppendASCII("chrome")
713                                   .AppendASCII("test")
714                                   .AppendASCII("data")
715                                   .AppendASCII("policy")
716                                   .AppendASCII("gpo");
717  }
718
719  // AppliedGPOListProvider:
720  virtual DWORD GetAppliedGPOList(DWORD flags,
721                                  LPCTSTR machine_name,
722                                  PSID sid_user,
723                                  GUID* extension_guid,
724                                  PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE {
725    *gpo_list = gpo_list_;
726    return gpo_list_status_;
727  }
728  virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE {
729    return TRUE;
730  }
731
732  void InitGPO(GROUP_POLICY_OBJECT* gpo,
733               DWORD options,
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());
740    gpo->pNext = next;
741    gpo->pPrev = prev;
742  }
743
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);
749  }
750
751  void InstallRegistrySentinel() {
752    RegKey hklm_key(HKEY_CURRENT_USER, kTestPolicyKey, KEY_ALL_ACCESS);
753    ASSERT_TRUE(hklm_key.Valid());
754    hklm_key.WriteValue(
755        UTF8ToUTF16(test_keys::kKeyString).c_str(),
756        UTF8ToUTF16("registry").c_str());
757  }
758
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);
766  }
767
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);
782  }
783
784  ScopedGroupPolicyRegistrySandbox registry_sandbox_;
785  PGROUP_POLICY_OBJECT gpo_list_;
786  DWORD gpo_list_status_;
787  base::FilePath test_data_dir_;
788};
789
790const base::char16 PolicyLoaderWinTest::kTestPolicyKey[] =
791    L"SOFTWARE\\Policies\\Chromium";
792
793TEST_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());
802
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           base::Value::CreateStringValue("hklm"), NULL);
809  EXPECT_TRUE(Matches(expected));
810}
811
812TEST_F(PolicyLoaderWinTest, Merge3rdPartyPolicies) {
813  // Policy for the same extension will be provided at the 4 level/scope
814  // combinations, to verify that they overlap as expected.
815  const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "merge");
816  ASSERT_TRUE(RegisterSchema(
817      ns,
818      "{"
819      "  \"type\": \"object\","
820      "  \"properties\": {"
821      "    \"a\": { \"type\": \"string\" },"
822      "    \"b\": { \"type\": \"string\" },"
823      "    \"c\": { \"type\": \"string\" },"
824      "    \"d\": { \"type\": \"string\" }"
825      "  }"
826      "}"));
827
828  const base::string16 kPathSuffix =
829      kTestPolicyKey + base::ASCIIToUTF16("\\3rdparty\\extensions\\merge");
830
831  const char kUserMandatory[] = "user-mandatory";
832  const char kUserRecommended[] = "user-recommended";
833  const char kMachineMandatory[] = "machine-mandatory";
834  const char kMachineRecommended[] = "machine-recommended";
835
836  base::DictionaryValue policy;
837  policy.SetString("a", kMachineMandatory);
838  EXPECT_TRUE(InstallValue(policy, HKEY_LOCAL_MACHINE,
839                           kPathSuffix, kMandatory));
840  policy.SetString("a", kUserMandatory);
841  policy.SetString("b", kUserMandatory);
842  EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER,
843                           kPathSuffix, kMandatory));
844  policy.SetString("a", kMachineRecommended);
845  policy.SetString("b", kMachineRecommended);
846  policy.SetString("c", kMachineRecommended);
847  EXPECT_TRUE(InstallValue(policy, HKEY_LOCAL_MACHINE,
848                           kPathSuffix, kRecommended));
849  policy.SetString("a", kUserRecommended);
850  policy.SetString("b", kUserRecommended);
851  policy.SetString("c", kUserRecommended);
852  policy.SetString("d", kUserRecommended);
853  EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER,
854                           kPathSuffix, kRecommended));
855
856  PolicyBundle expected;
857  PolicyMap& expected_policy = expected.Get(ns);
858  expected_policy.Set("a", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
859                      base::Value::CreateStringValue(kMachineMandatory), NULL);
860  expected_policy.Set("b", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
861                      base::Value::CreateStringValue(kUserMandatory), NULL);
862  expected_policy.Set("c", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE,
863                      base::Value::CreateStringValue(kMachineRecommended),
864                      NULL);
865  expected_policy.Set("d", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER,
866                      base::Value::CreateStringValue(kUserRecommended), NULL);
867  EXPECT_TRUE(Matches(expected));
868}
869
870TEST_F(PolicyLoaderWinTest, LoadStringEncodedValues) {
871  // Create a dictionary with all the types that can be stored encoded in a
872  // string.
873  const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "string");
874  ASSERT_TRUE(RegisterSchema(
875      ns,
876      "{"
877      "  \"type\": \"object\","
878      "  \"id\": \"MainType\","
879      "  \"properties\": {"
880      "    \"null\": { \"type\": \"null\" },"
881      "    \"bool\": { \"type\": \"boolean\" },"
882      "    \"int\": { \"type\": \"integer\" },"
883      "    \"double\": { \"type\": \"number\" },"
884      "    \"list\": {"
885      "      \"type\": \"array\","
886      "      \"items\": { \"$ref\": \"MainType\" }"
887      "    },"
888      "    \"dict\": { \"$ref\": \"MainType\" }"
889      "  }"
890      "}"));
891
892  base::DictionaryValue policy;
893  policy.Set("null", base::Value::CreateNullValue());
894  policy.SetBoolean("bool", true);
895  policy.SetInteger("int", -123);
896  policy.SetDouble("double", 456.78e9);
897  base::ListValue list;
898  list.Append(policy.DeepCopy());
899  list.Append(policy.DeepCopy());
900  policy.Set("list", list.DeepCopy());
901  // Encode |policy| before adding the "dict" entry.
902  std::string encoded_dict;
903  base::JSONWriter::Write(&policy, &encoded_dict);
904  ASSERT_FALSE(encoded_dict.empty());
905  policy.Set("dict", policy.DeepCopy());
906  std::string encoded_list;
907  base::JSONWriter::Write(&list, &encoded_list);
908  ASSERT_FALSE(encoded_list.empty());
909  base::DictionaryValue encoded_policy;
910  encoded_policy.SetString("null", "");
911  encoded_policy.SetString("bool", "1");
912  encoded_policy.SetString("int", "-123");
913  encoded_policy.SetString("double", "456.78e9");
914  encoded_policy.SetString("list", encoded_list);
915  encoded_policy.SetString("dict", encoded_dict);
916
917  const base::string16 kPathSuffix =
918      kTestPolicyKey + base::ASCIIToUTF16("\\3rdparty\\extensions\\string");
919  EXPECT_TRUE(
920      InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
921
922  PolicyBundle expected;
923  expected.Get(ns).LoadFrom(&policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
924  EXPECT_TRUE(Matches(expected));
925}
926
927TEST_F(PolicyLoaderWinTest, LoadIntegerEncodedValues) {
928  const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "int");
929  ASSERT_TRUE(RegisterSchema(
930      ns,
931      "{"
932      "  \"type\": \"object\","
933      "  \"properties\": {"
934      "    \"bool\": { \"type\": \"boolean\" },"
935      "    \"int\": { \"type\": \"integer\" },"
936      "    \"double\": { \"type\": \"number\" }"
937      "  }"
938      "}"));
939
940  base::DictionaryValue encoded_policy;
941  encoded_policy.SetInteger("bool", 1);
942  encoded_policy.SetInteger("int", 123);
943  encoded_policy.SetInteger("double", 456);
944
945  const base::string16 kPathSuffix =
946      kTestPolicyKey + base::ASCIIToUTF16("\\3rdparty\\extensions\\int");
947  EXPECT_TRUE(
948      InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
949
950  base::DictionaryValue policy;
951  policy.SetBoolean("bool", true);
952  policy.SetInteger("int", 123);
953  policy.SetDouble("double", 456.0);
954  PolicyBundle expected;
955  expected.Get(ns).LoadFrom(&policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
956  EXPECT_TRUE(Matches(expected));
957}
958
959TEST_F(PolicyLoaderWinTest, DefaultPropertySchemaType) {
960  // Build a schema for an "object" with a default schema for its properties.
961  // Note that the top-level object can't have "additionalProperties", so
962  // a "policy" property is used instead.
963  const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "test");
964  ASSERT_TRUE(RegisterSchema(
965      ns,
966      "{"
967      "  \"type\": \"object\","
968      "  \"properties\": {"
969      "    \"policy\": {"
970      "      \"type\": \"object\","
971      "      \"properties\": {"
972      "        \"special-int1\": { \"type\": \"integer\" },"
973      "        \"special-int2\": { \"type\": \"integer\" }"
974      "      },"
975      "      \"additionalProperties\": { \"type\": \"number\" }"
976      "    }"
977      "  }"
978      "}"));
979
980  // Write some test values.
981  base::DictionaryValue policy;
982  // These special values have a specific schema for them.
983  policy.SetInteger("special-int1", 123);
984  policy.SetString("special-int2", "-456");
985  // Other values default to be loaded as doubles.
986  policy.SetInteger("double1", 789.0);
987  policy.SetString("double2", "123.456e7");
988  policy.SetString("invalid", "omg");
989  base::DictionaryValue all_policies;
990  all_policies.Set("policy", policy.DeepCopy());
991
992  const base::string16 kPathSuffix =
993      kTestPolicyKey + base::ASCIIToUTF16("\\3rdparty\\extensions\\test");
994  EXPECT_TRUE(
995      InstallValue(all_policies, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
996
997  base::DictionaryValue expected_policy;
998  expected_policy.SetInteger("special-int1", 123);
999  expected_policy.SetInteger("special-int2", -456);
1000  expected_policy.SetDouble("double1", 789.0);
1001  expected_policy.SetDouble("double2", 123.456e7);
1002  base::DictionaryValue expected_policies;
1003  expected_policies.Set("policy", expected_policy.DeepCopy());
1004  PolicyBundle expected;
1005  expected.Get(ns).LoadFrom(
1006      &expected_policies, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
1007  EXPECT_TRUE(Matches(expected));
1008}
1009
1010TEST_F(PolicyLoaderWinTest, AppliedPolicyNotPresent) {
1011  InstallRegistrySentinel();
1012  gpo_list_ = NULL;
1013  gpo_list_status_ = ERROR_SUCCESS;
1014
1015  PolicyBundle empty;
1016  EXPECT_TRUE(Matches(empty));
1017}
1018
1019TEST_F(PolicyLoaderWinTest, AppliedPolicyEmpty) {
1020  InstallRegistrySentinel();
1021  base::FilePath gpo_dir(test_data_dir_.AppendASCII("empty"));
1022  GROUP_POLICY_OBJECT gpo;
1023  InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1024  gpo_list_ = &gpo;
1025  gpo_list_status_ = ERROR_SUCCESS;
1026
1027  PolicyBundle empty;
1028  EXPECT_TRUE(Matches(empty));
1029}
1030
1031TEST_F(PolicyLoaderWinTest, AppliedPolicyInDomain) {
1032  base::win::SetDomainStateForTesting(true);
1033  InstallRegistrySentinel();
1034  base::FilePath gpo_dir(test_data_dir_.AppendASCII("empty"));
1035  GROUP_POLICY_OBJECT gpo;
1036  InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1037  gpo_list_ = &gpo;
1038  gpo_list_status_ = ERROR_SUCCESS;
1039
1040  PolicyBundle empty;
1041  EXPECT_TRUE(MatchesRegistrySentinel());
1042}
1043
1044TEST_F(PolicyLoaderWinTest, AppliedPolicyNonExistingFile) {
1045  InstallRegistrySentinel();
1046  GROUP_POLICY_OBJECT gpo;
1047  InitGPO(&gpo, 0, test_data_dir_, NULL, NULL);
1048  gpo_list_ = &gpo;
1049  gpo_list_status_ = ERROR_SUCCESS;
1050
1051  EXPECT_TRUE(MatchesRegistrySentinel());
1052}
1053
1054TEST_F(PolicyLoaderWinTest, AppliedPolicyBadPath) {
1055  InstallRegistrySentinel();
1056  base::FilePath gpo_dir(test_data_dir_.AppendASCII("bad"));
1057  GROUP_POLICY_OBJECT gpo;
1058  InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1059  gpo_list_ = &gpo;
1060  gpo_list_status_ = ERROR_SUCCESS;
1061
1062  EXPECT_TRUE(MatchesRegistrySentinel());
1063}
1064
1065TEST_F(PolicyLoaderWinTest, AppliedPolicyPresent) {
1066  InstallRegistrySentinel();
1067  base::FilePath gpo_dir(test_data_dir_.AppendASCII("test1"));
1068  GROUP_POLICY_OBJECT gpo;
1069  InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1070  gpo_list_ = &gpo;
1071  gpo_list_status_ = ERROR_SUCCESS;
1072
1073  EXPECT_TRUE(MatchesTestBundle());
1074}
1075
1076TEST_F(PolicyLoaderWinTest, AppliedPolicyMerged) {
1077  InstallRegistrySentinel();
1078  base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test2"));
1079  base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test1"));
1080  GROUP_POLICY_OBJECT gpo1;
1081  GROUP_POLICY_OBJECT gpo2;
1082  InitGPO(&gpo1, 0, gpo1_dir, &gpo2, NULL);
1083  InitGPO(&gpo2, 0, gpo2_dir, NULL, &gpo1);
1084  gpo_list_ = &gpo1;
1085  gpo_list_status_ = ERROR_SUCCESS;
1086
1087  EXPECT_TRUE(MatchesTestBundle());
1088}
1089
1090TEST_F(PolicyLoaderWinTest, AppliedPolicyDisabled) {
1091  InstallRegistrySentinel();
1092  base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test1"));
1093  base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test2"));
1094  GROUP_POLICY_OBJECT gpo1;
1095  GROUP_POLICY_OBJECT gpo2;
1096  InitGPO(&gpo1, 0, gpo1_dir, &gpo2, NULL);
1097  InitGPO(&gpo2, GPO_FLAG_DISABLE, gpo2_dir, NULL, &gpo1);
1098  gpo_list_ = &gpo1;
1099  gpo_list_status_ = ERROR_SUCCESS;
1100
1101  EXPECT_TRUE(MatchesTestBundle());
1102}
1103
1104TEST_F(PolicyLoaderWinTest, AppliedPolicyForcedPolicy) {
1105  InstallRegistrySentinel();
1106  base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test1"));
1107  base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test2"));
1108  GROUP_POLICY_OBJECT gpo1;
1109  GROUP_POLICY_OBJECT gpo2;
1110  InitGPO(&gpo1, GPO_FLAG_FORCE, gpo1_dir, &gpo2, NULL);
1111  InitGPO(&gpo2, 0, gpo2_dir, NULL, &gpo1);
1112  gpo_list_ = &gpo1;
1113  gpo_list_status_ = ERROR_SUCCESS;
1114
1115  EXPECT_TRUE(MatchesTestBundle());
1116}
1117
1118TEST_F(PolicyLoaderWinTest, AppliedPolicyUNCPath) {
1119  InstallRegistrySentinel();
1120  base::FilePath gpo_dir(test_data_dir_.AppendASCII("test1"));
1121  base::FilePath unc_path(L"\\\\some_share\\GPO");
1122  GROUP_POLICY_OBJECT gpo1;
1123  GROUP_POLICY_OBJECT gpo2;
1124  InitGPO(&gpo1, 0, gpo_dir, &gpo2, NULL);
1125  InitGPO(&gpo2, 0, unc_path, NULL, &gpo1);
1126  gpo_list_ = &gpo1;
1127  gpo_list_status_ = ERROR_SUCCESS;
1128
1129  EXPECT_TRUE(MatchesRegistrySentinel());
1130}
1131
1132TEST_F(PolicyLoaderWinTest, LoadExtensionPolicyAlternativeSpelling) {
1133  base::FilePath gpo_dir(
1134      test_data_dir_.AppendASCII("extension_alternative_spelling"));
1135  GROUP_POLICY_OBJECT gpo;
1136  InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1137  gpo_list_ = &gpo;
1138  gpo_list_status_ = ERROR_SUCCESS;
1139
1140  const char kTestSchema[] =
1141      "{"
1142      "  \"type\": \"object\","
1143      "  \"properties\": {"
1144      "    \"policy 1\": { \"type\": \"integer\" },"
1145      "    \"policy 2\": { \"type\": \"integer\" }"
1146      "  }"
1147      "}";
1148  const PolicyNamespace ns_a(
1149      POLICY_DOMAIN_EXTENSIONS, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
1150  const PolicyNamespace ns_b(
1151      POLICY_DOMAIN_EXTENSIONS, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
1152  ASSERT_TRUE(RegisterSchema(ns_a, kTestSchema));
1153  ASSERT_TRUE(RegisterSchema(ns_b, kTestSchema));
1154
1155  PolicyBundle expected;
1156  base::DictionaryValue expected_a;
1157  expected_a.SetInteger("policy 1", 3);
1158  expected_a.SetInteger("policy 2", 3);
1159  expected.Get(ns_a).LoadFrom(
1160      &expected_a, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
1161  base::DictionaryValue expected_b;
1162  expected_b.SetInteger("policy 1", 2);
1163  expected.Get(ns_b).LoadFrom(
1164      &expected_b, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
1165  EXPECT_TRUE(Matches(expected));
1166}
1167
1168TEST_F(PolicyLoaderWinTest, LBSSupport) {
1169  const PolicyNamespace ns(
1170      POLICY_DOMAIN_EXTENSIONS, "heildphpnddilhkemkielfhnkaagiabh");
1171  schema_registry_.RegisterComponent(ns, Schema());
1172
1173  const char kIncompleteSchema[] =
1174      "{"
1175       "  \"type\": \"object\","
1176       "  \"properties\": {"
1177       "    \"url_list\": { \"type\": \"array\" },"
1178       "    \"url_greylist\": { \"type\": \"array\" }"
1179       "  }"
1180      "}";
1181
1182  const base::string16 kPathSuffix =
1183      kTestPolicyKey + base::ASCIIToUTF16("\\3rdparty\\extensions");
1184
1185  base::ListValue list;
1186  list.AppendString("youtube.com");
1187  base::DictionaryValue policy;
1188  policy.Set("url_list", list.DeepCopy());
1189  policy.SetString("alternative_browser_path", "c:\\legacy\\browser.exe");
1190  base::DictionaryValue root;
1191  root.Set(base::UTF16ToUTF8(kMandatory), policy.DeepCopy());
1192  root.SetString(kSchema, kIncompleteSchema);
1193  EXPECT_TRUE(InstallValue(root, HKEY_LOCAL_MACHINE,
1194                           kPathSuffix, base::ASCIIToUTF16(ns.component_id)));
1195
1196  PolicyBundle expected;
1197  PolicyMap& expected_policy = expected.Get(ns);
1198  expected_policy.Set("alternative_browser_path",
1199                      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
1200                      new base::StringValue("c:\\legacy\\browser.exe"), NULL);
1201  expected_policy.Set("url_list", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
1202                      list.DeepCopy(), NULL);
1203  EXPECT_TRUE(Matches(expected));
1204}
1205
1206}  // namespace policy
1207