user_cloud_policy_store_chromeos_unittest.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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/chromeos/policy/user_cloud_policy_store_chromeos.h" 6 7#include <vector> 8 9#include "base/basictypes.h" 10#include "base/bind.h" 11#include "base/file_util.h" 12#include "base/files/scoped_temp_dir.h" 13#include "base/memory/scoped_ptr.h" 14#include "base/message_loop.h" 15#include "base/threading/sequenced_worker_pool.h" 16#include "chrome/browser/policy/cloud/cloud_policy_constants.h" 17#include "chrome/browser/policy/cloud/mock_cloud_policy_store.h" 18#include "chrome/browser/policy/cloud/policy_builder.h" 19#include "chrome/browser/policy/cloud/proto/device_management_local.pb.h" 20#include "chromeos/dbus/mock_cryptohome_client.h" 21#include "chromeos/dbus/mock_session_manager_client.h" 22#include "content/public/test/test_browser_thread.h" 23#include "policy/policy_constants.h" 24#include "policy/proto/cloud_policy.pb.h" 25#include "testing/gmock/include/gmock/gmock.h" 26#include "testing/gtest/include/gtest/gtest.h" 27 28namespace em = enterprise_management; 29 30using testing::AllOf; 31using testing::AnyNumber; 32using testing::Eq; 33using testing::Mock; 34using testing::Property; 35using testing::SaveArg; 36using testing::_; 37 38namespace policy { 39 40namespace { 41 42const char kLegacyDeviceId[] = "legacy-device-id"; 43const char kLegacyToken[] = "legacy-token"; 44const char kSanitizedUsername[] = "0123456789ABCDEF0123456789ABCDEF012345678"; 45const char kDefaultHomepage[] = "http://chromium.org"; 46 47ACTION_P2(SendSanitizedUsername, call_status, sanitized_username) { 48 MessageLoop::current()->PostTask( 49 FROM_HERE, base::Bind(arg1, call_status, sanitized_username)); 50} 51 52class UserCloudPolicyStoreChromeOSTest : public testing::Test { 53 protected: 54 UserCloudPolicyStoreChromeOSTest() 55 : loop_(MessageLoop::TYPE_UI), 56 ui_thread_(content::BrowserThread::UI, &loop_), 57 file_thread_(content::BrowserThread::FILE, &loop_) {} 58 59 virtual void SetUp() OVERRIDE { 60 EXPECT_CALL(cryptohome_client_, 61 GetSanitizedUsername(PolicyBuilder::kFakeUsername, _)) 62 .Times(AnyNumber()) 63 .WillRepeatedly( 64 SendSanitizedUsername(chromeos::DBUS_METHOD_CALL_SUCCESS, 65 kSanitizedUsername)); 66 67 ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir()); 68 store_.reset(new UserCloudPolicyStoreChromeOS(&cryptohome_client_, 69 &session_manager_client_, 70 PolicyBuilder::kFakeUsername, 71 user_policy_dir(), 72 token_file(), 73 policy_file())); 74 store_->AddObserver(&observer_); 75 76 // Install the initial public key, so that by default the validation of 77 // the stored/loaded policy blob succeeds. 78 std::vector<uint8> public_key; 79 ASSERT_TRUE(policy_.signing_key()->ExportPublicKey(&public_key)); 80 StoreUserPolicyKey(public_key); 81 82 policy_.payload().mutable_homepagelocation()->set_value(kDefaultHomepage); 83 policy_.Build(); 84 } 85 86 virtual void TearDown() OVERRIDE { 87 store_->RemoveObserver(&observer_); 88 store_.reset(); 89 RunUntilIdle(); 90 } 91 92 // Install an expectation on |observer_| for an error code. 93 void ExpectError(CloudPolicyStore::Status error) { 94 EXPECT_CALL(observer_, 95 OnStoreError(AllOf(Eq(store_.get()), 96 Property(&CloudPolicyStore::status, 97 Eq(error))))); 98 } 99 100 // Triggers a store_->Load() operation, handles the expected call to 101 // |session_manager_client_| and sends |response|. 102 void PerformPolicyLoad(const std::string& response) { 103 // Issue a load command. 104 chromeos::SessionManagerClient::RetrievePolicyCallback retrieve_callback; 105 EXPECT_CALL(session_manager_client_, RetrieveUserPolicy(_)) 106 .WillOnce(SaveArg<0>(&retrieve_callback)); 107 store_->Load(); 108 RunUntilIdle(); 109 Mock::VerifyAndClearExpectations(&session_manager_client_); 110 ASSERT_FALSE(retrieve_callback.is_null()); 111 112 // Run the callback. 113 retrieve_callback.Run(response); 114 RunUntilIdle(); 115 } 116 117 // Verifies that store_->policy_map() has the HomepageLocation entry with 118 // the |expected_value|. 119 void VerifyPolicyMap(const char* expected_value) { 120 EXPECT_EQ(1U, store_->policy_map().size()); 121 const PolicyMap::Entry* entry = 122 store_->policy_map().Get(key::kHomepageLocation); 123 ASSERT_TRUE(entry); 124 EXPECT_TRUE(base::StringValue(expected_value).Equals(entry->value)); 125 } 126 127 void StoreUserPolicyKey(const std::vector<uint8>& public_key) { 128 ASSERT_TRUE(file_util::CreateDirectory(user_policy_key_file().DirName())); 129 ASSERT_TRUE( 130 file_util::WriteFile(user_policy_key_file(), 131 reinterpret_cast<const char*>(public_key.data()), 132 public_key.size())); 133 } 134 135 // Stores the current |policy_| and verifies that it is published. 136 // If |new_public_key| is set then it will be persisted after storing but 137 // before loading the policy, so that the signature validation can succeed. 138 // If |previous_value| is set then a previously existing policy with that 139 // value will be expected; otherwise no previous policy is expected. 140 // If |new_value| is set then a new policy with that value is expected after 141 // storing the |policy_| blob. 142 void PerformStorePolicy(const std::vector<uint8>* new_public_key, 143 const char* previous_value, 144 const char* new_value) { 145 chromeos::SessionManagerClient::StorePolicyCallback store_callback; 146 EXPECT_CALL(session_manager_client_, StoreUserPolicy(policy_.GetBlob(), _)) 147 .WillOnce(SaveArg<1>(&store_callback)); 148 store_->Store(policy_.policy()); 149 RunUntilIdle(); 150 Mock::VerifyAndClearExpectations(&session_manager_client_); 151 ASSERT_FALSE(store_callback.is_null()); 152 153 // The new policy shouldn't be present yet. 154 PolicyMap previous_policy; 155 EXPECT_EQ(previous_value != NULL, store_->policy() != NULL); 156 if (previous_value) { 157 previous_policy.Set(key::kHomepageLocation, 158 POLICY_LEVEL_MANDATORY, 159 POLICY_SCOPE_USER, 160 base::Value::CreateStringValue(previous_value)); 161 } 162 EXPECT_TRUE(previous_policy.Equals(store_->policy_map())); 163 EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status()); 164 165 // Store the new public key so that the validation after the retrieve 166 // operation completes can verify the signature. 167 if (new_public_key) 168 StoreUserPolicyKey(*new_public_key); 169 170 // Let the store operation complete. 171 chromeos::SessionManagerClient::RetrievePolicyCallback retrieve_callback; 172 EXPECT_CALL(session_manager_client_, RetrieveUserPolicy(_)) 173 .WillOnce(SaveArg<0>(&retrieve_callback)); 174 store_callback.Run(true); 175 RunUntilIdle(); 176 EXPECT_TRUE(previous_policy.Equals(store_->policy_map())); 177 EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status()); 178 Mock::VerifyAndClearExpectations(&session_manager_client_); 179 ASSERT_FALSE(retrieve_callback.is_null()); 180 181 // Finish the retrieve callback. 182 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())); 183 retrieve_callback.Run(policy_.GetBlob()); 184 RunUntilIdle(); 185 ASSERT_TRUE(store_->policy()); 186 EXPECT_EQ(policy_.policy_data().SerializeAsString(), 187 store_->policy()->SerializeAsString()); 188 VerifyPolicyMap(new_value); 189 EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status()); 190 } 191 192 void VerifyStoreHasValidationError() { 193 EXPECT_FALSE(store_->policy()); 194 EXPECT_TRUE(store_->policy_map().empty()); 195 EXPECT_EQ(CloudPolicyStore::STATUS_VALIDATION_ERROR, store_->status()); 196 } 197 198 void RunUntilIdle() { 199 loop_.RunUntilIdle(); 200 content::BrowserThread::GetBlockingPool()->FlushForTesting(); 201 loop_.RunUntilIdle(); 202 } 203 204 base::FilePath user_policy_dir() { 205 return tmp_dir_.path().AppendASCII("var_run_user_policy"); 206 } 207 208 base::FilePath user_policy_key_file() { 209 return user_policy_dir().AppendASCII(kSanitizedUsername) 210 .AppendASCII("policy.pub"); 211 } 212 213 base::FilePath token_file() { 214 return tmp_dir_.path().AppendASCII("token"); 215 } 216 217 base::FilePath policy_file() { 218 return tmp_dir_.path().AppendASCII("policy"); 219 } 220 221 MessageLoop loop_; 222 chromeos::MockCryptohomeClient cryptohome_client_; 223 chromeos::MockSessionManagerClient session_manager_client_; 224 UserPolicyBuilder policy_; 225 MockCloudPolicyStoreObserver observer_; 226 scoped_ptr<UserCloudPolicyStoreChromeOS> store_; 227 228 private: 229 content::TestBrowserThread ui_thread_; 230 content::TestBrowserThread file_thread_; 231 base::ScopedTempDir tmp_dir_; 232 233 DISALLOW_COPY_AND_ASSIGN(UserCloudPolicyStoreChromeOSTest); 234}; 235 236TEST_F(UserCloudPolicyStoreChromeOSTest, InitialStore) { 237 // Start without any public key to trigger the initial key checks. 238 ASSERT_TRUE(file_util::Delete(user_policy_key_file(), false)); 239 // Make the policy blob contain a new public key. 240 policy_.set_new_signing_key(PolicyBuilder::CreateTestNewSigningKey()); 241 policy_.Build(); 242 std::vector<uint8> new_public_key; 243 ASSERT_TRUE(policy_.new_signing_key()->ExportPublicKey(&new_public_key)); 244 ASSERT_NO_FATAL_FAILURE( 245 PerformStorePolicy(&new_public_key, NULL, kDefaultHomepage)); 246} 247 248TEST_F(UserCloudPolicyStoreChromeOSTest, StoreWithExistingKey) { 249 ASSERT_NO_FATAL_FAILURE( 250 PerformStorePolicy(NULL, NULL, kDefaultHomepage)); 251} 252 253TEST_F(UserCloudPolicyStoreChromeOSTest, StoreWithRotation) { 254 // Make the policy blob contain a new public key. 255 policy_.set_new_signing_key(PolicyBuilder::CreateTestNewSigningKey()); 256 policy_.Build(); 257 std::vector<uint8> new_public_key; 258 ASSERT_TRUE(policy_.new_signing_key()->ExportPublicKey(&new_public_key)); 259 ASSERT_NO_FATAL_FAILURE( 260 PerformStorePolicy(&new_public_key, NULL, kDefaultHomepage)); 261} 262 263TEST_F(UserCloudPolicyStoreChromeOSTest, StoreFail) { 264 // Store policy. 265 chromeos::SessionManagerClient::StorePolicyCallback store_callback; 266 EXPECT_CALL(session_manager_client_, StoreUserPolicy(policy_.GetBlob(), _)) 267 .WillOnce(SaveArg<1>(&store_callback)); 268 store_->Store(policy_.policy()); 269 RunUntilIdle(); 270 Mock::VerifyAndClearExpectations(&session_manager_client_); 271 ASSERT_FALSE(store_callback.is_null()); 272 273 // Let the store operation complete. 274 ExpectError(CloudPolicyStore::STATUS_STORE_ERROR); 275 store_callback.Run(false); 276 RunUntilIdle(); 277 EXPECT_FALSE(store_->policy()); 278 EXPECT_TRUE(store_->policy_map().empty()); 279 EXPECT_EQ(CloudPolicyStore::STATUS_STORE_ERROR, store_->status()); 280} 281 282TEST_F(UserCloudPolicyStoreChromeOSTest, StoreValidationError) { 283 policy_.policy_data().clear_policy_type(); 284 policy_.Build(); 285 286 // Store policy. 287 chromeos::SessionManagerClient::StorePolicyCallback store_callback; 288 ExpectError(CloudPolicyStore::STATUS_VALIDATION_ERROR); 289 EXPECT_CALL(session_manager_client_, StoreUserPolicy(policy_.GetBlob(), _)) 290 .Times(0); 291 store_->Store(policy_.policy()); 292 RunUntilIdle(); 293 Mock::VerifyAndClearExpectations(&session_manager_client_); 294} 295 296TEST_F(UserCloudPolicyStoreChromeOSTest, StoreWithoutPolicyKey) { 297 // Make the dbus call to cryptohome fail. 298 Mock::VerifyAndClearExpectations(&cryptohome_client_); 299 EXPECT_CALL(cryptohome_client_, 300 GetSanitizedUsername(PolicyBuilder::kFakeUsername, _)) 301 .Times(AnyNumber()) 302 .WillRepeatedly(SendSanitizedUsername(chromeos::DBUS_METHOD_CALL_FAILURE, 303 std::string())); 304 305 // Store policy. 306 chromeos::SessionManagerClient::StorePolicyCallback store_callback; 307 ExpectError(CloudPolicyStore::STATUS_VALIDATION_ERROR); 308 EXPECT_CALL(session_manager_client_, StoreUserPolicy(policy_.GetBlob(), _)) 309 .Times(0); 310 store_->Store(policy_.policy()); 311 RunUntilIdle(); 312 Mock::VerifyAndClearExpectations(&session_manager_client_); 313} 314 315TEST_F(UserCloudPolicyStoreChromeOSTest, StoreWithInvalidSignature) { 316 // Break the signature. 317 policy_.policy().mutable_policy_data_signature()->append("garbage"); 318 319 // Store policy. 320 chromeos::SessionManagerClient::StorePolicyCallback store_callback; 321 ExpectError(CloudPolicyStore::STATUS_VALIDATION_ERROR); 322 EXPECT_CALL(session_manager_client_, StoreUserPolicy(policy_.GetBlob(), _)) 323 .Times(0); 324 store_->Store(policy_.policy()); 325 RunUntilIdle(); 326 Mock::VerifyAndClearExpectations(&session_manager_client_); 327} 328 329TEST_F(UserCloudPolicyStoreChromeOSTest, Load) { 330 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())); 331 ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad(policy_.GetBlob())); 332 Mock::VerifyAndClearExpectations(&observer_); 333 334 // Verify that the policy has been loaded. 335 ASSERT_TRUE(store_->policy()); 336 EXPECT_EQ(policy_.policy_data().SerializeAsString(), 337 store_->policy()->SerializeAsString()); 338 VerifyPolicyMap(kDefaultHomepage); 339 EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status()); 340} 341 342TEST_F(UserCloudPolicyStoreChromeOSTest, LoadNoPolicy) { 343 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())); 344 ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad("")); 345 Mock::VerifyAndClearExpectations(&observer_); 346 347 // Verify no policy has been installed. 348 EXPECT_FALSE(store_->policy()); 349 EXPECT_TRUE(store_->policy_map().empty()); 350 EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status()); 351} 352 353TEST_F(UserCloudPolicyStoreChromeOSTest, LoadInvalidPolicy) { 354 ExpectError(CloudPolicyStore::STATUS_PARSE_ERROR); 355 ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad("invalid")); 356 357 // Verify no policy has been installed. 358 EXPECT_FALSE(store_->policy()); 359 EXPECT_TRUE(store_->policy_map().empty()); 360 EXPECT_EQ(CloudPolicyStore::STATUS_PARSE_ERROR, store_->status()); 361} 362 363TEST_F(UserCloudPolicyStoreChromeOSTest, LoadValidationError) { 364 policy_.policy_data().clear_policy_type(); 365 policy_.Build(); 366 367 ExpectError(CloudPolicyStore::STATUS_VALIDATION_ERROR); 368 ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad(policy_.GetBlob())); 369 VerifyStoreHasValidationError(); 370} 371 372TEST_F(UserCloudPolicyStoreChromeOSTest, LoadNoKey) { 373 // The loaded policy can't be verified without the public key. 374 ASSERT_TRUE(file_util::Delete(user_policy_key_file(), false)); 375 ExpectError(CloudPolicyStore::STATUS_VALIDATION_ERROR); 376 ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad(policy_.GetBlob())); 377 VerifyStoreHasValidationError(); 378} 379 380TEST_F(UserCloudPolicyStoreChromeOSTest, LoadInvalidSignature) { 381 // Break the signature. 382 policy_.policy().mutable_policy_data_signature()->append("garbage"); 383 ExpectError(CloudPolicyStore::STATUS_VALIDATION_ERROR); 384 ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad(policy_.GetBlob())); 385 VerifyStoreHasValidationError(); 386} 387 388TEST_F(UserCloudPolicyStoreChromeOSTest, MigrationFull) { 389 std::string data; 390 391 em::DeviceCredentials credentials; 392 credentials.set_device_token(kLegacyToken); 393 credentials.set_device_id(kLegacyDeviceId); 394 ASSERT_TRUE(credentials.SerializeToString(&data)); 395 ASSERT_NE(-1, file_util::WriteFile(token_file(), data.c_str(), data.size())); 396 397 em::CachedCloudPolicyResponse cached_policy; 398 cached_policy.mutable_cloud_policy()->CopyFrom(policy_.policy()); 399 ASSERT_TRUE(cached_policy.SerializeToString(&data)); 400 ASSERT_NE(-1, file_util::WriteFile(policy_file(), data.c_str(), data.size())); 401 402 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())); 403 ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad("")); 404 Mock::VerifyAndClearExpectations(&observer_); 405 406 // Verify that legacy user policy and token have been loaded. 407 em::PolicyData expected_policy_data; 408 EXPECT_TRUE(expected_policy_data.ParseFromString( 409 cached_policy.cloud_policy().policy_data())); 410 expected_policy_data.clear_public_key_version(); 411 expected_policy_data.set_request_token(kLegacyToken); 412 expected_policy_data.set_device_id(kLegacyDeviceId); 413 ASSERT_TRUE(store_->policy()); 414 EXPECT_EQ(expected_policy_data.SerializeAsString(), 415 store_->policy()->SerializeAsString()); 416 VerifyPolicyMap(kDefaultHomepage); 417 EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status()); 418} 419 420TEST_F(UserCloudPolicyStoreChromeOSTest, MigrationNoToken) { 421 std::string data; 422 testing::Sequence seq; 423 424 em::CachedCloudPolicyResponse cached_policy; 425 cached_policy.mutable_cloud_policy()->CopyFrom(policy_.policy()); 426 ASSERT_TRUE(cached_policy.SerializeToString(&data)); 427 ASSERT_NE(-1, file_util::WriteFile(policy_file(), data.c_str(), data.size())); 428 429 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())); 430 ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad("")); 431 Mock::VerifyAndClearExpectations(&observer_); 432 433 // Verify the legacy cache has been loaded. 434 em::PolicyData expected_policy_data; 435 EXPECT_TRUE(expected_policy_data.ParseFromString( 436 cached_policy.cloud_policy().policy_data())); 437 expected_policy_data.clear_public_key_version(); 438 ASSERT_TRUE(store_->policy()); 439 EXPECT_EQ(expected_policy_data.SerializeAsString(), 440 store_->policy()->SerializeAsString()); 441 VerifyPolicyMap(kDefaultHomepage); 442 EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status()); 443} 444 445TEST_F(UserCloudPolicyStoreChromeOSTest, MigrationNoPolicy) { 446 std::string data; 447 448 em::DeviceCredentials credentials; 449 credentials.set_device_token(kLegacyToken); 450 credentials.set_device_id(kLegacyDeviceId); 451 ASSERT_TRUE(credentials.SerializeToString(&data)); 452 ASSERT_NE(-1, file_util::WriteFile(token_file(), data.c_str(), data.size())); 453 454 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())); 455 ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad("")); 456 Mock::VerifyAndClearExpectations(&observer_); 457 458 // Verify that legacy user policy and token have been loaded. 459 em::PolicyData expected_policy_data; 460 expected_policy_data.set_request_token(kLegacyToken); 461 expected_policy_data.set_device_id(kLegacyDeviceId); 462 ASSERT_TRUE(store_->policy()); 463 EXPECT_EQ(expected_policy_data.SerializeAsString(), 464 store_->policy()->SerializeAsString()); 465 EXPECT_TRUE(store_->policy_map().empty()); 466 EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status()); 467} 468 469TEST_F(UserCloudPolicyStoreChromeOSTest, MigrationAndStoreNew) { 470 // Start without an existing public key. 471 ASSERT_TRUE(file_util::Delete(user_policy_key_file(), false)); 472 473 std::string data; 474 em::CachedCloudPolicyResponse cached_policy; 475 cached_policy.mutable_cloud_policy()->CopyFrom(policy_.policy()); 476 ASSERT_TRUE(cached_policy.SerializeToString(&data)); 477 ASSERT_NE(-1, file_util::WriteFile(policy_file(), data.c_str(), data.size())); 478 479 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())); 480 ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad("")); 481 Mock::VerifyAndClearExpectations(&observer_); 482 483 // Verify the legacy cache has been loaded. 484 em::PolicyData expected_policy_data; 485 EXPECT_TRUE(expected_policy_data.ParseFromString( 486 cached_policy.cloud_policy().policy_data())); 487 expected_policy_data.clear_public_key_version(); 488 ASSERT_TRUE(store_->policy()); 489 EXPECT_EQ(expected_policy_data.SerializeAsString(), 490 store_->policy()->SerializeAsString()); 491 VerifyPolicyMap(kDefaultHomepage); 492 EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status()); 493 EXPECT_TRUE(file_util::PathExists(policy_file())); 494 495 // Now store a new policy using the new homepage location. 496 const char kNewHomepage[] = "http://google.com"; 497 policy_.payload().mutable_homepagelocation()->set_value(kNewHomepage); 498 policy_.set_new_signing_key(PolicyBuilder::CreateTestNewSigningKey()); 499 policy_.Build(); 500 std::vector<uint8> new_public_key; 501 ASSERT_TRUE(policy_.new_signing_key()->ExportPublicKey(&new_public_key)); 502 ASSERT_NO_FATAL_FAILURE( 503 PerformStorePolicy(&new_public_key, kDefaultHomepage, kNewHomepage)); 504 VerifyPolicyMap(kNewHomepage); 505 506 // Verify that the legacy cache has been removed. 507 EXPECT_FALSE(file_util::PathExists(policy_file())); 508} 509 510} // namespace 511 512} // namespace policy 513