user_policy_cache_unittest.cc revision ddb351dbec246cf1fab5ec20d2d5520909041de1
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
23namespace 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.
28void DecodePolicy(const em::CloudPolicySettings& policy,
29                  PolicyMap* mandatory, PolicyMap* recommended);
30
31// The implementations of these methods are in cloud_policy_generated.cc.
32Value* DecodeIntegerValue(google::protobuf::int64 value);
33ListValue* DecodeStringList(const em::StringList& string_list);
34
35class MockConfigurationPolicyProviderObserver
36    : public ConfigurationPolicyProvider::Observer {
37 public:
38  MockConfigurationPolicyProviderObserver() {}
39  virtual ~MockConfigurationPolicyProviderObserver() {}
40  MOCK_METHOD0(OnUpdatePolicy, void());
41  void OnProviderGoingAway() {}
42};
43
44// Tests the device management policy cache.
45class UserPolicyCacheTest : public testing::Test {
46 protected:
47  UserPolicyCacheTest()
48      : loop_(MessageLoop::TYPE_UI),
49        ui_thread_(BrowserThread::UI, &loop_),
50        file_thread_(BrowserThread::FILE, &loop_) {}
51
52  void SetUp() {
53    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
54  }
55
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.
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
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|.
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
116  FilePath test_file() {
117    return temp_dir_.path().AppendASCII("UserPolicyCacheTest");
118  }
119
120  const PolicyMap& mandatory_policy(const UserPolicyCache& cache) {
121    return cache.mandatory_policy_;
122  }
123
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
137TEST_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
159TEST_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
183TEST_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
194TEST_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
202TEST_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
210TEST_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
223TEST_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
236TEST_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
250TEST_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
276TEST_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
297TEST_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
318TEST_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.
342TEST_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