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/policy/cloud/user_cloud_policy_store.h" 6 7 #include "base/file_util.h" 8 #include "base/files/scoped_temp_dir.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/prefs/pref_service.h" 11 #include "base/run_loop.h" 12 #include "chrome/browser/policy/cloud/mock_cloud_policy_store.h" 13 #include "chrome/browser/policy/cloud/policy_builder.h" 14 #include "chrome/browser/signin/fake_signin_manager.h" 15 #include "chrome/browser/signin/signin_manager.h" 16 #include "chrome/browser/signin/signin_manager_factory.h" 17 #include "chrome/common/pref_names.h" 18 #include "chrome/test/base/testing_profile.h" 19 #include "content/public/test/test_browser_thread.h" 20 #include "policy/policy_constants.h" 21 #include "testing/gmock/include/gmock/gmock.h" 22 #include "testing/gtest/include/gtest/gtest.h" 23 24 using testing::AllOf; 25 using testing::Eq; 26 using testing::Property; 27 28 namespace policy { 29 30 namespace { 31 32 void RunUntilIdle() { 33 base::RunLoop run_loop; 34 run_loop.RunUntilIdle(); 35 } 36 37 class UserCloudPolicyStoreTest : public testing::Test { 38 public: 39 UserCloudPolicyStoreTest() 40 : loop_(base::MessageLoop::TYPE_UI), 41 ui_thread_(content::BrowserThread::UI, &loop_), 42 file_thread_(content::BrowserThread::FILE, &loop_), 43 profile_(new TestingProfile()) {} 44 45 virtual void SetUp() OVERRIDE { 46 ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir()); 47 SigninManager* signin = static_cast<SigninManager*>( 48 SigninManagerFactory::GetInstance()->SetTestingFactoryAndUse( 49 profile_.get(), FakeSigninManager::Build)); 50 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, 51 PolicyBuilder::kFakeUsername); 52 signin->Initialize(profile_.get(), NULL); 53 store_.reset(new UserCloudPolicyStore(profile_.get(), policy_file())); 54 store_->AddObserver(&observer_); 55 56 policy_.payload().mutable_passwordmanagerenabled()->set_value(true); 57 policy_.payload().mutable_urlblacklist()->mutable_value()->add_entries( 58 "chromium.org"); 59 60 policy_.Build(); 61 } 62 63 virtual void TearDown() OVERRIDE { 64 store_->RemoveObserver(&observer_); 65 store_.reset(); 66 RunUntilIdle(); 67 } 68 69 base::FilePath policy_file() { 70 return tmp_dir_.path().AppendASCII("policy"); 71 } 72 73 // Verifies that store_->policy_map() has the appropriate entries. 74 void VerifyPolicyMap(CloudPolicyStore* store) { 75 EXPECT_EQ(2U, store->policy_map().size()); 76 const PolicyMap::Entry* entry = 77 store->policy_map().Get(key::kPasswordManagerEnabled); 78 ASSERT_TRUE(entry); 79 EXPECT_TRUE(base::FundamentalValue(true).Equals(entry->value)); 80 ASSERT_TRUE(store->policy_map().Get(key::kURLBlacklist)); 81 } 82 83 // Install an expectation on |observer_| for an error code. 84 void ExpectError(CloudPolicyStore* store, CloudPolicyStore::Status error) { 85 EXPECT_CALL(observer_, 86 OnStoreError(AllOf(Eq(store), 87 Property(&CloudPolicyStore::status, 88 Eq(error))))); 89 } 90 91 UserPolicyBuilder policy_; 92 MockCloudPolicyStoreObserver observer_; 93 scoped_ptr<UserCloudPolicyStore> store_; 94 95 // CloudPolicyValidator() requires a FILE thread so declare one here. Both 96 // |ui_thread_| and |file_thread_| share the same MessageLoop |loop_| so 97 // callers can use RunLoop to manage both virtual threads. 98 base::MessageLoop loop_; 99 content::TestBrowserThread ui_thread_; 100 content::TestBrowserThread file_thread_; 101 102 scoped_ptr<TestingProfile> profile_; 103 base::ScopedTempDir tmp_dir_; 104 105 DISALLOW_COPY_AND_ASSIGN(UserCloudPolicyStoreTest); 106 }; 107 108 TEST_F(UserCloudPolicyStoreTest, LoadWithNoFile) { 109 EXPECT_FALSE(store_->policy()); 110 EXPECT_TRUE(store_->policy_map().empty()); 111 112 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())); 113 store_->Load(); 114 RunUntilIdle(); 115 116 EXPECT_FALSE(store_->policy()); 117 EXPECT_TRUE(store_->policy_map().empty()); 118 EXPECT_FALSE(store_->policy_changed()); 119 } 120 121 TEST_F(UserCloudPolicyStoreTest, LoadWithInvalidFile) { 122 EXPECT_FALSE(store_->policy()); 123 EXPECT_TRUE(store_->policy_map().empty()); 124 125 // Create a bogus file. 126 ASSERT_TRUE(file_util::CreateDirectory(policy_file().DirName())); 127 std::string bogus_data = "bogus_data"; 128 int size = bogus_data.size(); 129 ASSERT_EQ(size, file_util::WriteFile(policy_file(), 130 bogus_data.c_str(), 131 bogus_data.size())); 132 133 ExpectError(store_.get(), CloudPolicyStore::STATUS_LOAD_ERROR); 134 store_->Load(); 135 RunUntilIdle(); 136 137 EXPECT_FALSE(store_->policy()); 138 EXPECT_TRUE(store_->policy_map().empty()); 139 EXPECT_FALSE(store_->policy_changed()); 140 } 141 142 TEST_F(UserCloudPolicyStoreTest, LoadImmediatelyWithNoFile) { 143 EXPECT_FALSE(store_->policy()); 144 EXPECT_TRUE(store_->policy_map().empty()); 145 146 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())); 147 store_->LoadImmediately(); // Should load without running the message loop. 148 149 EXPECT_FALSE(store_->policy()); 150 EXPECT_TRUE(store_->policy_map().empty()); 151 EXPECT_FALSE(store_->policy_changed()); 152 } 153 154 TEST_F(UserCloudPolicyStoreTest, LoadImmediatelyWithInvalidFile) { 155 EXPECT_FALSE(store_->policy()); 156 EXPECT_TRUE(store_->policy_map().empty()); 157 158 // Create a bogus file. 159 ASSERT_TRUE(file_util::CreateDirectory(policy_file().DirName())); 160 std::string bogus_data = "bogus_data"; 161 int size = bogus_data.size(); 162 ASSERT_EQ(size, file_util::WriteFile(policy_file(), 163 bogus_data.c_str(), 164 bogus_data.size())); 165 166 ExpectError(store_.get(), CloudPolicyStore::STATUS_LOAD_ERROR); 167 store_->LoadImmediately(); // Should load without running the message loop. 168 169 EXPECT_FALSE(store_->policy()); 170 EXPECT_TRUE(store_->policy_map().empty()); 171 EXPECT_FALSE(store_->policy_changed()); 172 } 173 174 TEST_F(UserCloudPolicyStoreTest, Store) { 175 EXPECT_FALSE(store_->policy()); 176 EXPECT_TRUE(store_->policy_map().empty()); 177 178 // Store a simple policy and make sure it ends up as the currently active 179 // policy. 180 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())); 181 store_->Store(policy_.policy()); 182 RunUntilIdle(); 183 184 // Policy should be decoded and stored. 185 ASSERT_TRUE(store_->policy()); 186 EXPECT_EQ(policy_.policy_data().SerializeAsString(), 187 store_->policy()->SerializeAsString()); 188 VerifyPolicyMap(store_.get()); 189 EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status()); 190 } 191 192 TEST_F(UserCloudPolicyStoreTest, StoreThenClear) { 193 EXPECT_FALSE(store_->policy()); 194 EXPECT_TRUE(store_->policy_map().empty()); 195 196 // Store a simple policy and make sure the file exists. 197 // policy. 198 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())); 199 store_->Store(policy_.policy()); 200 RunUntilIdle(); 201 202 EXPECT_TRUE(store_->policy()); 203 EXPECT_FALSE(store_->policy_map().empty()); 204 205 // Policy file should exist. 206 ASSERT_TRUE(base::PathExists(policy_file())); 207 208 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())); 209 store_->Clear(); 210 RunUntilIdle(); 211 212 // Policy file should not exist. 213 ASSERT_TRUE(!base::PathExists(policy_file())); 214 215 // Policy should be gone. 216 EXPECT_FALSE(store_->policy()); 217 EXPECT_TRUE(store_->policy_map().empty()); 218 EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status()); 219 } 220 221 TEST_F(UserCloudPolicyStoreTest, StoreTwoTimes) { 222 EXPECT_FALSE(store_->policy()); 223 EXPECT_TRUE(store_->policy_map().empty()); 224 225 // Store a simple policy then store a second policy before the first one 226 // finishes validating, and make sure the second policy ends up as the active 227 // policy. 228 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())).Times(2); 229 230 UserPolicyBuilder first_policy; 231 first_policy.payload().mutable_passwordmanagerenabled()->set_value(false); 232 first_policy.Build(); 233 store_->Store(first_policy.policy()); 234 RunUntilIdle(); 235 236 store_->Store(policy_.policy()); 237 RunUntilIdle(); 238 239 // Policy should be decoded and stored. 240 ASSERT_TRUE(store_->policy()); 241 EXPECT_EQ(policy_.policy_data().SerializeAsString(), 242 store_->policy()->SerializeAsString()); 243 VerifyPolicyMap(store_.get()); 244 EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status()); 245 } 246 247 TEST_F(UserCloudPolicyStoreTest, StoreThenLoad) { 248 // Store a simple policy and make sure it can be read back in. 249 // policy. 250 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())); 251 store_->Store(policy_.policy()); 252 RunUntilIdle(); 253 254 // Now, make sure the policy can be read back in from a second store. 255 scoped_ptr<UserCloudPolicyStore> store2( 256 new UserCloudPolicyStore(profile_.get(), policy_file())); 257 store2->AddObserver(&observer_); 258 EXPECT_CALL(observer_, OnStoreLoaded(store2.get())); 259 store2->Load(); 260 RunUntilIdle(); 261 262 ASSERT_TRUE(store2->policy()); 263 EXPECT_EQ(policy_.policy_data().SerializeAsString(), 264 store2->policy()->SerializeAsString()); 265 VerifyPolicyMap(store2.get()); 266 EXPECT_EQ(CloudPolicyStore::STATUS_OK, store2->status()); 267 store2->RemoveObserver(&observer_); 268 } 269 270 TEST_F(UserCloudPolicyStoreTest, StoreThenLoadImmediately) { 271 // Store a simple policy and make sure it can be read back in. 272 // policy. 273 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())); 274 store_->Store(policy_.policy()); 275 RunUntilIdle(); 276 277 // Now, make sure the policy can be read back in from a second store. 278 scoped_ptr<UserCloudPolicyStore> store2( 279 new UserCloudPolicyStore(profile_.get(), policy_file())); 280 store2->AddObserver(&observer_); 281 EXPECT_CALL(observer_, OnStoreLoaded(store2.get())); 282 store2->LoadImmediately(); // Should load without running the message loop. 283 284 ASSERT_TRUE(store2->policy()); 285 EXPECT_EQ(policy_.policy_data().SerializeAsString(), 286 store2->policy()->SerializeAsString()); 287 VerifyPolicyMap(store2.get()); 288 EXPECT_EQ(CloudPolicyStore::STATUS_OK, store2->status()); 289 store2->RemoveObserver(&observer_); 290 EXPECT_TRUE(store2->policy_changed()); 291 } 292 293 TEST_F(UserCloudPolicyStoreTest, StoreValidationError) { 294 // Create an invalid policy (no policy type). 295 policy_.policy_data().clear_policy_type(); 296 policy_.Build(); 297 298 // Store policy. 299 ExpectError(store_.get(), CloudPolicyStore::STATUS_VALIDATION_ERROR); 300 store_->Store(policy_.policy()); 301 RunUntilIdle(); 302 ASSERT_FALSE(store_->policy()); 303 EXPECT_FALSE(store_->policy_changed()); 304 } 305 306 TEST_F(UserCloudPolicyStoreTest, LoadValidationError) { 307 // Force a validation error by changing the username after policy is stored. 308 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())); 309 store_->Store(policy_.policy()); 310 RunUntilIdle(); 311 312 // Sign out, and sign back in as a different user, and try to load the profile 313 // data (should fail due to mismatched username). 314 SigninManagerFactory::GetForProfile(profile_.get())->SignOut(); 315 SigninManagerFactory::GetForProfile(profile_.get())->SetAuthenticatedUsername( 316 "foobar (at) foobar.com"); 317 318 scoped_ptr<UserCloudPolicyStore> store2( 319 new UserCloudPolicyStore(profile_.get(), policy_file())); 320 store2->AddObserver(&observer_); 321 ExpectError(store2.get(), CloudPolicyStore::STATUS_VALIDATION_ERROR); 322 store2->Load(); 323 RunUntilIdle(); 324 325 ASSERT_FALSE(store2->policy()); 326 store2->RemoveObserver(&observer_); 327 328 // Sign out - we should be able to load the policy (don't check usernames 329 // when signed out). 330 SigninManagerFactory::GetForProfile(profile_.get())->SignOut(); 331 scoped_ptr<UserCloudPolicyStore> store3( 332 new UserCloudPolicyStore(profile_.get(), policy_file())); 333 store3->AddObserver(&observer_); 334 EXPECT_CALL(observer_, OnStoreLoaded(store3.get())); 335 store3->Load(); 336 RunUntilIdle(); 337 338 ASSERT_TRUE(store3->policy()); 339 store3->RemoveObserver(&observer_); 340 341 // Now start a signin as a different user - this should fail validation. 342 FakeSigninManager* signin = static_cast<FakeSigninManager*>( 343 SigninManagerFactory::GetForProfile(profile_.get())); 344 signin->set_auth_in_progress("foobar (at) foobar.com"); 345 346 scoped_ptr<UserCloudPolicyStore> store4( 347 new UserCloudPolicyStore(profile_.get(), policy_file())); 348 store4->AddObserver(&observer_); 349 ExpectError(store4.get(), CloudPolicyStore::STATUS_VALIDATION_ERROR); 350 store4->Load(); 351 RunUntilIdle(); 352 353 ASSERT_FALSE(store4->policy()); 354 store4->RemoveObserver(&observer_); 355 } 356 357 TEST_F(UserCloudPolicyStoreTest, PolicyChanged) { 358 EXPECT_CALL(observer_, OnStoreLoaded(store_.get())).Times(7); 359 EXPECT_FALSE(store_->policy_changed()); 360 361 // Clearing before storing should not result in a change. 362 store_->Clear(); 363 EXPECT_FALSE(store_->policy_changed()); 364 365 // Storing an initial policy should result in a change. 366 store_->Store(policy_.policy()); 367 RunUntilIdle(); 368 EXPECT_TRUE(store_->policy_changed()); 369 370 // Storing the same policy should not result in a change. 371 store_->Store(policy_.policy()); 372 RunUntilIdle(); 373 EXPECT_FALSE(store_->policy_changed()); 374 375 // Storing a modified policy should result in a change. 376 policy_.payload().mutable_urlblacklist()->mutable_value()->add_entries( 377 "build.chromium.org"); 378 policy_.Build(); 379 store_->Store(policy_.policy()); 380 RunUntilIdle(); 381 EXPECT_TRUE(store_->policy_changed()); 382 383 // Storing the same policy should not result in a change. 384 store_->Store(policy_.policy()); 385 RunUntilIdle(); 386 EXPECT_FALSE(store_->policy_changed()); 387 388 // Clearing the policy should result in a change. 389 store_->Clear(); 390 EXPECT_TRUE(store_->policy_changed()); 391 392 // Clearing the policy again shouldn't result in a change. 393 store_->Clear(); 394 EXPECT_FALSE(store_->policy_changed()); 395 } 396 397 } // namespace 398 399 } // namespace policy 400