Home | History | Annotate | Download | only in policy
      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:
     38   MockConfigurationPolicyProviderObserver() {}
     39   virtual ~MockConfigurationPolicyProviderObserver() {}
     40   MOCK_METHOD0(OnUpdatePolicy, void());
     41   void OnProviderGoingAway() {}
     42 };
     43 
     44 // Tests the device management policy cache.
     45 class 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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    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