// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/policy/device_policy_cache.h" #include #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/file_path.h" #include "base/memory/ref_counted.h" #include "base/threading/sequenced_worker_pool.h" #include "chrome/browser/chromeos/cros/cryptohome_library.h" #include "chrome/browser/chromeos/settings/device_settings_test_helper.h" #include "chrome/browser/chromeos/settings/mock_owner_key_util.h" #include "chrome/browser/policy/cloud_policy_data_store.h" #include "chrome/browser/policy/enterprise_install_attributes.h" #include "chrome/browser/policy/policy_builder.h" #include "chrome/browser/policy/proto/chrome_device_policy.pb.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "content/public/test/test_browser_thread.h" #include "policy/policy_constants.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using ::testing::Mock; namespace em = enterprise_management; namespace policy { namespace { class MockCloudPolicyCacheObserver : public CloudPolicyCacheBase::Observer { public: virtual ~MockCloudPolicyCacheObserver() {} MOCK_METHOD1(OnCacheGoingAway, void(CloudPolicyCacheBase*)); MOCK_METHOD1(OnCacheUpdate, void(CloudPolicyCacheBase*)); }; } // namespace class DevicePolicyCacheTest : public testing::Test { protected: DevicePolicyCacheTest() : cryptohome_(chromeos::CryptohomeLibrary::GetImpl(true)), owner_key_util_(new chromeos::MockOwnerKeyUtil()), install_attributes_(cryptohome_.get()), message_loop_(MessageLoop::TYPE_UI), ui_thread_(content::BrowserThread::UI, &message_loop_), file_thread_(content::BrowserThread::FILE, &message_loop_) {} virtual void SetUp() OVERRIDE { policy_.payload().mutable_device_policy_refresh_rate()-> set_device_policy_refresh_rate(120); policy_.Build(); device_settings_test_helper_.set_policy_blob(policy_.GetBlob()); owner_key_util_->SetPublicKeyFromPrivateKey(policy_.signing_key()); device_settings_service_.Initialize(&device_settings_test_helper_, owner_key_util_); data_store_.reset(CloudPolicyDataStore::CreateForDevicePolicies()); cache_.reset(new DevicePolicyCache(data_store_.get(), &install_attributes_, &device_settings_service_)); cache_->AddObserver(&observer_); } virtual void TearDown() OVERRIDE { device_settings_test_helper_.Flush(); device_settings_service_.Shutdown(); cache_->RemoveObserver(&observer_); cache_.reset(); } void Startup() { EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())); device_settings_service_.Load(); device_settings_test_helper_.Flush(); cache_->Load(); Mock::VerifyAndClearExpectations(&observer_); } void MakeEnterpriseDevice() { ASSERT_EQ(EnterpriseInstallAttributes::LOCK_SUCCESS, install_attributes_.LockDevice( policy_.policy_data().username(), DEVICE_MODE_ENTERPRISE, std::string())); } const Value* GetPolicy(const char* policy_name) { return cache_->policy()->GetValue(policy_name); } MockCloudPolicyCacheObserver observer_; scoped_ptr cryptohome_; scoped_refptr owner_key_util_; chromeos::DeviceSettingsTestHelper device_settings_test_helper_; chromeos::DeviceSettingsService device_settings_service_; EnterpriseInstallAttributes install_attributes_; scoped_ptr data_store_; scoped_ptr cache_; DevicePolicyBuilder policy_; MessageLoop message_loop_; content::TestBrowserThread ui_thread_; content::TestBrowserThread file_thread_; private: DISALLOW_COPY_AND_ASSIGN(DevicePolicyCacheTest); }; TEST_F(DevicePolicyCacheTest, ColdStartup) { EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())).Times(0); cache_->Load(); Mock::VerifyAndClearExpectations(&observer_); EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())); device_settings_service_.Load(); device_settings_test_helper_.Flush(); Mock::VerifyAndClearExpectations(&observer_); base::FundamentalValue expected(120); EXPECT_TRUE(Value::Equals(&expected, GetPolicy(key::kDevicePolicyRefreshRate))); } TEST_F(DevicePolicyCacheTest, WarmStartup) { Startup(); base::FundamentalValue expected(120); EXPECT_TRUE(Value::Equals(&expected, GetPolicy(key::kDevicePolicyRefreshRate))); } TEST_F(DevicePolicyCacheTest, SetPolicy) { MakeEnterpriseDevice(); Startup(); base::FundamentalValue expected(120); EXPECT_TRUE(Value::Equals(&expected, GetPolicy(key::kDevicePolicyRefreshRate))); // Set new policy information. policy_.payload().mutable_device_policy_refresh_rate()-> set_device_policy_refresh_rate(300); policy_.Build(); EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())).Times(0); EXPECT_TRUE(cache_->SetPolicy(policy_.policy())); cache_->SetFetchingDone(); Mock::VerifyAndClearExpectations(&observer_); EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())).Times(0); device_settings_test_helper_.FlushStore(); Mock::VerifyAndClearExpectations(&observer_); // Cache update notification should only fire in the retrieve callback. EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())); device_settings_test_helper_.Flush(); Mock::VerifyAndClearExpectations(&observer_); base::FundamentalValue updated_expected(300); EXPECT_TRUE(Value::Equals(&updated_expected, GetPolicy(key::kDevicePolicyRefreshRate))); cache_->RemoveObserver(&observer_); } TEST_F(DevicePolicyCacheTest, SetPolicyOtherUserSameDomain) { MakeEnterpriseDevice(); Startup(); // Set new policy information. This should succeed as the domain is the same. policy_.policy_data().set_username("another_user@example.com"); policy_.Build(); EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())); EXPECT_TRUE(cache_->SetPolicy(policy_.policy())); device_settings_test_helper_.Flush(); Mock::VerifyAndClearExpectations(&observer_); EXPECT_EQ(policy_.GetBlob(), device_settings_test_helper_.policy_blob()); } TEST_F(DevicePolicyCacheTest, SetPolicyOtherUserOtherDomain) { MakeEnterpriseDevice(); Startup(); // Set new policy information. This should fail because the user is from // different domain. policy_.policy_data().set_username("foreign_user@hackers.com"); policy_.Build(); EXPECT_NE(policy_.GetBlob(), device_settings_test_helper_.policy_blob()); EXPECT_FALSE(cache_->SetPolicy(policy_.policy())); device_settings_test_helper_.Flush(); EXPECT_NE(policy_.GetBlob(), device_settings_test_helper_.policy_blob()); } TEST_F(DevicePolicyCacheTest, SetPolicyNonEnterpriseDevice) { Startup(); // Set new policy information. This should fail due to invalid user. device_settings_test_helper_.set_policy_blob(std::string()); EXPECT_FALSE(cache_->SetPolicy(policy_.policy())); device_settings_test_helper_.Flush(); EXPECT_TRUE(device_settings_test_helper_.policy_blob().empty()); } TEST_F(DevicePolicyCacheTest, SetProxyPolicy) { MakeEnterpriseDevice(); em::DeviceProxySettingsProto proxy_settings; proxy_settings.set_proxy_mode("direct"); proxy_settings.set_proxy_server("http://proxy:8080"); proxy_settings.set_proxy_pac_url("http://proxy:8080/pac.js"); proxy_settings.set_proxy_bypass_list("127.0.0.1,example.com"); policy_.payload().mutable_device_proxy_settings()->CopyFrom(proxy_settings); policy_.Build(); device_settings_test_helper_.set_policy_blob(policy_.GetBlob()); Startup(); DictionaryValue expected; expected.SetString(key::kProxyMode, proxy_settings.proxy_mode()); expected.SetString(key::kProxyServer, proxy_settings.proxy_server()); expected.SetString(key::kProxyPacUrl, proxy_settings.proxy_pac_url()); expected.SetString(key::kProxyBypassList, proxy_settings.proxy_bypass_list()); EXPECT_TRUE(Value::Equals(&expected, GetPolicy(key::kProxySettings))); } TEST_F(DevicePolicyCacheTest, SetDeviceNetworkConfigurationPolicy) { MakeEnterpriseDevice(); std::string fake_config("{ 'NetworkConfigurations': [] }"); policy_.payload().mutable_open_network_configuration()-> set_open_network_configuration(fake_config); policy_.Build(); device_settings_test_helper_.set_policy_blob(policy_.GetBlob()); Startup(); StringValue expected_config(fake_config); EXPECT_TRUE( Value::Equals(&expected_config, GetPolicy(key::kDeviceOpenNetworkConfiguration))); } } // namespace policy