diff options
-rw-r--r-- | chrome/browser/chromeos/cros/cryptohome_library.cc | 7 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/enterprise_enrollment_screen.cc | 98 | ||||
-rw-r--r-- | chrome/browser/policy/browser_policy_connector.cc | 32 | ||||
-rw-r--r-- | chrome/browser/policy/browser_policy_connector.h | 5 | ||||
-rw-r--r-- | chrome/browser/policy/device_policy_cache.cc | 34 | ||||
-rw-r--r-- | chrome/browser/policy/device_policy_cache.h | 10 | ||||
-rw-r--r-- | chrome/browser/policy/device_policy_cache_unittest.cc | 136 | ||||
-rw-r--r-- | chrome/browser/policy/enterprise_install_attributes.cc | 112 | ||||
-rw-r--r-- | chrome/browser/policy/enterprise_install_attributes.h | 65 | ||||
-rw-r--r-- | chrome/browser/policy/enterprise_install_attributes_unittest.cc | 55 | ||||
-rw-r--r-- | chrome/browser/policy/proto/device_management_backend.proto | 10 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 10 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 2 |
13 files changed, 443 insertions, 133 deletions
diff --git a/chrome/browser/chromeos/cros/cryptohome_library.cc b/chrome/browser/chromeos/cros/cryptohome_library.cc index 6c20330..55dfa15 100644 --- a/chrome/browser/chromeos/cros/cryptohome_library.cc +++ b/chrome/browser/chromeos/cros/cryptohome_library.cc @@ -245,7 +245,8 @@ class CryptohomeLibraryImpl : public CryptohomeLibrary { class CryptohomeLibraryStubImpl : public CryptohomeLibrary { public: - CryptohomeLibraryStubImpl() {} + CryptohomeLibraryStubImpl() + : locked_(false) {} virtual ~CryptohomeLibraryStubImpl() {} bool CheckKey(const std::string& user_email, const std::string& passhash) { @@ -399,7 +400,7 @@ class CryptohomeLibraryStubImpl : public CryptohomeLibrary { } bool InstallAttributesIsSecure() { - return locked_; + return false; } bool InstallAttributesIsInvalid() { @@ -407,7 +408,7 @@ class CryptohomeLibraryStubImpl : public CryptohomeLibrary { } bool InstallAttributesIsFirstInstall() { - return false; + return !locked_; } private: diff --git a/chrome/browser/chromeos/login/enterprise_enrollment_screen.cc b/chrome/browser/chromeos/login/enterprise_enrollment_screen.cc index 4f6e477..48ed015 100644 --- a/chrome/browser/chromeos/login/enterprise_enrollment_screen.cc +++ b/chrome/browser/chromeos/login/enterprise_enrollment_screen.cc @@ -15,7 +15,7 @@ namespace chromeos { // Retry for InstallAttrs initialization every 500ms. -const int kLockboxRetryIntervalMs = 500; +const int kLockRetryIntervalMs = 500; EnterpriseEnrollmentScreen::EnterpriseEnrollmentScreen( WizardScreenDelegate* delegate) @@ -227,79 +227,33 @@ void EnterpriseEnrollmentScreen::WriteInstallAttributesData( if (!view()) return; - chromeos::CryptohomeLibrary* cryptohome = - chromeos::CrosLibrary::Get()->GetCryptohomeLibrary(); - if (!cryptohome) { - LOG(ERROR) << "Enrollment can not proceed because the InstallAttrs can not " - << "be accessed."; - view()->ShowFatalEnrollmentError(); - return; - } - - if (!cryptohome->InstallAttributesIsReady()) { - // Lockbox is not ready yet, retry later. - LOG(WARNING) << "Lockbox is not ready yet will retry in " - << kLockboxRetryIntervalMs << "ms."; - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - runnable_method_factory_.NewRunnableMethod( - &EnterpriseEnrollmentScreen::WriteInstallAttributesData, result), - kLockboxRetryIntervalMs); - return; - } - - // Clearing the TPM password seems to be always a good deal. - if (cryptohome->TpmIsEnabled() && - !cryptohome->TpmIsBeingOwned() && - cryptohome->TpmIsOwned()) { - cryptohome->TpmClearStoredPassword(); - } - - // Make sure we really have a working InstallAttrs. - if (cryptohome->InstallAttributesIsInvalid()) { - LOG(ERROR) << "Enrollment can not proceed because the InstallAttrs " - << "is corrupt or failed to initialize!"; - view()->ShowFatalEnrollmentError(); - return; - } - if (!cryptohome->InstallAttributesIsFirstInstall()) { - std::string value; - if (cryptohome->InstallAttributesGet("enterprise.owned", &value) && - value == "true") { - if (cryptohome->InstallAttributesGet("enterprise.user", &value)) { - if (value == user_) { - // If we landed here with a locked InstallAttrs this would mean we - // only want to reenroll with the DMServer so lock just continue. - auth_fetcher_->StartIssueAuthToken( - result.sid, result.lsid, - GaiaConstants::kDeviceManagementService); - return; - } - } - } - - LOG(ERROR) << "Enrollment can not proceed because the InstallAttrs " - << "has been locked already!"; - view()->ShowFatalEnrollmentError(); - return; - } - - // Set values in the InstallAttrs and lock it. - DCHECK(cryptohome->InstallAttributesIsFirstInstall()); - cryptohome->InstallAttributesSet("enterprise.owned", "true"); - cryptohome->InstallAttributesSet("enterprise.user", user_); - DCHECK(cryptohome->InstallAttributesCount() == 2); - cryptohome->InstallAttributesFinalize(); - if (cryptohome->InstallAttributesIsFirstInstall()) { - LOG(ERROR) << "Enrollment can not proceed because the InstallAttrs " - << "can not be sealed!"; - view()->ShowFatalEnrollmentError(); - return; + switch (g_browser_process->browser_policy_connector()->LockDevice(user_)) { + case policy::EnterpriseInstallAttributes::LOCK_SUCCESS: + // Proceed with register and policy fetch. + auth_fetcher_->StartIssueAuthToken( + result.sid, result.lsid, GaiaConstants::kDeviceManagementService); + return; + case policy::EnterpriseInstallAttributes::LOCK_NOT_READY: + // InstallAttributes not ready yet, retry later. + LOG(WARNING) << "Install Attributes not ready yet will retry in " + << kLockRetryIntervalMs << "ms."; + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + runnable_method_factory_.NewRunnableMethod( + &EnterpriseEnrollmentScreen::WriteInstallAttributesData, result), + kLockRetryIntervalMs); + return; + case policy::EnterpriseInstallAttributes::LOCK_BACKEND_ERROR: + view()->ShowFatalEnrollmentError(); + return; + case policy::EnterpriseInstallAttributes::LOCK_WRONG_USER: + LOG(ERROR) << "Enrollment can not proceed because the InstallAttrs " + << "has been locked already!"; + view()->ShowFatalEnrollmentError(); + return; } - // Proceed with register and policy fetch. - auth_fetcher_->StartIssueAuthToken( - result.sid, result.lsid, GaiaConstants::kDeviceManagementService); + NOTREACHED(); } } // namespace chromeos diff --git a/chrome/browser/policy/browser_policy_connector.cc b/chrome/browser/policy/browser_policy_connector.cc index 56f4443..e6f375e 100644 --- a/chrome/browser/policy/browser_policy_connector.cc +++ b/chrome/browser/policy/browser_policy_connector.cc @@ -23,8 +23,10 @@ #endif #if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/policy/device_policy_cache.h" #include "chrome/browser/policy/device_policy_identity_strategy.h" +#include "chrome/browser/policy/enterprise_install_attributes.h" #endif namespace policy { @@ -38,9 +40,12 @@ BrowserPolicyConnector::BrowserPolicyConnector() CommandLine* command_line = CommandLine::ForCurrentProcess(); if (command_line->HasSwitch(switches::kEnableDevicePolicy)) { identity_strategy_.reset(new DevicePolicyIdentityStrategy()); + install_attributes_.reset(new EnterpriseInstallAttributes( + chromeos::CrosLibrary::Get()->GetCryptohomeLibrary())); cloud_policy_subsystem_.reset(new CloudPolicySubsystem( identity_strategy_.get(), - new DevicePolicyCache(identity_strategy_.get()))); + new DevicePolicyCache(identity_strategy_.get(), + install_attributes_.get()))); // Initialize the subsystem once the message loops are spinning. MessageLoop::current()->PostTask( @@ -149,22 +154,23 @@ bool BrowserPolicyConnector::IsEnterpriseManaged() { #endif } -std::string BrowserPolicyConnector::GetEnterpriseDomain() { - std::string domain; +EnterpriseInstallAttributes::LockResult + BrowserPolicyConnector::LockDevice(const std::string& user) { +#if defined(OS_CHROMEOS) + if (install_attributes_.get()) + return install_attributes_->LockDevice(user); +#endif + return EnterpriseInstallAttributes::LOCK_BACKEND_ERROR; +} + +std::string BrowserPolicyConnector::GetEnterpriseDomain() { #if defined(OS_CHROMEOS) - // TODO(xiyuan): Find a better way to get enterprise domain. - std::string username; - std::string auth_token; - if (identity_strategy_.get() && - identity_strategy_->GetCredentials(&username, &auth_token)) { - size_t pos = username.find('@'); - if (pos != std::string::npos) - domain = username.substr(pos + 1); - } + if (install_attributes_.get()) + return install_attributes_->GetDomain(); #endif - return domain; + return std::string(); } void BrowserPolicyConnector::StopAutoRetry() { diff --git a/chrome/browser/policy/browser_policy_connector.h b/chrome/browser/policy/browser_policy_connector.h index e055a97..de4af72 100644 --- a/chrome/browser/policy/browser_policy_connector.h +++ b/chrome/browser/policy/browser_policy_connector.h @@ -11,6 +11,7 @@ #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "base/task.h" +#include "chrome/browser/policy/enterprise_install_attributes.h" class PrefService; class TestingBrowserProcess; @@ -54,6 +55,9 @@ class BrowserPolicyConnector { // a local owner). bool IsEnterpriseManaged(); + // Locks the device to an enterprise domain. + EnterpriseInstallAttributes::LockResult LockDevice(const std::string& user); + // Returns the enterprise domain if device is managed. std::string GetEnterpriseDomain(); @@ -82,6 +86,7 @@ class BrowserPolicyConnector { #if defined(OS_CHROMEOS) scoped_ptr<DevicePolicyIdentityStrategy> identity_strategy_; + scoped_ptr<EnterpriseInstallAttributes> install_attributes_; #endif scoped_ptr<CloudPolicySubsystem> cloud_policy_subsystem_; diff --git a/chrome/browser/policy/device_policy_cache.cc b/chrome/browser/policy/device_policy_cache.cc index 6ab2e33..57456fb 100644 --- a/chrome/browser/policy/device_policy_cache.cc +++ b/chrome/browser/policy/device_policy_cache.cc @@ -15,6 +15,7 @@ #include "chrome/browser/chromeos/user_cros_settings_provider.h" #include "chrome/browser/policy/configuration_policy_pref_store.h" #include "chrome/browser/policy/device_policy_identity_strategy.h" +#include "chrome/browser/policy/enterprise_install_attributes.h" #include "chrome/browser/policy/policy_map.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "chrome/browser/policy/proto/device_management_constants.h" @@ -109,8 +110,10 @@ Value* DecodeIntegerValue(google::protobuf::int64 value) { namespace policy { DevicePolicyCache::DevicePolicyCache( - DevicePolicyIdentityStrategy* identity_strategy) + DevicePolicyIdentityStrategy* identity_strategy, + EnterpriseInstallAttributes* install_attributes) : identity_strategy_(identity_strategy), + install_attributes_(install_attributes), signed_settings_helper_(chromeos::SignedSettingsHelper::Get()), starting_up_(true), ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)) { @@ -118,8 +121,10 @@ DevicePolicyCache::DevicePolicyCache( DevicePolicyCache::DevicePolicyCache( DevicePolicyIdentityStrategy* identity_strategy, + EnterpriseInstallAttributes* install_attributes, chromeos::SignedSettingsHelper* signed_settings_helper) : identity_strategy_(identity_strategy), + install_attributes_(install_attributes), signed_settings_helper_(signed_settings_helper), starting_up_(true), ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)) { @@ -135,6 +140,33 @@ void DevicePolicyCache::Load() { void DevicePolicyCache::SetPolicy(const em::PolicyFetchResponse& policy) { DCHECK(!starting_up_); + + // Make sure we have an enterprise device. + std::string registration_user(install_attributes_->GetRegistrationUser()); + if (registration_user.empty()) { + LOG(WARNING) << "Refusing to accept policy on non-enterprise device."; + InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, + CloudPolicySubsystem::POLICY_LOCAL_ERROR); + return; + } + + // Check the user this policy is for against the device-locked name. + em::PolicyData policy_data; + if (!policy_data.ParseFromString(policy.policy_data())) { + LOG(WARNING) << "Invalid policy protobuf"; + InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, + CloudPolicySubsystem::POLICY_LOCAL_ERROR); + return; + } + + if (registration_user != policy_data.username()) { + LOG(WARNING) << "Refusing policy blob for " << policy_data.username() + << " which doesn't match " << registration_user; + InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, + CloudPolicySubsystem::POLICY_LOCAL_ERROR); + return; + } + set_last_policy_refresh_time(base::Time::NowFromSystemTime()); // Start a store operation. diff --git a/chrome/browser/policy/device_policy_cache.h b/chrome/browser/policy/device_policy_cache.h index 3602839..ce29c97 100644 --- a/chrome/browser/policy/device_policy_cache.h +++ b/chrome/browser/policy/device_policy_cache.h @@ -17,6 +17,7 @@ namespace policy { class DevicePolicyIdentityStrategy; +class EnterpriseInstallAttributes; class PolicyMap; namespace em = enterprise_management; @@ -26,7 +27,8 @@ namespace em = enterprise_management; class DevicePolicyCache : public CloudPolicyCacheBase, public chromeos::SignedSettingsHelper::Callback { public: - explicit DevicePolicyCache(DevicePolicyIdentityStrategy* identity_strategy); + explicit DevicePolicyCache(DevicePolicyIdentityStrategy* identity_strategy, + EnterpriseInstallAttributes* install_attributes); virtual ~DevicePolicyCache(); // CloudPolicyCacheBase implementation: @@ -46,6 +48,7 @@ class DevicePolicyCache : public CloudPolicyCacheBase, // singleton. DevicePolicyCache( DevicePolicyIdentityStrategy* identity_strategy, + EnterpriseInstallAttributes* install_attributes, chromeos::SignedSettingsHelper* signed_settings_helper); // CloudPolicyCacheBase implementation: @@ -55,11 +58,16 @@ class DevicePolicyCache : public CloudPolicyCacheBase, void PolicyStoreOpCompleted(chromeos::SignedSettings::ReturnCode code); + // Checks with immutable attributes whether this is an enterprise device and + // read the registration user if this is the case. + void CheckImmutableAttributes(); + static void DecodeDevicePolicy(const em::ChromeDeviceSettingsProto& policy, PolicyMap* mandatory, PolicyMap* recommended); DevicePolicyIdentityStrategy* identity_strategy_; + EnterpriseInstallAttributes* install_attributes_; chromeos::SignedSettingsHelper* signed_settings_helper_; diff --git a/chrome/browser/policy/device_policy_cache_unittest.cc b/chrome/browser/policy/device_policy_cache_unittest.cc index 4228470..27b645c 100644 --- a/chrome/browser/policy/device_policy_cache_unittest.cc +++ b/chrome/browser/policy/device_policy_cache_unittest.cc @@ -4,7 +4,9 @@ #include "chrome/browser/policy/device_policy_cache.h" +#include "chrome/browser/chromeos/cros/cryptohome_library.h" #include "chrome/browser/policy/device_policy_identity_strategy.h" +#include "chrome/browser/policy/enterprise_install_attributes.h" #include "policy/configuration_policy_type.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -13,6 +15,9 @@ namespace policy { namespace { +// Test registration user name. +const char kTestUser[] = "test@example.com"; + using ::chromeos::SignedSettings; using ::chromeos::SignedSettingsHelper; using ::testing::_; @@ -52,33 +57,34 @@ ACTION_P2(MockSignedSettingsHelperRetrievePolicy, status_code, policy) { arg0->OnRetrievePolicyCompleted(status_code, policy); } -em::PolicyFetchResponse* CreateProxyPolicy(const std::string& proxy) { +void CreatePolicy(em::PolicyFetchResponse* policy, + const std::string& user, + int refresh_rate) { // This method omits a few fields which currently aren't needed by tests: - // timestamp, machine_name, request_token, policy_type, public key info. + // timestamp, machine_name, policy_type, public key info. em::PolicyData signed_response; em::ChromeDeviceSettingsProto settings; - em::DeviceProxySettingsProto* proxy_proto = - settings.mutable_device_proxy_settings(); - proxy_proto->set_proxy_server(proxy); - proxy_proto->set_proxy_mode("fixed_servers"); + settings.mutable_policy_refresh_rate()->set_policy_refresh_rate(refresh_rate); + signed_response.set_username(user); + signed_response.set_request_token("dmtoken"); + signed_response.set_device_id("deviceid"); EXPECT_TRUE( settings.SerializeToString(signed_response.mutable_policy_value())); std::string serialized_signed_response; EXPECT_TRUE(signed_response.SerializeToString(&serialized_signed_response)); - em::PolicyFetchResponse* response = new em::PolicyFetchResponse; - response->set_policy_data(serialized_signed_response); - return response; + policy->set_policy_data(serialized_signed_response); } } // namespace class DevicePolicyCacheTest : public testing::Test { protected: - DevicePolicyCacheTest() { - } + DevicePolicyCacheTest() + : install_attributes_(chromeos::CryptohomeLibrary::GetImpl(true)) {} virtual void SetUp() { cache_.reset(new DevicePolicyCache(&identity_strategy_, + &install_attributes_, &signed_settings_helper_)); } @@ -87,11 +93,17 @@ class DevicePolicyCacheTest : public testing::Test { cache_.reset(); } - const PolicyMap& mandatory_policy(const DevicePolicyCache& cache) { - return cache.mandatory_policy_; + void MakeEnterpriseDevice(const char* registration_user) { + ASSERT_EQ(EnterpriseInstallAttributes::LOCK_SUCCESS, + install_attributes_.LockDevice(registration_user)); + } + + const Value* GetMandatoryPolicy(ConfigurationPolicyType policy) { + return cache_->mandatory_policy_.Get(policy); } scoped_ptr<DevicePolicyCache> cache_; + EnterpriseInstallAttributes install_attributes_; DevicePolicyIdentityStrategy identity_strategy_; MockSignedSettingsHelper signed_settings_helper_; @@ -100,46 +112,98 @@ class DevicePolicyCacheTest : public testing::Test { }; TEST_F(DevicePolicyCacheTest, Startup) { - scoped_ptr<em::PolicyFetchResponse> policy_response( - CreateProxyPolicy("proxy.server")); + em::PolicyFetchResponse policy; + CreatePolicy(&policy, kTestUser, 120); EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)).WillOnce( MockSignedSettingsHelperRetrievePolicy(SignedSettings::SUCCESS, - *policy_response)); + policy)); cache_->Load(); - // TODO(jkummerow): This will be EXPECT_GT once policy decoding is - // implemented in DevicePolicyCache::DecodeDevicePolicy(...). - EXPECT_EQ(mandatory_policy(*cache_).size(), 0U); + testing::Mock::VerifyAndClearExpectations(&signed_settings_helper_); + FundamentalValue expected(120); + EXPECT_TRUE(Value::Equals(&expected, + GetMandatoryPolicy(kPolicyPolicyRefreshRate))); } TEST_F(DevicePolicyCacheTest, SetPolicy) { InSequence s; + + MakeEnterpriseDevice(kTestUser); + // Startup. - scoped_ptr<em::PolicyFetchResponse> policy_response( - CreateProxyPolicy("proxy.server.old")); + em::PolicyFetchResponse policy; + CreatePolicy(&policy, kTestUser, 120); EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)).WillOnce( MockSignedSettingsHelperRetrievePolicy(SignedSettings::SUCCESS, - *policy_response)); + policy)); cache_->Load(); - scoped_ptr<Value> expected(Value::CreateStringValue("proxy.server.old")); - // TODO(jkummerow): This will be EXPECT_TRUE once policy decoding is - // implemented in DevicePolicyCache::DecodeDevicePolicy(...). - EXPECT_FALSE(Value::Equals( - mandatory_policy(*cache_).Get(kPolicyProxyServer), expected.get())); testing::Mock::VerifyAndClearExpectations(&signed_settings_helper_); + FundamentalValue expected(120); + EXPECT_TRUE(Value::Equals(&expected, + GetMandatoryPolicy(kPolicyPolicyRefreshRate))); + // Set new policy information. - scoped_ptr<em::PolicyFetchResponse> new_policy_response( - CreateProxyPolicy("proxy.server.new")); + em::PolicyFetchResponse new_policy; + CreatePolicy(&new_policy, kTestUser, 300); EXPECT_CALL(signed_settings_helper_, StartStorePolicyOp(_, _)).WillOnce( MockSignedSettingsHelperStorePolicy(chromeos::SignedSettings::SUCCESS)); EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)).WillOnce( MockSignedSettingsHelperRetrievePolicy(SignedSettings::SUCCESS, - *new_policy_response)); - cache_->SetPolicy(*new_policy_response); - expected.reset(Value::CreateStringValue("proxy.server.new")); - // TODO(jkummerow): This will be EXPECT_TRUE once policy decoding is - // implemented in DevicePolicyCache::DecodeDevicePolicy(...). - EXPECT_FALSE(Value::Equals( - mandatory_policy(*cache_).Get(kPolicyProxyServer), expected.get())); + new_policy)); + cache_->SetPolicy(new_policy); + testing::Mock::VerifyAndClearExpectations(&signed_settings_helper_); + FundamentalValue updated_expected(300); + EXPECT_TRUE(Value::Equals(&updated_expected, + GetMandatoryPolicy(kPolicyPolicyRefreshRate))); +} + +TEST_F(DevicePolicyCacheTest, SetPolicyWrongUser) { + InSequence s; + + MakeEnterpriseDevice(kTestUser); + + // Startup. + em::PolicyFetchResponse policy; + CreatePolicy(&policy, kTestUser, 120); + EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)).WillOnce( + MockSignedSettingsHelperRetrievePolicy(SignedSettings::SUCCESS, + policy)); + cache_->Load(); + testing::Mock::VerifyAndClearExpectations(&signed_settings_helper_); + + // Set new policy information. This should fail due to invalid user. + em::PolicyFetchResponse new_policy; + CreatePolicy(&new_policy, "foreign_user@example.com", 300); + EXPECT_CALL(signed_settings_helper_, StartStorePolicyOp(_, _)).Times(0); + cache_->SetPolicy(new_policy); + testing::Mock::VerifyAndClearExpectations(&signed_settings_helper_); + + FundamentalValue expected(120); + EXPECT_TRUE(Value::Equals(&expected, + GetMandatoryPolicy(kPolicyPolicyRefreshRate))); +} + +TEST_F(DevicePolicyCacheTest, SetPolicyNonEnterpriseDevice) { + InSequence s; + + // Startup. + em::PolicyFetchResponse policy; + CreatePolicy(&policy, kTestUser, 120); + EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)).WillOnce( + MockSignedSettingsHelperRetrievePolicy(SignedSettings::SUCCESS, + policy)); + cache_->Load(); + testing::Mock::VerifyAndClearExpectations(&signed_settings_helper_); + + // Set new policy information. This should fail due to invalid user. + em::PolicyFetchResponse new_policy; + CreatePolicy(&new_policy, kTestUser, 120); + EXPECT_CALL(signed_settings_helper_, StartStorePolicyOp(_, _)).Times(0); + cache_->SetPolicy(new_policy); + testing::Mock::VerifyAndClearExpectations(&signed_settings_helper_); + + FundamentalValue expected(120); + EXPECT_TRUE(Value::Equals(&expected, + GetMandatoryPolicy(kPolicyPolicyRefreshRate))); } } // namespace policy diff --git a/chrome/browser/policy/enterprise_install_attributes.cc b/chrome/browser/policy/enterprise_install_attributes.cc new file mode 100644 index 0000000..0fec96f --- /dev/null +++ b/chrome/browser/policy/enterprise_install_attributes.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2011 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/enterprise_install_attributes.h" + +#include "base/logging.h" +#include "chrome/browser/chromeos/cros/cryptohome_library.h" + +static const char kAttrEnterpriseOwned[] = "enterprise.owned"; +static const char kAttrEnterpriseUser[] = "enterprise.user"; + +namespace policy { + +EnterpriseInstallAttributes::EnterpriseInstallAttributes( + chromeos::CryptohomeLibrary* cryptohome) + : cryptohome_(cryptohome), + device_locked_(false) {} + +EnterpriseInstallAttributes::LockResult EnterpriseInstallAttributes::LockDevice( + const std::string& user) { + // Check for existing lock first. + if (device_locked_) { + return !registration_user_.empty() && user == registration_user_ ? + LOCK_SUCCESS : LOCK_WRONG_USER; + } + + if (!cryptohome_->InstallAttributesIsReady()) + return LOCK_NOT_READY; + + // Clearing the TPM password seems to be always a good deal. + if (cryptohome_->TpmIsEnabled() && + !cryptohome_->TpmIsBeingOwned() && + cryptohome_->TpmIsOwned()) { + cryptohome_->TpmClearStoredPassword(); + } + + // Make sure we really have a working InstallAttrs. + if (cryptohome_->InstallAttributesIsInvalid()) { + LOG(ERROR) << "Install attributes invalid."; + return LOCK_BACKEND_ERROR; + } + + if (!cryptohome_->InstallAttributesIsFirstInstall()) + return LOCK_WRONG_USER; + + // Set values in the InstallAttrs and lock it. + if (!cryptohome_->InstallAttributesSet(kAttrEnterpriseOwned, "true") || + !cryptohome_->InstallAttributesSet(kAttrEnterpriseUser, user)) { + LOG(ERROR) << "Failed writing attributes"; + return LOCK_BACKEND_ERROR; + } + + if (!cryptohome_->InstallAttributesFinalize() || + cryptohome_->InstallAttributesIsFirstInstall() || + GetRegistrationUser() != user) { + LOG(ERROR) << "Failed locking."; + return LOCK_BACKEND_ERROR; + } + + return LOCK_SUCCESS; +} + +bool EnterpriseInstallAttributes::IsEnterpriseDevice() { + ReadImmutableAttributes(); + return device_locked_ && !registration_user_.empty(); +} + +std::string EnterpriseInstallAttributes::GetRegistrationUser() { + ReadImmutableAttributes(); + + if (!device_locked_) + return std::string(); + + return registration_user_; +} + +std::string EnterpriseInstallAttributes::GetDomain() { + if (!IsEnterpriseDevice()) + return std::string(); + + std::string domain; + size_t pos = registration_user_.find('@'); + if (pos != std::string::npos) + domain = registration_user_.substr(pos + 1); + + return domain; +} + +void EnterpriseInstallAttributes::ReadImmutableAttributes() { + if (device_locked_) + return; + + if (cryptohome_ && + cryptohome_->InstallAttributesIsReady() && + !cryptohome_->InstallAttributesIsInvalid() && + !cryptohome_->InstallAttributesIsFirstInstall()) { + device_locked_ = true; + std::string enterprise_owned; + std::string enterprise_user; + if (cryptohome_->InstallAttributesGet(kAttrEnterpriseOwned, + &enterprise_owned) && + cryptohome_->InstallAttributesGet(kAttrEnterpriseUser, + &enterprise_user) && + enterprise_owned == "true" && + !enterprise_user.empty()) { + registration_user_ = enterprise_user; + } + } +} + +} // namespace policy diff --git a/chrome/browser/policy/enterprise_install_attributes.h b/chrome/browser/policy/enterprise_install_attributes.h new file mode 100644 index 0000000..90d728a --- /dev/null +++ b/chrome/browser/policy/enterprise_install_attributes.h @@ -0,0 +1,65 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_POLICY_ENTERPRISE_INSTALL_ATTRIBUTES_H_ +#define CHROME_BROWSER_POLICY_ENTERPRISE_INSTALL_ATTRIBUTES_H_ +#pragma once + +#include <string> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" + +namespace chromeos { +class CryptohomeLibrary; +} + +namespace policy { + +// Brokers access to the enterprise-related installation-time attributes on +// ChromeOS. +class EnterpriseInstallAttributes { + public: + // Return codes for LockDevice(). + enum LockResult { + LOCK_SUCCESS, + LOCK_NOT_READY, + LOCK_BACKEND_ERROR, + LOCK_WRONG_USER, + }; + + explicit EnterpriseInstallAttributes(chromeos::CryptohomeLibrary* cryptohome); + + // Locks the device to be an enterprise device registered by the given user. + // This can also be called after the lock has already been taken, in which + // case it checks that the passed user agrees with the locked attribute. + LockResult LockDevice(const std::string& user) WARN_UNUSED_RESULT; + + // Checks whether this is an enterprise device. + bool IsEnterpriseDevice(); + + // Gets the domain this device belongs to or an empty string if the device is + // not an enterprise device. + std::string GetDomain(); + + // Gets the user that registered the device. Returns an empty string if the + // device is not an enterprise device. + std::string GetRegistrationUser(); + + private: + // Makes sure the local caches for enterprise-related install attributes are + // up-to-date with what cryptohome has. + void ReadImmutableAttributes(); + + chromeos::CryptohomeLibrary* cryptohome_; + + bool device_locked_; + std::string registration_user_; + + DISALLOW_COPY_AND_ASSIGN(EnterpriseInstallAttributes); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_ENTERPRISE_INSTALL_ATTRIBUTES_H_ diff --git a/chrome/browser/policy/enterprise_install_attributes_unittest.cc b/chrome/browser/policy/enterprise_install_attributes_unittest.cc new file mode 100644 index 0000000..9d69924 --- /dev/null +++ b/chrome/browser/policy/enterprise_install_attributes_unittest.cc @@ -0,0 +1,55 @@ +// Copyright (c) 2011 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/enterprise_install_attributes.h" + +#include "chrome/browser/chromeos/cros/cryptohome_library.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace policy { + +static const char kTestUser[] = "test@example.com"; + +class EnterpriseInstallAttributesTest : public testing::Test { + protected: + EnterpriseInstallAttributesTest() + : cryptohome_(chromeos::CryptohomeLibrary::GetImpl(true)), + install_attributes_(cryptohome_.get()) {} + + scoped_ptr<chromeos::CryptohomeLibrary> cryptohome_; + EnterpriseInstallAttributes install_attributes_; +}; + +TEST_F(EnterpriseInstallAttributesTest, Lock) { + EXPECT_EQ(EnterpriseInstallAttributes::LOCK_SUCCESS, + install_attributes_.LockDevice(kTestUser)); + + EXPECT_EQ(EnterpriseInstallAttributes::LOCK_SUCCESS, + install_attributes_.LockDevice(kTestUser)); + EXPECT_EQ(EnterpriseInstallAttributes::LOCK_WRONG_USER, + install_attributes_.LockDevice("test1@example.com")); +} + +TEST_F(EnterpriseInstallAttributesTest, IsEnterpriseDevice) { + EXPECT_FALSE(install_attributes_.IsEnterpriseDevice()); + ASSERT_EQ(EnterpriseInstallAttributes::LOCK_SUCCESS, + install_attributes_.LockDevice(kTestUser)); + EXPECT_TRUE(install_attributes_.IsEnterpriseDevice()); +} + +TEST_F(EnterpriseInstallAttributesTest, GetDomain) { + EXPECT_EQ(std::string(), install_attributes_.GetDomain()); + ASSERT_EQ(EnterpriseInstallAttributes::LOCK_SUCCESS, + install_attributes_.LockDevice(kTestUser)); + EXPECT_EQ("example.com", install_attributes_.GetDomain()); +} + +TEST_F(EnterpriseInstallAttributesTest, GetRegistrationUser) { + EXPECT_EQ(std::string(), install_attributes_.GetRegistrationUser()); + ASSERT_EQ(EnterpriseInstallAttributes::LOCK_SUCCESS, + install_attributes_.LockDevice(kTestUser)); + EXPECT_EQ(kTestUser, install_attributes_.GetRegistrationUser()); +} + +} // namespace policy diff --git a/chrome/browser/policy/proto/device_management_backend.proto b/chrome/browser/policy/proto/device_management_backend.proto index 9d3923f..71bbfc1 100644 --- a/chrome/browser/policy/proto/device_management_backend.proto +++ b/chrome/browser/policy/proto/device_management_backend.proto @@ -106,7 +106,7 @@ message PolicyFetchRequest { SHA1_RSA = 1; } optional SignatureType signature_type = 3 [default = NONE]; - + // The version number of the public key that is currently stored // on the client. This should be the last number the server had // supplied as new_public_key_version in PolicyData. @@ -148,16 +148,16 @@ message PolicyData { // |machine_name| in DeviceRegisterResponse but it might have // changed since then. optional string machine_name = 5; - + // Version number of the server's current public key. (The key that // was used to sign this response. Numbering should start at 1 and be // increased by 1 at each key rotation.) optional int32 public_key_version = 6; - + // The user this policy is intended for. In case of device policy, the name // of the owner (who registered the device). optional string username = 7; - + // In this field the DMServer should echo back the "deviceid" HTTP parameter // from the request. optional string device_id = 8; @@ -274,4 +274,4 @@ message DeviceManagementResponse { // Policy response. optional DevicePolicyResponse policy_response = 5; -}
\ No newline at end of file +} diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index fcfab61..b975335 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1554,6 +1554,8 @@ 'browser/policy/device_token_fetcher.h', 'browser/policy/dummy_configuration_policy_provider.cc', 'browser/policy/dummy_configuration_policy_provider.h', + 'browser/policy/enterprise_install_attributes.cc', + 'browser/policy/enterprise_install_attributes.h', 'browser/policy/file_based_policy_loader.cc', 'browser/policy/file_based_policy_loader.h', 'browser/policy/file_based_policy_provider.cc', @@ -3433,10 +3435,14 @@ ['exclude', 'browser/extensions/file_manager_util.cc'], ['exclude', 'browser/oom_priority_manager.cc'], ['exclude', 'browser/oom_priority_manager.h'], - ['exclude', 'browser/policy/device_policy_cache\\.(h|cc)'], + ['exclude', 'browser/policy/device_policy_cache.cc'], + ['exclude', 'browser/policy/device_policy_cache.h'], + ['exclude', 'browser/policy/enterprise_install_attributes.cc'], + ['exclude', 'browser/policy/enterprise_install_attributes.h'], ['exclude', 'browser/policy/device_policy_identity_strategy.cc'], ['exclude', 'browser/policy/device_policy_identity_strategy.h'], - ['exclude', 'browser/policy/proto/chrome_device_policy\\.pb\\.(h|cc)'], + ['exclude', 'browser/policy/proto/chrome_device_policy.pb.cc'], + ['exclude', 'browser/policy/proto/chrome_device_policy.pb.h'], ['exclude', 'browser/renderer_host/offline_resource_handler.cc'], ['exclude', 'browser/renderer_host/offline_resource_handler.h'], ['exclude', 'browser/ui/login/login_prompt_ui.cc'], diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 94767c6..3d30545 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1444,6 +1444,7 @@ 'browser/policy/configuration_policy_store_interface_unittest.cc', 'browser/policy/device_policy_cache_unittest.cc', 'browser/policy/device_token_fetcher_unittest.cc', + 'browser/policy/enterprise_install_attributes_unittest.cc', 'browser/policy/file_based_policy_provider_unittest.cc', 'browser/policy/device_management_backend_mock.cc', 'browser/policy/device_management_backend_mock.h', @@ -1939,6 +1940,7 @@ 'sources/': [ ['exclude', '^browser/chromeos/'], ['exclude', '^browser/policy/device_policy_cache_unittest.cc'], + ['exclude', '^browser/policy/enterprise_install_attributes_unittest.cc' ], ['exclude', '^browser/ui/webui/chromeos/login'], ], }], |