OLD | NEW |
| (Empty) |
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 "chrome/browser/policy/user_policy_cache.h" | |
6 | |
7 #include <limits> | |
8 #include <string> | |
9 | |
10 #include "base/file_util.h" | |
11 #include "base/files/scoped_temp_dir.h" | |
12 #include "base/message_loop.h" | |
13 #include "base/values.h" | |
14 #include "chrome/browser/policy/proto/cloud_policy.pb.h" | |
15 #include "chrome/browser/policy/proto/device_management_backend.pb.h" | |
16 #include "chrome/browser/policy/proto/device_management_local.pb.h" | |
17 #include "chrome/browser/policy/proto/old_generic_format.pb.h" | |
18 #include "content/public/test/test_browser_thread.h" | |
19 #include "policy/policy_constants.h" | |
20 #include "testing/gmock/include/gmock/gmock.h" | |
21 #include "testing/gtest/include/gtest/gtest.h" | |
22 | |
23 using content::BrowserThread; | |
24 using testing::_; | |
25 | |
26 namespace em = enterprise_management; | |
27 | |
28 namespace policy { | |
29 | |
30 // Decodes a CloudPolicySettings object into a PolicyMap. | |
31 // The implementation is generated code in policy/cloud_policy_generated.cc. | |
32 void DecodePolicy(const em::CloudPolicySettings& policy, PolicyMap* policies); | |
33 | |
34 // The implementations of these methods are in cloud_policy_generated.cc. | |
35 Value* DecodeIntegerValue(google::protobuf::int64 value); | |
36 ListValue* DecodeStringList(const em::StringList& string_list); | |
37 | |
38 class MockCloudPolicyCacheBaseObserver | |
39 : public CloudPolicyCacheBase::Observer { | |
40 public: | |
41 MockCloudPolicyCacheBaseObserver() {} | |
42 virtual ~MockCloudPolicyCacheBaseObserver() {} | |
43 MOCK_METHOD1(OnCacheUpdate, void(CloudPolicyCacheBase*)); | |
44 }; | |
45 | |
46 // Tests the device management policy cache. | |
47 class UserPolicyCacheTest : public testing::Test { | |
48 protected: | |
49 UserPolicyCacheTest() | |
50 : loop_(MessageLoop::TYPE_UI), | |
51 ui_thread_(BrowserThread::UI, &loop_), | |
52 file_thread_(BrowserThread::FILE, &loop_) {} | |
53 | |
54 void SetUp() { | |
55 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
56 } | |
57 | |
58 void TearDown() { | |
59 loop_.RunUntilIdle(); | |
60 } | |
61 | |
62 // Creates a (signed) PolicyFetchResponse setting the given |homepage| and | |
63 // featuring the given |timestamp| (as issued by the server). | |
64 // Mildly hacky special feature: pass an empty string as |homepage| to get | |
65 // a completely empty policy. | |
66 em::PolicyFetchResponse* CreateHomepagePolicy( | |
67 const std::string& homepage, | |
68 const base::Time& timestamp, | |
69 const em::PolicyOptions::PolicyMode policy_mode) { | |
70 em::PolicyData signed_response; | |
71 if (homepage != "") { | |
72 em::CloudPolicySettings settings; | |
73 em::StringPolicyProto* homepagelocation_proto = | |
74 settings.mutable_homepagelocation(); | |
75 homepagelocation_proto->set_value(homepage); | |
76 homepagelocation_proto->mutable_policy_options()->set_mode(policy_mode); | |
77 EXPECT_TRUE( | |
78 settings.SerializeToString(signed_response.mutable_policy_value())); | |
79 } | |
80 signed_response.set_timestamp( | |
81 (timestamp - base::Time::UnixEpoch()).InMilliseconds()); | |
82 std::string serialized_signed_response; | |
83 EXPECT_TRUE(signed_response.SerializeToString(&serialized_signed_response)); | |
84 | |
85 em::PolicyFetchResponse* response = new em::PolicyFetchResponse; | |
86 response->set_policy_data(serialized_signed_response); | |
87 // TODO(jkummerow): Set proper new_public_key and signature (when | |
88 // implementing support for signature verification). | |
89 response->set_policy_data_signature("TODO"); | |
90 response->set_new_public_key("TODO"); | |
91 return response; | |
92 } | |
93 | |
94 void WritePolicy(const em::PolicyFetchResponse& policy) { | |
95 std::string data; | |
96 em::CachedCloudPolicyResponse cached_policy; | |
97 cached_policy.mutable_cloud_policy()->CopyFrom(policy); | |
98 EXPECT_TRUE(cached_policy.SerializeToString(&data)); | |
99 int size = static_cast<int>(data.size()); | |
100 EXPECT_EQ(size, file_util::WriteFile(test_file(), data.c_str(), size)); | |
101 } | |
102 | |
103 // Takes ownership of |policy_response|. | |
104 bool SetPolicy(UserPolicyCache* cache, | |
105 em::PolicyFetchResponse* policy_response) { | |
106 EXPECT_CALL(observer_, OnCacheUpdate(_)).Times(1); | |
107 cache->AddObserver(&observer_); | |
108 | |
109 scoped_ptr<em::PolicyFetchResponse> policy(policy_response); | |
110 bool result = cache->SetPolicy(*policy); | |
111 cache->SetReady(); | |
112 testing::Mock::VerifyAndClearExpectations(&observer_); | |
113 | |
114 cache->RemoveObserver(&observer_); | |
115 return result; | |
116 } | |
117 | |
118 void SetReady(UserPolicyCache* cache) { | |
119 cache->SetReady(); | |
120 } | |
121 | |
122 FilePath test_file() { | |
123 return temp_dir_.path().AppendASCII("UserPolicyCacheTest"); | |
124 } | |
125 | |
126 MessageLoop loop_; | |
127 MockCloudPolicyCacheBaseObserver observer_; | |
128 | |
129 private: | |
130 base::ScopedTempDir temp_dir_; | |
131 content::TestBrowserThread ui_thread_; | |
132 content::TestBrowserThread file_thread_; | |
133 }; | |
134 | |
135 TEST_F(UserPolicyCacheTest, DecodePolicy) { | |
136 em::CloudPolicySettings settings; | |
137 settings.mutable_homepagelocation()->set_value("chromium.org"); | |
138 settings.mutable_javascriptenabled()->set_value(true); | |
139 settings.mutable_javascriptenabled()->mutable_policy_options()->set_mode( | |
140 em::PolicyOptions::MANDATORY); | |
141 settings.mutable_policyrefreshrate()->set_value(5); | |
142 settings.mutable_policyrefreshrate()->mutable_policy_options()->set_mode( | |
143 em::PolicyOptions::RECOMMENDED); | |
144 settings.mutable_showhomebutton()->set_value(true); | |
145 settings.mutable_showhomebutton()->mutable_policy_options()->set_mode( | |
146 em::PolicyOptions::UNSET); | |
147 em::StringList* disabled_schemes = | |
148 settings.mutable_disabledschemes()->mutable_value(); | |
149 disabled_schemes->add_entries("ftp"); | |
150 disabled_schemes->add_entries("mailto"); | |
151 #ifdef NDEBUG | |
152 // Setting an invalid PolicyMode enum value triggers a DCHECK in protobuf. | |
153 settings.mutable_homepageisnewtabpage()->set_value(true); | |
154 settings.mutable_homepageisnewtabpage()->mutable_policy_options()->set_mode( | |
155 static_cast<em::PolicyOptions::PolicyMode>(-1)); | |
156 #endif | |
157 | |
158 PolicyMap policy; | |
159 DecodePolicy(settings, &policy); | |
160 | |
161 PolicyMap expected; | |
162 expected.Set(key::kHomepageLocation, | |
163 POLICY_LEVEL_MANDATORY, | |
164 POLICY_SCOPE_USER, | |
165 Value::CreateStringValue("chromium.org")); | |
166 expected.Set(key::kJavascriptEnabled, | |
167 POLICY_LEVEL_MANDATORY, | |
168 POLICY_SCOPE_USER, | |
169 Value::CreateBooleanValue(true)); | |
170 expected.Set(key::kPolicyRefreshRate, | |
171 POLICY_LEVEL_RECOMMENDED, | |
172 POLICY_SCOPE_USER, | |
173 Value::CreateIntegerValue(5)); | |
174 base::ListValue expected_schemes; | |
175 expected_schemes.AppendString("ftp"); | |
176 expected_schemes.AppendString("mailto"); | |
177 expected.Set(key::kDisabledSchemes, | |
178 POLICY_LEVEL_MANDATORY, | |
179 POLICY_SCOPE_USER, | |
180 expected_schemes.DeepCopy()); | |
181 | |
182 EXPECT_TRUE(policy.Equals(expected)); | |
183 } | |
184 | |
185 TEST_F(UserPolicyCacheTest, DecodeIntegerValue) { | |
186 const int min = std::numeric_limits<int>::min(); | |
187 const int max = std::numeric_limits<int>::max(); | |
188 scoped_ptr<Value> value( | |
189 DecodeIntegerValue(static_cast<google::protobuf::int64>(42))); | |
190 ASSERT_TRUE(value.get()); | |
191 base::FundamentalValue expected_42(42); | |
192 EXPECT_TRUE(value->Equals(&expected_42)); | |
193 value.reset( | |
194 DecodeIntegerValue(static_cast<google::protobuf::int64>(min - 1LL))); | |
195 EXPECT_EQ(NULL, value.get()); | |
196 value.reset(DecodeIntegerValue(static_cast<google::protobuf::int64>(min))); | |
197 ASSERT_TRUE(value.get()); | |
198 base::FundamentalValue expected_min(min); | |
199 EXPECT_TRUE(value->Equals(&expected_min)); | |
200 value.reset( | |
201 DecodeIntegerValue(static_cast<google::protobuf::int64>(max + 1LL))); | |
202 EXPECT_EQ(NULL, value.get()); | |
203 value.reset(DecodeIntegerValue(static_cast<google::protobuf::int64>(max))); | |
204 ASSERT_TRUE(value.get()); | |
205 base::FundamentalValue expected_max(max); | |
206 EXPECT_TRUE(value->Equals(&expected_max)); | |
207 } | |
208 | |
209 TEST_F(UserPolicyCacheTest, DecodeStringList) { | |
210 em::StringList string_list; | |
211 string_list.add_entries("ponies"); | |
212 string_list.add_entries("more ponies"); | |
213 scoped_ptr<ListValue> decoded(DecodeStringList(string_list)); | |
214 ListValue expected; | |
215 expected.Append(Value::CreateStringValue("ponies")); | |
216 expected.Append(Value::CreateStringValue("more ponies")); | |
217 EXPECT_TRUE(decoded->Equals(&expected)); | |
218 } | |
219 | |
220 TEST_F(UserPolicyCacheTest, Empty) { | |
221 UserPolicyCache cache(test_file(), false /* wait_for_policy_fetch */); | |
222 PolicyMap empty; | |
223 EXPECT_TRUE(empty.Equals(*cache.policy())); | |
224 EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); | |
225 } | |
226 | |
227 TEST_F(UserPolicyCacheTest, LoadNoFile) { | |
228 UserPolicyCache cache(test_file(), false /* wait_for_policy_fetch */); | |
229 cache.Load(); | |
230 loop_.RunUntilIdle(); | |
231 PolicyMap empty; | |
232 EXPECT_TRUE(empty.Equals(*cache.policy())); | |
233 EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); | |
234 } | |
235 | |
236 TEST_F(UserPolicyCacheTest, RejectFuture) { | |
237 scoped_ptr<em::PolicyFetchResponse> policy_response( | |
238 CreateHomepagePolicy("", base::Time::NowFromSystemTime() + | |
239 base::TimeDelta::FromMinutes(5), | |
240 em::PolicyOptions::MANDATORY)); | |
241 WritePolicy(*policy_response); | |
242 UserPolicyCache cache(test_file(), false /* wait_for_policy_fetch */); | |
243 cache.Load(); | |
244 loop_.RunUntilIdle(); | |
245 PolicyMap empty; | |
246 EXPECT_TRUE(empty.Equals(*cache.policy())); | |
247 EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); | |
248 } | |
249 | |
250 TEST_F(UserPolicyCacheTest, LoadWithFile) { | |
251 scoped_ptr<em::PolicyFetchResponse> policy_response( | |
252 CreateHomepagePolicy("", base::Time::NowFromSystemTime(), | |
253 em::PolicyOptions::MANDATORY)); | |
254 WritePolicy(*policy_response); | |
255 UserPolicyCache cache(test_file(), false /* wait_for_policy_fetch */); | |
256 cache.Load(); | |
257 loop_.RunUntilIdle(); | |
258 PolicyMap empty; | |
259 EXPECT_TRUE(empty.Equals(*cache.policy())); | |
260 EXPECT_NE(base::Time(), cache.last_policy_refresh_time()); | |
261 EXPECT_GE(base::Time::Now(), cache.last_policy_refresh_time()); | |
262 } | |
263 | |
264 TEST_F(UserPolicyCacheTest, LoadWithData) { | |
265 scoped_ptr<em::PolicyFetchResponse> policy( | |
266 CreateHomepagePolicy("http://www.example.com", | |
267 base::Time::NowFromSystemTime(), | |
268 em::PolicyOptions::MANDATORY)); | |
269 WritePolicy(*policy); | |
270 UserPolicyCache cache(test_file(), false /* wait_for_policy_fetch */); | |
271 cache.Load(); | |
272 loop_.RunUntilIdle(); | |
273 PolicyMap expected; | |
274 expected.Set(key::kHomepageLocation, | |
275 POLICY_LEVEL_MANDATORY, | |
276 POLICY_SCOPE_USER, | |
277 Value::CreateStringValue("http://www.example.com")); | |
278 EXPECT_TRUE(expected.Equals(*cache.policy())); | |
279 } | |
280 | |
281 TEST_F(UserPolicyCacheTest, SetPolicy) { | |
282 UserPolicyCache cache(test_file(), false /* wait_for_policy_fetch */); | |
283 em::PolicyFetchResponse* policy = | |
284 CreateHomepagePolicy("http://www.example.com", | |
285 base::Time::NowFromSystemTime(), | |
286 em::PolicyOptions::MANDATORY); | |
287 EXPECT_TRUE(SetPolicy(&cache, policy)); | |
288 em::PolicyFetchResponse* policy2 = | |
289 CreateHomepagePolicy("http://www.example.com", | |
290 base::Time::NowFromSystemTime(), | |
291 em::PolicyOptions::MANDATORY); | |
292 EXPECT_TRUE(SetPolicy(&cache, policy2)); | |
293 PolicyMap expected; | |
294 expected.Set(key::kHomepageLocation, | |
295 POLICY_LEVEL_MANDATORY, | |
296 POLICY_SCOPE_USER, | |
297 Value::CreateStringValue("http://www.example.com")); | |
298 EXPECT_TRUE(expected.Equals(*cache.policy())); | |
299 policy = CreateHomepagePolicy("http://www.example.com", | |
300 base::Time::NowFromSystemTime(), | |
301 em::PolicyOptions::RECOMMENDED); | |
302 EXPECT_TRUE(SetPolicy(&cache, policy)); | |
303 expected.Set(key::kHomepageLocation, | |
304 POLICY_LEVEL_RECOMMENDED, | |
305 POLICY_SCOPE_USER, | |
306 Value::CreateStringValue("http://www.example.com")); | |
307 EXPECT_TRUE(expected.Equals(*cache.policy())); | |
308 } | |
309 | |
310 TEST_F(UserPolicyCacheTest, ResetPolicy) { | |
311 UserPolicyCache cache(test_file(), false /* wait_for_policy_fetch */); | |
312 | |
313 em::PolicyFetchResponse* policy = | |
314 CreateHomepagePolicy("http://www.example.com", | |
315 base::Time::NowFromSystemTime(), | |
316 em::PolicyOptions::MANDATORY); | |
317 EXPECT_TRUE(SetPolicy(&cache, policy)); | |
318 PolicyMap expected; | |
319 expected.Set(key::kHomepageLocation, | |
320 POLICY_LEVEL_MANDATORY, | |
321 POLICY_SCOPE_USER, | |
322 Value::CreateStringValue("http://www.example.com")); | |
323 EXPECT_TRUE(expected.Equals(*cache.policy())); | |
324 | |
325 em::PolicyFetchResponse* empty_policy = | |
326 CreateHomepagePolicy("", base::Time::NowFromSystemTime(), | |
327 em::PolicyOptions::MANDATORY); | |
328 EXPECT_TRUE(SetPolicy(&cache, empty_policy)); | |
329 PolicyMap empty; | |
330 EXPECT_TRUE(empty.Equals(*cache.policy())); | |
331 } | |
332 | |
333 TEST_F(UserPolicyCacheTest, PersistPolicy) { | |
334 { | |
335 UserPolicyCache cache(test_file(), false /* wait_for_policy_fetch */); | |
336 scoped_ptr<em::PolicyFetchResponse> policy( | |
337 CreateHomepagePolicy("http://www.example.com", | |
338 base::Time::NowFromSystemTime(), | |
339 em::PolicyOptions::MANDATORY)); | |
340 EXPECT_TRUE(cache.SetPolicy(*policy)); | |
341 } | |
342 | |
343 loop_.RunUntilIdle(); | |
344 | |
345 EXPECT_TRUE(file_util::PathExists(test_file())); | |
346 UserPolicyCache cache(test_file(), false /* wait_for_policy_fetch */); | |
347 cache.Load(); | |
348 loop_.RunUntilIdle(); | |
349 PolicyMap expected; | |
350 expected.Set(key::kHomepageLocation, | |
351 POLICY_LEVEL_MANDATORY, | |
352 POLICY_SCOPE_USER, | |
353 Value::CreateStringValue("http://www.example.com")); | |
354 EXPECT_TRUE(expected.Equals(*cache.policy())); | |
355 } | |
356 | |
357 TEST_F(UserPolicyCacheTest, FreshPolicyOverride) { | |
358 scoped_ptr<em::PolicyFetchResponse> policy( | |
359 CreateHomepagePolicy("http://www.example.com", | |
360 base::Time::NowFromSystemTime(), | |
361 em::PolicyOptions::MANDATORY)); | |
362 WritePolicy(*policy); | |
363 | |
364 UserPolicyCache cache(test_file(), false /* wait_for_policy_fetch */); | |
365 em::PolicyFetchResponse* updated_policy = | |
366 CreateHomepagePolicy("http://www.chromium.org", | |
367 base::Time::NowFromSystemTime(), | |
368 em::PolicyOptions::MANDATORY); | |
369 EXPECT_TRUE(SetPolicy(&cache, updated_policy)); | |
370 | |
371 cache.Load(); | |
372 loop_.RunUntilIdle(); | |
373 PolicyMap expected; | |
374 expected.Set(key::kHomepageLocation, | |
375 POLICY_LEVEL_MANDATORY, | |
376 POLICY_SCOPE_USER, | |
377 Value::CreateStringValue("http://www.chromium.org")); | |
378 EXPECT_TRUE(expected.Equals(*cache.policy())); | |
379 } | |
380 | |
381 TEST_F(UserPolicyCacheTest, SetReady) { | |
382 UserPolicyCache cache(test_file(), false /* wait_for_policy_fetch */); | |
383 cache.AddObserver(&observer_); | |
384 scoped_ptr<em::PolicyFetchResponse> policy( | |
385 CreateHomepagePolicy("http://www.example.com", | |
386 base::Time::NowFromSystemTime(), | |
387 em::PolicyOptions::MANDATORY)); | |
388 EXPECT_CALL(observer_, OnCacheUpdate(_)).Times(0); | |
389 EXPECT_TRUE(cache.SetPolicy(*policy)); | |
390 testing::Mock::VerifyAndClearExpectations(&observer_); | |
391 | |
392 // Switching the cache to ready should send a notification. | |
393 EXPECT_CALL(observer_, OnCacheUpdate(_)).Times(1); | |
394 SetReady(&cache); | |
395 cache.RemoveObserver(&observer_); | |
396 } | |
397 | |
398 // Test case for the temporary support for GenericNamedValues in the | |
399 // CloudPolicySettings protobuf. Can be removed when this support is no longer | |
400 // required. | |
401 TEST_F(UserPolicyCacheTest, OldStylePolicy) { | |
402 UserPolicyCache cache(test_file(), false /* wait_for_policy_fetch */); | |
403 em::PolicyFetchResponse* policy = new em::PolicyFetchResponse(); | |
404 em::PolicyData signed_response; | |
405 em::LegacyChromeSettingsProto settings; | |
406 em::GenericNamedValue* named_value = settings.add_named_value(); | |
407 named_value->set_name("HomepageLocation"); | |
408 em::GenericValue* value_container = named_value->mutable_value(); | |
409 value_container->set_value_type(em::GenericValue::VALUE_TYPE_STRING); | |
410 value_container->set_string_value("http://www.example.com"); | |
411 EXPECT_TRUE( | |
412 settings.SerializeToString(signed_response.mutable_policy_value())); | |
413 base::TimeDelta timestamp = | |
414 base::Time::NowFromSystemTime() - base::Time::UnixEpoch(); | |
415 signed_response.set_timestamp(timestamp.InMilliseconds()); | |
416 EXPECT_TRUE( | |
417 signed_response.SerializeToString(policy->mutable_policy_data())); | |
418 | |
419 EXPECT_TRUE(SetPolicy(&cache, policy)); | |
420 PolicyMap expected; | |
421 expected.Set(key::kHomepageLocation, | |
422 POLICY_LEVEL_MANDATORY, | |
423 POLICY_SCOPE_USER, | |
424 Value::CreateStringValue("http://www.example.com")); | |
425 EXPECT_TRUE(expected.Equals(*cache.policy())); | |
426 // If new-style policy comes in, it should override old-style policy. | |
427 policy = CreateHomepagePolicy("http://www.example.com", | |
428 base::Time::NowFromSystemTime(), | |
429 em::PolicyOptions::RECOMMENDED); | |
430 expected.Set(key::kHomepageLocation, | |
431 POLICY_LEVEL_RECOMMENDED, | |
432 POLICY_SCOPE_USER, | |
433 Value::CreateStringValue("http://www.example.com")); | |
434 EXPECT_TRUE(SetPolicy(&cache, policy)); | |
435 EXPECT_TRUE(expected.Equals(*cache.policy())); | |
436 } | |
437 | |
438 TEST_F(UserPolicyCacheTest, CheckReadyNoWaiting) { | |
439 UserPolicyCache cache(test_file(), false /* wait_for_policy_fetch */); | |
440 EXPECT_FALSE(cache.IsReady()); | |
441 cache.Load(); | |
442 loop_.RunUntilIdle(); | |
443 EXPECT_TRUE(cache.IsReady()); | |
444 } | |
445 | |
446 TEST_F(UserPolicyCacheTest, CheckReadyWaitForFetch) { | |
447 UserPolicyCache cache(test_file(), true /* wait_for_policy_fetch */); | |
448 EXPECT_FALSE(cache.IsReady()); | |
449 cache.Load(); | |
450 loop_.RunUntilIdle(); | |
451 EXPECT_FALSE(cache.IsReady()); | |
452 cache.SetFetchingDone(); | |
453 EXPECT_TRUE(cache.IsReady()); | |
454 } | |
455 | |
456 TEST_F(UserPolicyCacheTest, CheckReadyWaitForDisk) { | |
457 UserPolicyCache cache(test_file(), true /* wait_for_policy_fetch */); | |
458 EXPECT_FALSE(cache.IsReady()); | |
459 cache.SetFetchingDone(); | |
460 EXPECT_FALSE(cache.IsReady()); | |
461 cache.Load(); | |
462 loop_.RunUntilIdle(); | |
463 EXPECT_TRUE(cache.IsReady()); | |
464 } | |
465 | |
466 } // namespace policy | |
OLD | NEW |