1 // Copyright 2013 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/configuration_policy_provider_test.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/task_scheduler/post_task.h"
12 #include "base/task_scheduler/task_traits.h"
13 #include "base/values.h"
14 #include "components/policy/core/common/configuration_policy_provider.h"
15 #include "components/policy/core/common/external_data_fetcher.h"
16 #include "components/policy/core/common/mock_configuration_policy_provider.h"
17 #include "components/policy/core/common/policy_bundle.h"
18 #include "components/policy/core/common/policy_map.h"
19 #include "components/policy/core/common/policy_namespace.h"
20 #include "components/policy/core/common/policy_types.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22
23 using ::testing::Mock;
24 using ::testing::_;
25
26 namespace policy {
27
28 const char kTestChromeSchema[] =
29 "{"
30 " \"type\": \"object\","
31 " \"properties\": {"
32 " \"StringPolicy\": { \"type\": \"string\" },"
33 " \"BooleanPolicy\": { \"type\": \"boolean\" },"
34 " \"IntegerPolicy\": { \"type\": \"integer\" },"
35 " \"StringListPolicy\": {"
36 " \"type\": \"array\","
37 " \"items\": { \"type\": \"string\" }"
38 " },"
39 " \"DictionaryPolicy\": {"
40 " \"type\": \"object\","
41 " \"properties\": {"
42 " \"bool\": { \"type\": \"boolean\" },"
43 " \"double\": { \"type\": \"number\" },"
44 " \"int\": { \"type\": \"integer\" },"
45 " \"string\": { \"type\": \"string\" },"
46 " \"array\": {"
47 " \"type\": \"array\","
48 " \"items\": { \"type\": \"string\" }"
49 " },"
50 " \"dictionary\": {"
51 " \"type\": \"object\","
52 " \"properties\": {"
53 " \"sub\": { \"type\": \"string\" },"
54 " \"sublist\": {"
55 " \"type\": \"array\","
56 " \"items\": {"
57 " \"type\": \"object\","
58 " \"properties\": {"
59 " \"aaa\": { \"type\": \"integer\" },"
60 " \"bbb\": { \"type\": \"integer\" },"
61 " \"ccc\": { \"type\": \"string\" },"
62 " \"ddd\": { \"type\": \"string\" }"
63 " }"
64 " }"
65 " }"
66 " }"
67 " },"
68 " \"list\": {"
69 " \"type\": \"array\","
70 " \"items\": {"
71 " \"type\": \"object\","
72 " \"properties\": {"
73 " \"subdictindex\": { \"type\": \"integer\" },"
74 " \"subdict\": {"
75 " \"type\": \"object\","
76 " \"properties\": {"
77 " \"bool\": { \"type\": \"boolean\" },"
78 " \"double\": { \"type\": \"number\" },"
79 " \"int\": { \"type\": \"integer\" },"
80 " \"string\": { \"type\": \"string\" }"
81 " }"
82 " }"
83 " }"
84 " }"
85 " },"
86 " \"dict\": {"
87 " \"type\": \"object\","
88 " \"properties\": {"
89 " \"bool\": { \"type\": \"boolean\" },"
90 " \"double\": { \"type\": \"number\" },"
91 " \"int\": { \"type\": \"integer\" },"
92 " \"string\": { \"type\": \"string\" },"
93 " \"list\": {"
94 " \"type\": \"array\","
95 " \"items\": {"
96 " \"type\": \"object\","
97 " \"properties\": {"
98 " \"subdictindex\": { \"type\": \"integer\" },"
99 " \"subdict\": {"
100 " \"type\": \"object\","
101 " \"properties\": {"
102 " \"bool\": { \"type\": \"boolean\" },"
103 " \"double\": { \"type\": \"number\" },"
104 " \"int\": { \"type\": \"integer\" },"
105 " \"string\": { \"type\": \"string\" }"
106 " }"
107 " }"
108 " }"
109 " }"
110 " }"
111 " }"
112 " }"
113 " }"
114 " }"
115 " }"
116 "}";
117
118 namespace test_keys {
119
120 const char kKeyString[] = "StringPolicy";
121 const char kKeyBoolean[] = "BooleanPolicy";
122 const char kKeyInteger[] = "IntegerPolicy";
123 const char kKeyStringList[] = "StringListPolicy";
124 const char kKeyDictionary[] = "DictionaryPolicy";
125
126 } // namespace test_keys
127
PolicyTestBase()128 PolicyTestBase::PolicyTestBase() {}
129
~PolicyTestBase()130 PolicyTestBase::~PolicyTestBase() {}
131
SetUp()132 void PolicyTestBase::SetUp() {
133 const PolicyNamespace ns(POLICY_DOMAIN_CHROME, "");
134 ASSERT_TRUE(RegisterSchema(ns, kTestChromeSchema));
135 }
136
TearDown()137 void PolicyTestBase::TearDown() {
138 scoped_task_environment_.RunUntilIdle();
139 }
140
RegisterSchema(const PolicyNamespace & ns,const std::string & schema_string)141 bool PolicyTestBase::RegisterSchema(const PolicyNamespace& ns,
142 const std::string& schema_string) {
143 std::string error;
144 Schema schema = Schema::Parse(schema_string, &error);
145 if (schema.valid()) {
146 schema_registry_.RegisterComponent(ns, schema);
147 return true;
148 }
149 ADD_FAILURE() << error;
150 return false;
151 }
152
PolicyProviderTestHarness(PolicyLevel level,PolicyScope scope,PolicySource source)153 PolicyProviderTestHarness::PolicyProviderTestHarness(PolicyLevel level,
154 PolicyScope scope,
155 PolicySource source)
156 : level_(level), scope_(scope), source_(source) {}
157
~PolicyProviderTestHarness()158 PolicyProviderTestHarness::~PolicyProviderTestHarness() {}
159
policy_level() const160 PolicyLevel PolicyProviderTestHarness::policy_level() const {
161 return level_;
162 }
163
policy_scope() const164 PolicyScope PolicyProviderTestHarness::policy_scope() const {
165 return scope_;
166 }
167
policy_source() const168 PolicySource PolicyProviderTestHarness::policy_source() const {
169 return source_;
170 }
171
Install3rdPartyPolicy(const base::DictionaryValue * policies)172 void PolicyProviderTestHarness::Install3rdPartyPolicy(
173 const base::DictionaryValue* policies) {
174 FAIL();
175 }
176
ConfigurationPolicyProviderTest()177 ConfigurationPolicyProviderTest::ConfigurationPolicyProviderTest() {}
178
~ConfigurationPolicyProviderTest()179 ConfigurationPolicyProviderTest::~ConfigurationPolicyProviderTest() {}
180
SetUp()181 void ConfigurationPolicyProviderTest::SetUp() {
182 PolicyTestBase::SetUp();
183
184 test_harness_.reset((*GetParam())());
185 ASSERT_NO_FATAL_FAILURE(test_harness_->SetUp());
186
187 const PolicyNamespace chrome_ns(POLICY_DOMAIN_CHROME, "");
188 Schema chrome_schema = *schema_registry_.schema_map()->GetSchema(chrome_ns);
189 Schema extension_schema =
190 chrome_schema.GetKnownProperty(test_keys::kKeyDictionary);
191 ASSERT_TRUE(extension_schema.valid());
192 schema_registry_.RegisterComponent(
193 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
194 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
195 extension_schema);
196 schema_registry_.RegisterComponent(
197 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
198 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
199 extension_schema);
200 schema_registry_.RegisterComponent(
201 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
202 "cccccccccccccccccccccccccccccccc"),
203 extension_schema);
204
205 provider_.reset(test_harness_->CreateProvider(
206 &schema_registry_,
207 base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()})));
208 provider_->Init(&schema_registry_);
209 // Some providers do a reload on init. Make sure any notifications generated
210 // are fired now.
211 scoped_task_environment_.RunUntilIdle();
212
213 const PolicyBundle kEmptyBundle;
214 EXPECT_TRUE(provider_->policies().Equals(kEmptyBundle));
215 }
216
TearDown()217 void ConfigurationPolicyProviderTest::TearDown() {
218 // Give providers the chance to clean up after themselves on the file thread.
219 provider_->Shutdown();
220 provider_.reset();
221
222 PolicyTestBase::TearDown();
223 }
224
CheckValue(const char * policy_name,const base::Value & expected_value,base::Closure install_value)225 void ConfigurationPolicyProviderTest::CheckValue(
226 const char* policy_name,
227 const base::Value& expected_value,
228 base::Closure install_value) {
229 // Install the value, reload policy and check the provider for the value.
230 install_value.Run();
231 provider_->RefreshPolicies();
232 scoped_task_environment_.RunUntilIdle();
233 PolicyBundle expected_bundle;
234 expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
235 .Set(policy_name, test_harness_->policy_level(),
236 test_harness_->policy_scope(), test_harness_->policy_source(),
237 expected_value.CreateDeepCopy(), nullptr);
238 EXPECT_TRUE(provider_->policies().Equals(expected_bundle));
239 // TODO(joaodasilva): set the policy in the POLICY_DOMAIN_EXTENSIONS too,
240 // and extend the |expected_bundle|, once all providers are ready.
241 }
242
TEST_P(ConfigurationPolicyProviderTest,Empty)243 TEST_P(ConfigurationPolicyProviderTest, Empty) {
244 provider_->RefreshPolicies();
245 scoped_task_environment_.RunUntilIdle();
246 const PolicyBundle kEmptyBundle;
247 EXPECT_TRUE(provider_->policies().Equals(kEmptyBundle));
248 }
249
TEST_P(ConfigurationPolicyProviderTest,StringValue)250 TEST_P(ConfigurationPolicyProviderTest, StringValue) {
251 const char kTestString[] = "string_value";
252 base::Value expected_value(kTestString);
253 CheckValue(test_keys::kKeyString,
254 expected_value,
255 base::Bind(&PolicyProviderTestHarness::InstallStringPolicy,
256 base::Unretained(test_harness_.get()),
257 test_keys::kKeyString,
258 kTestString));
259 }
260
TEST_P(ConfigurationPolicyProviderTest,BooleanValue)261 TEST_P(ConfigurationPolicyProviderTest, BooleanValue) {
262 base::Value expected_value(true);
263 CheckValue(test_keys::kKeyBoolean,
264 expected_value,
265 base::Bind(&PolicyProviderTestHarness::InstallBooleanPolicy,
266 base::Unretained(test_harness_.get()),
267 test_keys::kKeyBoolean,
268 true));
269 }
270
TEST_P(ConfigurationPolicyProviderTest,IntegerValue)271 TEST_P(ConfigurationPolicyProviderTest, IntegerValue) {
272 base::Value expected_value(42);
273 CheckValue(test_keys::kKeyInteger,
274 expected_value,
275 base::Bind(&PolicyProviderTestHarness::InstallIntegerPolicy,
276 base::Unretained(test_harness_.get()),
277 test_keys::kKeyInteger,
278 42));
279 }
280
TEST_P(ConfigurationPolicyProviderTest,StringListValue)281 TEST_P(ConfigurationPolicyProviderTest, StringListValue) {
282 base::ListValue expected_value;
283 expected_value.AppendString("first");
284 expected_value.AppendString("second");
285 CheckValue(test_keys::kKeyStringList,
286 expected_value,
287 base::Bind(&PolicyProviderTestHarness::InstallStringListPolicy,
288 base::Unretained(test_harness_.get()),
289 test_keys::kKeyStringList,
290 &expected_value));
291 }
292
TEST_P(ConfigurationPolicyProviderTest,DictionaryValue)293 TEST_P(ConfigurationPolicyProviderTest, DictionaryValue) {
294 base::DictionaryValue expected_value;
295 expected_value.SetBoolean("bool", true);
296 expected_value.SetDouble("double", 123.456);
297 expected_value.SetInteger("int", 123);
298 expected_value.SetString("string", "omg");
299
300 auto list = std::make_unique<base::ListValue>();
301 list->AppendString("first");
302 list->AppendString("second");
303 expected_value.Set("array", std::move(list));
304
305 auto dict = std::make_unique<base::DictionaryValue>();
306 dict->SetString("sub", "value");
307 list = std::make_unique<base::ListValue>();
308 auto sub = std::make_unique<base::DictionaryValue>();
309 sub->SetInteger("aaa", 111);
310 sub->SetInteger("bbb", 222);
311 list->Append(std::move(sub));
312 sub = std::make_unique<base::DictionaryValue>();
313 sub->SetString("ccc", "333");
314 sub->SetString("ddd", "444");
315 list->Append(std::move(sub));
316 dict->Set("sublist", std::move(list));
317 expected_value.Set("dictionary", std::move(dict));
318
319 CheckValue(test_keys::kKeyDictionary,
320 expected_value,
321 base::Bind(&PolicyProviderTestHarness::InstallDictionaryPolicy,
322 base::Unretained(test_harness_.get()),
323 test_keys::kKeyDictionary,
324 &expected_value));
325 }
326
TEST_P(ConfigurationPolicyProviderTest,RefreshPolicies)327 TEST_P(ConfigurationPolicyProviderTest, RefreshPolicies) {
328 PolicyBundle bundle;
329 EXPECT_TRUE(provider_->policies().Equals(bundle));
330
331 // OnUpdatePolicy is called even when there are no changes.
332 MockConfigurationPolicyObserver observer;
333 provider_->AddObserver(&observer);
334 EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(1);
335 provider_->RefreshPolicies();
336 scoped_task_environment_.RunUntilIdle();
337 Mock::VerifyAndClearExpectations(&observer);
338
339 EXPECT_TRUE(provider_->policies().Equals(bundle));
340
341 // OnUpdatePolicy is called when there are changes.
342 test_harness_->InstallStringPolicy(test_keys::kKeyString, "value");
343 EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(1);
344 provider_->RefreshPolicies();
345 scoped_task_environment_.RunUntilIdle();
346 Mock::VerifyAndClearExpectations(&observer);
347
348 bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
349 .Set(test_keys::kKeyString, test_harness_->policy_level(),
350 test_harness_->policy_scope(), test_harness_->policy_source(),
351 std::make_unique<base::Value>("value"), nullptr);
352 EXPECT_TRUE(provider_->policies().Equals(bundle));
353 provider_->RemoveObserver(&observer);
354 }
355
356 Configuration3rdPartyPolicyProviderTest::
Configuration3rdPartyPolicyProviderTest()357 Configuration3rdPartyPolicyProviderTest() {}
358
359 Configuration3rdPartyPolicyProviderTest::
~Configuration3rdPartyPolicyProviderTest()360 ~Configuration3rdPartyPolicyProviderTest() {}
361
TEST_P(Configuration3rdPartyPolicyProviderTest,Load3rdParty)362 TEST_P(Configuration3rdPartyPolicyProviderTest, Load3rdParty) {
363 base::DictionaryValue policy_dict;
364 policy_dict.SetBoolean("bool", true);
365 policy_dict.SetDouble("double", 123.456);
366 policy_dict.SetInteger("int", 789);
367 policy_dict.SetString("string", "string value");
368
369 auto list = std::make_unique<base::ListValue>();
370 for (int i = 0; i < 2; ++i) {
371 auto dict = std::make_unique<base::DictionaryValue>();
372 dict->SetInteger("subdictindex", i);
373 dict->SetKey("subdict", policy_dict.Clone());
374 list->Append(std::move(dict));
375 }
376 policy_dict.Set("list", std::move(list));
377 policy_dict.SetKey("dict", policy_dict.Clone());
378
379 // Install these policies as a Chrome policy.
380 test_harness_->InstallDictionaryPolicy(test_keys::kKeyDictionary,
381 &policy_dict);
382 // Install them as 3rd party policies too.
383 base::DictionaryValue policy_3rdparty;
384 policy_3rdparty.SetPath({"extensions", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
385 policy_dict.Clone());
386 policy_3rdparty.SetPath({"extensions", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"},
387 policy_dict.Clone());
388 // Install invalid 3rd party policies that shouldn't be loaded. These also
389 // help detecting memory leaks in the code paths that detect invalid input.
390 policy_3rdparty.SetPath({"invalid-domain", "component"}, policy_dict.Clone());
391 policy_3rdparty.SetString("extensions.cccccccccccccccccccccccccccccccc",
392 "invalid-value");
393 test_harness_->Install3rdPartyPolicy(&policy_3rdparty);
394
395 provider_->RefreshPolicies();
396 scoped_task_environment_.RunUntilIdle();
397
398 PolicyMap expected_policy;
399 expected_policy.Set(test_keys::kKeyDictionary, test_harness_->policy_level(),
400 test_harness_->policy_scope(),
401 test_harness_->policy_source(),
402 policy_dict.CreateDeepCopy(), nullptr);
403 PolicyBundle expected_bundle;
404 expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
405 .CopyFrom(expected_policy);
406 expected_policy.Clear();
407 expected_policy.LoadFrom(&policy_dict,
408 test_harness_->policy_level(),
409 test_harness_->policy_scope(),
410 test_harness_->policy_source());
411 expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
412 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
413 .CopyFrom(expected_policy);
414 expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
415 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"))
416 .CopyFrom(expected_policy);
417 EXPECT_TRUE(provider_->policies().Equals(expected_bundle));
418 }
419
420 } // namespace policy
421