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 "chrome/browser/policy/user_policy_cache.h"
6
7 #include <limits>
8 #include <string>
9
10 #include "base/file_util.h"
11 #include "base/memory/scoped_temp_dir.h"
12 #include "base/message_loop.h"
13 #include "base/values.h"
14 #include "chrome/browser/policy/configuration_policy_provider.h"
15 #include "chrome/browser/policy/proto/cloud_policy.pb.h"
16 #include "chrome/browser/policy/proto/device_management_backend.pb.h"
17 #include "chrome/browser/policy/proto/device_management_local.pb.h"
18 #include "chrome/browser/policy/proto/old_generic_format.pb.h"
19 #include "content/browser/browser_thread.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace policy {
24
25 // Decodes a CloudPolicySettings object into two maps with mandatory and
26 // recommended settings, respectively. The implementation is generated code
27 // in policy/cloud_policy_generated.cc.
28 void DecodePolicy(const em::CloudPolicySettings& policy,
29 PolicyMap* mandatory, PolicyMap* recommended);
30
31 // The implementations of these methods are in cloud_policy_generated.cc.
32 Value* DecodeIntegerValue(google::protobuf::int64 value);
33 ListValue* DecodeStringList(const em::StringList& string_list);
34
35 class MockConfigurationPolicyProviderObserver
36 : public ConfigurationPolicyProvider::Observer {
37 public:
MockConfigurationPolicyProviderObserver()38 MockConfigurationPolicyProviderObserver() {}
~MockConfigurationPolicyProviderObserver()39 virtual ~MockConfigurationPolicyProviderObserver() {}
40 MOCK_METHOD0(OnUpdatePolicy, void());
OnProviderGoingAway()41 void OnProviderGoingAway() {}
42 };
43
44 // Tests the device management policy cache.
45 class UserPolicyCacheTest : public testing::Test {
46 protected:
UserPolicyCacheTest()47 UserPolicyCacheTest()
48 : loop_(MessageLoop::TYPE_UI),
49 ui_thread_(BrowserThread::UI, &loop_),
50 file_thread_(BrowserThread::FILE, &loop_) {}
51
SetUp()52 void SetUp() {
53 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
54 }
55
TearDown()56 void TearDown() {
57 loop_.RunAllPending();
58 }
59
60 // Creates a (signed) PolicyFetchResponse setting the given |homepage| and
61 // featuring the given |timestamp| (as issued by the server).
62 // Mildly hacky special feature: pass an empty string as |homepage| to get
63 // a completely empty policy.
CreateHomepagePolicy(const std::string & homepage,const base::Time & timestamp,const em::PolicyOptions::PolicyMode policy_mode)64 em::PolicyFetchResponse* CreateHomepagePolicy(
65 const std::string& homepage,
66 const base::Time& timestamp,
67 const em::PolicyOptions::PolicyMode policy_mode) {
68 em::PolicyData signed_response;
69 if (homepage != "") {
70 em::CloudPolicySettings settings;
71 em::HomepageLocationProto* homepagelocation_proto =
72 settings.mutable_homepagelocation();
73 homepagelocation_proto->set_homepagelocation(homepage);
74 homepagelocation_proto->mutable_policy_options()->set_mode(policy_mode);
75 EXPECT_TRUE(
76 settings.SerializeToString(signed_response.mutable_policy_value()));
77 }
78 signed_response.set_timestamp(
79 (timestamp - base::Time::UnixEpoch()).InMilliseconds());
80 std::string serialized_signed_response;
81 EXPECT_TRUE(signed_response.SerializeToString(&serialized_signed_response));
82
83 em::PolicyFetchResponse* response = new em::PolicyFetchResponse;
84 response->set_policy_data(serialized_signed_response);
85 // TODO(jkummerow): Set proper new_public_key and signature (when
86 // implementing support for signature verification).
87 response->set_policy_data_signature("TODO");
88 response->set_new_public_key("TODO");
89 return response;
90 }
91
WritePolicy(const em::PolicyFetchResponse & policy)92 void WritePolicy(const em::PolicyFetchResponse& policy) {
93 std::string data;
94 em::CachedCloudPolicyResponse cached_policy;
95 cached_policy.mutable_cloud_policy()->CopyFrom(policy);
96 EXPECT_TRUE(cached_policy.SerializeToString(&data));
97 int size = static_cast<int>(data.size());
98 EXPECT_EQ(size, file_util::WriteFile(test_file(), data.c_str(), size));
99 }
100
101 // Takes ownership of |policy_response|.
SetPolicy(UserPolicyCache * cache,em::PolicyFetchResponse * policy_response,bool expect_changed_policy)102 void SetPolicy(UserPolicyCache* cache,
103 em::PolicyFetchResponse* policy_response,
104 bool expect_changed_policy) {
105 scoped_ptr<em::PolicyFetchResponse> policy(policy_response);
106 ConfigurationPolicyObserverRegistrar registrar;
107 registrar.Init(cache->GetManagedPolicyProvider(), &observer);
108 if (expect_changed_policy)
109 EXPECT_CALL(observer, OnUpdatePolicy()).Times(1);
110 else
111 EXPECT_CALL(observer, OnUpdatePolicy()).Times(0);
112 cache->SetPolicy(*policy);
113 testing::Mock::VerifyAndClearExpectations(&observer);
114 }
115
test_file()116 FilePath test_file() {
117 return temp_dir_.path().AppendASCII("UserPolicyCacheTest");
118 }
119
mandatory_policy(const UserPolicyCache & cache)120 const PolicyMap& mandatory_policy(const UserPolicyCache& cache) {
121 return cache.mandatory_policy_;
122 }
123
recommended_policy(const UserPolicyCache & cache)124 const PolicyMap& recommended_policy(const UserPolicyCache& cache) {
125 return cache.recommended_policy_;
126 }
127
128 MessageLoop loop_;
129 MockConfigurationPolicyProviderObserver observer;
130
131 private:
132 ScopedTempDir temp_dir_;
133 BrowserThread ui_thread_;
134 BrowserThread file_thread_;
135 };
136
TEST_F(UserPolicyCacheTest,DecodePolicy)137 TEST_F(UserPolicyCacheTest, DecodePolicy) {
138 em::CloudPolicySettings settings;
139 settings.mutable_homepagelocation()->set_homepagelocation("chromium.org");
140 settings.mutable_javascriptenabled()->set_javascriptenabled(true);
141 settings.mutable_javascriptenabled()->mutable_policy_options()->set_mode(
142 em::PolicyOptions::MANDATORY);
143 settings.mutable_policyrefreshrate()->set_policyrefreshrate(5);
144 settings.mutable_policyrefreshrate()->mutable_policy_options()->set_mode(
145 em::PolicyOptions::RECOMMENDED);
146 PolicyMap mandatory_policy;
147 PolicyMap recommended_policy;
148 DecodePolicy(settings, &mandatory_policy, &recommended_policy);
149 PolicyMap mandatory;
150 mandatory.Set(kPolicyHomepageLocation,
151 Value::CreateStringValue("chromium.org"));
152 mandatory.Set(kPolicyJavascriptEnabled, Value::CreateBooleanValue(true));
153 PolicyMap recommended;
154 recommended.Set(kPolicyPolicyRefreshRate, Value::CreateIntegerValue(5));
155 EXPECT_TRUE(mandatory.Equals(mandatory_policy));
156 EXPECT_TRUE(recommended.Equals(recommended_policy));
157 }
158
TEST_F(UserPolicyCacheTest,DecodeIntegerValue)159 TEST_F(UserPolicyCacheTest, DecodeIntegerValue) {
160 const int min = std::numeric_limits<int>::min();
161 const int max = std::numeric_limits<int>::max();
162 scoped_ptr<Value> value(
163 DecodeIntegerValue(static_cast<google::protobuf::int64>(42)));
164 ASSERT_TRUE(value.get());
165 FundamentalValue expected_42(42);
166 EXPECT_TRUE(value->Equals(&expected_42));
167 value.reset(
168 DecodeIntegerValue(static_cast<google::protobuf::int64>(min - 1LL)));
169 EXPECT_EQ(NULL, value.get());
170 value.reset(DecodeIntegerValue(static_cast<google::protobuf::int64>(min)));
171 ASSERT_TRUE(value.get());
172 FundamentalValue expected_min(min);
173 EXPECT_TRUE(value->Equals(&expected_min));
174 value.reset(
175 DecodeIntegerValue(static_cast<google::protobuf::int64>(max + 1LL)));
176 EXPECT_EQ(NULL, value.get());
177 value.reset(DecodeIntegerValue(static_cast<google::protobuf::int64>(max)));
178 ASSERT_TRUE(value.get());
179 FundamentalValue expected_max(max);
180 EXPECT_TRUE(value->Equals(&expected_max));
181 }
182
TEST_F(UserPolicyCacheTest,DecodeStringList)183 TEST_F(UserPolicyCacheTest, DecodeStringList) {
184 em::StringList string_list;
185 string_list.add_entries("ponies");
186 string_list.add_entries("more ponies");
187 scoped_ptr<ListValue> decoded(DecodeStringList(string_list));
188 ListValue expected;
189 expected.Append(Value::CreateStringValue("ponies"));
190 expected.Append(Value::CreateStringValue("more ponies"));
191 EXPECT_TRUE(decoded->Equals(&expected));
192 }
193
TEST_F(UserPolicyCacheTest,Empty)194 TEST_F(UserPolicyCacheTest, Empty) {
195 UserPolicyCache cache(test_file());
196 PolicyMap empty;
197 EXPECT_TRUE(empty.Equals(mandatory_policy(cache)));
198 EXPECT_TRUE(empty.Equals(recommended_policy(cache)));
199 EXPECT_EQ(base::Time(), cache.last_policy_refresh_time());
200 }
201
TEST_F(UserPolicyCacheTest,LoadNoFile)202 TEST_F(UserPolicyCacheTest, LoadNoFile) {
203 UserPolicyCache cache(test_file());
204 cache.Load();
205 PolicyMap empty;
206 EXPECT_TRUE(empty.Equals(mandatory_policy(cache)));
207 EXPECT_EQ(base::Time(), cache.last_policy_refresh_time());
208 }
209
TEST_F(UserPolicyCacheTest,RejectFuture)210 TEST_F(UserPolicyCacheTest, RejectFuture) {
211 scoped_ptr<em::PolicyFetchResponse> policy_response(
212 CreateHomepagePolicy("", base::Time::NowFromSystemTime() +
213 base::TimeDelta::FromMinutes(5),
214 em::PolicyOptions::MANDATORY));
215 WritePolicy(*policy_response);
216 UserPolicyCache cache(test_file());
217 cache.Load();
218 PolicyMap empty;
219 EXPECT_TRUE(empty.Equals(mandatory_policy(cache)));
220 EXPECT_EQ(base::Time(), cache.last_policy_refresh_time());
221 }
222
TEST_F(UserPolicyCacheTest,LoadWithFile)223 TEST_F(UserPolicyCacheTest, LoadWithFile) {
224 scoped_ptr<em::PolicyFetchResponse> policy_response(
225 CreateHomepagePolicy("", base::Time::NowFromSystemTime(),
226 em::PolicyOptions::MANDATORY));
227 WritePolicy(*policy_response);
228 UserPolicyCache cache(test_file());
229 cache.Load();
230 PolicyMap empty;
231 EXPECT_TRUE(empty.Equals(mandatory_policy(cache)));
232 EXPECT_NE(base::Time(), cache.last_policy_refresh_time());
233 EXPECT_GE(base::Time::Now(), cache.last_policy_refresh_time());
234 }
235
TEST_F(UserPolicyCacheTest,LoadWithData)236 TEST_F(UserPolicyCacheTest, LoadWithData) {
237 scoped_ptr<em::PolicyFetchResponse> policy(
238 CreateHomepagePolicy("http://www.example.com",
239 base::Time::NowFromSystemTime(),
240 em::PolicyOptions::MANDATORY));
241 WritePolicy(*policy);
242 UserPolicyCache cache(test_file());
243 cache.Load();
244 PolicyMap expected;
245 expected.Set(kPolicyHomepageLocation,
246 Value::CreateStringValue("http://www.example.com"));
247 EXPECT_TRUE(expected.Equals(mandatory_policy(cache)));
248 }
249
TEST_F(UserPolicyCacheTest,SetPolicy)250 TEST_F(UserPolicyCacheTest, SetPolicy) {
251 UserPolicyCache cache(test_file());
252 em::PolicyFetchResponse* policy =
253 CreateHomepagePolicy("http://www.example.com",
254 base::Time::NowFromSystemTime(),
255 em::PolicyOptions::MANDATORY);
256 SetPolicy(&cache, policy, true);
257 em::PolicyFetchResponse* policy2 =
258 CreateHomepagePolicy("http://www.example.com",
259 base::Time::NowFromSystemTime(),
260 em::PolicyOptions::MANDATORY);
261 SetPolicy(&cache, policy2, false);
262 PolicyMap expected;
263 expected.Set(kPolicyHomepageLocation,
264 Value::CreateStringValue("http://www.example.com"));
265 PolicyMap empty;
266 EXPECT_TRUE(expected.Equals(mandatory_policy(cache)));
267 EXPECT_TRUE(empty.Equals(recommended_policy(cache)));
268 policy = CreateHomepagePolicy("http://www.example.com",
269 base::Time::NowFromSystemTime(),
270 em::PolicyOptions::RECOMMENDED);
271 SetPolicy(&cache, policy, true);
272 EXPECT_TRUE(expected.Equals(recommended_policy(cache)));
273 EXPECT_TRUE(empty.Equals(mandatory_policy(cache)));
274 }
275
TEST_F(UserPolicyCacheTest,ResetPolicy)276 TEST_F(UserPolicyCacheTest, ResetPolicy) {
277 UserPolicyCache cache(test_file());
278
279 em::PolicyFetchResponse* policy =
280 CreateHomepagePolicy("http://www.example.com",
281 base::Time::NowFromSystemTime(),
282 em::PolicyOptions::MANDATORY);
283 SetPolicy(&cache, policy, true);
284 PolicyMap expected;
285 expected.Set(kPolicyHomepageLocation,
286 Value::CreateStringValue("http://www.example.com"));
287 EXPECT_TRUE(expected.Equals(mandatory_policy(cache)));
288
289 em::PolicyFetchResponse* empty_policy =
290 CreateHomepagePolicy("", base::Time::NowFromSystemTime(),
291 em::PolicyOptions::MANDATORY);
292 SetPolicy(&cache, empty_policy, true);
293 PolicyMap empty;
294 EXPECT_TRUE(empty.Equals(mandatory_policy(cache)));
295 }
296
TEST_F(UserPolicyCacheTest,PersistPolicy)297 TEST_F(UserPolicyCacheTest, PersistPolicy) {
298 {
299 UserPolicyCache cache(test_file());
300 scoped_ptr<em::PolicyFetchResponse> policy(
301 CreateHomepagePolicy("http://www.example.com",
302 base::Time::NowFromSystemTime(),
303 em::PolicyOptions::MANDATORY));
304 cache.SetPolicy(*policy);
305 }
306
307 loop_.RunAllPending();
308
309 EXPECT_TRUE(file_util::PathExists(test_file()));
310 UserPolicyCache cache(test_file());
311 cache.Load();
312 PolicyMap expected;
313 expected.Set(kPolicyHomepageLocation,
314 Value::CreateStringValue("http://www.example.com"));
315 EXPECT_TRUE(expected.Equals(mandatory_policy(cache)));
316 }
317
TEST_F(UserPolicyCacheTest,FreshPolicyOverride)318 TEST_F(UserPolicyCacheTest, FreshPolicyOverride) {
319 scoped_ptr<em::PolicyFetchResponse> policy(
320 CreateHomepagePolicy("http://www.example.com",
321 base::Time::NowFromSystemTime(),
322 em::PolicyOptions::MANDATORY));
323 WritePolicy(*policy);
324
325 UserPolicyCache cache(test_file());
326 em::PolicyFetchResponse* updated_policy =
327 CreateHomepagePolicy("http://www.chromium.org",
328 base::Time::NowFromSystemTime(),
329 em::PolicyOptions::MANDATORY);
330 SetPolicy(&cache, updated_policy, true);
331
332 cache.Load();
333 PolicyMap expected;
334 expected.Set(kPolicyHomepageLocation,
335 Value::CreateStringValue("http://www.chromium.org"));
336 EXPECT_TRUE(expected.Equals(mandatory_policy(cache)));
337 }
338
339 // Test case for the temporary support for GenericNamedValues in the
340 // CloudPolicySettings protobuf. Can be removed when this support is no longer
341 // required.
TEST_F(UserPolicyCacheTest,OldStylePolicy)342 TEST_F(UserPolicyCacheTest, OldStylePolicy) {
343 UserPolicyCache cache(test_file());
344 em::PolicyFetchResponse* policy = new em::PolicyFetchResponse();
345 em::PolicyData signed_response;
346 em::LegacyChromeSettingsProto settings;
347 em::GenericNamedValue* named_value = settings.add_named_value();
348 named_value->set_name("HomepageLocation");
349 em::GenericValue* value_container = named_value->mutable_value();
350 value_container->set_value_type(em::GenericValue::VALUE_TYPE_STRING);
351 value_container->set_string_value("http://www.example.com");
352 EXPECT_TRUE(
353 settings.SerializeToString(signed_response.mutable_policy_value()));
354 base::TimeDelta timestamp =
355 base::Time::NowFromSystemTime() - base::Time::UnixEpoch();
356 signed_response.set_timestamp(timestamp.InMilliseconds());
357 EXPECT_TRUE(
358 signed_response.SerializeToString(policy->mutable_policy_data()));
359
360 SetPolicy(&cache, policy, true);
361 PolicyMap expected;
362 expected.Set(kPolicyHomepageLocation,
363 Value::CreateStringValue("http://www.example.com"));
364 PolicyMap empty;
365 EXPECT_TRUE(expected.Equals(mandatory_policy(cache)));
366 EXPECT_TRUE(empty.Equals(recommended_policy(cache)));
367 // If new-style policy comes in, it should override old-style policy.
368 policy = CreateHomepagePolicy("http://www.example.com",
369 base::Time::NowFromSystemTime(),
370 em::PolicyOptions::RECOMMENDED);
371 SetPolicy(&cache, policy, true);
372 EXPECT_TRUE(expected.Equals(recommended_policy(cache)));
373 EXPECT_TRUE(empty.Equals(mandatory_policy(cache)));
374 }
375
376 } // namespace policy
377