// 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/chromeos/settings/device_settings_provider.h" #include #include "base/bind.h" #include "base/callback.h" #include "base/files/file_util.h" #include "base/path_service.h" #include "base/test/scoped_path_override.h" #include "base/values.h" #include "chrome/browser/chromeos/policy/device_local_account.h" #include "chrome/browser/chromeos/policy/device_policy_builder.h" #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h" #include "chrome/browser/chromeos/settings/device_settings_test_helper.h" #include "chrome/common/chrome_paths.h" #include "chrome/test/base/scoped_testing_local_state.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "chromeos/settings/cros_settings_names.h" #include "components/user_manager/fake_user_manager.h" #include "components/user_manager/user.h" #include "policy/proto/device_management_backend.pb.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace em = enterprise_management; namespace chromeos { using ::testing::AtLeast; using ::testing::AnyNumber; using ::testing::Mock; using ::testing::_; namespace { const char kDisabledMessage[] = "This device has been disabled."; } // namespace class DeviceSettingsProviderTest : public DeviceSettingsTestBase { public: MOCK_METHOD1(SettingChanged, void(const std::string&)); MOCK_METHOD0(GetTrustedCallback, void(void)); protected: DeviceSettingsProviderTest() : local_state_(TestingBrowserProcess::GetGlobal()), user_data_dir_override_(chrome::DIR_USER_DATA) {} void SetUp() override { DeviceSettingsTestBase::SetUp(); EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); provider_.reset( new DeviceSettingsProvider( base::Bind(&DeviceSettingsProviderTest::SettingChanged, base::Unretained(this)), &device_settings_service_)); Mock::VerifyAndClearExpectations(this); } void TearDown() override { DeviceSettingsTestBase::TearDown(); } // Helper routine to enable/disable all reporting settings in policy. void SetReportingSettings(bool enable_reporting, int frequency) { EXPECT_CALL(*this, SettingChanged(_)).Times(AtLeast(1)); em::DeviceReportingProto* proto = device_policy_.payload().mutable_device_reporting(); proto->set_report_version_info(enable_reporting); proto->set_report_activity_times(enable_reporting); proto->set_report_boot_mode(enable_reporting); proto->set_report_location(enable_reporting); proto->set_report_network_interfaces(enable_reporting); proto->set_report_users(enable_reporting); proto->set_report_hardware_status(enable_reporting); proto->set_report_session_status(enable_reporting); proto->set_device_status_frequency(frequency); device_policy_.Build(); device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob()); ReloadDeviceSettings(); Mock::VerifyAndClearExpectations(this); } // Helper routine to enable/disable all reporting settings in policy. void SetHeartbeatSettings(bool enable_heartbeat, int frequency) { EXPECT_CALL(*this, SettingChanged(_)).Times(AtLeast(1)); em::DeviceHeartbeatSettingsProto* proto = device_policy_.payload().mutable_device_heartbeat_settings(); proto->set_heartbeat_enabled(enable_heartbeat); proto->set_heartbeat_frequency(frequency); device_policy_.Build(); device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob()); ReloadDeviceSettings(); Mock::VerifyAndClearExpectations(this); } // Helper routine to ensure all heartbeat policies have been correctly // decoded. void VerifyHeartbeatSettings(bool expected_enable_state, int expected_frequency) { const base::FundamentalValue expected_enabled_value(expected_enable_state); EXPECT_TRUE(base::Value::Equals(provider_->Get(kHeartbeatEnabled), &expected_enabled_value)); const base::FundamentalValue expected_frequency_value(expected_frequency); EXPECT_TRUE(base::Value::Equals(provider_->Get(kHeartbeatFrequency), &expected_frequency_value)); } // Helper routine to ensure all reporting policies have been correctly // decoded. void VerifyReportingSettings(bool expected_enable_state, int expected_frequency) { const char* reporting_settings[] = { kReportDeviceVersionInfo, kReportDeviceActivityTimes, kReportDeviceBootMode, // Device location reporting is not currently supported. // kReportDeviceLocation, kReportDeviceNetworkInterfaces, kReportDeviceUsers, kReportDeviceHardwareStatus, kReportDeviceSessionStatus }; const base::FundamentalValue expected_enable_value(expected_enable_state); for (const auto& setting : reporting_settings) { EXPECT_TRUE(base::Value::Equals(provider_->Get(setting), &expected_enable_value)) << "Value for " << setting << " does not match expected"; } const base::FundamentalValue expected_frequency_value(expected_frequency); EXPECT_TRUE(base::Value::Equals(provider_->Get(kReportUploadFrequency), &expected_frequency_value)); } // Helper routine to set LoginScreenDomainAutoComplete policy. void SetDomainAutoComplete(const std::string& domain) { EXPECT_CALL(*this, SettingChanged(_)).Times(AtLeast(1)); em::LoginScreenDomainAutoCompleteProto* proto = device_policy_.payload().mutable_login_screen_domain_auto_complete(); proto->set_login_screen_domain_auto_complete(domain); device_policy_.Build(); device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob()); ReloadDeviceSettings(); Mock::VerifyAndClearExpectations(this); } // Helper routine to check value of the LoginScreenDomainAutoComplete policy. void VerifyDomainAutoComplete( const base::StringValue* const ptr_to_expected_value) { EXPECT_TRUE(base::Value::Equals( provider_->Get(kAccountsPrefLoginScreenDomainAutoComplete), ptr_to_expected_value)); } ScopedTestingLocalState local_state_; scoped_ptr provider_; base::ScopedPathOverride user_data_dir_override_; private: DISALLOW_COPY_AND_ASSIGN(DeviceSettingsProviderTest); }; TEST_F(DeviceSettingsProviderTest, InitializationTest) { // Have the service load a settings blob. EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); ReloadDeviceSettings(); Mock::VerifyAndClearExpectations(this); // Verify that the policy blob has been correctly parsed and trusted. // The trusted flag should be set before the call to PrepareTrustedValues. EXPECT_EQ(CrosSettingsProvider::TRUSTED, provider_->PrepareTrustedValues(base::Closure())); const base::Value* value = provider_->Get(kStatsReportingPref); ASSERT_TRUE(value); bool bool_value; EXPECT_TRUE(value->GetAsBoolean(&bool_value)); EXPECT_FALSE(bool_value); } TEST_F(DeviceSettingsProviderTest, InitializationTestUnowned) { // Have the service check the key. owner_key_util_->Clear(); ReloadDeviceSettings(); // The trusted flag should be set before the call to PrepareTrustedValues. EXPECT_EQ(CrosSettingsProvider::TRUSTED, provider_->PrepareTrustedValues(base::Closure())); const base::Value* value = provider_->Get(kReleaseChannel); ASSERT_TRUE(value); std::string string_value; EXPECT_TRUE(value->GetAsString(&string_value)); EXPECT_TRUE(string_value.empty()); // Sets should succeed though and be readable from the cache. EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); EXPECT_CALL(*this, SettingChanged(kReleaseChannel)).Times(1); base::StringValue new_value("stable-channel"); provider_->Set(kReleaseChannel, new_value); Mock::VerifyAndClearExpectations(this); // This shouldn't trigger a write. device_settings_test_helper_.set_policy_blob(std::string()); FlushDeviceSettings(); EXPECT_EQ(std::string(), device_settings_test_helper_.policy_blob()); // Verify the change has been applied. const base::Value* saved_value = provider_->Get(kReleaseChannel); ASSERT_TRUE(saved_value); EXPECT_TRUE(saved_value->GetAsString(&string_value)); ASSERT_EQ("stable-channel", string_value); } TEST_F(DeviceSettingsProviderTest, SetPrefFailed) { // If we are not the owner no sets should work. base::FundamentalValue value(true); EXPECT_CALL(*this, SettingChanged(kStatsReportingPref)).Times(1); provider_->Set(kStatsReportingPref, value); Mock::VerifyAndClearExpectations(this); // This shouldn't trigger a write. device_settings_test_helper_.set_policy_blob(std::string()); FlushDeviceSettings(); EXPECT_EQ(std::string(), device_settings_test_helper_.policy_blob()); // Verify the change has not been applied. const base::Value* saved_value = provider_->Get(kStatsReportingPref); ASSERT_TRUE(saved_value); bool bool_value; EXPECT_TRUE(saved_value->GetAsBoolean(&bool_value)); EXPECT_FALSE(bool_value); } TEST_F(DeviceSettingsProviderTest, SetPrefSucceed) { owner_key_util_->SetPrivateKey(device_policy_.GetSigningKey()); InitOwner(device_policy_.policy_data().username(), true); FlushDeviceSettings(); base::FundamentalValue value(true); EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); EXPECT_CALL(*this, SettingChanged(kStatsReportingPref)).Times(1); provider_->Set(kStatsReportingPref, value); Mock::VerifyAndClearExpectations(this); // Process the store. device_settings_test_helper_.set_policy_blob(std::string()); FlushDeviceSettings(); // Verify that the device policy has been adjusted. ASSERT_TRUE(device_settings_service_.device_settings()); EXPECT_TRUE(device_settings_service_.device_settings()-> metrics_enabled().metrics_enabled()); // Verify the change has been applied. const base::Value* saved_value = provider_->Get(kStatsReportingPref); ASSERT_TRUE(saved_value); bool bool_value; EXPECT_TRUE(saved_value->GetAsBoolean(&bool_value)); EXPECT_TRUE(bool_value); } TEST_F(DeviceSettingsProviderTest, SetPrefTwice) { owner_key_util_->SetPrivateKey(device_policy_.GetSigningKey()); InitOwner(device_policy_.policy_data().username(), true); FlushDeviceSettings(); EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); base::StringValue value1("beta"); provider_->Set(kReleaseChannel, value1); base::StringValue value2("dev"); provider_->Set(kReleaseChannel, value2); // Let the changes propagate through the system. device_settings_test_helper_.set_policy_blob(std::string()); FlushDeviceSettings(); // Verify the second change has been applied. const base::Value* saved_value = provider_->Get(kReleaseChannel); EXPECT_TRUE(value2.Equals(saved_value)); Mock::VerifyAndClearExpectations(this); } TEST_F(DeviceSettingsProviderTest, PolicyRetrievalFailedBadSignature) { owner_key_util_->SetPublicKeyFromPrivateKey(*device_policy_.GetSigningKey()); device_policy_.policy().set_policy_data_signature("bad signature"); device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob()); ReloadDeviceSettings(); // Verify that the cached settings blob is not "trusted". EXPECT_EQ(DeviceSettingsService::STORE_VALIDATION_ERROR, device_settings_service_.status()); EXPECT_EQ(CrosSettingsProvider::PERMANENTLY_UNTRUSTED, provider_->PrepareTrustedValues(base::Closure())); } TEST_F(DeviceSettingsProviderTest, PolicyRetrievalNoPolicy) { owner_key_util_->SetPublicKeyFromPrivateKey(*device_policy_.GetSigningKey()); device_settings_test_helper_.set_policy_blob(std::string()); ReloadDeviceSettings(); // Verify that the cached settings blob is not "trusted". EXPECT_EQ(DeviceSettingsService::STORE_NO_POLICY, device_settings_service_.status()); EXPECT_EQ(CrosSettingsProvider::PERMANENTLY_UNTRUSTED, provider_->PrepareTrustedValues(base::Closure())); } TEST_F(DeviceSettingsProviderTest, PolicyFailedPermanentlyNotification) { device_settings_test_helper_.set_policy_blob(std::string()); EXPECT_CALL(*this, GetTrustedCallback()); EXPECT_EQ(CrosSettingsProvider::TEMPORARILY_UNTRUSTED, provider_->PrepareTrustedValues( base::Bind(&DeviceSettingsProviderTest::GetTrustedCallback, base::Unretained(this)))); ReloadDeviceSettings(); Mock::VerifyAndClearExpectations(this); EXPECT_EQ(CrosSettingsProvider::PERMANENTLY_UNTRUSTED, provider_->PrepareTrustedValues(base::Closure())); } TEST_F(DeviceSettingsProviderTest, PolicyLoadNotification) { EXPECT_CALL(*this, GetTrustedCallback()); EXPECT_EQ(CrosSettingsProvider::TEMPORARILY_UNTRUSTED, provider_->PrepareTrustedValues( base::Bind(&DeviceSettingsProviderTest::GetTrustedCallback, base::Unretained(this)))); ReloadDeviceSettings(); Mock::VerifyAndClearExpectations(this); } TEST_F(DeviceSettingsProviderTest, StatsReportingMigration) { // Create the legacy consent file. base::FilePath consent_file; ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &consent_file)); consent_file = consent_file.AppendASCII("Consent To Send Stats"); ASSERT_EQ(1, base::WriteFile(consent_file, "0", 1)); // This should trigger migration because the metrics policy isn't in the blob. device_settings_test_helper_.set_policy_blob(std::string()); FlushDeviceSettings(); EXPECT_EQ(std::string(), device_settings_test_helper_.policy_blob()); // Verify that migration has kicked in. const base::Value* saved_value = provider_->Get(kStatsReportingPref); ASSERT_TRUE(saved_value); bool bool_value; EXPECT_TRUE(saved_value->GetAsBoolean(&bool_value)); EXPECT_FALSE(bool_value); } TEST_F(DeviceSettingsProviderTest, LegacyDeviceLocalAccounts) { EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); em::DeviceLocalAccountInfoProto* account = device_policy_.payload().mutable_device_local_accounts()->add_account(); account->set_deprecated_public_session_id( policy::PolicyBuilder::kFakeUsername); device_policy_.Build(); device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob()); ReloadDeviceSettings(); Mock::VerifyAndClearExpectations(this); // On load, the deprecated spec should have been converted to the new format. base::ListValue expected_accounts; scoped_ptr entry_dict(new base::DictionaryValue()); entry_dict->SetString(kAccountsPrefDeviceLocalAccountsKeyId, policy::PolicyBuilder::kFakeUsername); entry_dict->SetInteger(kAccountsPrefDeviceLocalAccountsKeyType, policy::DeviceLocalAccount::TYPE_PUBLIC_SESSION); expected_accounts.Append(entry_dict.release()); const base::Value* actual_accounts = provider_->Get(kAccountsPrefDeviceLocalAccounts); EXPECT_TRUE(base::Value::Equals(&expected_accounts, actual_accounts)); } TEST_F(DeviceSettingsProviderTest, OwnerIsStillSetWhenDeviceIsConsumerManaged) { owner_key_util_->SetPrivateKey(device_policy_.GetSigningKey()); InitOwner(device_policy_.policy_data().username(), true); device_policy_.policy_data().set_management_mode( em::PolicyData::CONSUMER_MANAGED); device_policy_.policy_data().set_request_token("test request token"); device_policy_.Build(); device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob()); FlushDeviceSettings(); // Expect that kDeviceOwner is not empty. const base::Value* value = provider_->Get(kDeviceOwner); ASSERT_TRUE(value); std::string string_value; EXPECT_TRUE(value->GetAsString(&string_value)); EXPECT_FALSE(string_value.empty()); } TEST_F(DeviceSettingsProviderTest, DecodeDeviceState) { EXPECT_CALL(*this, SettingChanged(_)).Times(AtLeast(1)); device_policy_.policy_data().mutable_device_state()->set_device_mode( em::DeviceState::DEVICE_MODE_DISABLED); device_policy_.policy_data().mutable_device_state()-> mutable_disabled_state()->set_message(kDisabledMessage); device_policy_.Build(); device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob()); ReloadDeviceSettings(); Mock::VerifyAndClearExpectations(this); // Verify that the device state has been decoded correctly. const base::FundamentalValue expected_disabled_value(true); EXPECT_TRUE(base::Value::Equals(provider_->Get(kDeviceDisabled), &expected_disabled_value)); const base::StringValue expected_disabled_message_value(kDisabledMessage); EXPECT_TRUE(base::Value::Equals(provider_->Get(kDeviceDisabledMessage), &expected_disabled_message_value)); // Verify that a change to the device state triggers a notification. EXPECT_CALL(*this, SettingChanged(_)).Times(AtLeast(1)); device_policy_.policy_data().mutable_device_state()->clear_device_mode(); device_policy_.Build(); device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob()); ReloadDeviceSettings(); Mock::VerifyAndClearExpectations(this); // Verify that the updated state has been decoded correctly. EXPECT_FALSE(provider_->Get(kDeviceDisabled)); } TEST_F(DeviceSettingsProviderTest, DecodeReportingSettings) { // Turn on all reporting and verify that the reporting settings have been // decoded correctly. const int status_frequency = 50000; SetReportingSettings(true, status_frequency); VerifyReportingSettings(true, status_frequency); // Turn off all reporting and verify that the settings are decoded // correctly. SetReportingSettings(false, status_frequency); VerifyReportingSettings(false, status_frequency); } TEST_F(DeviceSettingsProviderTest, DecodeHeartbeatSettings) { // Turn on heartbeats and verify that the heartbeat settings have been // decoded correctly. const int heartbeat_frequency = 50000; SetHeartbeatSettings(true, heartbeat_frequency); VerifyHeartbeatSettings(true, heartbeat_frequency); // Turn off all reporting and verify that the settings are decoded // correctly. SetHeartbeatSettings(false, heartbeat_frequency); VerifyHeartbeatSettings(false, heartbeat_frequency); } TEST_F(DeviceSettingsProviderTest, DecodeDomainAutoComplete) { // By default LoginScreenDomainAutoComplete policy should not be set. VerifyDomainAutoComplete(nullptr); // Empty string means that the policy is not set. SetDomainAutoComplete(""); VerifyDomainAutoComplete(nullptr); // Check some meaningful value. Policy should be set. const std::string domain = "domain.test"; const base::StringValue domain_value(domain); SetDomainAutoComplete(domain); VerifyDomainAutoComplete(&domain_value); } } // namespace chromeos