1// Copyright (c) 2011 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 <gtest/gtest.h>
6#include <windows.h>
7
8#include "base/memory/scoped_ptr.h"
9#include "base/message_loop.h"
10#include "base/stl_util-inl.h"
11#include "base/string_number_conversions.h"
12#include "base/string_piece.h"
13#include "base/utf_string_conversions.h"
14#include "base/win/registry.h"
15#include "chrome/browser/policy/asynchronous_policy_loader.h"
16#include "chrome/browser/policy/configuration_policy_pref_store.h"
17#include "chrome/browser/policy/configuration_policy_provider_win.h"
18#include "chrome/browser/policy/mock_configuration_policy_store.h"
19#include "chrome/common/pref_names.h"
20#include "content/browser/browser_thread.h"
21#include "policy/policy_constants.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24using base::win::RegKey;
25
26namespace policy {
27
28const wchar_t kUnitTestRegistrySubKey[] = L"SOFTWARE\\Chromium Unit Tests";
29const wchar_t kUnitTestMachineOverrideSubKey[] =
30    L"SOFTWARE\\Chromium Unit Tests\\HKLM Override";
31const wchar_t kUnitTestUserOverrideSubKey[] =
32    L"SOFTWARE\\Chromium Unit Tests\\HKCU Override";
33
34namespace {
35
36// Holds policy type, corresponding policy name string and a valid value for use
37// in parametrized value tests.
38class PolicyTestParams {
39 public:
40  // Assumes ownership of |hklm_value| and |hkcu_value|.
41  PolicyTestParams(ConfigurationPolicyType type,
42                   const char* policy_name,
43                   Value* hklm_value,
44                   Value* hkcu_value)
45      : type_(type),
46        policy_name_(policy_name),
47        hklm_value_(hklm_value),
48        hkcu_value_(hkcu_value) {}
49
50  // testing::TestWithParam does copy the parameters, so provide copy
51  // constructor and assignment operator.
52  PolicyTestParams(const PolicyTestParams& other)
53      : type_(other.type_),
54        policy_name_(other.policy_name_),
55        hklm_value_(other.hklm_value_->DeepCopy()),
56        hkcu_value_(other.hkcu_value_->DeepCopy()) {}
57
58  const PolicyTestParams& operator=(PolicyTestParams other) {
59    swap(other);
60    return *this;
61  }
62
63  void swap(PolicyTestParams& other) {
64    std::swap(type_, other.type_);
65    std::swap(policy_name_, other.policy_name_);
66    hklm_value_.swap(other.hklm_value_);
67    hkcu_value_.swap(other.hkcu_value_);
68  }
69
70  ConfigurationPolicyType type() const { return type_; }
71  const char* policy_name() const { return policy_name_; }
72  const Value* hklm_value() const { return hklm_value_.get(); }
73  const Value* hkcu_value() const { return hkcu_value_.get(); }
74
75  // Factory methods for different value types.
76  static PolicyTestParams ForStringPolicy(
77      ConfigurationPolicyType type,
78      const char* policy_name) {
79    return PolicyTestParams(type,
80                            policy_name,
81                            Value::CreateStringValue("string_a"),
82                            Value::CreateStringValue("string_b"));
83  }
84  static PolicyTestParams ForBooleanPolicy(
85      ConfigurationPolicyType type,
86      const char* policy_name) {
87    return PolicyTestParams(type,
88                            policy_name,
89                            Value::CreateBooleanValue(true),
90                            Value::CreateBooleanValue(false));
91  }
92  static PolicyTestParams ForIntegerPolicy(
93      ConfigurationPolicyType type,
94      const char* policy_name) {
95    return PolicyTestParams(type,
96                            policy_name,
97                            Value::CreateIntegerValue(42),
98                            Value::CreateIntegerValue(17));
99  }
100  static PolicyTestParams ForListPolicy(
101      ConfigurationPolicyType type,
102      const char* policy_name) {
103    ListValue* hklm_value = new ListValue;
104    hklm_value->Set(0U, Value::CreateStringValue("It's a plane!"));
105    ListValue* hkcu_value = new ListValue;
106    hkcu_value->Set(0U, Value::CreateStringValue("It's a bird!"));
107    hkcu_value->Set(0U, Value::CreateStringValue("It's a flying carpet!"));
108    return PolicyTestParams(type, policy_name, hklm_value, hkcu_value);
109  }
110
111 private:
112  ConfigurationPolicyType type_;
113  const char* policy_name_;
114  scoped_ptr<Value> hklm_value_;
115  scoped_ptr<Value> hkcu_value_;
116};
117
118}  // namespace
119
120// This test class provides sandboxing and mocking for the parts of the
121// Windows Registry implementing Group Policy. The |SetUp| method prepares
122// two temporary sandbox keys in |kUnitTestRegistrySubKey|, one for HKLM and one
123// for HKCU. A test's calls to the registry are redirected by Windows to these
124// sandboxes, allowing the tests to manipulate and access policy as if it
125// were active, but without actually changing the parts of the Registry that
126// are managed by Group Policy.
127class ConfigurationPolicyProviderWinTest
128    : public testing::TestWithParam<PolicyTestParams> {
129 public:
130  ConfigurationPolicyProviderWinTest();
131
132  // testing::Test method overrides:
133  virtual void SetUp();
134  virtual void TearDown();
135
136  void ActivateOverrides();
137  void DeactivateOverrides();
138
139  // Deletes the registry key created during the tests.
140  void DeleteRegistrySandbox();
141
142  // Write a string value to the registry.
143  void WriteString(HKEY hive, const char* name, const wchar_t* value);
144  // Write a DWORD value to the registry.
145  void WriteDWORD(HKEY hive, const char* name, DWORD value);
146
147  // Write the given value to the registry.
148  void WriteValue(HKEY hive, const char* name, const Value* value);
149  // Write a value that is not compatible with the given |value|.
150  void WriteInvalidValue(HKEY hive, const char* name, const Value* value);
151
152 protected:
153  scoped_ptr<MockConfigurationPolicyStore> store_;
154  scoped_ptr<ConfigurationPolicyProviderWin> provider_;
155
156  // A message loop must be declared and instantiated for these tests,
157  // because Windows policy provider create WaitableEvents and
158  // ObjectWatchers that require the tests to have a MessageLoop associated
159  // with the thread executing the tests.
160  MessageLoop loop_;
161
162 private:
163  BrowserThread ui_thread_;
164  BrowserThread file_thread_;
165
166  // Keys are created for the lifetime of a test to contain
167  // the sandboxed HKCU and HKLM hives, respectively.
168  RegKey temp_hkcu_hive_key_;
169  RegKey temp_hklm_hive_key_;
170};
171
172ConfigurationPolicyProviderWinTest::ConfigurationPolicyProviderWinTest()
173    : ui_thread_(BrowserThread::UI, &loop_),
174      file_thread_(BrowserThread::FILE, &loop_),
175      temp_hklm_hive_key_(HKEY_CURRENT_USER, kUnitTestMachineOverrideSubKey,
176                          KEY_READ),
177      temp_hkcu_hive_key_(HKEY_CURRENT_USER, kUnitTestUserOverrideSubKey,
178                          KEY_READ) {
179}
180
181void ConfigurationPolicyProviderWinTest::SetUp() {
182  // Cleanup any remnants of previous tests.
183  DeleteRegistrySandbox();
184
185  // Create the subkeys to hold the overridden HKLM and HKCU
186  // policy settings.
187  temp_hklm_hive_key_.Create(HKEY_CURRENT_USER,
188                             kUnitTestMachineOverrideSubKey,
189                             KEY_ALL_ACCESS);
190  temp_hkcu_hive_key_.Create(HKEY_CURRENT_USER,
191                             kUnitTestUserOverrideSubKey,
192                             KEY_ALL_ACCESS);
193
194  ActivateOverrides();
195
196  store_.reset(new MockConfigurationPolicyStore);
197  provider_.reset(new ConfigurationPolicyProviderWin(
198      ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList()));
199}
200
201void ConfigurationPolicyProviderWinTest::TearDown() {
202  DeactivateOverrides();
203  DeleteRegistrySandbox();
204  loop_.RunAllPending();
205}
206
207void ConfigurationPolicyProviderWinTest::ActivateOverrides() {
208  HRESULT result = RegOverridePredefKey(HKEY_LOCAL_MACHINE,
209                                        temp_hklm_hive_key_.Handle());
210  EXPECT_EQ(ERROR_SUCCESS, result);
211  result = RegOverridePredefKey(HKEY_CURRENT_USER,
212                                temp_hkcu_hive_key_.Handle());
213  EXPECT_EQ(ERROR_SUCCESS, result);
214}
215
216void ConfigurationPolicyProviderWinTest::DeactivateOverrides() {
217  uint32 result = RegOverridePredefKey(HKEY_LOCAL_MACHINE, 0);
218  EXPECT_EQ(ERROR_SUCCESS, result);
219  result = RegOverridePredefKey(HKEY_CURRENT_USER, 0);
220  EXPECT_EQ(ERROR_SUCCESS, result);
221}
222
223void ConfigurationPolicyProviderWinTest::DeleteRegistrySandbox() {
224  temp_hklm_hive_key_.Close();
225  temp_hkcu_hive_key_.Close();
226  RegKey key(HKEY_CURRENT_USER, kUnitTestRegistrySubKey, KEY_ALL_ACCESS);
227  key.DeleteKey(L"");
228}
229
230void ConfigurationPolicyProviderWinTest::WriteString(HKEY hive,
231                                                     const char* name,
232                                                     const wchar_t* value) {
233  RegKey key(hive, policy::kRegistrySubKey, KEY_ALL_ACCESS);
234  key.WriteValue(UTF8ToUTF16(name).c_str(), value);
235}
236
237void ConfigurationPolicyProviderWinTest::WriteDWORD(HKEY hive,
238                                                    const char* name,
239                                                    DWORD value) {
240  RegKey key(hive, policy::kRegistrySubKey, KEY_ALL_ACCESS);
241  key.WriteValue(UTF8ToUTF16(name).c_str(), value);
242}
243
244void ConfigurationPolicyProviderWinTest::WriteValue(HKEY hive,
245                                                    const char* name,
246                                                    const Value* value) {
247  switch (value->GetType()) {
248    case Value::TYPE_BOOLEAN: {
249      bool v;
250      ASSERT_TRUE(value->GetAsBoolean(&v));
251      WriteDWORD(hive, name, v);
252      break;
253    }
254    case Value::TYPE_INTEGER: {
255      int v;
256      ASSERT_TRUE(value->GetAsInteger(&v));
257      WriteDWORD(hive, name, v);
258      break;
259    }
260    case Value::TYPE_STRING: {
261      std::string v;
262      ASSERT_TRUE(value->GetAsString(&v));
263      WriteString(hive, name, UTF8ToUTF16(v).c_str());
264      break;
265    }
266    case Value::TYPE_LIST: {
267      const ListValue* list = static_cast<const ListValue*>(value);
268      RegKey key(hive,
269                 (string16(policy::kRegistrySubKey) + ASCIIToUTF16("\\") +
270                  UTF8ToUTF16(name)).c_str(),
271                 KEY_ALL_ACCESS);
272      int index = 1;
273      for (ListValue::const_iterator element(list->begin());
274           element != list->end(); ++element) {
275        ASSERT_TRUE((*element)->IsType(Value::TYPE_STRING));
276        std::string element_value;
277        ASSERT_TRUE((*element)->GetAsString(&element_value));
278        key.WriteValue(base::IntToString16(index++).c_str(),
279                       UTF8ToUTF16(element_value).c_str());
280      }
281      break;
282    }
283    default:
284      FAIL() << "Unsupported value type " << value->GetType();
285      break;
286  }
287}
288
289void ConfigurationPolicyProviderWinTest::WriteInvalidValue(HKEY hive,
290                                                           const char* name,
291                                                           const Value* value) {
292  if (value->IsType(Value::TYPE_STRING))
293    WriteDWORD(hive, name, -1);
294  else
295    WriteString(hive, name, L"bad value");
296}
297
298TEST_P(ConfigurationPolicyProviderWinTest, Default) {
299  provider_->Provide(store_.get());
300  EXPECT_TRUE(store_->policy_map().empty());
301}
302
303TEST_P(ConfigurationPolicyProviderWinTest, InvalidValue) {
304  WriteInvalidValue(HKEY_LOCAL_MACHINE,
305                    GetParam().policy_name(),
306                    GetParam().hklm_value());
307  WriteInvalidValue(HKEY_CURRENT_USER,
308                    GetParam().policy_name(),
309                    GetParam().hkcu_value());
310  provider_->loader()->Reload();
311  loop_.RunAllPending();
312  provider_->Provide(store_.get());
313  EXPECT_TRUE(store_->policy_map().empty());
314}
315
316TEST_P(ConfigurationPolicyProviderWinTest, HKLM) {
317  WriteValue(HKEY_LOCAL_MACHINE,
318             GetParam().policy_name(),
319             GetParam().hklm_value());
320  provider_->loader()->Reload();
321  loop_.RunAllPending();
322  provider_->Provide(store_.get());
323  const Value* value = store_->Get(GetParam().type());
324  ASSERT_TRUE(value);
325  EXPECT_TRUE(value->Equals(GetParam().hklm_value()));
326}
327
328TEST_P(ConfigurationPolicyProviderWinTest, HKCU) {
329  WriteValue(HKEY_CURRENT_USER,
330             GetParam().policy_name(),
331             GetParam().hkcu_value());
332  provider_->loader()->Reload();
333  loop_.RunAllPending();
334  provider_->Provide(store_.get());
335  const Value* value = store_->Get(GetParam().type());
336  ASSERT_TRUE(value);
337  EXPECT_TRUE(value->Equals(GetParam().hkcu_value()));
338}
339
340TEST_P(ConfigurationPolicyProviderWinTest, HKLMOverHKCU) {
341  WriteValue(HKEY_LOCAL_MACHINE,
342             GetParam().policy_name(),
343             GetParam().hklm_value());
344  WriteValue(HKEY_CURRENT_USER,
345             GetParam().policy_name(),
346             GetParam().hkcu_value());
347  provider_->loader()->Reload();
348  loop_.RunAllPending();
349  provider_->Provide(store_.get());
350  const Value* value = store_->Get(GetParam().type());
351  ASSERT_TRUE(value);
352  EXPECT_TRUE(value->Equals(GetParam().hklm_value()));
353}
354
355// Instantiate the test case for all supported policies.
356INSTANTIATE_TEST_CASE_P(
357    ConfigurationPolicyProviderWinTestInstance,
358    ConfigurationPolicyProviderWinTest,
359    testing::Values(
360        PolicyTestParams::ForStringPolicy(
361            kPolicyHomepageLocation,
362            key::kHomepageLocation),
363        PolicyTestParams::ForBooleanPolicy(
364            kPolicyHomepageIsNewTabPage,
365            key::kHomepageIsNewTabPage),
366        PolicyTestParams::ForIntegerPolicy(
367            kPolicyRestoreOnStartup,
368            key::kRestoreOnStartup),
369        PolicyTestParams::ForListPolicy(
370            kPolicyRestoreOnStartupURLs,
371            key::kRestoreOnStartupURLs),
372        PolicyTestParams::ForBooleanPolicy(
373            kPolicyDefaultSearchProviderEnabled,
374            key::kDefaultSearchProviderEnabled),
375        PolicyTestParams::ForStringPolicy(
376            kPolicyDefaultSearchProviderName,
377            key::kDefaultSearchProviderName),
378        PolicyTestParams::ForStringPolicy(
379            kPolicyDefaultSearchProviderKeyword,
380            key::kDefaultSearchProviderKeyword),
381        PolicyTestParams::ForStringPolicy(
382            kPolicyDefaultSearchProviderSearchURL,
383            key::kDefaultSearchProviderSearchURL),
384        PolicyTestParams::ForStringPolicy(
385            kPolicyDefaultSearchProviderSuggestURL,
386            key::kDefaultSearchProviderSuggestURL),
387        PolicyTestParams::ForStringPolicy(
388            kPolicyDefaultSearchProviderInstantURL,
389            key::kDefaultSearchProviderInstantURL),
390        PolicyTestParams::ForStringPolicy(
391            kPolicyDefaultSearchProviderIconURL,
392            key::kDefaultSearchProviderIconURL),
393        PolicyTestParams::ForStringPolicy(
394            kPolicyDefaultSearchProviderEncodings,
395            key::kDefaultSearchProviderEncodings),
396        PolicyTestParams::ForStringPolicy(
397            kPolicyProxyMode,
398            key::kProxyMode),
399        PolicyTestParams::ForIntegerPolicy(
400            kPolicyProxyServerMode,
401            key::kProxyServerMode),
402        PolicyTestParams::ForStringPolicy(
403            kPolicyProxyServer,
404            key::kProxyServer),
405        PolicyTestParams::ForStringPolicy(
406            kPolicyProxyPacUrl,
407            key::kProxyPacUrl),
408        PolicyTestParams::ForStringPolicy(
409            kPolicyProxyBypassList,
410            key::kProxyBypassList),
411        PolicyTestParams::ForBooleanPolicy(
412            kPolicyAlternateErrorPagesEnabled,
413            key::kAlternateErrorPagesEnabled),
414        PolicyTestParams::ForBooleanPolicy(
415            kPolicySearchSuggestEnabled,
416            key::kSearchSuggestEnabled),
417        PolicyTestParams::ForBooleanPolicy(
418            kPolicyDnsPrefetchingEnabled,
419            key::kDnsPrefetchingEnabled),
420        PolicyTestParams::ForBooleanPolicy(
421            kPolicySafeBrowsingEnabled,
422            key::kSafeBrowsingEnabled),
423        PolicyTestParams::ForBooleanPolicy(
424            kPolicyMetricsReportingEnabled,
425            key::kMetricsReportingEnabled),
426        PolicyTestParams::ForBooleanPolicy(
427            kPolicyPasswordManagerEnabled,
428            key::kPasswordManagerEnabled),
429        PolicyTestParams::ForListPolicy(
430            kPolicyDisabledPlugins,
431            key::kDisabledPlugins),
432        PolicyTestParams::ForListPolicy(
433            kPolicyDisabledPluginsExceptions,
434            key::kDisabledPluginsExceptions),
435        PolicyTestParams::ForListPolicy(
436            kPolicyEnabledPlugins,
437            key::kEnabledPlugins),
438        PolicyTestParams::ForBooleanPolicy(
439            kPolicyAutoFillEnabled,
440            key::kAutoFillEnabled),
441        PolicyTestParams::ForBooleanPolicy(
442            kPolicySyncDisabled,
443            key::kSyncDisabled),
444        PolicyTestParams::ForStringPolicy(
445            kPolicyApplicationLocaleValue,
446            key::kApplicationLocaleValue),
447        PolicyTestParams::ForListPolicy(
448            kPolicyExtensionInstallWhitelist,
449            key::kExtensionInstallWhitelist),
450        PolicyTestParams::ForListPolicy(
451            kPolicyExtensionInstallBlacklist,
452            key::kExtensionInstallBlacklist),
453        PolicyTestParams::ForBooleanPolicy(
454            kPolicyShowHomeButton,
455            key::kShowHomeButton),
456        PolicyTestParams::ForBooleanPolicy(
457            kPolicyPrintingEnabled,
458            key::kPrintingEnabled),
459        PolicyTestParams::ForIntegerPolicy(
460            kPolicyPolicyRefreshRate,
461            key::kPolicyRefreshRate),
462        PolicyTestParams::ForBooleanPolicy(
463            kPolicyInstantEnabled,
464            key::kInstantEnabled),
465        PolicyTestParams::ForBooleanPolicy(
466            kPolicyIncognitoEnabled,
467            key::kIncognitoEnabled),
468        PolicyTestParams::ForBooleanPolicy(
469            kPolicyDisablePluginFinder,
470            key::kDisablePluginFinder),
471        PolicyTestParams::ForBooleanPolicy(
472            kPolicyClearSiteDataOnExit,
473            key::kClearSiteDataOnExit),
474        PolicyTestParams::ForStringPolicy(
475            kPolicyDownloadDirectory,
476            key::kDownloadDirectory),
477        PolicyTestParams::ForBooleanPolicy(
478            kPolicyDefaultBrowserSettingEnabled,
479            key::kDefaultBrowserSettingEnabled),
480        PolicyTestParams::ForBooleanPolicy(
481            kPolicyCloudPrintProxyEnabled,
482            key::kCloudPrintProxyEnabled),
483        PolicyTestParams::ForBooleanPolicy(
484            kPolicyTranslateEnabled,
485            key::kTranslateEnabled),
486        PolicyTestParams::ForBooleanPolicy(
487            kPolicyAllowOutdatedPlugins,
488            key::kAllowOutdatedPlugins),
489        PolicyTestParams::ForBooleanPolicy(
490            kPolicyBookmarkBarEnabled,
491            key::kBookmarkBarEnabled),
492        PolicyTestParams::ForBooleanPolicy(
493            kPolicyEditBookmarksEnabled,
494            key::kEditBookmarksEnabled),
495        PolicyTestParams::ForBooleanPolicy(
496            kPolicyAllowFileSelectionDialogs,
497            key::kAllowFileSelectionDialogs),
498        PolicyTestParams::ForListPolicy(
499            kPolicyDisabledSchemes,
500            key::kDisabledSchemes)));
501
502}  // namespace policy
503