diff options
-rw-r--r-- | chrome/browser/chromeos/cros/login_library.cc | 30 | ||||
-rw-r--r-- | chrome/browser/chromeos/cros/login_library.h | 5 | ||||
-rw-r--r-- | chrome/browser/chromeos/cros_settings_names.cc | 5 | ||||
-rw-r--r-- | chrome/browser/chromeos/cros_settings_names.h | 4 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/mock_ownership_service.h | 5 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/ownership_service.cc | 14 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/ownership_service.h | 14 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/signed_settings.cc | 633 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/signed_settings.h | 35 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/signed_settings_helper_unittest.cc | 106 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/signed_settings_unittest.cc | 413 | ||||
-rw-r--r-- | chrome/browser/chromeos/proxy_config_service_impl.cc | 4 | ||||
-rw-r--r-- | chrome/browser/chromeos/user_cros_settings_provider.cc | 4 |
13 files changed, 979 insertions, 293 deletions
diff --git a/chrome/browser/chromeos/cros/login_library.cc b/chrome/browser/chromeos/cros/login_library.cc index 4d5d4e4..3a042f9 100644 --- a/chrome/browser/chromeos/cros/login_library.cc +++ b/chrome/browser/chromeos/cros/login_library.cc @@ -9,12 +9,15 @@ #include "base/timer.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/login/signed_settings.h" #include "chrome/browser/chromeos/login/signed_settings_temp_storage.h" +#include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "chrome/browser/prefs/pref_service.h" #include "content/browser/browser_thread.h" #include "content/common/notification_service.h" #include "content/common/notification_type.h" +namespace em = enterprise_management; namespace chromeos { class LoginLibraryImpl : public LoginLibrary { @@ -113,7 +116,9 @@ class LoginLibraryImpl : public LoginLibrary { return rv; } + // DEPRECATED. bool EnumerateWhitelisted(std::vector<std::string>* whitelisted) { + NOTREACHED(); UserList* list = NULL; if (chromeos::EnumerateWhitelistedSafe(&list)) { for (int i = 0; i < list->num_users; i++) @@ -193,6 +198,24 @@ class LoginLibraryImpl : public LoginLibrary { base::OneShotTimer<JobRestartRequest> timer_; }; + class StubDelegate + : public SignedSettings::Delegate<const em::PolicyFetchResponse&> { + public: + StubDelegate() : polfetcher_(NULL) {} + virtual ~StubDelegate() {} + void set_fetcher(SignedSettings* s) { polfetcher_ = s; } + SignedSettings* fetcher() { return polfetcher_.get(); } + // Implementation of SignedSettings::Delegate + virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code, + const em::PolicyFetchResponse& value) { + VLOG(2) << "Done Fetching Policy"; + delete this; + } + private: + scoped_refptr<SignedSettings> polfetcher_; + DISALLOW_COPY_AND_ASSIGN(StubDelegate); + }; + static void Handler(void* object, const OwnershipEvent& event) { LoginLibraryImpl* self = static_cast<LoginLibraryImpl*>(object); switch (event) { @@ -253,9 +276,10 @@ class LoginLibraryImpl : public LoginLibrary { } void CompletePropertyOp(bool result) { - if (property_op_callback_) { - property_op_callback_->OnComplete(result); - property_op_callback_ = NULL; + if (result) { + StubDelegate* stub = new StubDelegate(); // Manages its own lifetime. + stub->set_fetcher(SignedSettings::CreateRetrievePolicyOp(stub)); + stub->fetcher()->Execute(); } } diff --git a/chrome/browser/chromeos/cros/login_library.h b/chrome/browser/chromeos/cros/login_library.h index 55d1ce6..d61f6ac 100644 --- a/chrome/browser/chromeos/cros/login_library.h +++ b/chrome/browser/chromeos/cros/login_library.h @@ -77,6 +77,11 @@ class LoginLibrary { const std::vector<uint8>& signature, Delegate* callback) = 0; + // DEPRECATED. We have re-implemented owner-signed settings by fetching + // and caching a policy, and then pulling values from there. This is all + // handled at the SignedSettings layer, so anyone using this stuff directly + // should not be doing so anymore. + // // Retrieves the user white list. Note the call is for display purpose only. // To determine if an email is white listed, you MUST use CheckWhitelist. // Returns true if the request is successfully dispatched. diff --git a/chrome/browser/chromeos/cros_settings_names.cc b/chrome/browser/chromeos/cros_settings_names.cc index 46e5ee5..ea9aa69 100644 --- a/chrome/browser/chromeos/cros_settings_names.cc +++ b/chrome/browser/chromeos/cros_settings_names.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// 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. @@ -15,6 +15,9 @@ const char kAccountsPrefShowUserNamesOnSignIn[] = "cros.accounts.showUserNamesOnSignIn"; const char kAccountsPrefUsers[] = "cros.accounts.users"; +// Name of signed setting persisted on device, writeable only by owner. +const char kSettingProxyEverywhere[] = "cros.proxy.everywhere"; + // All cros.signed.* settings are stored in SignedSettings. const char kSignedDataRoamingEnabled[] = "cros.signed.data_roaming_enabled"; diff --git a/chrome/browser/chromeos/cros_settings_names.h b/chrome/browser/chromeos/cros_settings_names.h index 14b3889..75f4fa9 100644 --- a/chrome/browser/chromeos/cros_settings_names.h +++ b/chrome/browser/chromeos/cros_settings_names.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// 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. @@ -15,6 +15,8 @@ extern const char kAccountsPrefAllowNewUser[]; extern const char kAccountsPrefShowUserNamesOnSignIn[]; extern const char kAccountsPrefUsers[]; +extern const char kSettingProxyEverywhere[]; + extern const char kSignedDataRoamingEnabled[]; extern const char kSystemTimezone[]; diff --git a/chrome/browser/chromeos/login/mock_ownership_service.h b/chrome/browser/chromeos/login/mock_ownership_service.h index db88843..3c9aae0 100644 --- a/chrome/browser/chromeos/login/mock_ownership_service.h +++ b/chrome/browser/chromeos/login/mock_ownership_service.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// 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. @@ -15,6 +15,9 @@ namespace chromeos { class MockOwnershipService : public OwnershipService { public: + MOCK_METHOD1(set_cached_policy, void(const em::PolicyData&)); + MOCK_METHOD0(has_cached_policy, bool(void)); + MOCK_METHOD0(cached_policy, const em::PolicyData&(void)); MOCK_METHOD0(IsAlreadyOwned, bool(void)); MOCK_METHOD1(GetStatus, OwnershipService::Status(bool)); MOCK_METHOD0(StartLoadOwnerKeyAttempt, void(void)); diff --git a/chrome/browser/chromeos/login/ownership_service.cc b/chrome/browser/chromeos/login/ownership_service.cc index 85ad7a1..34643c9 100644 --- a/chrome/browser/chromeos/login/ownership_service.cc +++ b/chrome/browser/chromeos/login/ownership_service.cc @@ -28,6 +28,7 @@ OwnershipService* OwnershipService::GetSharedInstance() { OwnershipService::OwnershipService() : manager_(new OwnerManager), utils_(OwnerKeyUtils::Create()), + policy_(NULL), ownership_status_(OWNERSHIP_UNKNOWN) { notification_registrar_.Add( this, @@ -50,6 +51,19 @@ OwnershipService::OwnershipService() OwnershipService::~OwnershipService() {} +void OwnershipService::set_cached_policy(const em::PolicyData& pol) { + policy_.reset(pol.New()); + policy_->CheckTypeAndMergeFrom(pol); +} + +bool OwnershipService::has_cached_policy() { + return policy_.get(); +} + +const em::PolicyData& OwnershipService::cached_policy() { + return *(policy_.get()); +} + bool OwnershipService::IsAlreadyOwned() { return file_util::PathExists(utils_->GetOwnerKeyFilePath()); } diff --git a/chrome/browser/chromeos/login/ownership_service.h b/chrome/browser/chromeos/login/ownership_service.h index 3ec68d7..c82cbcd 100644 --- a/chrome/browser/chromeos/login/ownership_service.h +++ b/chrome/browser/chromeos/login/ownership_service.h @@ -13,6 +13,7 @@ #include "base/synchronization/lock.h" #include "chrome/browser/chromeos/login/owner_key_utils.h" #include "chrome/browser/chromeos/login/owner_manager.h" +#include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "content/browser/browser_thread.h" #include "content/common/notification_observer.h" #include "content/common/notification_registrar.h" @@ -22,6 +23,7 @@ namespace base { template <typename T> struct DefaultLazyInstanceTraits; } +namespace em = enterprise_management; namespace chromeos { class OwnershipService : public NotificationObserver { @@ -37,6 +39,17 @@ class OwnershipService : public NotificationObserver { static OwnershipService* GetSharedInstance(); virtual ~OwnershipService(); + // Owner settings are being re-implemented as a single, signed protobuf + // that is stored by the session manager. Thus, to write a setting, you + // need to have the existing policy, update it, re-sign it, and then have + // it stored. This could be done by requesting the policy every time, or + // by caching it and updating it upon every successful store. + // Caching is faster and easier, so we'll do that. These are the + // getters/setters for the cached policy. + virtual void set_cached_policy(const em::PolicyData& pol); + virtual bool has_cached_policy(); + virtual const em::PolicyData& cached_policy(); + // Sets a new owner key. This will _not_ load the key material from disk, but // rather update Chrome's in-memory copy of the key. |callback| will be // invoked once the operation completes. @@ -120,6 +133,7 @@ class OwnershipService : public NotificationObserver { scoped_refptr<OwnerManager> manager_; scoped_refptr<OwnerKeyUtils> utils_; + scoped_ptr<em::PolicyData> policy_; NotificationRegistrar notification_registrar_; Status ownership_status_; base::Lock ownership_status_lock_; diff --git a/chrome/browser/chromeos/login/signed_settings.cc b/chrome/browser/chromeos/login/signed_settings.cc index 6e90a93..93d22b4 100644 --- a/chrome/browser/chromeos/login/signed_settings.cc +++ b/chrome/browser/chromeos/login/signed_settings.cc @@ -13,30 +13,90 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/cros/login_library.h" +#include "chrome/browser/chromeos/cros_settings_names.h" #include "chrome/browser/chromeos/login/authenticator.h" #include "chrome/browser/chromeos/login/ownership_service.h" #include "chrome/browser/chromeos/login/signed_settings_temp_storage.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" +#include "chrome/browser/policy/proto/chrome_device_policy.pb.h" #include "content/browser/browser_thread.h" namespace chromeos { +using google::protobuf::RepeatedPtrField; +using std::string; + +// static +const char SignedSettings::kDevicePolicyType[] = "google/chromeos/device"; + +SignedSettings::Relay::Relay(SignedSettings* s) : settings_(s) { +} + +SignedSettings::Relay::~Relay() {} + +void SignedSettings::Relay::OnSettingsOpCompleted( + SignedSettings::ReturnCode code, + const em::PolicyFetchResponse& value) { + if (code == SignedSettings::SUCCESS) { + settings_->Execute(); + return; + } + settings_->Fail(code); +} SignedSettings::SignedSettings() - : service_(OwnershipService::GetSharedInstance()) { + : service_(OwnershipService::GetSharedInstance()), + relay_(NULL), + polfetcher_(NULL) { } SignedSettings::~SignedSettings() {} +void SignedSettings::TryToFetchPolicyAndCallBack() { + relay_.reset(new Relay(this)); + polfetcher_ = SignedSettings::CreateRetrievePolicyOp(relay_.get()); + polfetcher_->set_service(service_); + polfetcher_->Execute(); +} + +// static +bool SignedSettings::PolicyIsSane(const em::PolicyFetchResponse& value, + em::PolicyData* poldata) { + if (value.has_policy_data()) { + poldata->ParseFromString(value.policy_data()); + if (poldata->has_policy_type() && + poldata->policy_type() == kDevicePolicyType && + poldata->has_policy_value()) { + return true; + } + } + return false; +} + +// static SignedSettings::ReturnCode SignedSettings::MapKeyOpCode( OwnerManager::KeyOpCode return_code) { return (return_code == OwnerManager::KEY_UNAVAILABLE ? KEY_UNAVAILABLE : BAD_SIGNATURE); } -void SignedSettings::OnBoolComplete(void* delegate, bool success) { - SignedSettings::Delegate<bool>* d = - static_cast< SignedSettings::Delegate<bool>* >(delegate); - d->OnSettingsOpCompleted(success ? SUCCESS : NOT_FOUND, success); +// static +bool SignedSettings::EnumerateWhitelist(std::vector<std::string>* whitelisted) { + OwnershipService* service = OwnershipService::GetSharedInstance(); + if (!service->has_cached_policy()) + return false; + em::ChromeDeviceSettingsProto pol; + pol.ParseFromString(service->cached_policy().policy_value()); + if (!pol.has_user_whitelist()) + return false; + + const RepeatedPtrField<std::string>& whitelist = + pol.user_whitelist().user_whitelist(); + for (RepeatedPtrField<std::string>::const_iterator it = whitelist.begin(); + it != whitelist.end(); + ++it) { + whitelisted->push_back(*it); + } + return true; } class CheckWhitelistOp : public SignedSettings { @@ -45,55 +105,88 @@ class CheckWhitelistOp : public SignedSettings { SignedSettings::Delegate<bool>* d); virtual ~CheckWhitelistOp(); void Execute(); - // Implementation of OwnerManager::Delegate::OnKeyOpComplete() + void Fail(SignedSettings::ReturnCode code); + void Succeed(bool value); + // Implementation of OwnerManager::Delegate void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload); private: + bool LookUpInPolicy(const std::string& email); + // Always call d_->OnSettingOpCompleted() via this call. + // It guarantees that the callback will not be triggered until _after_ + // Execute() returns, which is implicitly assumed by SignedSettingsHelper + // in some cases. + void PerformCallback(SignedSettings::ReturnCode code, bool value); + const std::string email_; SignedSettings::Delegate<bool>* d_; }; class WhitelistOp : public SignedSettings, - public LoginLibrary::Delegate { + public SignedSettings::Delegate<bool> { public: WhitelistOp(const std::string& email, bool add_to_whitelist, SignedSettings::Delegate<bool>* d); virtual ~WhitelistOp(); void Execute(); - // Implementation of OwnerManager::Delegate::OnKeyOpComplete() + void Fail(SignedSettings::ReturnCode code); + void Succeed(bool value); + // Implementation of OwnerManager::Delegate void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload); - // Implementation of LoginLibrary::Delegate::OnComplete() - void OnComplete(bool value); + // Implementation of SignedSettings::Delegate + void OnSettingsOpCompleted(ReturnCode code, bool value); private: - bool InitiateWhitelistOp(const std::vector<uint8>& signature); + void ModifyWhitelist(const std::string& email, + bool add_to_whitelist, + em::UserWhitelistProto* whitelist_proto); + // Always call d_->OnSettingOpCompleted() via this call. + // It guarantees that the callback will not be triggered until _after_ + // Execute() returns, which is implicitly assumed by SignedSettingsHelper + // in some cases. + void PerformCallback(SignedSettings::ReturnCode code, bool value); const std::string email_; const bool add_to_whitelist_; SignedSettings::Delegate<bool>* d_; + em::PolicyFetchResponse to_store_; + scoped_refptr<SignedSettings> store_op_; }; class StorePropertyOp : public SignedSettings, - public LoginLibrary::Delegate { + public SignedSettings::Delegate<bool> { public: StorePropertyOp(const std::string& name, const std::string& value, SignedSettings::Delegate<bool>* d); virtual ~StorePropertyOp(); void Execute(); - // Implementation of OwnerManager::Delegate::OnKeyOpComplete() + void Fail(SignedSettings::ReturnCode code); + void Succeed(bool value); + // Implementation of OwnerManager::Delegate void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload); - // Implementation of LoginLibrary::Delegate::OnComplete() - void OnComplete(bool value); + // Implementation of SignedSettings::Delegate + void OnSettingsOpCompleted(ReturnCode code, bool value); private: + void SetInPolicy(const std::string& prop, + const std::string& value, + em::PolicyData* poldata); + // Always call d_->OnSettingOpCompleted() via this call. + // It guarantees that the callback will not be triggered until _after_ + // Execute() returns, which is implicitly assumed by SignedSettingsHelper + // in some cases. + void PerformCallback(SignedSettings::ReturnCode code, bool value); + std::string name_; std::string value_; SignedSettings::Delegate<bool>* d_; + em::PolicyFetchResponse to_store_; + scoped_refptr<SignedSettings> store_op_; }; class RetrievePropertyOp : public SignedSettings { @@ -102,15 +195,22 @@ class RetrievePropertyOp : public SignedSettings { SignedSettings::Delegate<std::string>* d); virtual ~RetrievePropertyOp(); void Execute(); + void Fail(SignedSettings::ReturnCode code); + void Succeed(const std::string& value); // Implementation of OwnerManager::Delegate::OnKeyOpComplete() void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload); private: - // RetrievePropertyCallback - static void OnRetrievePropertyNotify(void* user_data, - bool success, - const Property* property); + static const char* kVeritas[]; + + std::string LookUpInPolicy(const std::string& prop); + // Always call d_->OnSettingOpCompleted() via this call. + // It guarantees that the callback will not be triggered until _after_ + // Execute() returns, which is implicitly assumed by SignedSettingsHelper + // in some cases. + void PerformCallback(SignedSettings::ReturnCode code, + const std::string& value); std::string name_; std::string value_; @@ -123,11 +223,20 @@ class StorePolicyOp : public SignedSettings { SignedSettings::Delegate<bool>* d); virtual ~StorePolicyOp(); void Execute(); - // Implementation of OwnerManager::Delegate::OnKeyOpComplete() + void Fail(SignedSettings::ReturnCode code); + void Succeed(bool value); + // Implementation of OwnerManager::Delegate void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload); private: + static void OnBoolComplete(void* delegate, bool success); + // Always call d_->OnSettingOpCompleted() via this call. + // It guarantees that the callback will not be triggered until _after_ + // Execute() returns, which is implicitly assumed by SignedSettingsHelper + // in some cases. + void PerformCallback(SignedSettings::ReturnCode code, bool value); + em::PolicyFetchResponse* policy_; SignedSettings::Delegate<bool>* d_; @@ -140,7 +249,9 @@ class RetrievePolicyOp : public SignedSettings { SignedSettings::Delegate<const em::PolicyFetchResponse&>* d); virtual ~RetrievePolicyOp(); void Execute(); - // Implementation of OwnerManager::Delegate::OnKeyOpComplete() + void Fail(SignedSettings::ReturnCode code); + void Succeed(const em::PolicyFetchResponse& value); + // Implementation of OwnerManager::Delegate void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload); @@ -148,11 +259,17 @@ class RetrievePolicyOp : public SignedSettings { static void OnStringComplete(void* delegate, const char* policy, const unsigned int len); + // Always call d_->OnSettingOpCompleted() via this call. + // It guarantees that the callback will not be triggered until _after_ + // Execute() returns, which is implicitly assumed by SignedSettingsHelper + // in some cases. + void PerformCallback(SignedSettings::ReturnCode code, + const em::PolicyFetchResponse& value); + + void ProcessPolicy(const char* out, const unsigned int len); em::PolicyFetchResponse policy_; SignedSettings::Delegate<const em::PolicyFetchResponse&>* d_; - - void ProcessPolicy(const char* out, const unsigned int len); }; // static @@ -219,31 +336,48 @@ void CheckWhitelistOp::Execute() { CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded()); std::vector<uint8> sig; std::string email_to_check = email_; - if (!CrosLibrary::Get()->GetLoginLibrary()->CheckWhitelist( - email_to_check, &sig)) { - // If the exact match was not found try to match agains a wildcard entry - // where the domain only matches (e.g. *@example.com). In theory we should - // always have correctly formated mail address here but a little precaution - // does no harm. - if (email_.find('@') != std::string::npos) { - email_to_check = std::string("*").append(email_.substr(email_.find('@'))); - if (!CrosLibrary::Get()->GetLoginLibrary()->CheckWhitelist( - email_to_check, &sig)) { - d_->OnSettingsOpCompleted(NOT_FOUND, false); - return; - } - } else { - d_->OnSettingsOpCompleted(NOT_FOUND, false); + if (!service_->has_cached_policy()) { + TryToFetchPolicyAndCallBack(); + return; + } + if (LookUpInPolicy(email_to_check)) { + VLOG(2) << "Whitelist check was successful for " << email_to_check; + Succeed(true); + return; + } + // If the exact match was not found try to match against a wildcard entry + // where the domain only matches (e.g. *@example.com). In theory we should + // always have correctly formated mail address here but a little precaution + // does no harm. + if (email_.find('@') != std::string::npos) { + email_to_check = std::string("*").append(email_.substr(email_.find('@'))); + if (LookUpInPolicy(email_to_check)) { + VLOG(2) << "Whitelist check was successful for " << email_to_check; + Succeed(true); return; } } - // Posts a task to the FILE thread to verify |sig|. - service_->StartVerifyAttempt(email_to_check, sig, this); + Fail(NOT_FOUND); + return; +} + +void CheckWhitelistOp::Fail(SignedSettings::ReturnCode code) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, &CheckWhitelistOp::PerformCallback, code, false)); +} + +void CheckWhitelistOp::Succeed(bool value) { + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, + &CheckWhitelistOp::PerformCallback, + SUCCESS, value)); } void CheckWhitelistOp::OnKeyOpComplete( const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload) { + NOTREACHED(); // Ensure we're on the UI thread, due to the need to send DBus traffic. if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { BrowserThread::PostTask( @@ -255,11 +389,33 @@ void CheckWhitelistOp::OnKeyOpComplete( } if (return_code == OwnerManager::SUCCESS) { VLOG(2) << "Whitelist check was successful."; - d_->OnSettingsOpCompleted(SUCCESS, true); + Succeed(true); } else { VLOG(2) << "Whitelist check failed."; - d_->OnSettingsOpCompleted(SignedSettings::MapKeyOpCode(return_code), false); + Fail(SignedSettings::MapKeyOpCode(return_code)); + } +} + +bool CheckWhitelistOp::LookUpInPolicy(const std::string& email) { + em::ChromeDeviceSettingsProto pol; + pol.ParseFromString(service_->cached_policy().policy_value()); + if (!pol.has_user_whitelist()) + return false; + + const RepeatedPtrField<std::string>& whitelist = + pol.user_whitelist().user_whitelist(); + for (RepeatedPtrField<std::string>::const_iterator it = whitelist.begin(); + it != whitelist.end(); + ++it) { + if (email == *it) + return true; } + return false; +} + +void CheckWhitelistOp::PerformCallback(SignedSettings::ReturnCode code, + bool value) { + d_->OnSettingsOpCompleted(code, value); } WhitelistOp::WhitelistOp(const std::string& email, @@ -273,43 +429,98 @@ WhitelistOp::WhitelistOp(const std::string& email, WhitelistOp::~WhitelistOp() {} void WhitelistOp::Execute() { - // Posts a task to the FILE thread to sign |email_|. - service_->StartSigningAttempt(email_, this); + if (!service_->has_cached_policy()) { + TryToFetchPolicyAndCallBack(); + return; + } + em::PolicyData to_sign; + to_sign.CheckTypeAndMergeFrom(service_->cached_policy()); + em::ChromeDeviceSettingsProto pol; + pol.ParseFromString(to_sign.policy_value()); + em::UserWhitelistProto* whitelist_proto = pol.mutable_user_whitelist(); + ModifyWhitelist(email_, add_to_whitelist_, whitelist_proto); + to_sign.set_policy_value(pol.SerializeAsString()); + to_store_.set_policy_data(to_sign.SerializeAsString()); + service_->StartSigningAttempt(to_store_.policy_data(), this); +} + +void WhitelistOp::Fail(SignedSettings::ReturnCode code) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, &WhitelistOp::PerformCallback, code, false)); +} + +void WhitelistOp::Succeed(bool value) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, &WhitelistOp::PerformCallback, SUCCESS, value)); } void WhitelistOp::OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, - const std::vector<uint8>& payload) { + const std::vector<uint8>& sig) { // Ensure we're on the UI thread, due to the need to send DBus traffic. if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &WhitelistOp::OnKeyOpComplete, - return_code, payload)); + return_code, sig)); return; } + VLOG(2) << "WhitelistOp::OnKeyOpComplete return_code = " << return_code; // Now, sure we're on the UI thread. if (return_code == OwnerManager::SUCCESS) { - // OnComplete() will be called by this call, if it succeeds. - if (!InitiateWhitelistOp(payload)) - d_->OnSettingsOpCompleted(OPERATION_FAILED, false); + to_store_.set_policy_data_signature( + std::string(reinterpret_cast<const char*>(&sig[0]), sig.size())); + store_op_ = CreateStorePolicyOp(&to_store_, this); + // d_->OnSettingsOpCompleted() will be called by this call. + store_op_->Execute(); } else { - d_->OnSettingsOpCompleted(SignedSettings::MapKeyOpCode(return_code), false); + Fail(SignedSettings::MapKeyOpCode(return_code)); } } -void WhitelistOp::OnComplete(bool value) { - if (value) - d_->OnSettingsOpCompleted(SUCCESS, value); - else - d_->OnSettingsOpCompleted(NOT_FOUND, false); +void WhitelistOp::OnSettingsOpCompleted(ReturnCode code, bool value) { + if (value && to_store_.has_policy_data()) { + em::PolicyData poldata; + poldata.ParseFromString(to_store_.policy_data()); + service_->set_cached_policy(poldata); + Succeed(value); + return; + } + Fail(NOT_FOUND); +} + +void WhitelistOp::ModifyWhitelist(const std::string& email, + bool add_to_whitelist, + em::UserWhitelistProto* whitelist_proto) { + int i = 0; + const RepeatedPtrField<string>& whitelist = whitelist_proto->user_whitelist(); + for (RepeatedPtrField<string>::const_iterator it = whitelist.begin(); + it != whitelist.end(); + ++it, ++i) { + if (email == *it) + break; + } + // |i| contains the index of |email|, if it is in |whitelist|. + if (add_to_whitelist) { + if (i >= whitelist.size()) // |email| was not in |whitelist|, we must add. + whitelist_proto->add_user_whitelist(email); + return; + } else { + if (i < whitelist.size()) { // |email| was in |whitelist|, we must remove. + RepeatedPtrField<string>* change_list = + whitelist_proto->mutable_user_whitelist(); + change_list->SwapElements(i, whitelist.size() - 1); // Move to end. + change_list->RemoveLast(); + } + return; + } + LOG(WARNING) << "Whitelist modification no-op: " << email; } -bool WhitelistOp::InitiateWhitelistOp(const std::vector<uint8>& signature) { - LoginLibrary* library = CrosLibrary::Get()->GetLoginLibrary(); - if (add_to_whitelist_) - return library->WhitelistAsync(email_, signature, this); - return library->UnwhitelistAsync(email_, signature, this); +void WhitelistOp::PerformCallback(SignedSettings::ReturnCode code, bool value) { + d_->OnSettingsOpCompleted(code, value); } StorePropertyOp::StorePropertyOp(const std::string& name, @@ -317,7 +528,8 @@ StorePropertyOp::StorePropertyOp(const std::string& name, SignedSettings::Delegate<bool>* d) : name_(name), value_(value), - d_(d) { + d_(d), + store_op_(NULL) { } StorePropertyOp::~StorePropertyOp() {} @@ -328,50 +540,111 @@ void StorePropertyOp::Execute() { g_browser_process->local_state() && SignedSettingsTempStorage::Store(name_, value_, g_browser_process->local_state())) { - d_->OnSettingsOpCompleted(SUCCESS, true); + Succeed(true); return; } } - // Posts a task to the FILE thread to sign |name_|=|value_|. - std::string to_sign = base::StringPrintf("%s=%s", - name_.c_str(), - value_.c_str()); - service_->StartSigningAttempt(to_sign, this); + if (!service_->has_cached_policy()) { + TryToFetchPolicyAndCallBack(); + return; + } + // Posts a task to the FILE thread to sign policy. + em::PolicyData to_sign; + to_sign.CheckTypeAndMergeFrom(service_->cached_policy()); + SetInPolicy(name_, value_, &to_sign); + to_store_.set_policy_data(to_sign.SerializeAsString()); + service_->StartSigningAttempt(to_store_.policy_data(), this); +} + +void StorePropertyOp::Fail(SignedSettings::ReturnCode code) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, &StorePropertyOp::PerformCallback, code, false)); +} + +void StorePropertyOp::Succeed(bool value) { + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, + &StorePropertyOp::PerformCallback, + SUCCESS, value)); } void StorePropertyOp::OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, - const std::vector<uint8>& payload) { + const std::vector<uint8>& sig) { // Ensure we're on the UI thread, due to the need to send DBus traffic. if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &StorePropertyOp::OnKeyOpComplete, - return_code, payload)); + return_code, sig)); return; } VLOG(2) << "StorePropertyOp::OnKeyOpComplete return_code = " << return_code; // Now, sure we're on the UI thread. if (return_code == OwnerManager::SUCCESS) { - // OnComplete() will be called by this call, if it succeeds. - if (!CrosLibrary::Get()->GetLoginLibrary()->StorePropertyAsync(name_, - value_, - payload, - this)) { - d_->OnSettingsOpCompleted(OPERATION_FAILED, false); - } + to_store_.set_policy_data_signature( + std::string(reinterpret_cast<const char*>(&sig[0]), sig.size())); + store_op_ = CreateStorePolicyOp(&to_store_, this); + // d_->OnSettingsOpCompleted() will be called by this call. + store_op_->Execute(); } else { - d_->OnSettingsOpCompleted(SignedSettings::MapKeyOpCode(return_code), false); + Fail(SignedSettings::MapKeyOpCode(return_code)); } } -void StorePropertyOp::OnComplete(bool value) { - if (value) - d_->OnSettingsOpCompleted(SUCCESS, value); - else - d_->OnSettingsOpCompleted(NOT_FOUND, false); +void StorePropertyOp::OnSettingsOpCompleted(ReturnCode code, bool value) { + if (value && to_store_.has_policy_data()) { + em::PolicyData poldata; + poldata.ParseFromString(to_store_.policy_data()); + service_->set_cached_policy(poldata); + Succeed(value); + return; + } + Fail(NOT_FOUND); +} + +void StorePropertyOp::SetInPolicy(const std::string& prop, + const std::string& value, + em::PolicyData* poldata) { + em::ChromeDeviceSettingsProto pol; + pol.ParseFromString(poldata->policy_value()); + if (prop == kAccountsPrefAllowNewUser) { + em::AllowNewUsersProto* allow = pol.mutable_allow_new_users(); + allow->set_allow_new_users(value == "true"); + + } else if (prop == kAccountsPrefAllowGuest) { + em::GuestModeEnabledProto* guest = pol.mutable_guest_mode_enabled(); + guest->set_guest_mode_enabled(value == "true"); + + } else if (prop == kAccountsPrefShowUserNamesOnSignIn) { + em::ShowUserNamesOnSigninProto* show = pol.mutable_show_user_names(); + show->set_show_user_names(value == "true"); + + } else if (prop == kSignedDataRoamingEnabled) { + em::DataRoamingEnabledProto* roam = pol.mutable_data_roaming_enabled(); + roam->set_data_roaming_enabled(value == "true"); + + } else if (prop == kSettingProxyEverywhere) { + // TODO(cmasone): NOTIMPLEMENTED() once http://crosbug.com/13052 is fixed. + // TODO(cmasone): Until then, we will have to parse serialized JSON + // representing proxy settings, as generated by + // ProxyConfigServiceImpl::Serialize(). The code needs to translate into a + // DeviceProxySettingsProto (defined in chrome_device_policy.proto). + } else { + NOTREACHED(); + } + poldata->set_policy_value(pol.SerializeAsString()); +} + +void StorePropertyOp::PerformCallback(SignedSettings::ReturnCode code, + bool value) { + d_->OnSettingsOpCompleted(code, value); } +// static +const char* RetrievePropertyOp::kVeritas[] = { "false", "true" }; + RetrievePropertyOp::RetrievePropertyOp(const std::string& name, SignedSettings::Delegate<std::string>* d) : name_(name), @@ -392,58 +665,93 @@ void RetrievePropertyOp::Execute() { g_browser_process->local_state() && SignedSettingsTempStorage::Retrieve( name_, &value_, g_browser_process->local_state())) { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod(this, - &RetrievePropertyOp::OnKeyOpComplete, - OwnerManager::SUCCESS, std::vector<uint8>())); + Succeed(value_); return; } } - CrosLibrary::Get()->GetLoginLibrary()->RequestRetrieveProperty(name_, - &RetrievePropertyOp::OnRetrievePropertyNotify, this); -} - -// static -void RetrievePropertyOp::OnRetrievePropertyNotify(void* user_data, - bool success, const Property* property) { - RetrievePropertyOp* self = static_cast<RetrievePropertyOp*>(user_data); - if (!success) { - self->d_->OnSettingsOpCompleted(NOT_FOUND, std::string()); + if (!service_->has_cached_policy()) { + TryToFetchPolicyAndCallBack(); return; } + std::string value = LookUpInPolicy(name_); + if (value.empty()) + Fail(NOT_FOUND); + else + Succeed(value); +} - self->value_ = property->value; - - std::vector<uint8> sig; - sig.assign(property->signature->data, - property->signature->data + property->signature->length); +void RetrievePropertyOp::Fail(SignedSettings::ReturnCode code) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, + &RetrievePropertyOp::PerformCallback, + code, std::string())); +} - std::string to_verify = base::StringPrintf("%s=%s", - self->name_.c_str(), - self->value_.c_str()); - // Posts a task to the FILE thread to verify |sig|. - self->service_->StartVerifyAttempt(to_verify, sig, self); +void RetrievePropertyOp::Succeed(const std::string& value) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, + &RetrievePropertyOp::PerformCallback, SUCCESS, value)); } +// DEPRECATED. void RetrievePropertyOp::OnKeyOpComplete( const OwnerManager::KeyOpCode return_code, - const std::vector<uint8>& payload) { - if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod(this, - &RetrievePropertyOp::OnKeyOpComplete, - return_code, payload)); - return; + const std::vector<uint8>& sig) { + NOTREACHED(); +} + +std::string RetrievePropertyOp::LookUpInPolicy(const std::string& prop) { + em::ChromeDeviceSettingsProto pol; + pol.ParseFromString(service_->cached_policy().policy_value()); + if (prop == kAccountsPrefAllowNewUser) { + if (pol.has_allow_new_users() && + pol.allow_new_users().has_allow_new_users() && + pol.allow_new_users().allow_new_users()) { + return kVeritas[1]; // New users allowed, user_whitelist() ignored. + } + // If we have the allow_new_users bool, and it is true, we honor that above. + // In all other cases (don't have it, have it and it is set to false, etc), + // We will honor the user_whitelist() if it is there and populated. + // Otherwise, fail open (to do otherwise could render the device unusable). + if (!pol.has_user_whitelist()) + return kVeritas[1]; // Default to allowing new users. + return kVeritas[pol.user_whitelist().user_whitelist_size() == 0]; + + } else if (prop == kAccountsPrefAllowGuest) { + if (!pol.has_guest_mode_enabled() || + !pol.guest_mode_enabled().has_guest_mode_enabled()) + return kVeritas[1]; // Default to allowing guests; + return kVeritas[pol.guest_mode_enabled().guest_mode_enabled()]; + + } else if (prop == kAccountsPrefShowUserNamesOnSignIn) { + if (!pol.has_show_user_names() || + !pol.show_user_names().has_show_user_names()) + return kVeritas[1]; // Default to showing pods on the login screen; + return kVeritas[pol.show_user_names().show_user_names()]; + + } else if (prop == kSignedDataRoamingEnabled) { + if (!pol.has_data_roaming_enabled() || + !pol.data_roaming_enabled().has_data_roaming_enabled()) + return kVeritas[0]; // Default to disabling cellular data roaming; + return kVeritas[pol.data_roaming_enabled().data_roaming_enabled()]; + + } else if (prop == kSettingProxyEverywhere) { + // TODO(cmasone): NOTIMPLEMENTED() once http://crosbug.com/13052 is fixed. + // TODO(cmasone): Until then, we will have to return serialized JSON + // representing proxy settings, to be consumed by + // ProxyConfigServiceImpl::Deserialize(). We need code to translate a + // DeviceProxySettingsProto (defined in chrome_device_policy.proto) into + // a serialzed JSON string of this form. } - // Now, sure we're on the UI thread. - if (return_code == OwnerManager::SUCCESS) - d_->OnSettingsOpCompleted(SUCCESS, value_); - else - d_->OnSettingsOpCompleted(SignedSettings::MapKeyOpCode(return_code), - std::string()); + return std::string(); +} + +void RetrievePropertyOp::PerformCallback(SignedSettings::ReturnCode code, + const std::string& value) { + d_->OnSettingsOpCompleted(code, value); } StorePolicyOp::StorePolicyOp(em::PolicyFetchResponse* policy, @@ -454,16 +762,46 @@ StorePolicyOp::StorePolicyOp(em::PolicyFetchResponse* policy, StorePolicyOp::~StorePolicyOp() {} +// static +void StorePolicyOp::OnBoolComplete(void* delegate, bool success) { + StorePolicyOp* op = static_cast<StorePolicyOp*>(delegate); + if (success) + op->Succeed(true); + else + op->Fail(NOT_FOUND); +} + void StorePolicyOp::Execute() { // get protobuf contents to sign if (!policy_->has_policy_data()) - d_->OnSettingsOpCompleted(OPERATION_FAILED, false); + Fail(OPERATION_FAILED); if (!policy_->has_policy_data_signature()) service_->StartSigningAttempt(policy_->policy_data(), this); else RequestStorePolicy(); } +void StorePolicyOp::Fail(SignedSettings::ReturnCode code) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, &StorePolicyOp::PerformCallback, code, false)); +} + +void StorePolicyOp::Succeed(bool ignored) { + SignedSettings::ReturnCode code = SUCCESS; + bool to_ret = true; + em::PolicyData poldata; + if (SignedSettings::PolicyIsSane(*policy_, &poldata)) { + service_->set_cached_policy(poldata); + } else { + code = NOT_FOUND; + to_ret = false; + } + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, &StorePolicyOp::PerformCallback, code, to_ret)); +} + void StorePolicyOp::OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload) { // Ensure we're on the UI thread, due to the need to send DBus traffic. @@ -483,7 +821,7 @@ void StorePolicyOp::OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, RequestStorePolicy(); return; } - d_->OnSettingsOpCompleted(SignedSettings::MapKeyOpCode(return_code), false); + Fail(SignedSettings::MapKeyOpCode(return_code)); } void StorePolicyOp::RequestStorePolicy() { @@ -491,13 +829,18 @@ void StorePolicyOp::RequestStorePolicy() { if (policy_->SerializeToString(&serialized)) { CrosLibrary::Get()->GetLoginLibrary()->RequestStorePolicy( serialized, - &SignedSettings::OnBoolComplete, - d_); + &StorePolicyOp::OnBoolComplete, + this); } else { - d_->OnSettingsOpCompleted(OPERATION_FAILED, false); + Fail(OPERATION_FAILED); } } +void StorePolicyOp::PerformCallback(SignedSettings::ReturnCode code, + bool value) { + d_->OnSettingsOpCompleted(code, value); +} + RetrievePolicyOp::RetrievePolicyOp( SignedSettings::Delegate<const em::PolicyFetchResponse&>* d) : d_(d) { @@ -510,6 +853,28 @@ void RetrievePolicyOp::Execute() { &RetrievePolicyOp::OnStringComplete, this); } +void RetrievePolicyOp::Fail(SignedSettings::ReturnCode code) { + VLOG(2) << "RetrievePolicyOp::Execute() failed with " << code; + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, &RetrievePolicyOp::PerformCallback, code, + em::PolicyFetchResponse())); +} + +void RetrievePolicyOp::Succeed(const em::PolicyFetchResponse& value) { + em::PolicyData poldata; + if (SignedSettings::PolicyIsSane(value, &poldata)) { + service_->set_cached_policy(poldata); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, + &RetrievePolicyOp::PerformCallback, + SUCCESS, value)); + } else { + Fail(NOT_FOUND); + } +} + void RetrievePolicyOp::OnKeyOpComplete( const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload) { @@ -523,10 +888,9 @@ void RetrievePolicyOp::OnKeyOpComplete( } // Now, sure we're on the UI thread. if (return_code == OwnerManager::SUCCESS) - d_->OnSettingsOpCompleted(SUCCESS, policy_); + Succeed(policy_); else - d_->OnSettingsOpCompleted(SignedSettings::MapKeyOpCode(return_code), - em::PolicyFetchResponse()); + Fail(SignedSettings::MapKeyOpCode(return_code)); } // static @@ -540,15 +904,15 @@ void RetrievePolicyOp::OnStringComplete(void* delegate, void RetrievePolicyOp::ProcessPolicy(const char* out, const unsigned int len) { if (!out || !policy_.ParseFromString(std::string(out, len)) || (!policy_.has_policy_data() && !policy_.has_policy_data_signature())) { - d_->OnSettingsOpCompleted(NOT_FOUND, policy_); + Fail(NOT_FOUND); return; } if (!policy_.has_policy_data()) { - d_->OnSettingsOpCompleted(OPERATION_FAILED, em::PolicyFetchResponse()); + Fail(OPERATION_FAILED); return; } if (!policy_.has_policy_data_signature()) { - d_->OnSettingsOpCompleted(BAD_SIGNATURE, em::PolicyFetchResponse()); + Fail(BAD_SIGNATURE); return; } std::vector<uint8> sig; @@ -557,4 +921,9 @@ void RetrievePolicyOp::ProcessPolicy(const char* out, const unsigned int len) { service_->StartVerifyAttempt(policy_.policy_data(), sig, this); } +void RetrievePolicyOp::PerformCallback(SignedSettings::ReturnCode code, + const em::PolicyFetchResponse& value) { + d_->OnSettingsOpCompleted(code, value); +} + } // namespace chromeos diff --git a/chrome/browser/chromeos/login/signed_settings.h b/chrome/browser/chromeos/login/signed_settings.h index 1a374d2..8cef17b 100644 --- a/chrome/browser/chromeos/login/signed_settings.h +++ b/chrome/browser/chromeos/login/signed_settings.h @@ -32,6 +32,7 @@ namespace enterprise_management { class PolicyFetchResponse; +class PolicyData; } // namespace enterprise_management namespace em = enterprise_management; @@ -89,16 +90,25 @@ class SignedSettings : public base::RefCountedThreadSafe<SignedSettings>, static SignedSettings* CreateRetrievePolicyOp( SignedSettings::Delegate<const em::PolicyFetchResponse&>* d); + static bool EnumerateWhitelist(std::vector<std::string>* whitelisted); + static ReturnCode MapKeyOpCode(OwnerManager::KeyOpCode code); virtual void Execute() = 0; - // Implementation of OwnerManager::Delegate::OnKeyOpComplete() + virtual void Fail(ReturnCode code) = 0; + + // Implementation of OwnerManager::Delegate void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload) = 0; protected: - static void OnBoolComplete(void* delegate, bool success); + static bool PolicyIsSane(const em::PolicyFetchResponse& value, + em::PolicyData* poldata); + + void set_service(OwnershipService* service) { service_ = service; } + + void TryToFetchPolicyAndCallBack(); OwnershipService* service_; @@ -106,7 +116,26 @@ class SignedSettings : public base::RefCountedThreadSafe<SignedSettings>, friend class SignedSettingsTest; friend class SignedSettingsHelperTest; - void set_service(OwnershipService* service) { service_ = service; } + class Relay + : public SignedSettings::Delegate<const em::PolicyFetchResponse&> { + public: + // |s| must outlive your Relay instance. + explicit Relay(SignedSettings* s); + virtual ~Relay(); + // Implementation of SignedSettings::Delegate + virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code, + const em::PolicyFetchResponse& value); + private: + SignedSettings* settings_; + DISALLOW_COPY_AND_ASSIGN(Relay); + }; + + // Format of this string is documented in device_management_backend.proto. + static const char kDevicePolicyType[]; + + scoped_ptr<Relay> relay_; + scoped_refptr<SignedSettings> polfetcher_; + DISALLOW_COPY_AND_ASSIGN(SignedSettings); }; } // namespace chromeos diff --git a/chrome/browser/chromeos/login/signed_settings_helper_unittest.cc b/chrome/browser/chromeos/login/signed_settings_helper_unittest.cc index 7badf48..f0db486 100644 --- a/chrome/browser/chromeos/login/signed_settings_helper_unittest.cc +++ b/chrome/browser/chromeos/login/signed_settings_helper_unittest.cc @@ -1,21 +1,31 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// 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/chromeos/login/signed_settings_helper.h" #include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros_settings_names.h" #include "chrome/browser/chromeos/login/mock_ownership_service.h" #include "chrome/browser/chromeos/login/owner_manager.h" #include "chrome/browser/chromeos/login/signed_settings.h" +#include "chrome/browser/policy/proto/chrome_device_policy.pb.h" +#include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "content/browser/browser_thread.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using ::testing::_; +using ::testing::A; +using ::testing::AtLeast; using ::testing::InSequence; +using ::testing::Invoke; using ::testing::Return; +using ::testing::ReturnRef; +using ::testing::SaveArg; +using ::testing::WithArg; +namespace em = enterprise_management; namespace chromeos { class MockSignedSettingsHelperCallback : public SignedSettingsHelper::Callback { @@ -41,8 +51,8 @@ class SignedSettingsHelperTest : public ::testing::Test, public: SignedSettingsHelperTest() : fake_email_("fakey@example.com"), - fake_prop_("prop_name"), - fake_value_("stub"), + fake_prop_(kAccountsPrefAllowGuest), + fake_value_("false"), message_loop_(MessageLoop::TYPE_UI), ui_thread_(BrowserThread::UI, &message_loop_), file_thread_(BrowserThread::FILE), @@ -64,7 +74,6 @@ class SignedSettingsHelperTest : public ::testing::Test, } virtual void OnOpStarted(SignedSettings* op) { - op->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>()); } virtual void OnOpCompleted(SignedSettings* op) { @@ -73,6 +82,18 @@ class SignedSettingsHelperTest : public ::testing::Test, MessageLoop::current()->Quit(); } + static void OnKeyOpComplete(OwnerManager::Delegate* op) { + op->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>()); + } + + em::PolicyData BuildPolicyData() { + em::PolicyData to_return; + em::ChromeDeviceSettingsProto pol; + to_return.set_policy_type(SignedSettings::kDevicePolicyType); + to_return.set_policy_value(pol.SerializeAsString()); + return to_return; + } + const std::string fake_email_; const std::string fake_prop_; const std::string fake_value_; @@ -90,29 +111,45 @@ class SignedSettingsHelperTest : public ::testing::Test, TEST_F(SignedSettingsHelperTest, SerializedOps) { MockSignedSettingsHelperCallback cb; - ON_CALL(m_, GetStatus(_)) - .WillByDefault(Return(OwnershipService::OWNERSHIP_TAKEN)); - EXPECT_CALL(m_, GetStatus(_)).Times(2); + EXPECT_CALL(m_, GetStatus(_)) + .Times(2) + .WillRepeatedly(Return(OwnershipService::OWNERSHIP_TAKEN)); + EXPECT_CALL(m_, has_cached_policy()) + .Times(5) + .WillRepeatedly(Return(true)); + em::PolicyData fake_pol = BuildPolicyData(); + EXPECT_CALL(m_, cached_policy()) + .Times(5) + .WillRepeatedly(ReturnRef(fake_pol)); + EXPECT_CALL(m_, set_cached_policy(A<const em::PolicyData&>())) + .Times(3) + .WillRepeatedly(SaveArg<0>(&fake_pol)); + InSequence s; - EXPECT_CALL(m_, StartVerifyAttempt(_, _, _)).Times(1); - EXPECT_CALL(cb, OnCheckWhitelistCompleted(SignedSettings::SUCCESS, _)) - .Times(1); - EXPECT_CALL(m_, StartSigningAttempt(_, _)).Times(1); + EXPECT_CALL(m_, StartSigningAttempt(_, A<OwnerManager::Delegate*>())) + .WillOnce(WithArg<1>(Invoke(&SignedSettingsHelperTest::OnKeyOpComplete))); EXPECT_CALL(cb, OnWhitelistCompleted(SignedSettings::SUCCESS, _)) .Times(1); - EXPECT_CALL(m_, StartSigningAttempt(_, _)).Times(1); + + EXPECT_CALL(cb, OnCheckWhitelistCompleted(SignedSettings::SUCCESS, _)) + .Times(1); + + EXPECT_CALL(m_, StartSigningAttempt(_, A<OwnerManager::Delegate*>())) + .WillOnce(WithArg<1>(Invoke(&SignedSettingsHelperTest::OnKeyOpComplete))); EXPECT_CALL(cb, OnUnwhitelistCompleted(SignedSettings::SUCCESS, _)) .Times(1); - EXPECT_CALL(m_, StartSigningAttempt(_, _)).Times(1); + + EXPECT_CALL(m_, StartSigningAttempt(_, A<OwnerManager::Delegate*>())) + .WillOnce(WithArg<1>(Invoke(&SignedSettingsHelperTest::OnKeyOpComplete))); EXPECT_CALL(cb, OnStorePropertyCompleted(SignedSettings::SUCCESS, _, _)) .Times(1); - EXPECT_CALL(m_, StartVerifyAttempt(_, _, _)).Times(1); + EXPECT_CALL(cb, OnRetrievePropertyCompleted(SignedSettings::SUCCESS, _, _)) .Times(1); pending_ops_ = 5; - SignedSettingsHelper::Get()->StartCheckWhitelistOp(fake_email_, &cb); SignedSettingsHelper::Get()->StartWhitelistOp(fake_email_, true, &cb); + SignedSettingsHelper::Get()->StartCheckWhitelistOp(fake_email_, &cb); SignedSettingsHelper::Get()->StartWhitelistOp(fake_email_, false, &cb); SignedSettingsHelper::Get()->StartStorePropertyOp(fake_prop_, fake_value_, &cb); @@ -124,34 +161,49 @@ TEST_F(SignedSettingsHelperTest, SerializedOps) { TEST_F(SignedSettingsHelperTest, CanceledOps) { MockSignedSettingsHelperCallback cb; - ON_CALL(m_, GetStatus(_)) - .WillByDefault(Return(OwnershipService::OWNERSHIP_TAKEN)); - EXPECT_CALL(m_, GetStatus(_)).Times(2); + EXPECT_CALL(m_, GetStatus(_)) + .Times(2) + .WillRepeatedly(Return(OwnershipService::OWNERSHIP_TAKEN)); + EXPECT_CALL(m_, has_cached_policy()) + .Times(6) + .WillRepeatedly(Return(true)); + em::PolicyData fake_pol = BuildPolicyData(); + EXPECT_CALL(m_, cached_policy()) + .Times(7) + .WillRepeatedly(ReturnRef(fake_pol)); + EXPECT_CALL(m_, set_cached_policy(A<const em::PolicyData&>())) + .Times(3) + .WillRepeatedly(SaveArg<0>(&fake_pol)); + InSequence s; - EXPECT_CALL(m_, StartVerifyAttempt(_, _, _)).Times(1); - EXPECT_CALL(cb, OnCheckWhitelistCompleted(SignedSettings::SUCCESS, _)) - .Times(1); - EXPECT_CALL(m_, StartSigningAttempt(_, _)).Times(1); + + EXPECT_CALL(m_, StartSigningAttempt(_, A<OwnerManager::Delegate*>())) + .WillOnce(WithArg<1>(Invoke(&SignedSettingsHelperTest::OnKeyOpComplete))); EXPECT_CALL(cb, OnWhitelistCompleted(SignedSettings::SUCCESS, _)) .Times(1); - EXPECT_CALL(m_, StartSigningAttempt(_, _)).Times(1); + + EXPECT_CALL(cb, OnCheckWhitelistCompleted(SignedSettings::SUCCESS, _)) + .Times(1); + + EXPECT_CALL(m_, StartSigningAttempt(_, A<OwnerManager::Delegate*>())) + .WillOnce(WithArg<1>(Invoke(&SignedSettingsHelperTest::OnKeyOpComplete))); EXPECT_CALL(cb, OnUnwhitelistCompleted(SignedSettings::SUCCESS, _)) .Times(1); // CheckWhitelistOp for cb_to_be_canceled still gets executed but callback // does not happen. - EXPECT_CALL(m_, StartVerifyAttempt(_, _, _)).Times(1); - EXPECT_CALL(m_, StartSigningAttempt(_, _)).Times(1); + EXPECT_CALL(m_, StartSigningAttempt(_, A<OwnerManager::Delegate*>())) + .WillOnce(WithArg<1>(Invoke(&SignedSettingsHelperTest::OnKeyOpComplete))); EXPECT_CALL(cb, OnStorePropertyCompleted(SignedSettings::SUCCESS, _, _)) .Times(1); - EXPECT_CALL(m_, StartVerifyAttempt(_, _, _)).Times(1); + EXPECT_CALL(cb, OnRetrievePropertyCompleted(SignedSettings::SUCCESS, _, _)) .Times(1); pending_ops_ = 6; - SignedSettingsHelper::Get()->StartCheckWhitelistOp(fake_email_, &cb); SignedSettingsHelper::Get()->StartWhitelistOp(fake_email_, true, &cb); + SignedSettingsHelper::Get()->StartCheckWhitelistOp(fake_email_, &cb); SignedSettingsHelper::Get()->StartWhitelistOp(fake_email_, false, &cb); MockSignedSettingsHelperCallback cb_to_be_canceled; diff --git a/chrome/browser/chromeos/login/signed_settings_unittest.cc b/chrome/browser/chromeos/login/signed_settings_unittest.cc index 80f6815..cbe0a10 100644 --- a/chrome/browser/chromeos/login/signed_settings_unittest.cc +++ b/chrome/browser/chromeos/login/signed_settings_unittest.cc @@ -11,9 +11,11 @@ #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/cros/mock_library_loader.h" #include "chrome/browser/chromeos/cros/mock_login_library.h" +#include "chrome/browser/chromeos/cros_settings_names.h" #include "chrome/browser/chromeos/login/mock_owner_key_utils.h" #include "chrome/browser/chromeos/login/mock_ownership_service.h" #include "chrome/browser/chromeos/login/owner_manager_unittest.h" +#include "chrome/browser/policy/proto/chrome_device_policy.pb.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "chrome/test/thread_test_helper.h" #include "content/browser/browser_thread.h" @@ -21,11 +23,16 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using ::testing::A; using ::testing::AnyNumber; using ::testing::InvokeArgument; using ::testing::Return; +using ::testing::ReturnRef; +using ::testing::SaveArg; using ::testing::StrEq; +using ::testing::WithArg; using ::testing::_; +using google::protobuf::RepeatedPtrField; namespace em = enterprise_management; namespace chromeos { @@ -97,8 +104,8 @@ class SignedSettingsTest : public ::testing::Test { SignedSettingsTest() : fake_email_("fakey@example.com"), fake_domain_("*@example.com"), - fake_prop_("prop_name"), - fake_value_("stub"), + fake_prop_(kAccountsPrefAllowGuest), + fake_value_("false"), message_loop_(MessageLoop::TYPE_UI), ui_thread_(BrowserThread::UI, &message_loop_), file_thread_(BrowserThread::FILE), @@ -120,32 +127,65 @@ class SignedSettingsTest : public ::testing::Test { s->set_service(m); } - void FailingCheckWhitelist(const OwnerManager::KeyOpCode return_code) { - NormalDelegate<bool> d(false); - scoped_refptr<SignedSettings> s( - SignedSettings::CreateCheckWhitelistOp(fake_email_, &d)); - d.expect_failure(SignedSettings::MapKeyOpCode(return_code)); - - mock_service(s.get(), &m_); - EXPECT_CALL(m_, StartVerifyAttempt(fake_email_, _, _)) - .Times(1); + em::PolicyData BuildPolicyData(std::vector<std::string> whitelist) { + em::PolicyData to_return; + em::ChromeDeviceSettingsProto pol; + em::GuestModeEnabledProto* allow = pol.mutable_guest_mode_enabled(); + allow->set_guest_mode_enabled(false); + + if (!whitelist.empty()) { + em::UserWhitelistProto* whitelist_proto = pol.mutable_user_whitelist(); + for (std::vector<std::string>::const_iterator it = whitelist.begin(); + it != whitelist.end(); + ++it) { + whitelist_proto->add_user_whitelist(*it); + } + } + + to_return.set_policy_type(SignedSettings::kDevicePolicyType); + to_return.set_policy_value(pol.SerializeAsString()); + return to_return; + } - s->Execute(); - s->OnKeyOpComplete(return_code, std::vector<uint8>()); + void SetAllowNewUsers(bool desired, em::PolicyData* poldata) { + em::ChromeDeviceSettingsProto pol; + pol.ParseFromString(poldata->policy_value()); + em::AllowNewUsersProto* allow = pol.mutable_allow_new_users(); + allow->set_allow_new_users(desired); + poldata->set_policy_value(pol.SerializeAsString()); } - void FailingWhitelistOp(const OwnerManager::KeyOpCode return_code) { - NormalDelegate<bool> d(false); - scoped_refptr<SignedSettings> s( - SignedSettings::CreateWhitelistOp(fake_email_, true, &d)); - d.expect_failure(SignedSettings::MapKeyOpCode(return_code)); + bool CheckWhitelist(const std::string& email, const em::PolicyData& poldata) { + if (!poldata.has_policy_value()) + return false; + em::ChromeDeviceSettingsProto pol; + pol.ParseFromString(poldata.policy_value()); + if (!pol.has_user_whitelist()) + return false; + + const RepeatedPtrField<std::string>& whitelist = + pol.user_whitelist().user_whitelist(); + for (RepeatedPtrField<std::string>::const_iterator it = whitelist.begin(); + it != whitelist.end(); + ++it) { + if (email == *it) + return true; + } + return false; + } - mock_service(s.get(), &m_); - EXPECT_CALL(m_, StartSigningAttempt(fake_email_, _)) + void ExpectWhitelistOp(SignedSettings* s, + em::PolicyData* fake_pol, + em::PolicyData* out_pol) { + mock_service(s, &m_); + EXPECT_CALL(m_, StartSigningAttempt(_, _)) .Times(1); - - s->Execute(); - s->OnKeyOpComplete(return_code, std::vector<uint8>()); + EXPECT_CALL(m_, has_cached_policy()) + .WillOnce(Return(true)); + EXPECT_CALL(m_, cached_policy()) + .WillOnce(ReturnRef(*fake_pol)); + EXPECT_CALL(m_, set_cached_policy(A<const em::PolicyData&>())) + .WillOnce(SaveArg<0>(out_pol)); } void FailingStorePropertyOp(const OwnerManager::KeyOpCode return_code) { @@ -153,35 +193,21 @@ class SignedSettingsTest : public ::testing::Test { scoped_refptr<SignedSettings> s( SignedSettings::CreateStorePropertyOp(fake_prop_, fake_value_, &d)); d.expect_failure(SignedSettings::MapKeyOpCode(return_code)); - std::string to_sign = base::StringPrintf("%s=%s", - fake_prop_.c_str(), - fake_value_.c_str()); - mock_service(s.get(), &m_); - EXPECT_CALL(m_, StartSigningAttempt(to_sign, _)) - .Times(1); - EXPECT_CALL(m_, GetStatus(_)) - .WillOnce(Return(OwnershipService::OWNERSHIP_TAKEN)); - s->Execute(); - s->OnKeyOpComplete(return_code, std::vector<uint8>()); - } - - void FailingRetrievePropertyOp(const OwnerManager::KeyOpCode return_code) { - NormalDelegate<std::string> d(fake_value_); - scoped_refptr<SignedSettings> s( - SignedSettings::CreateRetrievePropertyOp(fake_prop_, &d)); - d.expect_failure(SignedSettings::MapKeyOpCode(return_code)); - std::string to_verify = base::StringPrintf("%s=%s", - fake_prop_.c_str(), - fake_value_.c_str()); mock_service(s.get(), &m_); - EXPECT_CALL(m_, StartVerifyAttempt(to_verify, _, _)) + EXPECT_CALL(m_, StartSigningAttempt(_, _)) .Times(1); EXPECT_CALL(m_, GetStatus(_)) .WillOnce(Return(OwnershipService::OWNERSHIP_TAKEN)); + EXPECT_CALL(m_, has_cached_policy()) + .WillOnce(Return(true)); + em::PolicyData fake_pol; + EXPECT_CALL(m_, cached_policy()) + .WillOnce(ReturnRef(fake_pol)); s->Execute(); s->OnKeyOpComplete(return_code, std::vector<uint8>()); + message_loop_.RunAllPending(); } void FailingStorePolicyOp(const OwnerManager::KeyOpCode return_code) { @@ -202,6 +228,7 @@ class SignedSettingsTest : public ::testing::Test { s->Execute(); s->OnKeyOpComplete(return_code, std::vector<uint8>()); + message_loop_.RunAllPending(); } MockLoginLibrary* MockLoginLib() { @@ -245,6 +272,26 @@ class SignedSettingsTest : public ::testing::Test { return fake_policy; } + void DoRetrieveProperty(const std::string& name, + const std::string& value, + em::PolicyData* fake_pol) { + NormalDelegate<std::string> d(value); + d.expect_success(); + scoped_refptr<SignedSettings> s( + SignedSettings::CreateRetrievePropertyOp(name, &d)); + mock_service(s.get(), &m_); + EXPECT_CALL(m_, GetStatus(_)) + .WillOnce(Return(OwnershipService::OWNERSHIP_TAKEN)); + EXPECT_CALL(m_, has_cached_policy()) + .WillOnce(Return(true)); + + EXPECT_CALL(m_, cached_policy()) + .WillOnce(ReturnRef(*fake_pol)); + + s->Execute(); + message_loop_.RunAllPending(); + } + const std::string fake_email_; const std::string fake_domain_; const std::string fake_prop_; @@ -274,25 +321,38 @@ TEST_F(SignedSettingsTest, CheckWhitelist) { SignedSettings::CreateCheckWhitelistOp(fake_email_, &d)); mock_service(s.get(), &m_); - EXPECT_CALL(m_, StartVerifyAttempt(fake_email_, _, _)) - .Times(1); + EXPECT_CALL(m_, has_cached_policy()) + .WillOnce(Return(true)); + + std::vector<std::string> whitelist(1, fake_email_); + whitelist.push_back(fake_email_ + "m"); + em::PolicyData fake_pol = BuildPolicyData(whitelist); + EXPECT_CALL(m_, cached_policy()) + .WillOnce(ReturnRef(fake_pol)); s->Execute(); - s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>()); + message_loop_.RunAllPending(); } TEST_F(SignedSettingsTest, CheckWhitelistWildcards) { NormalDelegate<bool> d(true); d.expect_success(); scoped_refptr<SignedSettings> s( - SignedSettings::CreateCheckWhitelistOp(fake_domain_, &d)); + SignedSettings::CreateCheckWhitelistOp(fake_email_, &d)); mock_service(s.get(), &m_); - EXPECT_CALL(m_, StartVerifyAttempt(fake_domain_, _, _)) - .Times(1); + EXPECT_CALL(m_, has_cached_policy()) + .WillOnce(Return(true)); + + std::vector<std::string> whitelist(1, fake_domain_); + whitelist.push_back(fake_email_ + "m"); + em::PolicyData fake_pol = BuildPolicyData(whitelist); + EXPECT_CALL(m_, cached_policy()) + .WillOnce(ReturnRef(fake_pol)) + .WillOnce(ReturnRef(fake_pol)); s->Execute(); - s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>()); + message_loop_.RunAllPending(); } TEST_F(SignedSettingsTest, CheckWhitelistNotFound) { @@ -300,23 +360,19 @@ TEST_F(SignedSettingsTest, CheckWhitelistNotFound) { scoped_refptr<SignedSettings> s( SignedSettings::CreateCheckWhitelistOp(fake_email_, &d)); d.expect_failure(SignedSettings::NOT_FOUND); - MockLoginLibrary* lib = MockLoginLib(); - EXPECT_CALL(*lib, CheckWhitelist(fake_email_, _)) - .WillOnce(Return(false)) - .RetiresOnSaturation(); - EXPECT_CALL(*lib, CheckWhitelist(fake_domain_, _)) - .WillOnce(Return(false)) - .RetiresOnSaturation(); - s->Execute(); - UnMockLoginLib(); -} -TEST_F(SignedSettingsTest, CheckWhitelistNoKey) { - FailingCheckWhitelist(OwnerManager::KEY_UNAVAILABLE); -} + mock_service(s.get(), &m_); + EXPECT_CALL(m_, has_cached_policy()) + .WillOnce(Return(true)); + + std::vector<std::string> whitelist(1, fake_email_ + "m"); + em::PolicyData fake_pol = BuildPolicyData(whitelist); + EXPECT_CALL(m_, cached_policy()) + .WillOnce(ReturnRef(fake_pol)) + .WillOnce(ReturnRef(fake_pol)); -TEST_F(SignedSettingsTest, CheckWhitelistFailed) { - FailingCheckWhitelist(OwnerManager::OPERATION_FAILED); + s->Execute(); + message_loop_.RunAllPending(); } TEST_F(SignedSettingsTest, Whitelist) { @@ -324,14 +380,32 @@ TEST_F(SignedSettingsTest, Whitelist) { d.expect_success(); scoped_refptr<SignedSettings> s( SignedSettings::CreateWhitelistOp(fake_email_, true, &d)); + em::PolicyData in_pol = BuildPolicyData(std::vector<std::string>()); + em::PolicyData out_pol; + ExpectWhitelistOp(s.get(), &in_pol, &out_pol); - mock_service(s.get(), &m_); - EXPECT_CALL(m_, StartSigningAttempt(fake_email_, _)) - .Times(1); + s->Execute(); + s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>()); + message_loop_.RunAllPending(); + + ASSERT_TRUE(CheckWhitelist(fake_email_, out_pol)); +} + +TEST_F(SignedSettingsTest, AddToExistingWhitelist) { + NormalDelegate<bool> d(true); + d.expect_success(); + scoped_refptr<SignedSettings> s( + SignedSettings::CreateWhitelistOp(fake_email_, true, &d)); + em::PolicyData in_pol = + BuildPolicyData(std::vector<std::string>(1, fake_domain_)); + em::PolicyData out_pol; + ExpectWhitelistOp(s.get(), &in_pol, &out_pol); s->Execute(); s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>()); message_loop_.RunAllPending(); + + ASSERT_TRUE(CheckWhitelist(fake_email_, out_pol)); } TEST_F(SignedSettingsTest, Unwhitelist) { @@ -339,22 +413,35 @@ TEST_F(SignedSettingsTest, Unwhitelist) { d.expect_success(); scoped_refptr<SignedSettings> s( SignedSettings::CreateWhitelistOp(fake_email_, false, &d)); - - mock_service(s.get(), &m_); - EXPECT_CALL(m_, StartSigningAttempt(fake_email_, _)) - .Times(1); + em::PolicyData in_pol = + BuildPolicyData(std::vector<std::string>(1, fake_email_)); + em::PolicyData out_pol; + ExpectWhitelistOp(s.get(), &in_pol, &out_pol); s->Execute(); s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>()); message_loop_.RunAllPending(); -} -TEST_F(SignedSettingsTest, WhitelistNoKey) { - FailingWhitelistOp(OwnerManager::KEY_UNAVAILABLE); + ASSERT_FALSE(CheckWhitelist(fake_email_, out_pol)); } -TEST_F(SignedSettingsTest, WhitelistFailed) { - FailingWhitelistOp(OwnerManager::OPERATION_FAILED); +TEST_F(SignedSettingsTest, RemoveFromExistingWhitelist) { + NormalDelegate<bool> d(true); + d.expect_success(); + scoped_refptr<SignedSettings> s( + SignedSettings::CreateWhitelistOp(fake_email_, false, &d)); + std::vector<std::string> whitelist(1, fake_domain_); + whitelist.push_back(fake_email_); + whitelist.push_back(fake_email_ + "m"); + em::PolicyData in_pol = BuildPolicyData(whitelist); + em::PolicyData out_pol; + ExpectWhitelistOp(s.get(), &in_pol, &out_pol); + + s->Execute(); + s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>()); + message_loop_.RunAllPending(); + + ASSERT_FALSE(CheckWhitelist(fake_email_, out_pol)); } TEST_F(SignedSettingsTest, StoreProperty) { @@ -362,18 +449,32 @@ TEST_F(SignedSettingsTest, StoreProperty) { d.expect_success(); scoped_refptr<SignedSettings> s( SignedSettings::CreateStorePropertyOp(fake_prop_, fake_value_, &d)); - std::string to_sign = base::StringPrintf("%s=%s", - fake_prop_.c_str(), - fake_value_.c_str()); + mock_service(s.get(), &m_); - EXPECT_CALL(m_, StartSigningAttempt(to_sign, _)) + EXPECT_CALL(m_, StartSigningAttempt(_, _)) .Times(1); EXPECT_CALL(m_, GetStatus(_)) .WillOnce(Return(OwnershipService::OWNERSHIP_TAKEN)); + EXPECT_CALL(m_, has_cached_policy()) + .WillOnce(Return(true)); + em::PolicyData in_pol = + BuildPolicyData(std::vector<std::string>(1, fake_email_)); + EXPECT_CALL(m_, cached_policy()) + .WillOnce(ReturnRef(in_pol)); + em::PolicyData out_pol; + EXPECT_CALL(m_, set_cached_policy(A<const em::PolicyData&>())) + .WillOnce(SaveArg<0>(&out_pol)); s->Execute(); s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>()); message_loop_.RunAllPending(); + + ASSERT_TRUE(out_pol.has_policy_value()); + em::ChromeDeviceSettingsProto pol; + pol.ParseFromString(out_pol.policy_value()); + ASSERT_TRUE(pol.has_guest_mode_enabled()); + ASSERT_TRUE(pol.guest_mode_enabled().has_guest_mode_enabled()); + ASSERT_FALSE(pol.guest_mode_enabled().guest_mode_enabled()); } TEST_F(SignedSettingsTest, StorePropertyNoKey) { @@ -385,61 +486,118 @@ TEST_F(SignedSettingsTest, StorePropertyFailed) { } TEST_F(SignedSettingsTest, RetrieveProperty) { + em::PolicyData fake_pol = BuildPolicyData(std::vector<std::string>()); + DoRetrieveProperty(fake_prop_, fake_value_, &fake_pol); +} + +TEST_F(SignedSettingsTest, ExplicitlyAllowNewUsers) { + em::PolicyData fake_pol = BuildPolicyData(std::vector<std::string>()); + SetAllowNewUsers(true, &fake_pol); + DoRetrieveProperty(kAccountsPrefAllowNewUser, "true", &fake_pol); +} + +TEST_F(SignedSettingsTest, ExplicitlyDisallowNewUsers) { + std::vector<std::string> whitelist(1, fake_email_ + "m"); + em::PolicyData fake_pol = BuildPolicyData(whitelist); + SetAllowNewUsers(false, &fake_pol); + DoRetrieveProperty(kAccountsPrefAllowNewUser, "false", &fake_pol); +} + +TEST_F(SignedSettingsTest, ImplicitlyDisallowNewUsers) { + std::vector<std::string> whitelist(1, fake_email_ + "m"); + em::PolicyData fake_pol = BuildPolicyData(whitelist); + DoRetrieveProperty(kAccountsPrefAllowNewUser, "false", &fake_pol); +} + +TEST_F(SignedSettingsTest, AccidentallyDisallowNewUsers) { + em::PolicyData fake_pol = BuildPolicyData(std::vector<std::string>()); + SetAllowNewUsers(false, &fake_pol); + DoRetrieveProperty(kAccountsPrefAllowNewUser, "true", &fake_pol); +} + +TEST_F(SignedSettingsTest, RetrievePropertyNotFound) { NormalDelegate<std::string> d(fake_value_); - d.expect_success(); + d.expect_failure(SignedSettings::NOT_FOUND); scoped_refptr<SignedSettings> s( - SignedSettings::CreateRetrievePropertyOp(fake_prop_, &d)); - std::string to_verify = base::StringPrintf("%s=%s", - fake_prop_.c_str(), - fake_value_.c_str()); + SignedSettings::CreateRetrievePropertyOp("unknown_prop", &d)); mock_service(s.get(), &m_); - EXPECT_CALL(m_, StartVerifyAttempt(to_verify, _, _)) - .Times(1); EXPECT_CALL(m_, GetStatus(_)) .WillOnce(Return(OwnershipService::OWNERSHIP_TAKEN)); + EXPECT_CALL(m_, has_cached_policy()) + .WillOnce(Return(true)); + + em::PolicyData fake_pol = BuildPolicyData(std::vector<std::string>()); + EXPECT_CALL(m_, cached_policy()) + .WillOnce(ReturnRef(fake_pol)); s->Execute(); - s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>()); + message_loop_.RunAllPending(); } -TEST_F(SignedSettingsTest, RetrievePropertyNotFound) { +ACTION_P(Retrieve, s) { (*arg0)((void*)arg1, s.c_str(), s.length()); } +ACTION_P(FinishKeyOp, s) { arg2->OnKeyOpComplete(OwnerManager::SUCCESS, s); } + +TEST_F(SignedSettingsTest, RetrievePolicyToRetrieveProperty) { NormalDelegate<std::string> d(fake_value_); + d.expect_success(); scoped_refptr<SignedSettings> s( SignedSettings::CreateRetrievePropertyOp(fake_prop_, &d)); - d.expect_failure(SignedSettings::NOT_FOUND); + + em::PolicyData fake_pol = BuildPolicyData(std::vector<std::string>()); + std::string data = fake_pol.SerializeAsString(); + std::string signed_serialized; + em::PolicyFetchResponse signed_policy = BuildProto(data, + fake_value_, + &signed_serialized); MockLoginLibrary* lib = MockLoginLib(); - EXPECT_CALL(*lib, RequestRetrieveProperty(fake_prop_, _, _)) - .WillOnce( - InvokeArgument<1>(static_cast<void*>(s.get()), - false, - static_cast<chromeos::Property*>(NULL))) + EXPECT_CALL(*lib, RequestRetrievePolicy(_, _)) + .WillOnce(Retrieve(signed_serialized)) .RetiresOnSaturation(); - s->Execute(); - UnMockLoginLib(); -} -TEST_F(SignedSettingsTest, RetrievePropertyNoKey) { - FailingRetrievePropertyOp(OwnerManager::KEY_UNAVAILABLE); -} + mock_service(s.get(), &m_); -TEST_F(SignedSettingsTest, RetrievePropertyFailed) { - FailingRetrievePropertyOp(OwnerManager::OPERATION_FAILED); + EXPECT_CALL(m_, GetStatus(_)) + .WillOnce(Return(OwnershipService::OWNERSHIP_TAKEN)) + .WillOnce(Return(OwnershipService::OWNERSHIP_TAKEN)); + EXPECT_CALL(m_, has_cached_policy()) + .WillOnce(Return(false)) + .WillOnce(Return(true)); + em::PolicyData out_pol; + EXPECT_CALL(m_, set_cached_policy(A<const em::PolicyData&>())) + .WillOnce(SaveArg<0>(&out_pol)); + EXPECT_CALL(m_, cached_policy()) + .WillOnce(ReturnRef(out_pol)); + + std::vector<uint8> fake_sig(fake_value_.c_str(), + fake_value_.c_str() + fake_value_.length()); + EXPECT_CALL(m_, StartVerifyAttempt(data, fake_sig, _)) + .WillOnce(FinishKeyOp(fake_sig)) + .RetiresOnSaturation(); + + s->Execute(); + message_loop_.RunAllPending(); + UnMockLoginLib(); } TEST_F(SignedSettingsTest, SignAndStorePolicy) { NormalDelegate<bool> d(true); d.expect_success(); + em::PolicyData in_pol = BuildPolicyData(std::vector<std::string>()); + std::string data_serialized = in_pol.SerializeAsString(); std::string serialized; - em::PolicyFetchResponse fake_policy = BuildProto(fake_prop_, + em::PolicyFetchResponse fake_policy = BuildProto(data_serialized, std::string(), &serialized); scoped_refptr<SignedSettings> s( SignedSettings::CreateStorePolicyOp(&fake_policy, &d)); mock_service(s.get(), &m_); - EXPECT_CALL(m_, StartSigningAttempt(StrEq(fake_prop_), _)) + EXPECT_CALL(m_, StartSigningAttempt(StrEq(data_serialized), _)) .Times(1); + em::PolicyData out_pol; + EXPECT_CALL(m_, set_cached_policy(A<const em::PolicyData&>())) + .WillOnce(SaveArg<0>(&out_pol)); // Ask for signature over unsigned policy. s->Execute(); @@ -447,17 +605,18 @@ TEST_F(SignedSettingsTest, SignAndStorePolicy) { // Fake out a successful signing. std::string signed_serialized; - em::PolicyFetchResponse signed_policy = BuildProto(fake_prop_, + em::PolicyFetchResponse signed_policy = BuildProto(data_serialized, fake_value_, &signed_serialized); std::vector<uint8> fake_sig(fake_value_.c_str(), fake_value_.c_str() + fake_value_.length()); MockLoginLibrary* lib = MockLoginLib(); - EXPECT_CALL(*lib, RequestStorePolicy(StrEq(signed_serialized), _, &d)) - .WillOnce(InvokeArgument<1>(static_cast<void*>(&d), true)) + EXPECT_CALL(*lib, RequestStorePolicy(StrEq(signed_serialized), _, s.get())) + .WillOnce(InvokeArgument<1>(static_cast<void*>(s.get()), true)) .RetiresOnSaturation(); s->OnKeyOpComplete(OwnerManager::SUCCESS, fake_sig); + message_loop_.RunAllPending(); UnMockLoginLib(); } @@ -465,16 +624,24 @@ TEST_F(SignedSettingsTest, StoreSignedPolicy) { NormalDelegate<bool> d(true); d.expect_success(); - std::string serialized; - em::PolicyFetchResponse fake_policy = BuildProto(fake_prop_, - fake_value_, - &serialized); + em::PolicyData in_pol = BuildPolicyData(std::vector<std::string>()); + std::string serialized = in_pol.SerializeAsString(); + std::string signed_serialized; + em::PolicyFetchResponse signed_policy = BuildProto(serialized, + fake_value_, + &signed_serialized); scoped_refptr<SignedSettings> s( - SignedSettings::CreateStorePolicyOp(&fake_policy, &d)); + SignedSettings::CreateStorePolicyOp(&signed_policy, &d)); MockLoginLibrary* lib = MockLoginLib(); - EXPECT_CALL(*lib, RequestStorePolicy(StrEq(serialized), _, &d)) - .WillOnce(InvokeArgument<1>(static_cast<void*>(&d), true)) + EXPECT_CALL(*lib, RequestStorePolicy(StrEq(signed_serialized), _, s.get())) + .WillOnce(InvokeArgument<1>(static_cast<void*>(s.get()), true)) .RetiresOnSaturation(); + + mock_service(s.get(), &m_); + em::PolicyData out_pol; + EXPECT_CALL(m_, set_cached_policy(A<const em::PolicyData&>())) + .WillOnce(SaveArg<0>(&out_pol)); + s->Execute(); message_loop_.RunAllPending(); UnMockLoginLib(); @@ -500,11 +667,14 @@ TEST_F(SignedSettingsTest, StorePolicyNoPolicyData) { SignedSettings::CreateStorePolicyOp(&fake_policy, &d)); s->Execute(); + message_loop_.RunAllPending(); } TEST_F(SignedSettingsTest, RetrievePolicy) { + em::PolicyData in_pol = BuildPolicyData(std::vector<std::string>()); + std::string serialized = in_pol.SerializeAsString(); std::string signed_serialized; - em::PolicyFetchResponse signed_policy = BuildProto(fake_prop_, + em::PolicyFetchResponse signed_policy = BuildProto(serialized, fake_value_, &signed_serialized); ProtoDelegate d(signed_policy); @@ -521,14 +691,18 @@ TEST_F(SignedSettingsTest, RetrievePolicy) { mock_service(s.get(), &m_); std::vector<uint8> fake_sig(fake_value_.c_str(), fake_value_.c_str() + fake_value_.length()); - EXPECT_CALL(m_, StartVerifyAttempt(fake_prop_, fake_sig, _)) + EXPECT_CALL(m_, StartVerifyAttempt(serialized, fake_sig, _)) .Times(1); + em::PolicyData out_pol; + EXPECT_CALL(m_, set_cached_policy(A<const em::PolicyData&>())) + .WillOnce(SaveArg<0>(&out_pol)); s->Execute(); message_loop_.RunAllPending(); UnMockLoginLib(); s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>()); + message_loop_.RunAllPending(); } TEST_F(SignedSettingsTest, RetrieveNullPolicy) { @@ -614,6 +788,7 @@ TEST_F(SignedSettingsTest, RetrieveMalsignedPolicy) { UnMockLoginLib(); s->OnKeyOpComplete(OwnerManager::OPERATION_FAILED, std::vector<uint8>()); + message_loop_.RunAllPending(); } } // namespace chromeos diff --git a/chrome/browser/chromeos/proxy_config_service_impl.cc b/chrome/browser/chromeos/proxy_config_service_impl.cc index 4613dec..161aaa4 100644 --- a/chrome/browser/chromeos/proxy_config_service_impl.cc +++ b/chrome/browser/chromeos/proxy_config_service_impl.cc @@ -10,6 +10,7 @@ #include "base/string_util.h" #include "base/task.h" #include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros_settings_names.h" #include "chrome/common/json_value_serializer.h" #include "content/browser/browser_thread.h" @@ -92,9 +93,6 @@ std::string ProxyConfigToString( return stream.str(); } -// Name of signed setting persisted on device, writeable only by owner. -const char* kSettingProxyEverywhere = "cros.proxy.everywhere"; - // Names used for dictionary values to serialize chromeos::ProxyConfig. const char* kMode = "mode"; const char* kSource = "src"; diff --git a/chrome/browser/chromeos/user_cros_settings_provider.cc b/chrome/browser/chromeos/user_cros_settings_provider.cc index 4e76d86..d0b9a4e 100644 --- a/chrome/browser/chromeos/user_cros_settings_provider.cc +++ b/chrome/browser/chromeos/user_cros_settings_provider.cc @@ -133,9 +133,7 @@ bool GetUserWhitelist(ListValue* user_list) { DCHECK(!prefs->IsManagedPreference(kAccountsPrefUsers)); std::vector<std::string> whitelist; - if (!CrosLibrary::Get()->EnsureLoaded() || - !CrosLibrary::Get()->GetLoginLibrary()->EnumerateWhitelisted( - &whitelist)) { + if (!SignedSettings::EnumerateWhitelist(&whitelist)) { LOG(WARNING) << "Failed to retrieve user whitelist."; return false; } |