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/files/file_path.h"
19#include "base/files/file_util.h"
20#include "base/files/scoped_temp_dir.h"
21#include "base/json/json_writer.h"
22#include "base/path_service.h"
23#include "base/process/process.h"
24#include "base/strings/string16.h"
25#include "base/strings/string_number_conversions.h"
26#include "base/strings/string_util.h"
27#include "base/strings/stringprintf.h"
28#include "base/strings/utf_string_conversions.h"
29#include "base/sys_byteorder.h"
30#include "base/win/registry.h"
31#include "base/win/win_util.h"
32#include "components/policy/core/common/async_policy_provider.h"
33#include "components/policy/core/common/configuration_policy_provider_test.h"
34#include "components/policy/core/common/external_data_fetcher.h"
35#include "components/policy/core/common/policy_bundle.h"
36#include "components/policy/core/common/policy_map.h"
37#include "components/policy/core/common/preg_parser_win.h"
38#include "components/policy/core/common/schema_map.h"
39#include "testing/gtest/include/gtest/gtest.h"
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           new base::StringValue("hklm"),
809           NULL);
810  EXPECT_TRUE(Matches(expected));
811}
812
813TEST_F(PolicyLoaderWinTest, Merge3rdPartyPolicies) {
814  // Policy for the same extension will be provided at the 4 level/scope
815  // combinations, to verify that they overlap as expected.
816  const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "merge");
817  ASSERT_TRUE(RegisterSchema(
818      ns,
819      "{"
820      "  \"type\": \"object\","
821      "  \"properties\": {"
822      "    \"a\": { \"type\": \"string\" },"
823      "    \"b\": { \"type\": \"string\" },"
824      "    \"c\": { \"type\": \"string\" },"
825      "    \"d\": { \"type\": \"string\" }"
826      "  }"
827      "}"));
828
829  const base::string16 kPathSuffix =
830      kTestPolicyKey + base::ASCIIToUTF16("\\3rdparty\\extensions\\merge");
831
832  const char kUserMandatory[] = "user-mandatory";
833  const char kUserRecommended[] = "user-recommended";
834  const char kMachineMandatory[] = "machine-mandatory";
835  const char kMachineRecommended[] = "machine-recommended";
836
837  base::DictionaryValue policy;
838  policy.SetString("a", kMachineMandatory);
839  EXPECT_TRUE(InstallValue(policy, HKEY_LOCAL_MACHINE,
840                           kPathSuffix, kMandatory));
841  policy.SetString("a", kUserMandatory);
842  policy.SetString("b", kUserMandatory);
843  EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER,
844                           kPathSuffix, kMandatory));
845  policy.SetString("a", kMachineRecommended);
846  policy.SetString("b", kMachineRecommended);
847  policy.SetString("c", kMachineRecommended);
848  EXPECT_TRUE(InstallValue(policy, HKEY_LOCAL_MACHINE,
849                           kPathSuffix, kRecommended));
850  policy.SetString("a", kUserRecommended);
851  policy.SetString("b", kUserRecommended);
852  policy.SetString("c", kUserRecommended);
853  policy.SetString("d", kUserRecommended);
854  EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER,
855                           kPathSuffix, kRecommended));
856
857  PolicyBundle expected;
858  PolicyMap& expected_policy = expected.Get(ns);
859  expected_policy.Set("a",
860                      POLICY_LEVEL_MANDATORY,
861                      POLICY_SCOPE_MACHINE,
862                      new base::StringValue(kMachineMandatory),
863                      NULL);
864  expected_policy.Set("b",
865                      POLICY_LEVEL_MANDATORY,
866                      POLICY_SCOPE_USER,
867                      new base::StringValue(kUserMandatory),
868                      NULL);
869  expected_policy.Set("c",
870                      POLICY_LEVEL_RECOMMENDED,
871                      POLICY_SCOPE_MACHINE,
872                      new base::StringValue(kMachineRecommended),
873                      NULL);
874  expected_policy.Set("d",
875                      POLICY_LEVEL_RECOMMENDED,
876                      POLICY_SCOPE_USER,
877                      new base::StringValue(kUserRecommended),
878                      NULL);
879  EXPECT_TRUE(Matches(expected));
880}
881
882TEST_F(PolicyLoaderWinTest, LoadStringEncodedValues) {
883  // Create a dictionary with all the types that can be stored encoded in a
884  // string.
885  const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "string");
886  ASSERT_TRUE(RegisterSchema(
887      ns,
888      "{"
889      "  \"type\": \"object\","
890      "  \"id\": \"MainType\","
891      "  \"properties\": {"
892      "    \"null\": { \"type\": \"null\" },"
893      "    \"bool\": { \"type\": \"boolean\" },"
894      "    \"int\": { \"type\": \"integer\" },"
895      "    \"double\": { \"type\": \"number\" },"
896      "    \"list\": {"
897      "      \"type\": \"array\","
898      "      \"items\": { \"$ref\": \"MainType\" }"
899      "    },"
900      "    \"dict\": { \"$ref\": \"MainType\" }"
901      "  }"
902      "}"));
903
904  base::DictionaryValue policy;
905  policy.Set("null", base::Value::CreateNullValue());
906  policy.SetBoolean("bool", true);
907  policy.SetInteger("int", -123);
908  policy.SetDouble("double", 456.78e9);
909  base::ListValue list;
910  list.Append(policy.DeepCopy());
911  list.Append(policy.DeepCopy());
912  policy.Set("list", list.DeepCopy());
913  // Encode |policy| before adding the "dict" entry.
914  std::string encoded_dict;
915  base::JSONWriter::Write(&policy, &encoded_dict);
916  ASSERT_FALSE(encoded_dict.empty());
917  policy.Set("dict", policy.DeepCopy());
918  std::string encoded_list;
919  base::JSONWriter::Write(&list, &encoded_list);
920  ASSERT_FALSE(encoded_list.empty());
921  base::DictionaryValue encoded_policy;
922  encoded_policy.SetString("null", "");
923  encoded_policy.SetString("bool", "1");
924  encoded_policy.SetString("int", "-123");
925  encoded_policy.SetString("double", "456.78e9");
926  encoded_policy.SetString("list", encoded_list);
927  encoded_policy.SetString("dict", encoded_dict);
928
929  const base::string16 kPathSuffix =
930      kTestPolicyKey + base::ASCIIToUTF16("\\3rdparty\\extensions\\string");
931  EXPECT_TRUE(
932      InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
933
934  PolicyBundle expected;
935  expected.Get(ns).LoadFrom(&policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
936  EXPECT_TRUE(Matches(expected));
937}
938
939TEST_F(PolicyLoaderWinTest, LoadIntegerEncodedValues) {
940  const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "int");
941  ASSERT_TRUE(RegisterSchema(
942      ns,
943      "{"
944      "  \"type\": \"object\","
945      "  \"properties\": {"
946      "    \"bool\": { \"type\": \"boolean\" },"
947      "    \"int\": { \"type\": \"integer\" },"
948      "    \"double\": { \"type\": \"number\" }"
949      "  }"
950      "}"));
951
952  base::DictionaryValue encoded_policy;
953  encoded_policy.SetInteger("bool", 1);
954  encoded_policy.SetInteger("int", 123);
955  encoded_policy.SetInteger("double", 456);
956
957  const base::string16 kPathSuffix =
958      kTestPolicyKey + base::ASCIIToUTF16("\\3rdparty\\extensions\\int");
959  EXPECT_TRUE(
960      InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
961
962  base::DictionaryValue policy;
963  policy.SetBoolean("bool", true);
964  policy.SetInteger("int", 123);
965  policy.SetDouble("double", 456.0);
966  PolicyBundle expected;
967  expected.Get(ns).LoadFrom(&policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
968  EXPECT_TRUE(Matches(expected));
969}
970
971TEST_F(PolicyLoaderWinTest, DefaultPropertySchemaType) {
972  // Build a schema for an "object" with a default schema for its properties.
973  // Note that the top-level object can't have "additionalProperties", so
974  // a "policy" property is used instead.
975  const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "test");
976  ASSERT_TRUE(RegisterSchema(
977      ns,
978      "{"
979      "  \"type\": \"object\","
980      "  \"properties\": {"
981      "    \"policy\": {"
982      "      \"type\": \"object\","
983      "      \"properties\": {"
984      "        \"special-int1\": { \"type\": \"integer\" },"
985      "        \"special-int2\": { \"type\": \"integer\" }"
986      "      },"
987      "      \"additionalProperties\": { \"type\": \"number\" }"
988      "    }"
989      "  }"
990      "}"));
991
992  // Write some test values.
993  base::DictionaryValue policy;
994  // These special values have a specific schema for them.
995  policy.SetInteger("special-int1", 123);
996  policy.SetString("special-int2", "-456");
997  // Other values default to be loaded as doubles.
998  policy.SetInteger("double1", 789.0);
999  policy.SetString("double2", "123.456e7");
1000  policy.SetString("invalid", "omg");
1001  base::DictionaryValue all_policies;
1002  all_policies.Set("policy", policy.DeepCopy());
1003
1004  const base::string16 kPathSuffix =
1005      kTestPolicyKey + base::ASCIIToUTF16("\\3rdparty\\extensions\\test");
1006  EXPECT_TRUE(
1007      InstallValue(all_policies, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
1008
1009  base::DictionaryValue expected_policy;
1010  expected_policy.SetInteger("special-int1", 123);
1011  expected_policy.SetInteger("special-int2", -456);
1012  expected_policy.SetDouble("double1", 789.0);
1013  expected_policy.SetDouble("double2", 123.456e7);
1014  base::DictionaryValue expected_policies;
1015  expected_policies.Set("policy", expected_policy.DeepCopy());
1016  PolicyBundle expected;
1017  expected.Get(ns).LoadFrom(
1018      &expected_policies, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
1019  EXPECT_TRUE(Matches(expected));
1020}
1021
1022TEST_F(PolicyLoaderWinTest, AppliedPolicyNotPresent) {
1023  InstallRegistrySentinel();
1024  gpo_list_ = NULL;
1025  gpo_list_status_ = ERROR_SUCCESS;
1026
1027  PolicyBundle empty;
1028  EXPECT_TRUE(Matches(empty));
1029}
1030
1031TEST_F(PolicyLoaderWinTest, AppliedPolicyEmpty) {
1032  InstallRegistrySentinel();
1033  base::FilePath gpo_dir(test_data_dir_.AppendASCII("empty"));
1034  GROUP_POLICY_OBJECT gpo;
1035  InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1036  gpo_list_ = &gpo;
1037  gpo_list_status_ = ERROR_SUCCESS;
1038
1039  PolicyBundle empty;
1040  EXPECT_TRUE(Matches(empty));
1041}
1042
1043TEST_F(PolicyLoaderWinTest, AppliedPolicyInDomain) {
1044  base::win::SetDomainStateForTesting(true);
1045  InstallRegistrySentinel();
1046  base::FilePath gpo_dir(test_data_dir_.AppendASCII("empty"));
1047  GROUP_POLICY_OBJECT gpo;
1048  InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1049  gpo_list_ = &gpo;
1050  gpo_list_status_ = ERROR_SUCCESS;
1051
1052  PolicyBundle empty;
1053  EXPECT_TRUE(MatchesRegistrySentinel());
1054}
1055
1056TEST_F(PolicyLoaderWinTest, AppliedPolicyNonExistingFile) {
1057  InstallRegistrySentinel();
1058  GROUP_POLICY_OBJECT gpo;
1059  InitGPO(&gpo, 0, test_data_dir_, NULL, NULL);
1060  gpo_list_ = &gpo;
1061  gpo_list_status_ = ERROR_SUCCESS;
1062
1063  EXPECT_TRUE(MatchesRegistrySentinel());
1064}
1065
1066TEST_F(PolicyLoaderWinTest, AppliedPolicyBadPath) {
1067  InstallRegistrySentinel();
1068  base::FilePath gpo_dir(test_data_dir_.AppendASCII("bad"));
1069  GROUP_POLICY_OBJECT gpo;
1070  InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1071  gpo_list_ = &gpo;
1072  gpo_list_status_ = ERROR_SUCCESS;
1073
1074  EXPECT_TRUE(MatchesRegistrySentinel());
1075}
1076
1077TEST_F(PolicyLoaderWinTest, AppliedPolicyPresent) {
1078  InstallRegistrySentinel();
1079  base::FilePath gpo_dir(test_data_dir_.AppendASCII("test1"));
1080  GROUP_POLICY_OBJECT gpo;
1081  InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1082  gpo_list_ = &gpo;
1083  gpo_list_status_ = ERROR_SUCCESS;
1084
1085  EXPECT_TRUE(MatchesTestBundle());
1086}
1087
1088TEST_F(PolicyLoaderWinTest, AppliedPolicyMerged) {
1089  InstallRegistrySentinel();
1090  base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test2"));
1091  base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test1"));
1092  GROUP_POLICY_OBJECT gpo1;
1093  GROUP_POLICY_OBJECT gpo2;
1094  InitGPO(&gpo1, 0, gpo1_dir, &gpo2, NULL);
1095  InitGPO(&gpo2, 0, gpo2_dir, NULL, &gpo1);
1096  gpo_list_ = &gpo1;
1097  gpo_list_status_ = ERROR_SUCCESS;
1098
1099  EXPECT_TRUE(MatchesTestBundle());
1100}
1101
1102TEST_F(PolicyLoaderWinTest, AppliedPolicyDisabled) {
1103  InstallRegistrySentinel();
1104  base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test1"));
1105  base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test2"));
1106  GROUP_POLICY_OBJECT gpo1;
1107  GROUP_POLICY_OBJECT gpo2;
1108  InitGPO(&gpo1, 0, gpo1_dir, &gpo2, NULL);
1109  InitGPO(&gpo2, GPO_FLAG_DISABLE, gpo2_dir, NULL, &gpo1);
1110  gpo_list_ = &gpo1;
1111  gpo_list_status_ = ERROR_SUCCESS;
1112
1113  EXPECT_TRUE(MatchesTestBundle());
1114}
1115
1116TEST_F(PolicyLoaderWinTest, AppliedPolicyForcedPolicy) {
1117  InstallRegistrySentinel();
1118  base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test1"));
1119  base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test2"));
1120  GROUP_POLICY_OBJECT gpo1;
1121  GROUP_POLICY_OBJECT gpo2;
1122  InitGPO(&gpo1, GPO_FLAG_FORCE, gpo1_dir, &gpo2, NULL);
1123  InitGPO(&gpo2, 0, gpo2_dir, NULL, &gpo1);
1124  gpo_list_ = &gpo1;
1125  gpo_list_status_ = ERROR_SUCCESS;
1126
1127  EXPECT_TRUE(MatchesTestBundle());
1128}
1129
1130TEST_F(PolicyLoaderWinTest, AppliedPolicyUNCPath) {
1131  InstallRegistrySentinel();
1132  base::FilePath gpo_dir(test_data_dir_.AppendASCII("test1"));
1133  base::FilePath unc_path(L"\\\\some_share\\GPO");
1134  GROUP_POLICY_OBJECT gpo1;
1135  GROUP_POLICY_OBJECT gpo2;
1136  InitGPO(&gpo1, 0, gpo_dir, &gpo2, NULL);
1137  InitGPO(&gpo2, 0, unc_path, NULL, &gpo1);
1138  gpo_list_ = &gpo1;
1139  gpo_list_status_ = ERROR_SUCCESS;
1140
1141  EXPECT_TRUE(MatchesRegistrySentinel());
1142}
1143
1144TEST_F(PolicyLoaderWinTest, LoadExtensionPolicyAlternativeSpelling) {
1145  base::FilePath gpo_dir(
1146      test_data_dir_.AppendASCII("extension_alternative_spelling"));
1147  GROUP_POLICY_OBJECT gpo;
1148  InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1149  gpo_list_ = &gpo;
1150  gpo_list_status_ = ERROR_SUCCESS;
1151
1152  const char kTestSchema[] =
1153      "{"
1154      "  \"type\": \"object\","
1155      "  \"properties\": {"
1156      "    \"policy 1\": { \"type\": \"integer\" },"
1157      "    \"policy 2\": { \"type\": \"integer\" }"
1158      "  }"
1159      "}";
1160  const PolicyNamespace ns_a(
1161      POLICY_DOMAIN_EXTENSIONS, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
1162  const PolicyNamespace ns_b(
1163      POLICY_DOMAIN_EXTENSIONS, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
1164  ASSERT_TRUE(RegisterSchema(ns_a, kTestSchema));
1165  ASSERT_TRUE(RegisterSchema(ns_b, kTestSchema));
1166
1167  PolicyBundle expected;
1168  base::DictionaryValue expected_a;
1169  expected_a.SetInteger("policy 1", 3);
1170  expected_a.SetInteger("policy 2", 3);
1171  expected.Get(ns_a).LoadFrom(
1172      &expected_a, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
1173  base::DictionaryValue expected_b;
1174  expected_b.SetInteger("policy 1", 2);
1175  expected.Get(ns_b).LoadFrom(
1176      &expected_b, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
1177  EXPECT_TRUE(Matches(expected));
1178}
1179
1180TEST_F(PolicyLoaderWinTest, LBSSupport) {
1181  const PolicyNamespace ns(
1182      POLICY_DOMAIN_EXTENSIONS, "heildphpnddilhkemkielfhnkaagiabh");
1183  schema_registry_.RegisterComponent(ns, Schema());
1184
1185  const char kIncompleteSchema[] =
1186      "{"
1187       "  \"type\": \"object\","
1188       "  \"properties\": {"
1189       "    \"url_list\": { \"type\": \"array\" },"
1190       "    \"url_greylist\": { \"type\": \"array\" }"
1191       "  }"
1192      "}";
1193
1194  const base::string16 kPathSuffix =
1195      kTestPolicyKey + base::ASCIIToUTF16("\\3rdparty\\extensions");
1196
1197  base::ListValue list;
1198  list.AppendString("youtube.com");
1199  base::DictionaryValue policy;
1200  policy.Set("url_list", list.DeepCopy());
1201  policy.SetString("alternative_browser_path", "c:\\legacy\\browser.exe");
1202  base::DictionaryValue root;
1203  root.Set(base::UTF16ToUTF8(kMandatory), policy.DeepCopy());
1204  root.SetString(kSchema, kIncompleteSchema);
1205  EXPECT_TRUE(InstallValue(root, HKEY_LOCAL_MACHINE,
1206                           kPathSuffix, base::ASCIIToUTF16(ns.component_id)));
1207
1208  PolicyBundle expected;
1209  PolicyMap& expected_policy = expected.Get(ns);
1210  expected_policy.Set("alternative_browser_path",
1211                      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
1212                      new base::StringValue("c:\\legacy\\browser.exe"), NULL);
1213  expected_policy.Set("url_list", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
1214                      list.DeepCopy(), NULL);
1215  EXPECT_TRUE(Matches(expected));
1216}
1217
1218}  // namespace policy
1219