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/config_dir_policy_loader.h"
6 #include <memory>
7
8 #include <utility>
9
10 #include "base/compiler_specific.h"
11 #include "base/files/file_util.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/json/json_string_value_serializer.h"
14 #include "base/macros.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/sequenced_task_runner.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/values.h"
19 #include "components/policy/core/common/async_policy_provider.h"
20 #include "components/policy/core/common/configuration_policy_provider_test.h"
21 #include "components/policy/core/common/policy_bundle.h"
22 #include "components/policy/core/common/policy_map.h"
23 #include "components/policy/core/common/policy_types.h"
24
25 namespace policy {
26
27 namespace {
28
29 // Subdirectory of the config dir that contains mandatory policies.
30 const base::FilePath::CharType kMandatoryPath[] = FILE_PATH_LITERAL("managed");
31
32 class TestHarness : public PolicyProviderTestHarness {
33 public:
34 TestHarness();
35 ~TestHarness() override;
36
37 void SetUp() override;
38
39 ConfigurationPolicyProvider* CreateProvider(
40 SchemaRegistry* registry,
41 scoped_refptr<base::SequencedTaskRunner> task_runner) override;
42
43 void InstallEmptyPolicy() override;
44 void InstallStringPolicy(const std::string& policy_name,
45 const std::string& policy_value) override;
46 void InstallIntegerPolicy(const std::string& policy_name,
47 int policy_value) override;
48 void InstallBooleanPolicy(const std::string& policy_name,
49 bool policy_value) override;
50 void InstallStringListPolicy(const std::string& policy_name,
51 const base::ListValue* policy_value) override;
52 void InstallDictionaryPolicy(
53 const std::string& policy_name,
54 const base::DictionaryValue* policy_value) override;
55 void Install3rdPartyPolicy(const base::DictionaryValue* policies) override;
56
test_dir()57 const base::FilePath& test_dir() { return test_dir_.GetPath(); }
58
59 // JSON-encode a dictionary and write it to a file.
60 void WriteConfigFile(const base::DictionaryValue& dict,
61 const std::string& file_name);
62
63 // Returns a unique name for a policy file. Each subsequent call returns a new
64 // name that comes lexicographically after the previous one.
65 std::string NextConfigFileName();
66
67 static PolicyProviderTestHarness* Create();
68
69 private:
70 base::ScopedTempDir test_dir_;
71 int next_policy_file_index_;
72
73 DISALLOW_COPY_AND_ASSIGN(TestHarness);
74 };
75
TestHarness()76 TestHarness::TestHarness()
77 : PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY,
78 POLICY_SCOPE_MACHINE,
79 POLICY_SOURCE_PLATFORM),
80 next_policy_file_index_(100) {}
81
~TestHarness()82 TestHarness::~TestHarness() {}
83
SetUp()84 void TestHarness::SetUp() {
85 ASSERT_TRUE(test_dir_.CreateUniqueTempDir());
86 }
87
CreateProvider(SchemaRegistry * registry,scoped_refptr<base::SequencedTaskRunner> task_runner)88 ConfigurationPolicyProvider* TestHarness::CreateProvider(
89 SchemaRegistry* registry,
90 scoped_refptr<base::SequencedTaskRunner> task_runner) {
91 std::unique_ptr<AsyncPolicyLoader> loader(
92 new ConfigDirPolicyLoader(task_runner, test_dir(), POLICY_SCOPE_MACHINE));
93 return new AsyncPolicyProvider(registry, std::move(loader));
94 }
95
InstallEmptyPolicy()96 void TestHarness::InstallEmptyPolicy() {
97 base::DictionaryValue dict;
98 WriteConfigFile(dict, NextConfigFileName());
99 }
100
InstallStringPolicy(const std::string & policy_name,const std::string & policy_value)101 void TestHarness::InstallStringPolicy(const std::string& policy_name,
102 const std::string& policy_value) {
103 base::DictionaryValue dict;
104 dict.SetString(policy_name, policy_value);
105 WriteConfigFile(dict, NextConfigFileName());
106 }
107
InstallIntegerPolicy(const std::string & policy_name,int policy_value)108 void TestHarness::InstallIntegerPolicy(const std::string& policy_name,
109 int policy_value) {
110 base::DictionaryValue dict;
111 dict.SetInteger(policy_name, policy_value);
112 WriteConfigFile(dict, NextConfigFileName());
113 }
114
InstallBooleanPolicy(const std::string & policy_name,bool policy_value)115 void TestHarness::InstallBooleanPolicy(const std::string& policy_name,
116 bool policy_value) {
117 base::DictionaryValue dict;
118 dict.SetBoolean(policy_name, policy_value);
119 WriteConfigFile(dict, NextConfigFileName());
120 }
121
InstallStringListPolicy(const std::string & policy_name,const base::ListValue * policy_value)122 void TestHarness::InstallStringListPolicy(const std::string& policy_name,
123 const base::ListValue* policy_value) {
124 base::DictionaryValue dict;
125 dict.Set(policy_name, std::make_unique<base::Value>(policy_value->Clone()));
126 WriteConfigFile(dict, NextConfigFileName());
127 }
128
InstallDictionaryPolicy(const std::string & policy_name,const base::DictionaryValue * policy_value)129 void TestHarness::InstallDictionaryPolicy(
130 const std::string& policy_name,
131 const base::DictionaryValue* policy_value) {
132 base::DictionaryValue dict;
133 dict.Set(policy_name, std::make_unique<base::Value>(policy_value->Clone()));
134 WriteConfigFile(dict, NextConfigFileName());
135 }
136
Install3rdPartyPolicy(const base::DictionaryValue * policies)137 void TestHarness::Install3rdPartyPolicy(const base::DictionaryValue* policies) {
138 base::DictionaryValue dict;
139 dict.SetKey("3rdparty", policies->Clone());
140 WriteConfigFile(dict, NextConfigFileName());
141 }
142
WriteConfigFile(const base::DictionaryValue & dict,const std::string & file_name)143 void TestHarness::WriteConfigFile(const base::DictionaryValue& dict,
144 const std::string& file_name) {
145 std::string data;
146 JSONStringValueSerializer serializer(&data);
147 serializer.Serialize(dict);
148 const base::FilePath mandatory_dir(test_dir().Append(kMandatoryPath));
149 ASSERT_TRUE(base::CreateDirectory(mandatory_dir));
150 const base::FilePath file_path(mandatory_dir.AppendASCII(file_name));
151 ASSERT_EQ((int) data.size(),
152 base::WriteFile(file_path, data.c_str(), data.size()));
153 }
154
NextConfigFileName()155 std::string TestHarness::NextConfigFileName() {
156 EXPECT_LE(next_policy_file_index_, 999);
157 return std::string("policy") + base::IntToString(next_policy_file_index_++);
158 }
159
160 // static
Create()161 PolicyProviderTestHarness* TestHarness::Create() {
162 return new TestHarness();
163 }
164
165 } // namespace
166
167 // Instantiate abstract test case for basic policy reading tests.
168 INSTANTIATE_TEST_CASE_P(
169 ConfigDirPolicyLoaderTest,
170 ConfigurationPolicyProviderTest,
171 testing::Values(TestHarness::Create));
172
173 // Instantiate abstract test case for 3rd party policy reading tests.
174 INSTANTIATE_TEST_CASE_P(
175 ConfigDir3rdPartyPolicyLoaderTest,
176 Configuration3rdPartyPolicyProviderTest,
177 testing::Values(TestHarness::Create));
178
179 // Some tests that exercise special functionality in ConfigDirPolicyLoader.
180 class ConfigDirPolicyLoaderTest : public PolicyTestBase {
181 protected:
SetUp()182 void SetUp() override {
183 PolicyTestBase::SetUp();
184 harness_.SetUp();
185 }
186
187 TestHarness harness_;
188 };
189
190 // The preferences dictionary is expected to be empty when there are no files to
191 // load.
TEST_F(ConfigDirPolicyLoaderTest,ReadPrefsEmpty)192 TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsEmpty) {
193 ConfigDirPolicyLoader loader(
194 scoped_task_environment_.GetMainThreadTaskRunner(), harness_.test_dir(),
195 POLICY_SCOPE_MACHINE);
196 std::unique_ptr<PolicyBundle> bundle(loader.Load());
197 ASSERT_TRUE(bundle.get());
198 const PolicyBundle kEmptyBundle;
199 EXPECT_TRUE(bundle->Equals(kEmptyBundle));
200 }
201
202 // Reading from a non-existent directory should result in an empty preferences
203 // dictionary.
TEST_F(ConfigDirPolicyLoaderTest,ReadPrefsNonExistentDirectory)204 TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsNonExistentDirectory) {
205 base::FilePath non_existent_dir(
206 harness_.test_dir().Append(FILE_PATH_LITERAL("not_there")));
207 ConfigDirPolicyLoader loader(
208 scoped_task_environment_.GetMainThreadTaskRunner(), non_existent_dir,
209 POLICY_SCOPE_MACHINE);
210 std::unique_ptr<PolicyBundle> bundle(loader.Load());
211 ASSERT_TRUE(bundle.get());
212 const PolicyBundle kEmptyBundle;
213 EXPECT_TRUE(bundle->Equals(kEmptyBundle));
214 }
215
216 // Test merging values from different files.
TEST_F(ConfigDirPolicyLoaderTest,ReadPrefsMergePrefs)217 TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsMergePrefs) {
218 // Write a bunch of data files in order to increase the chance to detect the
219 // provider not respecting lexicographic ordering when reading them. Since the
220 // filesystem may return files in arbitrary order, there is no way to be sure,
221 // but this is better than nothing.
222 base::DictionaryValue test_dict_bar;
223 test_dict_bar.SetString("HomepageLocation", "http://bar.com");
224 for (unsigned int i = 1; i <= 4; ++i)
225 harness_.WriteConfigFile(test_dict_bar, base::UintToString(i));
226 base::DictionaryValue test_dict_foo;
227 test_dict_foo.SetString("HomepageLocation", "http://foo.com");
228 harness_.WriteConfigFile(test_dict_foo, "9");
229 for (unsigned int i = 5; i <= 8; ++i)
230 harness_.WriteConfigFile(test_dict_bar, base::UintToString(i));
231
232 ConfigDirPolicyLoader loader(
233 scoped_task_environment_.GetMainThreadTaskRunner(), harness_.test_dir(),
234 POLICY_SCOPE_USER);
235 std::unique_ptr<PolicyBundle> bundle(loader.Load());
236 ASSERT_TRUE(bundle.get());
237 PolicyBundle expected_bundle;
238 expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
239 .LoadFrom(&test_dict_foo, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
240 POLICY_SOURCE_PLATFORM);
241 EXPECT_TRUE(bundle->Equals(expected_bundle));
242 }
243
244 } // namespace policy
245