• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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