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/policy_bundle.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/callback.h"
11 #include "base/values.h"
12 #include "components/policy/core/common/external_data_fetcher.h"
13 #include "components/policy/core/common/policy_map.h"
14 #include "components/policy/core/common/policy_types.h"
15 #include "components/strings/grit/components_strings.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 namespace policy {
19 
20 namespace {
21 
22 const char kPolicyClashing0[] = "policy-clashing-0";
23 const char kPolicyClashing1[] = "policy-clashing-1";
24 const char kPolicy0[] = "policy-0";
25 const char kPolicy1[] = "policy-1";
26 const char kPolicy2[] = "policy-2";
27 const char kExtension0[] = "extension-0";
28 const char kExtension1[] = "extension-1";
29 const char kExtension2[] = "extension-2";
30 const char kExtension3[] = "extension-3";
31 
32 // Adds test policies to |policy|.
AddTestPolicies(PolicyMap * policy)33 void AddTestPolicies(PolicyMap* policy) {
34   policy->Set("mandatory-user", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
35               POLICY_SOURCE_CLOUD, base::Value(123), nullptr);
36   policy->Set("mandatory-machine", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
37               POLICY_SOURCE_CLOUD, base::Value("omg"), nullptr);
38   policy->Set("recommended-user", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER,
39               POLICY_SOURCE_CLOUD, base::Value(true), nullptr);
40   base::Value dict(base::Value::Type::DICTIONARY);
41   dict.SetBoolKey("false", false);
42   dict.SetIntKey("int", 456);
43   dict.SetStringKey("str", "bbq");
44   policy->Set("recommended-machine", POLICY_LEVEL_RECOMMENDED,
45               POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, std::move(dict),
46               nullptr);
47 }
48 
49 // Adds test policies to |policy| based on the parameters:
50 // - kPolicyClashing0 mapped to |value|, user mandatory
51 // - kPolicyClashing1 mapped to |value|, with |level| and |scope|
52 // - |name| mapped to |value|, user mandatory
AddTestPoliciesWithParams(PolicyMap * policy,const char * name,int value,PolicyLevel level,PolicyScope scope)53 void AddTestPoliciesWithParams(PolicyMap *policy,
54                                const char* name,
55                                int value,
56                                PolicyLevel level,
57                                PolicyScope scope) {
58   policy->Set(kPolicyClashing0, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
59               POLICY_SOURCE_CLOUD, base::Value(value), nullptr);
60   policy->Set(kPolicyClashing1, level, scope, POLICY_SOURCE_CLOUD,
61               base::Value(value), nullptr);
62   policy->Set(name, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
63               POLICY_SOURCE_CLOUD, base::Value(value), nullptr);
64 }
65 
66 // Returns true if |bundle| is empty.
IsEmpty(const PolicyBundle & bundle)67 bool IsEmpty(const PolicyBundle& bundle) {
68   return bundle.begin() == bundle.end();
69 }
70 
71 }  // namespace
72 
TEST(PolicyBundleTest,Get)73 TEST(PolicyBundleTest, Get) {
74   PolicyBundle bundle;
75   EXPECT_TRUE(IsEmpty(bundle));
76 
77   AddTestPolicies(&bundle.Get(
78       PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())));
79   EXPECT_FALSE(IsEmpty(bundle));
80 
81   PolicyMap policy;
82   AddTestPolicies(&policy);
83   EXPECT_TRUE(bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME,
84                                          std::string())).Equals(policy));
85 
86   PolicyBundle::const_iterator it = bundle.begin();
87   ASSERT_TRUE(it != bundle.end());
88   EXPECT_EQ(POLICY_DOMAIN_CHROME, it->first.domain);
89   EXPECT_EQ("", it->first.component_id);
90   ASSERT_TRUE(it->second);
91   EXPECT_TRUE(it->second->Equals(policy));
92   ++it;
93   EXPECT_TRUE(it == bundle.end());
94   EXPECT_TRUE(bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
95                                          kExtension0)).empty());
96 
97   EXPECT_FALSE(IsEmpty(bundle));
98   bundle.Clear();
99   EXPECT_TRUE(IsEmpty(bundle));
100 }
101 
TEST(PolicyBundleTest,SwapAndCopy)102 TEST(PolicyBundleTest, SwapAndCopy) {
103   PolicyBundle bundle0;
104   PolicyBundle bundle1;
105 
106   AddTestPolicies(&bundle0.Get(
107       PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())));
108   AddTestPolicies(&bundle0.Get(
109       PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension0)));
110   EXPECT_FALSE(IsEmpty(bundle0));
111   EXPECT_TRUE(IsEmpty(bundle1));
112 
113   PolicyMap policy;
114   AddTestPolicies(&policy);
115   EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_CHROME,
116                                           std::string())).Equals(policy));
117   EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
118                                           kExtension0)).Equals(policy));
119 
120   bundle0.Swap(&bundle1);
121   EXPECT_TRUE(IsEmpty(bundle0));
122   EXPECT_FALSE(IsEmpty(bundle1));
123 
124   EXPECT_TRUE(bundle1.Get(PolicyNamespace(POLICY_DOMAIN_CHROME,
125                                           std::string())).Equals(policy));
126   EXPECT_TRUE(bundle1.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
127                                           kExtension0)).Equals(policy));
128 
129   bundle0.CopyFrom(bundle1);
130   EXPECT_FALSE(IsEmpty(bundle0));
131   EXPECT_FALSE(IsEmpty(bundle1));
132   EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_CHROME,
133                                           std::string())).Equals(policy));
134   EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
135                                           kExtension0)).Equals(policy));
136 }
137 
TEST(PolicyBundleTest,MergeFrom)138 TEST(PolicyBundleTest, MergeFrom) {
139   // Each bundleN has kExtensionN. Each bundle also has policy for
140   // chrome and kExtension3.
141   // |bundle0| has the highest priority, |bundle2| the lowest.
142   PolicyBundle bundle0;
143   PolicyBundle bundle1;
144   PolicyBundle bundle2;
145 
146   PolicyMap policy0;
147   AddTestPoliciesWithParams(
148       &policy0, kPolicy0, 0u, POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER);
149   bundle0.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
150       .CopyFrom(policy0);
151   bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension0))
152       .CopyFrom(policy0);
153   bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension3))
154       .CopyFrom(policy0);
155 
156   PolicyMap policy1;
157   AddTestPoliciesWithParams(
158       &policy1, kPolicy1, 1u, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
159   bundle1.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
160       .CopyFrom(policy1);
161   bundle1.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension1))
162       .CopyFrom(policy1);
163   bundle1.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension3))
164       .CopyFrom(policy1);
165 
166   PolicyMap policy2;
167   AddTestPoliciesWithParams(
168       &policy2, kPolicy2, 2u, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
169   bundle2.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
170       .CopyFrom(policy2);
171   bundle2.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension2))
172       .CopyFrom(policy2);
173   bundle2.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension3))
174       .CopyFrom(policy2);
175 
176   // Merge in order of decreasing priority.
177   PolicyBundle merged;
178   merged.MergeFrom(bundle0);
179   merged.MergeFrom(bundle1);
180   merged.MergeFrom(bundle2);
181   PolicyBundle empty_bundle;
182   merged.MergeFrom(empty_bundle);
183 
184   // chrome and kExtension3 policies are merged:
185   // - kPolicyClashing0 comes from bundle0, which has the highest priority;
186   // - kPolicyClashing1 comes from bundle1, which has the highest level/scope
187   //   combination;
188   // - kPolicyN are merged from each bundle.
189   PolicyMap expected;
190   expected.Set(kPolicyClashing0, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
191                POLICY_SOURCE_CLOUD, base::Value(0), nullptr);
192   expected.GetMutable(kPolicyClashing0)
193       ->AddConflictingPolicy(policy1.Get(kPolicyClashing0)->DeepCopy());
194   expected.GetMutable(kPolicyClashing0)
195       ->AddConflictingPolicy(policy2.Get(kPolicyClashing0)->DeepCopy());
196   expected.GetMutable(kPolicyClashing0)
197       ->AddWarning(IDS_POLICY_CONFLICT_DIFF_VALUE);
198   expected.GetMutable(kPolicyClashing0)
199       ->AddWarning(IDS_POLICY_CONFLICT_DIFF_VALUE);
200   expected.Set(kPolicyClashing1, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
201                POLICY_SOURCE_CLOUD, base::Value(1), nullptr);
202   expected.GetMutable(kPolicyClashing1)
203       ->AddConflictingPolicy(policy0.Get(kPolicyClashing1)->DeepCopy());
204   expected.GetMutable(kPolicyClashing1)
205       ->AddConflictingPolicy(policy2.Get(kPolicyClashing1)->DeepCopy());
206   expected.GetMutable(kPolicyClashing1)
207       ->AddWarning(IDS_POLICY_CONFLICT_DIFF_VALUE);
208   expected.GetMutable(kPolicyClashing1)
209       ->AddWarning(IDS_POLICY_CONFLICT_DIFF_VALUE);
210   expected.Set(kPolicy0, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
211                POLICY_SOURCE_CLOUD, base::Value(0), nullptr);
212   expected.Set(kPolicy1, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
213                POLICY_SOURCE_CLOUD, base::Value(1), nullptr);
214   expected.Set(kPolicy2, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
215                POLICY_SOURCE_CLOUD, base::Value(2), nullptr);
216   EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_CHROME,
217                                          std::string())).Equals(expected));
218   EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
219                                          kExtension3)).Equals(expected));
220   // extension0 comes only from bundle0.
221   EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
222                                          kExtension0)).Equals(policy0));
223   // extension1 comes only from bundle1.
224   EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
225                                          kExtension1)).Equals(policy1));
226   // extension2 comes only from bundle2.
227   EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
228                                          kExtension2)).Equals(policy2));
229 }
230 
TEST(PolicyBundleTest,Equals)231 TEST(PolicyBundleTest, Equals) {
232   PolicyBundle bundle;
233   AddTestPolicies(&bundle.Get(
234       PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())));
235   AddTestPolicies(&bundle.Get(
236       PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension0)));
237 
238   PolicyBundle other;
239   EXPECT_FALSE(bundle.Equals(other));
240   other.CopyFrom(bundle);
241   EXPECT_TRUE(bundle.Equals(other));
242 
243   AddTestPolicies(&bundle.Get(
244       PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension1)));
245   EXPECT_FALSE(bundle.Equals(other));
246   other.CopyFrom(bundle);
247   EXPECT_TRUE(bundle.Equals(other));
248   AddTestPolicies(&other.Get(
249       PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension2)));
250   EXPECT_FALSE(bundle.Equals(other));
251 
252   other.CopyFrom(bundle);
253   bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
254       .Set(kPolicy0, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
255            POLICY_SOURCE_CLOUD, base::Value(123), nullptr);
256   EXPECT_FALSE(bundle.Equals(other));
257   other.CopyFrom(bundle);
258   EXPECT_TRUE(bundle.Equals(other));
259   bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
260       .Set(kPolicy0, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
261            POLICY_SOURCE_CLOUD, base::Value(123), nullptr);
262   EXPECT_FALSE(bundle.Equals(other));
263 
264   // Test non-const Get().
265   bundle.Clear();
266   other.Clear();
267   PolicyMap& policy_map =
268       bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
269   EXPECT_TRUE(bundle.Equals(other));
270   policy_map.Set(kPolicy0, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
271                  POLICY_SOURCE_CLOUD, base::Value(123), nullptr);
272   EXPECT_FALSE(bundle.Equals(other));
273 }
274 
275 }  // namespace policy
276