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