diff options
Diffstat (limited to 'chrome/browser')
43 files changed, 1396 insertions, 914 deletions
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc index a03b156..0a8a01c 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc @@ -50,8 +50,8 @@ #include "chrome/browser/chromeos/power/screen_lock_observer.h" #include "chrome/browser/chromeos/power/user_activity_notifier.h" #include "chrome/browser/chromeos/power/video_activity_notifier.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" -#include "chrome/browser/chromeos/settings/owner_key_util.h" +#include "chrome/browser/chromeos/settings/ownership_service.h" +#include "chrome/browser/chromeos/settings/session_manager_observer.h" #include "chrome/browser/chromeos/system/statistics_provider.h" #include "chrome/browser/chromeos/system_key_event_listener.h" #include "chrome/browser/chromeos/upgrade_detector_chromeos.h" @@ -294,11 +294,9 @@ void ChromeBrowserMainPartsChromeos::PostMainMessageLoopStart() { chromeos::CrosDBusService::Initialize(); - // Initialize the device settings service so that we'll take actions per - // signals sent from the session manager. - chromeos::DeviceSettingsService::Get()->Initialize( - chromeos::DBusThreadManager::Get()->GetSessionManagerClient(), - chromeos::OwnerKeyUtil::Create()); + // Initialize the session manager observer so that we'll take actions + // per signals sent from the session manager. + session_manager_observer_.reset(new chromeos::SessionManagerObserver); chromeos::disks::DiskMountManager::Initialize(); chromeos::mtp::MediaTransferProtocolManager::Initialize(); @@ -351,7 +349,7 @@ void ChromeBrowserMainPartsChromeos::PreProfileInit() { chromeos::BootTimesLoader::Get()->RecordChromeMainStats(); // Trigger prefetching of ownership status. - chromeos::DeviceSettingsService::Get()->Load(); + chromeos::OwnershipService::GetSharedInstance()->Prewarm(); // -- This used to be in ChromeBrowserMainParts::PreMainMessageLoopRun() // -- just before CreateProfile(). @@ -522,11 +520,9 @@ void ChromeBrowserMainPartsChromeos::PostMainMessageLoopRun() { if (chromeos::CrosNetworkChangeNotifierFactory::GetInstance()) chromeos::CrosNetworkChangeNotifierFactory::GetInstance()->Shutdown(); - // Tell DeviceSettingsService to stop talking to session_manager. - chromeos::DeviceSettingsService::Get()->Shutdown(); - // We should remove observers attached to D-Bus clients before // DBusThreadManager is shut down. + session_manager_observer_.reset(); screen_lock_observer_.reset(); resume_observer_.reset(); brightness_observer_.reset(); diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h index cb0ddd1..c4df57e 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h @@ -62,6 +62,7 @@ class ChromeBrowserMainPartsChromeos : public ChromeBrowserMainPartsLinux { scoped_ptr<chromeos::OutputObserver> output_observer_; scoped_ptr<chromeos::ResumeObserver> resume_observer_; scoped_ptr<chromeos::ScreenLockObserver> screen_lock_observer_; + scoped_ptr<chromeos::SessionManagerObserver> session_manager_observer_; scoped_ptr<chromeos::PowerButtonObserver> power_button_observer_; scoped_ptr<chromeos::PowerStateOverride> power_state_override_; scoped_ptr<chromeos::UserActivityNotifier> user_activity_notifier_; diff --git a/chrome/browser/chromeos/kiosk_mode/kiosk_mode_idle_logout_unittest.cc b/chrome/browser/chromeos/kiosk_mode/kiosk_mode_idle_logout_unittest.cc index f0c8fc6..da3331c8 100644 --- a/chrome/browser/chromeos/kiosk_mode/kiosk_mode_idle_logout_unittest.cc +++ b/chrome/browser/chromeos/kiosk_mode/kiosk_mode_idle_logout_unittest.cc @@ -10,7 +10,6 @@ #include "base/message_loop.h" #include "base/synchronization/waitable_event.h" #include "chrome/browser/chromeos/login/user_manager.h" -#include "chrome/browser/chromeos/settings/device_settings_test_helper.h" #include "chrome/common/chrome_notification_types.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "content/public/browser/browser_thread.h" @@ -57,8 +56,6 @@ class KioskModeIdleLogoutTest : public ash::test::AshTestBase { content::TestBrowserThread ui_thread_; - ScopedDeviceSettingsTestHelper device_settings_test_helper_; - KioskModeIdleLogout* idle_logout_; content::NotificationRegistrar registrar_; }; diff --git a/chrome/browser/chromeos/locale_change_guard.cc b/chrome/browser/chromeos/locale_change_guard.cc index fe076b4..6687dad 100644 --- a/chrome/browser/chromeos/locale_change_guard.cc +++ b/chrome/browser/chromeos/locale_change_guard.cc @@ -12,7 +12,7 @@ #include "base/utf_string_conversions.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" +#include "chrome/browser/chromeos/login/user_manager.h" #include "chrome/browser/notifications/notification_delegate.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" @@ -60,7 +60,7 @@ LocaleChangeGuard::LocaleChangeGuard(Profile* profile) note_(NULL), reverted_(false) { DCHECK(profile_); - registrar_.Add(this, chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED, + registrar_.Add(this, chrome::NOTIFICATION_OWNERSHIP_CHECKED, content::NotificationService::AllSources()); } @@ -112,8 +112,8 @@ void LocaleChangeGuard::Observe(int type, } break; } - case chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED: { - if (DeviceSettingsService::Get()->HasPrivateOwnerKey()) { + case chrome::NOTIFICATION_OWNERSHIP_CHECKED: { + if (UserManager::Get()->IsCurrentUserOwner()) { PrefService* local_state = g_browser_process->local_state(); if (local_state) { PrefService* prefs = profile_->GetPrefs(); diff --git a/chrome/browser/chromeos/login/base_login_display_host.cc b/chrome/browser/chromeos/login/base_login_display_host.cc index 5d70c27..964e09f 100644 --- a/chrome/browser/chromeos/login/base_login_display_host.cc +++ b/chrome/browser/chromeos/login/base_login_display_host.cc @@ -262,7 +262,7 @@ void BaseLoginDisplayHost::CheckForAutoEnrollment() { // Start by checking if the device has already been owned. pointer_factory_.InvalidateWeakPtrs(); - DeviceSettingsService::Get()->GetOwnershipStatusAsync( + OwnershipService::GetSharedInstance()->GetStatusAsync( base::Bind(&BaseLoginDisplayHost::OnOwnershipStatusCheckDone, pointer_factory_.GetWeakPtr())); } @@ -407,9 +407,9 @@ void BaseLoginDisplayHost::StartAnimation() { } void BaseLoginDisplayHost::OnOwnershipStatusCheckDone( - DeviceSettingsService::OwnershipStatus status, + OwnershipService::Status status, bool current_user_is_owner) { - if (status != DeviceSettingsService::OWNERSHIP_NONE) { + if (status != OwnershipService::OWNERSHIP_NONE) { // The device is already owned. No need for auto-enrollment checks. VLOG(1) << "CheckForAutoEnrollment: device already owned"; return; diff --git a/chrome/browser/chromeos/login/base_login_display_host.h b/chrome/browser/chromeos/login/base_login_display_host.h index 453e408..ea9300c 100644 --- a/chrome/browser/chromeos/login/base_login_display_host.h +++ b/chrome/browser/chromeos/login/base_login_display_host.h @@ -12,7 +12,7 @@ #include "base/memory/weak_ptr.h" #include "chrome/browser/chromeos/login/login_display.h" #include "chrome/browser/chromeos/login/login_display_host.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" +#include "chrome/browser/chromeos/settings/ownership_service.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "ui/gfx/rect.h" @@ -74,8 +74,8 @@ class BaseLoginDisplayHost : public LoginDisplayHost, // Start sign in transition animation. void StartAnimation(); - // Callback for the ownership status check. - void OnOwnershipStatusCheckDone(DeviceSettingsService::OwnershipStatus status, + // Callback for completion of the |ownership_status_checker_|. + void OnOwnershipStatusCheckDone(OwnershipService::Status status, bool current_user_is_owner); // Callback for completion of the |auto_enrollment_client_|. diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc index 40da2ca..1662ff7 100644 --- a/chrome/browser/chromeos/login/existing_user_controller.cc +++ b/chrome/browser/chromeos/login/existing_user_controller.cc @@ -229,11 +229,10 @@ void ExistingUserController::Observe( } if (type == chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED || type == chrome::NOTIFICATION_POLICY_USER_LIST_CHANGED) { - if (host_ != NULL) { - // Signed settings or user list changed. Notify views and update them. - UpdateLoginDisplay(chromeos::UserManager::Get()->GetUsers()); - return; - } + // Signed settings or user list changed. Notify views and update them. + const chromeos::UserList& users = chromeos::UserManager::Get()->GetUsers(); + UpdateLoginDisplay(users); + return; } if (type == chrome::NOTIFICATION_AUTH_SUPPLIED) { // Possibly the user has authenticated against a proxy server and we might @@ -340,10 +339,22 @@ void ExistingUserController::CompleteLoginInternal(std::string username, std::string password) { resume_login_callback_.Reset(); - DeviceSettingsService::Get()->GetOwnershipStatusAsync( - base::Bind(&ExistingUserController::PerformLogin, - weak_factory_.GetWeakPtr(), username, password, - LoginPerformer::AUTH_MODE_EXTENSION)); + if (!login_performer_.get()) { + LoginPerformer::Delegate* delegate = this; + if (login_performer_delegate_.get()) + delegate = login_performer_delegate_.get(); + // Only one instance of LoginPerformer should exist at a time. + login_performer_.reset(new LoginPerformer(delegate)); + } + + // If the device is not owned yet, successfully logged in user will be owner. + is_owner_login_ = OwnershipService::GetSharedInstance()->GetStatus(true) == + OwnershipService::OWNERSHIP_NONE; + + is_login_in_progress_ = true; + login_performer_->CompleteLogin(username, password); + accessibility::MaybeSpeak( + l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNING_IN)); } void ExistingUserController::Login(const std::string& username, @@ -353,6 +364,10 @@ void ExistingUserController::Login(const std::string& username, // Disable clicking on other windows. login_display_->SetUIEnabled(false); + // If the device is not owned yet, successfully logged in user will be owner. + is_owner_login_ = OwnershipService::GetSharedInstance()->GetStatus(true) == + OwnershipService::OWNERSHIP_NONE; + BootTimesLoader::Get()->RecordLoginAttempted(); if (last_login_attempt_username_ != username) { @@ -364,21 +379,6 @@ void ExistingUserController::Login(const std::string& username, } num_login_attempts_++; - DeviceSettingsService::Get()->GetOwnershipStatusAsync( - base::Bind(&ExistingUserController::PerformLogin, - weak_factory_.GetWeakPtr(), username, password, - LoginPerformer::AUTH_MODE_INTERNAL)); -} - -void ExistingUserController::PerformLogin( - const std::string& username, - const std::string& password, - LoginPerformer::AuthorizationMode auth_mode, - DeviceSettingsService::OwnershipStatus ownership_status, - bool is_owner) { - // If the device is not owned yet, successfully logged in user will be owner. - is_owner_login_ = ownership_status == DeviceSettingsService::OWNERSHIP_NONE; - // Use the same LoginPerformer for subsequent login as it has state // such as Authenticator instance. if (!login_performer_.get() || num_login_attempts_ <= 1) { @@ -389,9 +389,8 @@ void ExistingUserController::PerformLogin( login_performer_.reset(NULL); login_performer_.reset(new LoginPerformer(delegate)); } - is_login_in_progress_ = true; - login_performer_->PerformLogin(username, password, auth_mode); + login_performer_->Login(username, password); accessibility::MaybeSpeak( l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNING_IN)); } @@ -466,17 +465,17 @@ void ExistingUserController::OnUserSelected(const std::string& username) { } void ExistingUserController::OnStartEnterpriseEnrollment() { - DeviceSettingsService::Get()->GetOwnershipStatusAsync( + OwnershipService::GetSharedInstance()->GetStatusAsync( base::Bind(&ExistingUserController::OnEnrollmentOwnershipCheckCompleted, weak_factory_.GetWeakPtr())); } void ExistingUserController::OnEnrollmentOwnershipCheckCompleted( - DeviceSettingsService::OwnershipStatus status, + OwnershipService::Status status, bool current_user_is_owner) { - if (status == DeviceSettingsService::OWNERSHIP_NONE) { + if (status == OwnershipService::OWNERSHIP_NONE) { ShowEnrollmentScreen(false, std::string()); - } else if (status == DeviceSettingsService::OWNERSHIP_TAKEN) { + } else if (status == OwnershipService::OWNERSHIP_TAKEN) { // On a device that is already owned we might want to allow users to // re-enroll if the policy information is invalid. CrosSettingsProvider::TrustedStatus trusted_status = diff --git a/chrome/browser/chromeos/login/existing_user_controller.h b/chrome/browser/chromeos/login/existing_user_controller.h index adfe116..1b62b09 100644 --- a/chrome/browser/chromeos/login/existing_user_controller.h +++ b/chrome/browser/chromeos/login/existing_user_controller.h @@ -20,7 +20,7 @@ #include "chrome/browser/chromeos/login/login_utils.h" #include "chrome/browser/chromeos/login/password_changed_view.h" #include "chrome/browser/chromeos/login/user.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" +#include "chrome/browser/chromeos/settings/ownership_service.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "googleurl/src/gurl.h" @@ -28,8 +28,8 @@ namespace chromeos { -class CrosSettings; class LoginDisplayHost; +class CrosSettings; // ExistingUserController is used to handle login when someone has // already logged into the machine. @@ -149,9 +149,8 @@ class ExistingUserController : public LoginDisplay::Delegate, // Handles result of ownership check and starts enterprise enrollment if // applicable. - void OnEnrollmentOwnershipCheckCompleted( - DeviceSettingsService::OwnershipStatus status, - bool current_user_is_owner); + void OnEnrollmentOwnershipCheckCompleted(OwnershipService::Status status, + bool current_user_is_owner); // Enters the enterprise enrollment screen. |forced| is true if this is the // result of an auto-enrollment check, and the user shouldn't be able to @@ -163,13 +162,6 @@ class ExistingUserController : public LoginDisplay::Delegate, // has to be performed, and will resume once auto-enrollment completes. void CompleteLoginInternal(std::string username, std::string password); - // Creates |login_performer_| if necessary and calls login() on it. - void PerformLogin(const std::string& username, - const std::string& password, - LoginPerformer::AuthorizationMode auth_mode, - DeviceSettingsService::OwnershipStatus ownership_status, - bool is_owner); - void set_login_performer_delegate(LoginPerformer::Delegate* d) { login_performer_delegate_.reset(d); } diff --git a/chrome/browser/chromeos/login/language_switch_menu.cc b/chrome/browser/chromeos/login/language_switch_menu.cc index 8312390..14d5335 100644 --- a/chrome/browser/chromeos/login/language_switch_menu.cc +++ b/chrome/browser/chromeos/login/language_switch_menu.cc @@ -14,6 +14,7 @@ #include "chrome/browser/chromeos/input_method/input_method_util.h" #include "chrome/browser/chromeos/login/language_list.h" #include "chrome/browser/chromeos/login/screen_observer.h" +#include "chrome/browser/chromeos/settings/ownership_service.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/common/pref_names.h" #include "grit/generated_resources.h" diff --git a/chrome/browser/chromeos/login/login_performer.cc b/chrome/browser/chromeos/login/login_performer.cc index 169d6d4..7a364d7 100644 --- a/chrome/browser/chromeos/login/login_performer.cc +++ b/chrome/browser/chromeos/login/login_performer.cc @@ -258,10 +258,9 @@ void LoginPerformer::Observe(int type, //////////////////////////////////////////////////////////////////////////////// // LoginPerformer, public: -void LoginPerformer::PerformLogin(const std::string& username, - const std::string& password, - AuthorizationMode auth_mode) { - auth_mode_ = auth_mode; +void LoginPerformer::CompleteLogin(const std::string& username, + const std::string& password) { + auth_mode_ = AUTH_MODE_EXTENSION; username_ = username; password_ = password; @@ -272,9 +271,9 @@ void LoginPerformer::PerformLogin(const std::string& username, if (!ScreenLocker::default_screen_locker()) { CrosSettingsProvider::TrustedStatus status = cros_settings->PrepareTrustedValues( - base::Bind(&LoginPerformer::PerformLogin, + base::Bind(&LoginPerformer::CompleteLogin, weak_factory_.GetWeakPtr(), - username, password, auth_mode)); + username, password)); // Must not proceed without signature verification. if (status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) { if (delegate_) @@ -292,14 +291,50 @@ void LoginPerformer::PerformLogin(const std::string& username, bool is_whitelisted = LoginUtils::IsWhitelisted( gaia::CanonicalizeEmail(username)); if (ScreenLocker::default_screen_locker() || is_whitelisted) { - switch (auth_mode_) { - case AUTH_MODE_EXTENSION: - StartLoginCompletion(); - break; - case AUTH_MODE_INTERNAL: - StartAuthentication(); - break; + // Starts authentication if guest login is allowed or online auth pending. + StartLoginCompletion(); + } else { + if (delegate_) + delegate_->WhiteListCheckFailed(username); + else + NOTREACHED(); + } +} + +void LoginPerformer::Login(const std::string& username, + const std::string& password) { + auth_mode_ = AUTH_MODE_INTERNAL; + username_ = username; + password_ = password; + + CrosSettings* cros_settings = CrosSettings::Get(); + + // Whitelist check is always performed during initial login and + // should not be performed when ScreenLock is active (pending online auth). + if (!ScreenLocker::default_screen_locker()) { + CrosSettingsProvider::TrustedStatus status = + cros_settings->PrepareTrustedValues( + base::Bind(&LoginPerformer::Login, + weak_factory_.GetWeakPtr(), + username, password)); + // Must not proceed without signature verification. + if (status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) { + if (delegate_) + delegate_->PolicyLoadFailed(); + else + NOTREACHED(); + return; + } else if (status != CrosSettingsProvider::TRUSTED) { + // Value of AllowNewUser setting is still not verified. + // Another attempt will be invoked after verification completion. + return; } + } + + bool is_whitelisted = LoginUtils::IsWhitelisted(username); + if (ScreenLocker::default_screen_locker() || is_whitelisted) { + // Starts authentication if guest login is allowed or online auth pending. + StartAuthentication(); } else { if (delegate_) delegate_->WhiteListCheckFailed(username); diff --git a/chrome/browser/chromeos/login/login_performer.h b/chrome/browser/chromeos/login/login_performer.h index db7611a..43da2a5 100644 --- a/chrome/browser/chromeos/login/login_performer.h +++ b/chrome/browser/chromeos/login/login_performer.h @@ -54,13 +54,6 @@ class LoginPerformer : public LoginStatusConsumer, public content::NotificationObserver, public OnlineAttemptHost::Delegate { public: - typedef enum AuthorizationMode { - // Authorization performed internally by Chrome. - AUTH_MODE_INTERNAL, - // Authorization performed by an extension. - AUTH_MODE_EXTENSION - } AuthorizationMode; - // Delegate class to get notifications from the LoginPerformer. class Delegate : public LoginStatusConsumer { public: @@ -91,12 +84,12 @@ class LoginPerformer : public LoginStatusConsumer, virtual void OnOffTheRecordLoginSuccess() OVERRIDE; virtual void OnPasswordChangeDetected() OVERRIDE; - // Performs a login for |username| and |password|. If auth_mode is - // AUTH_MODE_EXTENSION, there are no further auth checks, AUTH_MODE_INTERNAL - // will perform auth checks. - void PerformLogin(const std::string& username, - const std::string& password, - AuthorizationMode auth_mode); + // Completes login process that has already been authenticated with + // provided |username| and |password|. + void CompleteLogin(const std::string& username, const std::string& password); + + // Performs login with the |username| and |password| specified. + void Login(const std::string& username, const std::string& password); // Performs login for the demo user. void LoginDemoUser(); @@ -134,6 +127,12 @@ class LoginPerformer : public LoginStatusConsumer, void set_delegate(Delegate* delegate) { delegate_ = delegate; } + typedef enum AuthorizationMode { + // Authorization performed internally by Chrome. + AUTH_MODE_INTERNAL, + // Authorization performed by an extension. + AUTH_MODE_EXTENSION + } AuthorizationMode; AuthorizationMode auth_mode() const { return auth_mode_; } protected: diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc index 3b41805..52bd4be 100644 --- a/chrome/browser/chromeos/login/login_utils.cc +++ b/chrome/browser/chromeos/login/login_utils.cc @@ -44,6 +44,7 @@ #include "chrome/browser/chromeos/login/user_manager.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/cros_settings_names.h" +#include "chrome/browser/chromeos/settings/ownership_service.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/first_run/first_run.h" #include "chrome/browser/net/chrome_url_request_context.h" diff --git a/chrome/browser/chromeos/login/login_utils_browsertest.cc b/chrome/browser/chromeos/login/login_utils_browsertest.cc index 97046c7..2c2ed0f 100644 --- a/chrome/browser/chromeos/login/login_utils_browsertest.cc +++ b/chrome/browser/chromeos/login/login_utils_browsertest.cc @@ -17,7 +17,6 @@ #include "chrome/browser/chromeos/login/authenticator.h" #include "chrome/browser/chromeos/login/login_status_consumer.h" #include "chrome/browser/chromeos/login/user_manager.h" -#include "chrome/browser/chromeos/settings/device_settings_test_helper.h" #include "chrome/browser/io_thread.h" #include "chrome/browser/net/predictor.h" #include "chrome/browser/policy/browser_policy_connector.h" @@ -288,10 +287,9 @@ class LoginUtilsTest : public testing::Test, } void PrepareProfile(const std::string& username) { - ScopedDeviceSettingsTestHelper device_settings_test_helper; - MockSessionManagerClient* session_manager_client = + MockSessionManagerClient* session_managed_client = mock_dbus_thread_manager_.mock_session_manager_client(); - EXPECT_CALL(*session_manager_client, StartSession(_)); + EXPECT_CALL(*session_managed_client, StartSession(_)); EXPECT_CALL(*cryptohome_, GetSystemSalt()) .WillRepeatedly(Return(std::string("stub_system_salt"))); EXPECT_CALL(*mock_async_method_caller_, AsyncMount(_, _, _, _)) @@ -305,7 +303,6 @@ class LoginUtilsTest : public testing::Test, LoginUtils::Get()->PrepareProfile(username, std::string(), "password", false, true, false, this); - device_settings_test_helper.Flush(); RunAllPending(); } diff --git a/chrome/browser/chromeos/login/parallel_authenticator.cc b/chrome/browser/chromeos/login/parallel_authenticator.cc index 83a576d..9a59998 100644 --- a/chrome/browser/chromeos/login/parallel_authenticator.cc +++ b/chrome/browser/chromeos/login/parallel_authenticator.cc @@ -19,6 +19,7 @@ #include "chrome/browser/chromeos/login/login_status_consumer.h" #include "chrome/browser/chromeos/login/user_manager.h" #include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/settings/ownership_service.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/net/gaia/gaia_auth_util.h" @@ -200,6 +201,9 @@ ParallelAuthenticator::ParallelAuthenticator(LoginStatusConsumer* consumer) using_oauth_( !CommandLine::ForCurrentProcess()->HasSwitch( switches::kSkipOAuthLogin)) { + // If not already owned, this is a no-op. If it is, this loads the owner's + // public key off of disk. + OwnershipService::GetSharedInstance()->StartLoadOwnerKeyAttempt(); } void ParallelAuthenticator::AuthenticateToLogin( @@ -218,8 +222,11 @@ void ParallelAuthenticator::AuthenticateToLogin( login_token, login_captcha, !UserManager::Get()->IsKnownUser(canonicalized))); - // Reset the verified flag. - owner_is_verified_ = false; + { + // Reset the verified flag. + base::AutoLock for_this_block(owner_verified_lock_); + owner_is_verified_ = false; + } const bool create_if_missing = false; BrowserThread::PostTask( @@ -250,9 +257,11 @@ void ParallelAuthenticator::CompleteLogin(Profile* profile, password, HashPassword(password), !UserManager::Get()->IsKnownUser(canonicalized))); - - // Reset the verified flag. - owner_is_verified_ = false; + { + // Reset the verified flag. + base::AutoLock for_this_block(owner_verified_lock_); + owner_is_verified_ = false; + } const bool create_if_missing = false; BrowserThread::PostTask( @@ -406,6 +415,7 @@ void ParallelAuthenticator::ResyncEncryptedData() { } bool ParallelAuthenticator::VerifyOwner() { + base::AutoLock for_this_block(owner_verified_lock_); if (owner_is_verified_) return true; // Check if policy data is fine and continue in safe mode if needed. @@ -420,19 +430,21 @@ bool ParallelAuthenticator::VerifyOwner() { // First we have to make sure the current user's cert store is available. CrosLibrary::Get()->GetCertLibrary()->LoadKeyStore(); // Now we can continue reading the private key. - DeviceSettingsService::Get()->SetUsername(current_state_->username); - DeviceSettingsService::Get()->GetOwnershipStatusAsync( - base::Bind(&ParallelAuthenticator::OnOwnershipChecked, this)); + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + base::Bind(&ParallelAuthenticator::FinishVerifyOwnerOnFileThread, this)); return false; } -void ParallelAuthenticator::OnOwnershipChecked( - DeviceSettingsService::OwnershipStatus status, - bool is_owner) { +void ParallelAuthenticator::FinishVerifyOwnerOnFileThread() { + base::AutoLock for_this_block(owner_verified_lock_); // Now we can check if this user is the owner. - user_can_login_ = is_owner; + user_can_login_ = + OwnershipService::GetSharedInstance()->IsCurrentUserOwner(); owner_is_verified_ = true; - Resolve(); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&ParallelAuthenticator::Resolve, this)); } void ParallelAuthenticator::RetryAuth(Profile* profile, @@ -791,6 +803,7 @@ void ParallelAuthenticator::ResolveLoginCompletionStatus() { void ParallelAuthenticator::SetOwnerState(bool owner_check_finished, bool check_result) { + base::AutoLock for_this_block(owner_verified_lock_); owner_is_verified_ = owner_check_finished; user_can_login_ = check_result; } diff --git a/chrome/browser/chromeos/login/parallel_authenticator.h b/chrome/browser/chromeos/login/parallel_authenticator.h index a7ab996..8f29a44 100644 --- a/chrome/browser/chromeos/login/parallel_authenticator.h +++ b/chrome/browser/chromeos/login/parallel_authenticator.h @@ -12,12 +12,11 @@ #include "base/gtest_prod_util.h" #include "base/memory/scoped_ptr.h" #include "base/synchronization/lock.h" +#include "chrome/browser/chromeos/login/authenticator.h" #include "chrome/browser/chromeos/login/auth_attempt_state.h" #include "chrome/browser/chromeos/login/auth_attempt_state_resolver.h" -#include "chrome/browser/chromeos/login/authenticator.h" #include "chrome/browser/chromeos/login/online_attempt.h" #include "chrome/browser/chromeos/login/test_attempt_state.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" #include "chrome/common/net/gaia/gaia_auth_consumer.h" class LoginFailure; @@ -220,9 +219,9 @@ class ParallelAuthenticator : public Authenticator, // Returns true if the owner check has been successful or if it is not needed. bool VerifyOwner(); - // Handles completion of the ownership check and continues login. - void OnOwnershipChecked(DeviceSettingsService::OwnershipStatus status, - bool is_owner); + // checks if the current mounted home contains the owner case and either + // continues or fails the log-in. Used for policy lost mitigation "safe-mode". + void FinishVerifyOwnerOnFileThread(); // Records OAuth1 access token verification failure for |user_account|. void RecordOAuthCheckFailure(const std::string& user_account); @@ -253,6 +252,8 @@ class ParallelAuthenticator : public Authenticator, // of it. bool owner_is_verified_; bool user_can_login_; + // A lock for |owner_is_verified_| and |user_can_login_|. + base::Lock owner_verified_lock_; // True if we use OAuth-based authentication flow. bool using_oauth_; diff --git a/chrome/browser/chromeos/login/parallel_authenticator_unittest.cc b/chrome/browser/chromeos/login/parallel_authenticator_unittest.cc index 3b6bc70..4296fca2 100644 --- a/chrome/browser/chromeos/login/parallel_authenticator_unittest.cc +++ b/chrome/browser/chromeos/login/parallel_authenticator_unittest.cc @@ -20,7 +20,6 @@ #include "chrome/browser/chromeos/login/mock_user_manager.h" #include "chrome/browser/chromeos/login/test_attempt_state.h" #include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/settings/device_settings_test_helper.h" #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h" #include "chrome/common/net/gaia/mock_url_fetcher_factory.h" #include "chrome/test/base/testing_profile.h" @@ -35,13 +34,13 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/cros_system_api/dbus/service_constants.h" +using content::BrowserThread; using ::testing::AnyNumber; using ::testing::DoAll; using ::testing::Invoke; using ::testing::Return; using ::testing::SetArgPointee; using ::testing::_; -using content::BrowserThread; namespace chromeos { @@ -209,10 +208,8 @@ class ParallelAuthenticatorTest : public testing::Test { std::string password_; std::string hash_ascii_; - ScopedDeviceSettingsTestHelper device_settings_test_helper_; - // Initializes / shuts down a stub CrosLibrary. - ScopedStubCrosEnabler stub_cros_enabler_; + chromeos::ScopedStubCrosEnabler stub_cros_enabler_; // Mocks, destroyed by CrosLibrary class. MockCertLibrary* mock_cert_library_; @@ -343,8 +340,8 @@ TEST_F(ParallelAuthenticatorTest, ResolveOwnerNeededFailedMount) { EXPECT_EQ(ParallelAuthenticator::CONTINUE, SetAndResolveState(auth_, state_.release())); - // Let the owner verification run. - device_settings_test_helper_.Flush(); + // Let the owner verification run on the FILE thread... + message_loop_.RunAllPending(); // and test that the mount has succeeded. state_.reset(new TestAttemptState(username_, password_, diff --git a/chrome/browser/chromeos/login/screen_locker.cc b/chrome/browser/chromeos/login/screen_locker.cc index a9a8d4a..4ea2184 100644 --- a/chrome/browser/chromeos/login/screen_locker.cc +++ b/chrome/browser/chromeos/login/screen_locker.cc @@ -226,9 +226,8 @@ void ScreenLocker::Authenticate(const string16& password) { // initial online login phase is still active. if (LoginPerformer::default_performer()) { DVLOG(1) << "Delegating authentication to LoginPerformer."; - LoginPerformer::default_performer()->PerformLogin( - user_.email(), UTF16ToUTF8(password), - LoginPerformer::AUTH_MODE_INTERNAL); + LoginPerformer::default_performer()->Login(user_.email(), + UTF16ToUTF8(password)); } else { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, diff --git a/chrome/browser/chromeos/login/user_manager_impl.cc b/chrome/browser/chromeos/login/user_manager_impl.cc index 33d4ae8..a06c0d9 100644 --- a/chrome/browser/chromeos/login/user_manager_impl.cc +++ b/chrome/browser/chromeos/login/user_manager_impl.cc @@ -34,6 +34,7 @@ #include "chrome/browser/chromeos/login/user_image.h" #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/settings/ownership_service.h" #include "chrome/browser/policy/browser_policy_connector.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/prefs/scoped_user_pref_update.h" @@ -202,7 +203,7 @@ UserManagerImpl::UserManagerImpl() DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); MigrateWallpaperData(); - registrar_.Add(this, chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED, + registrar_.Add(this, chrome::NOTIFICATION_OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED, content::NotificationService::AllSources()); registrar_.Add(this, chrome::NOTIFICATION_PROFILE_ADDED, content::NotificationService::AllSources()); @@ -211,7 +212,7 @@ UserManagerImpl::UserManagerImpl() UserManagerImpl::~UserManagerImpl() { // Can't use STLDeleteElements because of the private destructor of User. - for (size_t i = 0; i < users_.size(); ++i) + for (size_t i = 0; i < users_.size();++i) delete users_[i]; users_.clear(); if (is_current_user_ephemeral_) @@ -584,9 +585,13 @@ void UserManagerImpl::Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) { switch (type) { - case chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED: - CheckOwnership(); - RetrieveTrustedDevicePolicies(); + case chrome::NOTIFICATION_OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED: + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + base::Bind(&UserManagerImpl::CheckOwnership, + base::Unretained(this))); + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&UserManagerImpl::RetrieveTrustedDevicePolicies, + base::Unretained(this))); break; case chrome::NOTIFICATION_PROFILE_ADDED: if (IsUserLoggedIn() && !IsLoggedInAsGuest()) { @@ -613,13 +618,13 @@ void UserManagerImpl::OnStateChanged() { state != AuthError::CONNECTION_FAILED && state != AuthError::SERVICE_UNAVAILABLE && state != AuthError::REQUEST_CANCELED) { - // Invalidate OAuth token to force Gaia sign-in flow. This is needed - // because sign-out/sign-in solution is suggested to the user. - // TODO(altimofeev): this code isn't needed after crosbug.com/25978 is - // implemented. - DVLOG(1) << "Invalidate OAuth token because of a sync error."; - SaveUserOAuthStatus(GetLoggedInUser().email(), - User::OAUTH_TOKEN_STATUS_INVALID); + // Invalidate OAuth token to force Gaia sign-in flow. This is needed + // because sign-out/sign-in solution is suggested to the user. + // TODO(altimofeev): this code isn't needed after crosbug.com/25978 is + // implemented. + DVLOG(1) << "Invalidate OAuth token because of a sync error."; + SaveUserOAuthStatus(GetLoggedInUser().email(), + User::OAUTH_TOKEN_STATUS_INVALID); } } @@ -693,12 +698,12 @@ bool UserManagerImpl::IsEphemeralUser(const std::string& email) const { HasSwitch(switches::kLoginManager)); } -void UserManagerImpl::AddObserver(UserManager::Observer* obs) { +void UserManagerImpl::AddObserver(Observer* obs) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); observer_list_.AddObserver(obs); } -void UserManagerImpl::RemoveObserver(UserManager::Observer* obs) { +void UserManagerImpl::RemoveObserver(Observer* obs) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); observer_list_.RemoveObserver(obs); } @@ -710,8 +715,10 @@ const gfx::ImageSkia& UserManagerImpl::DownloadedProfileImage() const { void UserManagerImpl::NotifyLocalStateChanged() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - FOR_EACH_OBSERVER(UserManager::Observer, observer_list_, - LocalStateChanged(this)); + FOR_EACH_OBSERVER( + Observer, + observer_list_, + LocalStateChanged(this)); } FilePath UserManagerImpl::GetImagePathForUser(const std::string& username) { @@ -888,9 +895,10 @@ void UserManagerImpl::NotifyOnLogin() { CrosLibrary::Get()->GetCertLibrary()->LoadKeyStore(); - // Indicate to DeviceSettingsService that the owner key may have become - // available. - DeviceSettingsService::Get()->SetUsername(logged_in_user_->email()); + // Schedules current user ownership check on file thread. + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + base::Bind(&UserManagerImpl::CheckOwnership, + base::Unretained(this))); } void UserManagerImpl::SetInitialUserImage(const std::string& username) { @@ -1147,18 +1155,32 @@ void UserManagerImpl::DeleteUserImage(const FilePath& image_path) { } } -void UserManagerImpl::UpdateOwnership( - DeviceSettingsService::OwnershipStatus status, - bool is_owner) { - VLOG(1) << "Current user " << (is_owner ? "is owner" : "is not owner"); +void UserManagerImpl::UpdateOwnership(bool is_owner) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); SetCurrentUserIsOwner(is_owner); + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_OWNERSHIP_CHECKED, + content::NotificationService::AllSources(), + content::NotificationService::NoDetails()); + if (is_owner) { + // Also update cached value. + CrosSettings::Get()->SetString(kDeviceOwner, GetLoggedInUser().email()); + } } void UserManagerImpl::CheckOwnership() { - DeviceSettingsService::Get()->GetOwnershipStatusAsync( + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + bool is_owner = OwnershipService::GetSharedInstance()->IsCurrentUserOwner(); + VLOG(1) << "Current user " << (is_owner ? "is owner" : "is not owner"); + + // UserManagerImpl should be accessed only on UI thread. + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, base::Bind(&UserManagerImpl::UpdateOwnership, - base::Unretained(this))); + base::Unretained(this), + is_owner)); } // ProfileDownloaderDelegate override. diff --git a/chrome/browser/chromeos/login/user_manager_impl.h b/chrome/browser/chromeos/login/user_manager_impl.h index 3aec437..7ba782c 100644 --- a/chrome/browser/chromeos/login/user_manager_impl.h +++ b/chrome/browser/chromeos/login/user_manager_impl.h @@ -20,18 +20,17 @@ #include "chrome/browser/chromeos/login/user_image_loader.h" #include "chrome/browser/chromeos/login/user_manager.h" #include "chrome/browser/chromeos/login/wallpaper_manager.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" #include "chrome/browser/profiles/profile_downloader_delegate.h" #include "chrome/browser/sync/profile_sync_service_observer.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "ui/gfx/image/image_skia.h" +class SkBitmap; class FilePath; class PrefService; class ProfileDownloader; class ProfileSyncService; -class SkBitmap; namespace chromeos { @@ -94,8 +93,8 @@ class UserManagerImpl : public UserManager, virtual bool IsLoggedInAsStub() const OVERRIDE; virtual bool IsSessionStarted() const OVERRIDE; virtual bool IsEphemeralUser(const std::string& email) const OVERRIDE; - virtual void AddObserver(UserManager::Observer* obs) OVERRIDE; - virtual void RemoveObserver(UserManager::Observer* obs) OVERRIDE; + virtual void AddObserver(Observer* obs) OVERRIDE; + virtual void RemoveObserver(Observer* obs) OVERRIDE; virtual void NotifyLocalStateChanged() OVERRIDE; virtual const gfx::ImageSkia& DownloadedProfileImage() const OVERRIDE; @@ -214,10 +213,9 @@ class UserManagerImpl : public UserManager, void DeleteUserImage(const FilePath& image_path); // Updates current user ownership on UI thread. - void UpdateOwnership(DeviceSettingsService::OwnershipStatus status, - bool is_owner); + void UpdateOwnership(bool is_owner); - // Triggers an asynchronous ownership check. + // Checks current user's ownership on file thread. void CheckOwnership(); // ProfileDownloaderDelegate implementation. @@ -283,7 +281,7 @@ class UserManagerImpl : public UserManager, // service, so do NOT use it outside |OnStateChanged| method. ProfileSyncService* observed_sync_service_; - ObserverList<UserManager::Observer> observer_list_; + ObserverList<Observer> observer_list_; // Download user profile image on login to update it if it's changed. scoped_ptr<ProfileDownloader> profile_image_downloader_; diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc index 53a9b00..8a08f07 100644 --- a/chrome/browser/chromeos/login/wizard_controller.cc +++ b/chrome/browser/chromeos/login/wizard_controller.cc @@ -43,7 +43,6 @@ #include "chrome/browser/ui/options/options_util.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/pref_names.h" -#include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" #include "ui/base/accelerators/accelerator.h" diff --git a/chrome/browser/chromeos/settings/cros_settings.cc b/chrome/browser/chromeos/settings/cros_settings.cc index f0592f3..a0622b4 100644 --- a/chrome/browser/chromeos/settings/cros_settings.cc +++ b/chrome/browser/chromeos/settings/cros_settings.cc @@ -11,7 +11,7 @@ #include "base/string_util.h" #include "base/values.h" #include "chrome/browser/chromeos/settings/device_settings_provider.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" +#include "chrome/browser/chromeos/settings/signed_settings_helper.h" #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h" #include "chrome/browser/chromeos/settings/system_settings_provider.h" #include "chrome/common/chrome_notification_types.h" @@ -35,6 +35,22 @@ bool CrosSettings::IsCrosSettings(const std::string& path) { return StartsWithASCII(path, kCrosSettingsPrefix, true); } +void CrosSettings::FireObservers(const std::string& path) { + DCHECK(CalledOnValidThread()); + SettingsObserverMap::iterator observer_iterator = + settings_observers_.find(path); + if (observer_iterator == settings_observers_.end()) + return; + + NotificationObserverList::Iterator it(*(observer_iterator->second)); + content::NotificationObserver* observer; + while ((observer = it.GetNext()) != NULL) { + observer->Observe(chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED, + content::Source<CrosSettings>(this), + content::Details<const std::string>(&path)); + } +} + void CrosSettings::Set(const std::string& path, const base::Value& in_value) { DCHECK(CalledOnValidThread()); CrosSettingsProvider* provider; @@ -43,27 +59,6 @@ void CrosSettings::Set(const std::string& path, const base::Value& in_value) { provider->Set(path, in_value); } -const base::Value* CrosSettings::GetPref(const std::string& path) const { - DCHECK(CalledOnValidThread()); - CrosSettingsProvider* provider = GetProvider(path); - if (provider) - return provider->Get(path); - NOTREACHED() << path << " preference was not found in the signed settings."; - return NULL; -} - -CrosSettingsProvider::TrustedStatus CrosSettings::PrepareTrustedValues( - const base::Closure& callback) const { - DCHECK(CalledOnValidThread()); - for (size_t i = 0; i < providers_.size(); ++i) { - CrosSettingsProvider::TrustedStatus status = - providers_[i]->PrepareTrustedValues(callback); - if (status != CrosSettingsProvider::TRUSTED) - return status; - } - return CrosSettingsProvider::TRUSTED; -} - void CrosSettings::SetBoolean(const std::string& path, bool in_value) { DCHECK(CalledOnValidThread()); base::FundamentalValue value(in_value); @@ -109,51 +104,6 @@ void CrosSettings::RemoveFromList(const std::string& path, Set(path, *new_value); } -bool CrosSettings::GetBoolean(const std::string& path, - bool* bool_value) const { - DCHECK(CalledOnValidThread()); - const base::Value* value = GetPref(path); - if (value) - return value->GetAsBoolean(bool_value); - return false; -} - -bool CrosSettings::GetInteger(const std::string& path, - int* out_value) const { - DCHECK(CalledOnValidThread()); - const base::Value* value = GetPref(path); - if (value) - return value->GetAsInteger(out_value); - return false; -} - -bool CrosSettings::GetDouble(const std::string& path, - double* out_value) const { - DCHECK(CalledOnValidThread()); - const base::Value* value = GetPref(path); - if (value) - return value->GetAsDouble(out_value); - return false; -} - -bool CrosSettings::GetString(const std::string& path, - std::string* out_value) const { - DCHECK(CalledOnValidThread()); - const base::Value* value = GetPref(path); - if (value) - return value->GetAsString(out_value); - return false; -} - -bool CrosSettings::GetList(const std::string& path, - const base::ListValue** out_value) const { - DCHECK(CalledOnValidThread()); - const base::Value* value = GetPref(path); - if (value) - return value->GetAsList(out_value); - return false; -} - bool CrosSettings::FindEmailInList(const std::string& path, const std::string& email) const { DCHECK(CalledOnValidThread()); @@ -270,6 +220,77 @@ CrosSettingsProvider* CrosSettings::GetProvider( return NULL; } +void CrosSettings::ReloadProviders() { + for (size_t i = 0; i < providers_.size(); ++i) + providers_[i]->Reload(); +} + +const base::Value* CrosSettings::GetPref(const std::string& path) const { + DCHECK(CalledOnValidThread()); + CrosSettingsProvider* provider = GetProvider(path); + if (provider) + return provider->Get(path); + NOTREACHED() << path << " preference was not found in the signed settings."; + return NULL; +} + +CrosSettingsProvider::TrustedStatus CrosSettings::PrepareTrustedValues( + const base::Closure& callback) const { + DCHECK(CalledOnValidThread()); + for (size_t i = 0; i < providers_.size(); ++i) { + CrosSettingsProvider::TrustedStatus status = + providers_[i]->PrepareTrustedValues(callback); + if (status != CrosSettingsProvider::TRUSTED) + return status; + } + return CrosSettingsProvider::TRUSTED; +} + +bool CrosSettings::GetBoolean(const std::string& path, + bool* bool_value) const { + DCHECK(CalledOnValidThread()); + const base::Value* value = GetPref(path); + if (value) + return value->GetAsBoolean(bool_value); + return false; +} + +bool CrosSettings::GetInteger(const std::string& path, + int* out_value) const { + DCHECK(CalledOnValidThread()); + const base::Value* value = GetPref(path); + if (value) + return value->GetAsInteger(out_value); + return false; +} + +bool CrosSettings::GetDouble(const std::string& path, + double* out_value) const { + DCHECK(CalledOnValidThread()); + const base::Value* value = GetPref(path); + if (value) + return value->GetAsDouble(out_value); + return false; +} + +bool CrosSettings::GetString(const std::string& path, + std::string* out_value) const { + DCHECK(CalledOnValidThread()); + const base::Value* value = GetPref(path); + if (value) + return value->GetAsString(out_value); + return false; +} + +bool CrosSettings::GetList(const std::string& path, + const base::ListValue** out_value) const { + DCHECK(CalledOnValidThread()); + const base::Value* value = GetPref(path); + if (value) + return value->GetAsList(out_value); + return false; +} + CrosSettings::CrosSettings() { CrosSettingsProvider::NotifyObserversCallback notify_cb( base::Bind(&CrosSettings::FireObservers, @@ -280,7 +301,7 @@ CrosSettings::CrosSettings() { AddSettingsProvider(new StubCrosSettingsProvider(notify_cb)); } else { AddSettingsProvider( - new DeviceSettingsProvider(notify_cb, DeviceSettingsService::Get())); + new DeviceSettingsProvider(notify_cb, SignedSettingsHelper::Get())); } // System settings are not mocked currently. AddSettingsProvider(new SystemSettingsProvider(notify_cb)); @@ -291,20 +312,4 @@ CrosSettings::~CrosSettings() { STLDeleteValues(&settings_observers_); } -void CrosSettings::FireObservers(const std::string& path) { - DCHECK(CalledOnValidThread()); - SettingsObserverMap::iterator observer_iterator = - settings_observers_.find(path); - if (observer_iterator == settings_observers_.end()) - return; - - NotificationObserverList::Iterator it(*(observer_iterator->second)); - content::NotificationObserver* observer; - while ((observer = it.GetNext()) != NULL) { - observer->Observe(chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED, - content::Source<CrosSettings>(this), - content::Details<const std::string>(&path)); - } -} - } // namespace chromeos diff --git a/chrome/browser/chromeos/settings/cros_settings.h b/chrome/browser/chromeos/settings/cros_settings.h index 4148ee6..128184c 100644 --- a/chrome/browser/chromeos/settings/cros_settings.h +++ b/chrome/browser/chromeos/settings/cros_settings.h @@ -91,16 +91,12 @@ class CrosSettings : public base::NonThreadSafe { // Returns the provider that handles settings with the |path| or prefix. CrosSettingsProvider* GetProvider(const std::string& path) const; + // Forces all providers to reload their caches from the respective backing + // stores if they have any. + void ReloadProviders(); + private: friend struct base::DefaultLazyInstanceTraits<CrosSettings>; - friend class CrosSettingsTest; - - // Public for testing. - CrosSettings(); - ~CrosSettings(); - - // Fires system setting change notification. - void FireObservers(const std::string& path); // List of ChromeOS system settings providers. std::vector<CrosSettingsProvider*> providers_; @@ -113,6 +109,12 @@ class CrosSettings : public base::NonThreadSafe { SettingsObserverMap; SettingsObserverMap settings_observers_; + CrosSettings(); + ~CrosSettings(); + + // Fires system setting change notification. + void FireObservers(const std::string& path); + DISALLOW_COPY_AND_ASSIGN(CrosSettings); }; diff --git a/chrome/browser/chromeos/settings/cros_settings_provider.h b/chrome/browser/chromeos/settings/cros_settings_provider.h index 6196555..2477f34 100644 --- a/chrome/browser/chromeos/settings/cros_settings_provider.h +++ b/chrome/browser/chromeos/settings/cros_settings_provider.h @@ -58,6 +58,9 @@ class CrosSettingsProvider { // Gets the namespace prefix provided by this provider. virtual bool HandlesSetting(const std::string& path) const = 0; + // Reloads the caches if the provider has any. + virtual void Reload() = 0; + void SetNotifyObserversCallback(const NotifyObserversCallback& notify_cb); protected: diff --git a/chrome/browser/chromeos/settings/cros_settings_unittest.cc b/chrome/browser/chromeos/settings/cros_settings_unittest.cc index e3fc928..f5fb133 100644 --- a/chrome/browser/chromeos/settings/cros_settings_unittest.cc +++ b/chrome/browser/chromeos/settings/cros_settings_unittest.cc @@ -2,19 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/chromeos/settings/signed_settings.h" + #include <map> #include <string> #include "base/bind.h" -#include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/message_loop.h" #include "base/stl_util.h" #include "base/values.h" +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/login/mock_user_manager.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/cros_settings_names.h" -#include "chrome/browser/chromeos/settings/device_settings_test_helper.h" -#include "chrome/browser/policy/cloud_policy_constants.h" +#include "chrome/browser/chromeos/settings/signed_settings_cache.h" #include "chrome/browser/policy/proto/chrome_device_policy.pb.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "chrome/test/base/testing_browser_process.h" @@ -22,8 +24,10 @@ #include "content/public/test/test_browser_thread.h" #include "testing/gtest/include/gtest/gtest.h" -namespace em = enterprise_management; +using ::testing::AnyNumber; +using ::testing::Return; +namespace em = enterprise_management; namespace chromeos { class CrosSettingsTest : public testing::Test { @@ -31,15 +35,28 @@ class CrosSettingsTest : public testing::Test { CrosSettingsTest() : message_loop_(MessageLoop::TYPE_UI), ui_thread_(content::BrowserThread::UI, &message_loop_), - local_state_(static_cast<TestingBrowserProcess*>(g_browser_process)), - weak_factory_(this) {} + file_thread_(content::BrowserThread::FILE, &message_loop_), + pointer_factory_(this), + local_state_(static_cast<TestingBrowserProcess*>(g_browser_process)) { + } - virtual ~CrosSettingsTest() {} + virtual ~CrosSettingsTest() { + } + + virtual void SetUp() { + EXPECT_CALL(*mock_user_manager_.user_manager(), IsCurrentUserOwner()) + .Times(AnyNumber()) + .WillRepeatedly(Return(true)); + // Reset the cache between tests. + ApplyEmptyPolicy(); + } - virtual void TearDown() OVERRIDE { + virtual void TearDown() { + message_loop_.RunAllPending(); ASSERT_TRUE(expected_props_.empty()); + // Reset the cache between tests. + ApplyEmptyPolicy(); STLDeleteValues(&expected_props_); - expected_props_.clear(); } void FetchPref(const std::string& pref) { @@ -48,12 +65,12 @@ class CrosSettingsTest : public testing::Test { return; if (CrosSettingsProvider::TRUSTED == - settings_.PrepareTrustedValues( - base::Bind(&CrosSettingsTest::FetchPref, - weak_factory_.GetWeakPtr(), pref))) { + CrosSettings::Get()->PrepareTrustedValues( + base::Bind(&CrosSettingsTest::FetchPref, + pointer_factory_.GetWeakPtr(), pref))) { scoped_ptr<base::Value> expected_value( expected_props_.find(pref)->second); - const base::Value* pref_value = settings_.GetPref(pref); + const base::Value* pref_value = CrosSettings::Get()->GetPref(pref); if (expected_value.get()) { ASSERT_TRUE(pref_value); ASSERT_TRUE(expected_value->Equals(pref_value)); @@ -66,7 +83,7 @@ class CrosSettingsTest : public testing::Test { void SetPref(const std::string& pref_name, const base::Value* value) { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - settings_.Set(pref_name, *value); + CrosSettings::Get()->Set(pref_name, *value); } void AddExpectation(const std::string& pref_name, base::Value* value) { @@ -79,7 +96,7 @@ class CrosSettingsTest : public testing::Test { // Prepare some policy blob. em::PolicyFetchResponse response; em::ChromeDeviceSettingsProto pol; - policy->set_policy_type(policy::dm_protocol::kChromeDevicePolicyType); + policy->set_policy_type(chromeos::kDevicePolicyType); policy->set_username("me@owner"); policy->set_policy_value(pol.SerializeAsString()); // Wipe the signed settings store. @@ -87,16 +104,25 @@ class CrosSettingsTest : public testing::Test { response.set_policy_data_signature("false"); } + void ApplyEmptyPolicy() { + em::PolicyData fake_pol; + PrepareEmptyPolicy(&fake_pol); + signed_settings_cache::Store(fake_pol, local_state_.Get()); + CrosSettings::Get()->ReloadProviders(); + } + + std::map<std::string, base::Value*> expected_props_; + MessageLoop message_loop_; content::TestBrowserThread ui_thread_; + content::TestBrowserThread file_thread_; - ScopedTestingLocalState local_state_; - ScopedDeviceSettingsTestHelper device_settings_test_helper_; - CrosSettings settings_; + base::WeakPtrFactory<CrosSettingsTest> pointer_factory_; - base::WeakPtrFactory<CrosSettingsTest> weak_factory_; + ScopedTestingLocalState local_state_; - std::map<std::string, base::Value*> expected_props_; + ScopedMockUserManagerEnabler mock_user_manager_; + ScopedStubCrosEnabler stub_cros_enabler_; }; TEST_F(CrosSettingsTest, SetPref) { @@ -105,6 +131,7 @@ TEST_F(CrosSettingsTest, SetPref) { base::Value::CreateBooleanValue(false)); SetPref(kAccountsPrefAllowGuest, expected_props_[kAccountsPrefAllowGuest]); FetchPref(kAccountsPrefAllowGuest); + message_loop_.RunAllPending(); ASSERT_TRUE(expected_props_.empty()); } @@ -136,7 +163,7 @@ TEST_F(CrosSettingsTest, SetWhitelistWithListOps) { base::Value::CreateBooleanValue(false)); AddExpectation(kAccountsPrefUsers, whitelist); // Add some user to the whitelist. - settings_.AppendToList(kAccountsPrefUsers, &hacky_user); + CrosSettings::Get()->AppendToList(kAccountsPrefUsers, &hacky_user); FetchPref(kAccountsPrefAllowNewUser); FetchPref(kAccountsPrefUsers); } @@ -154,10 +181,11 @@ TEST_F(CrosSettingsTest, SetWhitelistWithListOps2) { SetPref(kAccountsPrefUsers, &whitelist); FetchPref(kAccountsPrefAllowNewUser); FetchPref(kAccountsPrefUsers); + message_loop_.RunAllPending(); ASSERT_TRUE(expected_props_.empty()); // Now try to remove one element from that list. AddExpectation(kAccountsPrefUsers, expected_list); - settings_.RemoveFromList(kAccountsPrefUsers, &lamy_user); + CrosSettings::Get()->RemoveFromList(kAccountsPrefUsers, &lamy_user); FetchPref(kAccountsPrefAllowNewUser); FetchPref(kAccountsPrefUsers); } @@ -199,6 +227,13 @@ TEST_F(CrosSettingsTest, SetAllowNewUsers) { FetchPref(kAccountsPrefAllowNewUser); } +TEST_F(CrosSettingsTest, SetOwner) { + base::StringValue hacky_owner("h@xxor"); + AddExpectation(kDeviceOwner, base::Value::CreateStringValue("h@xxor")); + SetPref(kDeviceOwner, &hacky_owner); + FetchPref(kDeviceOwner); +} + TEST_F(CrosSettingsTest, SetEphemeralUsersEnabled) { base::FundamentalValue ephemeral_users_enabled(true); AddExpectation(kAccountsPrefEphemeralUsersEnabled, @@ -214,7 +249,7 @@ TEST_F(CrosSettingsTest, FindEmailInList) { list.Append(base::Value::CreateStringValue("with.dots@gmail.com")); list.Append(base::Value::CreateStringValue("Upper@example.com")); - CrosSettings* cs = &settings_; + CrosSettings* cs = CrosSettings::Get(); cs->Set(kAccountsPrefUsers, list); EXPECT_TRUE(cs->FindEmailInList(kAccountsPrefUsers, "user@example.com")); diff --git a/chrome/browser/chromeos/settings/device_settings_cache.cc b/chrome/browser/chromeos/settings/device_settings_cache.cc deleted file mode 100644 index 178cbfb..0000000 --- a/chrome/browser/chromeos/settings/device_settings_cache.cc +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/chromeos/settings/device_settings_cache.h" - -#include <string> - -#include "base/base64.h" -#include "base/bind.h" -#include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/policy/proto/device_management_backend.pb.h" -#include "chrome/browser/prefs/pref_service.h" -#include "chrome/common/pref_names.h" - -namespace em = enterprise_management; - -namespace chromeos { - -namespace device_settings_cache { - -void RegisterPrefs(PrefService* local_state) { - local_state->RegisterStringPref(prefs::kDeviceSettingsCache, - "invalid", - PrefService::UNSYNCABLE_PREF); -} - -bool Store(const em::PolicyData& policy, PrefService* local_state) { - if (local_state) { - std::string policy_string = policy.SerializeAsString(); - std::string encoded; - if (!base::Base64Encode(policy_string, &encoded)) { - LOG(ERROR) << "Can't encode policy in base64."; - return false; - } - local_state->SetString(prefs::kDeviceSettingsCache, encoded); - return true; - } - return false; -} - -bool Retrieve(em::PolicyData *policy, PrefService* local_state) { - if (local_state) { - std::string encoded = - local_state->GetString(prefs::kDeviceSettingsCache); - std::string policy_string; - if (!base::Base64Decode(encoded, &policy_string)) { - // This is normal and happens on first boot. - VLOG(1) << "Can't decode policy from base64."; - return false; - } - return policy->ParseFromString(policy_string); - } - return false; -} - -} // namespace device_settings_cache - -} // namespace chromeos diff --git a/chrome/browser/chromeos/settings/device_settings_provider.cc b/chrome/browser/chromeos/settings/device_settings_provider.cc index 1a6b56b..ed03b55 100644 --- a/chrome/browser/chromeos/settings/device_settings_provider.cc +++ b/chrome/browser/chromeos/settings/device_settings_provider.cc @@ -15,15 +15,19 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/cros/network_library.h" +#include "chrome/browser/chromeos/login/user_manager.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/cros_settings_names.h" -#include "chrome/browser/chromeos/settings/device_settings_cache.h" +#include "chrome/browser/chromeos/settings/signed_settings_cache.h" +#include "chrome/browser/chromeos/settings/signed_settings_helper.h" #include "chrome/browser/policy/app_pack_updater.h" #include "chrome/browser/policy/browser_policy_connector.h" #include "chrome/browser/policy/cloud_policy_constants.h" -#include "chrome/browser/policy/proto/device_management_backend.pb.h" +#include "chrome/browser/policy/proto/chrome_device_policy.pb.h" #include "chrome/browser/ui/options/options_util.h" +#include "chrome/common/chrome_notification_types.h" #include "chrome/installer/util/google_update_settings.h" +#include "content/public/browser/notification_service.h" using google::protobuf::RepeatedPtrField; @@ -60,6 +64,9 @@ const char* kKnownSettings[] = { kSystemTimezonePolicy, }; +// Upper bound for number of retries to fetch a signed setting. +static const int kNumRetriesLimit = 9; + // Legacy policy file location. Used to detect migration from pre v12 ChromeOS. const char kLegacyPolicyFile[] = "/var/lib/whitelist/preferences"; @@ -81,30 +88,43 @@ bool HasOldMetricsFile() { DeviceSettingsProvider::DeviceSettingsProvider( const NotifyObserversCallback& notify_cb, - DeviceSettingsService* device_settings_service) + SignedSettingsHelper* signed_settings_helper) : CrosSettingsProvider(notify_cb), - device_settings_service_(device_settings_service), - trusted_status_(TEMPORARILY_UNTRUSTED), - ownership_status_(device_settings_service_->GetOwnershipStatus()), - ALLOW_THIS_IN_INITIALIZER_LIST(store_callback_factory_(this)) { - device_settings_service_->AddObserver(this); - - if (!UpdateFromService()) { - // Make sure we have at least the cache data immediately. - RetrieveCachedData(); - } + signed_settings_helper_(signed_settings_helper), + ownership_status_(OwnershipService::GetSharedInstance()->GetStatus(true)), + migration_helper_(new SignedSettingsMigrationHelper()), + retries_left_(kNumRetriesLimit), + trusted_status_(TEMPORARILY_UNTRUSTED) { + // Register for notification when ownership is taken so that we can update + // the |ownership_status_| and reload if needed. + registrar_.Add(this, chrome::NOTIFICATION_OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED, + content::NotificationService::AllSources()); + // Make sure we have at least the cache data immediately. + RetrieveCachedData(); + // Start prefetching preferences. + Reload(); } DeviceSettingsProvider::~DeviceSettingsProvider() { - device_settings_service_->RemoveObserver(this); +} + +void DeviceSettingsProvider::Reload() { + // While fetching we can't trust the cache anymore. + trusted_status_ = TEMPORARILY_UNTRUSTED; + if (ownership_status_ == OwnershipService::OWNERSHIP_NONE) { + RetrieveCachedData(); + } else { + // Retrieve the real data. + signed_settings_helper_->StartRetrievePolicyOp( + base::Bind(&DeviceSettingsProvider::OnRetrievePolicyCompleted, + base::Unretained(this))); + } } void DeviceSettingsProvider::DoSet(const std::string& path, const base::Value& in_value) { - // Make sure that either the current user is the device owner or the - // device doesn't have an owner yet. - if (!(device_settings_service_->HasPrivateOwnerKey() || - ownership_status_ == DeviceSettingsService::OWNERSHIP_NONE)) { + if (!UserManager::Get()->IsCurrentUserOwner() && + ownership_status_ != OwnershipService::OWNERSHIP_NONE) { LOG(WARNING) << "Changing settings from non-owner, setting=" << path; // Revert UI change. @@ -114,60 +134,43 @@ void DeviceSettingsProvider::DoSet(const std::string& path, if (IsControlledSetting(path)) { pending_changes_.push_back(PendingQueueElement(path, in_value.DeepCopy())); - if (!store_callback_factory_.HasWeakPtrs()) + if (pending_changes_.size() == 1) SetInPolicy(); } else { NOTREACHED() << "Try to set unhandled cros setting " << path; } } -void DeviceSettingsProvider::OwnershipStatusChanged() { - DeviceSettingsService::OwnershipStatus new_ownership_status = - device_settings_service_->GetOwnershipStatus(); - - // If the device just became owned, write the settings accumulated in the - // cache to device settings proper. It is important that writing only happens - // in this case, as during normal operation, the contents of the cache should - // never overwrite actual device settings. - if (new_ownership_status == DeviceSettingsService::OWNERSHIP_TAKEN && - ownership_status_ == DeviceSettingsService::OWNERSHIP_NONE && - device_settings_service_->HasPrivateOwnerKey()) { - - // There shouldn't be any pending writes, since the cache writes are all - // immediate. - DCHECK(!store_callback_factory_.HasWeakPtrs()); - - // Apply the locally-accumulated device settings on top of the initial - // settings from the service and write back the result. - if (device_settings_service_->device_settings()) { - em::ChromeDeviceSettingsProto new_settings( - *device_settings_service_->device_settings()); - new_settings.MergeFrom(device_settings_); - device_settings_.Swap(&new_settings); - } - StoreDeviceSettings(); +void DeviceSettingsProvider::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + if (type == chrome::NOTIFICATION_OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED) { + // Reload the policy blob once the owner key has been loaded or updated. + ownership_status_ = OwnershipService::OWNERSHIP_TAKEN; + Reload(); } - - // The owner key might have become available, allowing migration to happen. - AttemptMigration(); - - ownership_status_ = new_ownership_status; } -void DeviceSettingsProvider::DeviceSettingsUpdated() { - if (!store_callback_factory_.HasWeakPtrs()) - UpdateAndProceedStoring(); +const em::PolicyData DeviceSettingsProvider::policy() const { + return policy_; } void DeviceSettingsProvider::RetrieveCachedData() { - em::PolicyData policy_data; - if (!device_settings_cache::Retrieve(&policy_data, - g_browser_process->local_state()) || - !device_settings_.ParseFromString(policy_data.policy_value())) { - VLOG(1) << "Can't retrieve temp store, possibly not created yet."; + // If there is no owner yet, this function will pull the policy cache from the + // temp storage and use that instead. + em::PolicyData policy; + if (!signed_settings_cache::Retrieve(&policy, + g_browser_process->local_state())) { + VLOG(1) << "Can't retrieve temp store possibly not created yet."; + // Prepare empty data for the case we don't have temp cache yet. + policy.set_policy_type(kDevicePolicyType); + em::ChromeDeviceSettingsProto pol; + policy.set_policy_value(pol.SerializeAsString()); } - UpdateValuesCache(policy_data, device_settings_); + policy_ = policy; + UpdateValuesCache(); } void DeviceSettingsProvider::SetInPolicy() { @@ -176,44 +179,62 @@ void DeviceSettingsProvider::SetInPolicy() { return; } - if (RequestTrustedEntity() != TRUSTED) { - // Re-sync device settings before proceeding. - device_settings_service_->Load(); + const std::string& prop = pending_changes_[0].first; + base::Value* value = pending_changes_[0].second; + if (prop == kDeviceOwner) { + // Just store it in the memory cache without trusted checks or persisting. + std::string owner; + if (value->GetAsString(&owner)) { + policy_.set_username(owner); + // In this case the |value_cache_| takes the ownership of |value|. + values_cache_.SetValue(prop, value); + NotifyObservers(prop); + // We can't trust this value anymore until we reload the real username. + trusted_status_ = TEMPORARILY_UNTRUSTED; + pending_changes_.erase(pending_changes_.begin()); + if (!pending_changes_.empty()) + SetInPolicy(); + } else { + NOTREACHED(); + } return; } - std::string prop(pending_changes_.front().first); - scoped_ptr<base::Value> value(pending_changes_.front().second); - pending_changes_.pop_front(); + if (RequestTrustedEntity() != TRUSTED) { + // Otherwise we should first reload and apply on top of that. + signed_settings_helper_->StartRetrievePolicyOp( + base::Bind(&DeviceSettingsProvider::FinishSetInPolicy, + base::Unretained(this))); + return; + } trusted_status_ = TEMPORARILY_UNTRUSTED; + em::PolicyData data = policy(); + em::ChromeDeviceSettingsProto pol; + pol.ParseFromString(data.policy_value()); if (prop == kAccountsPrefAllowNewUser) { - em::AllowNewUsersProto* allow = - device_settings_.mutable_allow_new_users(); + em::AllowNewUsersProto* allow = pol.mutable_allow_new_users(); bool allow_value; if (value->GetAsBoolean(&allow_value)) allow->set_allow_new_users(allow_value); else NOTREACHED(); } else if (prop == kAccountsPrefAllowGuest) { - em::GuestModeEnabledProto* guest = - device_settings_.mutable_guest_mode_enabled(); + em::GuestModeEnabledProto* guest = pol.mutable_guest_mode_enabled(); bool guest_value; if (value->GetAsBoolean(&guest_value)) guest->set_guest_mode_enabled(guest_value); else NOTREACHED(); } else if (prop == kAccountsPrefShowUserNamesOnSignIn) { - em::ShowUserNamesOnSigninProto* show = - device_settings_.mutable_show_user_names(); + em::ShowUserNamesOnSigninProto* show = pol.mutable_show_user_names(); bool show_value; if (value->GetAsBoolean(&show_value)) show->set_show_user_names(show_value); else NOTREACHED(); } else if (prop == kSignedDataRoamingEnabled) { - em::DataRoamingEnabledProto* roam = - device_settings_.mutable_data_roaming_enabled(); + em::DataRoamingEnabledProto* roam = pol.mutable_data_roaming_enabled(); bool roaming_value = false; if (value->GetAsBoolean(&roaming_value)) roam->set_data_roaming_enabled(roaming_value); @@ -225,23 +246,20 @@ void DeviceSettingsProvider::SetInPolicy() { std::string proxy_value; if (value->GetAsString(&proxy_value)) { bool success = - device_settings_.mutable_device_proxy_settings()->ParseFromString( - proxy_value); + pol.mutable_device_proxy_settings()->ParseFromString(proxy_value); DCHECK(success); } else { NOTREACHED(); } } else if (prop == kReleaseChannel) { - em::ReleaseChannelProto* release_channel = - device_settings_.mutable_release_channel(); + em::ReleaseChannelProto* release_channel = pol.mutable_release_channel(); std::string channel_value; if (value->GetAsString(&channel_value)) release_channel->set_release_channel(channel_value); else NOTREACHED(); } else if (prop == kStatsReportingPref) { - em::MetricsEnabledProto* metrics = - device_settings_.mutable_metrics_enabled(); + em::MetricsEnabledProto* metrics = pol.mutable_metrics_enabled(); bool metrics_value = false; if (value->GetAsBoolean(&metrics_value)) metrics->set_metrics_enabled(metrics_value); @@ -249,8 +267,7 @@ void DeviceSettingsProvider::SetInPolicy() { NOTREACHED(); ApplyMetricsSetting(false, metrics_value); } else if (prop == kAccountsPrefUsers) { - em::UserWhitelistProto* whitelist_proto = - device_settings_.mutable_user_whitelist(); + em::UserWhitelistProto* whitelist_proto = pol.mutable_user_whitelist(); whitelist_proto->clear_user_whitelist(); base::ListValue& users = static_cast<base::ListValue&>(*value); for (base::ListValue::const_iterator i = users.begin(); @@ -261,19 +278,17 @@ void DeviceSettingsProvider::SetInPolicy() { } } else if (prop == kAccountsPrefEphemeralUsersEnabled) { em::EphemeralUsersEnabledProto* ephemeral_users_enabled = - device_settings_.mutable_ephemeral_users_enabled(); + pol.mutable_ephemeral_users_enabled(); bool ephemeral_users_enabled_value = false; - if (value->GetAsBoolean(&ephemeral_users_enabled_value)) { + if (value->GetAsBoolean(&ephemeral_users_enabled_value)) ephemeral_users_enabled->set_ephemeral_users_enabled( ephemeral_users_enabled_value); - } else { + else NOTREACHED(); - } } else { // The remaining settings don't support Set(), since they are not // intended to be customizable by the user: // kAppPack - // kDeviceOwner // kIdleLogoutTimeout // kIdleLogoutWarningDuration // kReleaseChannelDelegated @@ -286,29 +301,48 @@ void DeviceSettingsProvider::SetInPolicy() { // kStartUpUrls // kSystemTimezonePolicy - LOG(FATAL) << "Device setting " << prop << " is read-only."; + NOTREACHED(); } - - em::PolicyData data; - data.set_username(device_settings_service_->GetUsername()); - CHECK(device_settings_.SerializeToString(data.mutable_policy_value())); - + data.set_policy_value(pol.SerializeAsString()); // Set the cache to the updated value. - UpdateValuesCache(data, device_settings_); + policy_ = data; + UpdateValuesCache(); - if (!device_settings_cache::Store(data, g_browser_process->local_state())) + if (!signed_settings_cache::Store(data, g_browser_process->local_state())) LOG(ERROR) << "Couldn't store to the temp storage."; - if (ownership_status_ == DeviceSettingsService::OWNERSHIP_TAKEN) { - StoreDeviceSettings(); + if (ownership_status_ == OwnershipService::OWNERSHIP_TAKEN) { + em::PolicyFetchResponse policy_envelope; + policy_envelope.set_policy_data(policy_.SerializeAsString()); + signed_settings_helper_->StartStorePolicyOp( + policy_envelope, + base::Bind(&DeviceSettingsProvider::OnStorePolicyCompleted, + base::Unretained(this))); } else { // OnStorePolicyCompleted won't get called in this case so proceed with any // pending operations immediately. + delete pending_changes_[0].second; + pending_changes_.erase(pending_changes_.begin()); if (!pending_changes_.empty()) SetInPolicy(); } } +void DeviceSettingsProvider::FinishSetInPolicy( + SignedSettings::ReturnCode code, + const em::PolicyFetchResponse& policy) { + if (code != SignedSettings::SUCCESS) { + LOG(ERROR) << "Can't serialize to policy error code: " << code; + Reload(); + return; + } + // Update the internal caches and set the trusted flag to true so that we + // can pass the trustedness check in the second call to SetInPolicy. + OnRetrievePolicyCompleted(code, policy); + + SetInPolicy(); +} + void DeviceSettingsProvider::DecodeLoginPolicies( const em::ChromeDeviceSettingsProto& policy, PrefValueMap* new_values_cache) const { @@ -504,19 +538,21 @@ void DeviceSettingsProvider::DecodeGenericPolicies( } } -void DeviceSettingsProvider::UpdateValuesCache( - const em::PolicyData& policy_data, - const em::ChromeDeviceSettingsProto& settings) { +void DeviceSettingsProvider::UpdateValuesCache() { + const em::PolicyData data = policy(); PrefValueMap new_values_cache; - if (policy_data.has_username() && !policy_data.has_request_token()) - new_values_cache.SetString(kDeviceOwner, policy_data.username()); + if (data.has_username() && !data.has_request_token()) + new_values_cache.SetString(kDeviceOwner, data.username()); - DecodeLoginPolicies(settings, &new_values_cache); - DecodeKioskPolicies(settings, &new_values_cache); - DecodeNetworkPolicies(settings, &new_values_cache); - DecodeReportingPolicies(settings, &new_values_cache); - DecodeGenericPolicies(settings, &new_values_cache); + em::ChromeDeviceSettingsProto pol; + pol.ParseFromString(data.policy_value()); + + DecodeLoginPolicies(pol, &new_values_cache); + DecodeKioskPolicies(pol, &new_values_cache); + DecodeNetworkPolicies(pol, &new_values_cache); + DecodeReportingPolicies(pol, &new_values_cache); + DecodeGenericPolicies(pol, &new_values_cache); // Collect all notifications but send them only after we have swapped the // cache so that if somebody actually reads the cache will be already valid. @@ -543,18 +579,18 @@ void DeviceSettingsProvider::UpdateValuesCache( } void DeviceSettingsProvider::ApplyMetricsSetting(bool use_file, - bool new_value) { + bool new_value) const { // TODO(pastarmovj): Remove this once migration is not needed anymore. // If the value is not set we should try to migrate legacy consent file. if (use_file) { new_value = HasOldMetricsFile(); // Make sure the values will get eventually written to the policy file. - migration_values_.SetValue(kStatsReportingPref, - base::Value::CreateBooleanValue(new_value)); - AttemptMigration(); + migration_helper_->AddMigrationValue( + kStatsReportingPref, base::Value::CreateBooleanValue(new_value)); + migration_helper_->MigrateValues(); LOG(INFO) << "No metrics policy set will revert to checking " - << "consent file which is " - << (new_value ? "on." : "off."); + << "consent file which is " + << (new_value ? "on." : "off."); } VLOG(1) << "Metrics policy is being set to : " << new_value << "(use file : " << use_file << ")"; @@ -563,7 +599,7 @@ void DeviceSettingsProvider::ApplyMetricsSetting(bool use_file, OptionsUtil::ResolveMetricsReportingEnabled(new_value); } -void DeviceSettingsProvider::ApplyRoamingSetting(bool new_value) { +void DeviceSettingsProvider::ApplyRoamingSetting(bool new_value) const { NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); const NetworkDevice* cellular = cros->FindCellularDevice(); if (cellular) { @@ -578,26 +614,25 @@ void DeviceSettingsProvider::ApplyRoamingSetting(bool new_value) { } } -void DeviceSettingsProvider::ApplySideEffects( - const em::ChromeDeviceSettingsProto& settings) { +void DeviceSettingsProvider::ApplySideEffects() const { + const em::PolicyData data = policy(); + em::ChromeDeviceSettingsProto pol; + pol.ParseFromString(data.policy_value()); // First migrate metrics settings as needed. - if (settings.has_metrics_enabled()) - ApplyMetricsSetting(false, settings.metrics_enabled().metrics_enabled()); + if (pol.has_metrics_enabled()) + ApplyMetricsSetting(false, pol.metrics_enabled().metrics_enabled()); else ApplyMetricsSetting(true, false); - // Next set the roaming setting as needed. - ApplyRoamingSetting( - settings.has_data_roaming_enabled() ? - settings.data_roaming_enabled().data_roaming_enabled() : - false); + ApplyRoamingSetting(pol.has_data_roaming_enabled() ? + pol.data_roaming_enabled().data_roaming_enabled() : false); } bool DeviceSettingsProvider::MitigateMissingPolicy() { // First check if the device has been owned already and if not exit // immediately. if (g_browser_process->browser_policy_connector()->GetDeviceMode() != - policy::DEVICE_MODE_CONSUMER) { + policy::DEVICE_MODE_CONSUMER) { return false; } @@ -610,15 +645,17 @@ bool DeviceSettingsProvider::MitigateMissingPolicy() { LOG(ERROR) << "Corruption of the policy data has been detected." << "Switching to \"safe-mode\" policies until the owner logs in " << "to regenerate the policy data."; - - device_settings_.Clear(); - device_settings_.mutable_allow_new_users()->set_allow_new_users(true); - device_settings_.mutable_guest_mode_enabled()->set_guest_mode_enabled(true); - em::PolicyData empty_policy_data; - UpdateValuesCache(empty_policy_data, device_settings_); + values_cache_.SetBoolean(kAccountsPrefAllowNewUser, true); + values_cache_.SetBoolean(kAccountsPrefAllowGuest, true); values_cache_.SetBoolean(kPolicyMissingMitigationMode, true); trusted_status_ = TRUSTED; - + // Make sure we will recreate the policy once the owner logs in. + // Any value not in this list will be left to the default which is fine as + // we repopulate the whitelist with the owner and all other existing users + // every time the owner enables whitelist filtering on the UI. + migration_helper_->AddMigrationValue( + kAccountsPrefAllowNewUser, base::Value::CreateBooleanValue(true)); + migration_helper_->MigrateValues(); return true; } @@ -648,93 +685,83 @@ bool DeviceSettingsProvider::HandlesSetting(const std::string& path) const { DeviceSettingsProvider::TrustedStatus DeviceSettingsProvider::RequestTrustedEntity() { - if (ownership_status_ == DeviceSettingsService::OWNERSHIP_NONE) + if (ownership_status_ == OwnershipService::OWNERSHIP_NONE) return TRUSTED; return trusted_status_; } -void DeviceSettingsProvider::UpdateAndProceedStoring() { - // Re-sync the cache from the service. - UpdateFromService(); +void DeviceSettingsProvider::OnStorePolicyCompleted( + SignedSettings::ReturnCode code) { + // In any case reload the policy cache to now. + if (code != SignedSettings::SUCCESS) { + Reload(); + } else { + trusted_status_ = TRUSTED; + // TODO(pastarmovj): Make those side effects responsibility of the + // respective subsystems. + ApplySideEffects(); + // Notify the observers we are done. + std::vector<base::Closure> callbacks; + callbacks.swap(callbacks_); + for (size_t i = 0; i < callbacks.size(); ++i) + callbacks[i].Run(); + } - // Trigger the next change if necessary. - if (trusted_status_ == TRUSTED && - !store_callback_factory_.HasWeakPtrs() && - !pending_changes_.empty()) { + // Clear the finished task and proceed with any other stores that could be + // pending by now. + delete pending_changes_[0].second; + pending_changes_.erase(pending_changes_.begin()); + if (!pending_changes_.empty()) SetInPolicy(); - } } -bool DeviceSettingsProvider::UpdateFromService() { - bool settings_loaded = false; - switch (device_settings_service_->status()) { - case DeviceSettingsService::STORE_SUCCESS: { - const em::PolicyData* policy_data = - device_settings_service_->policy_data(); - const em::ChromeDeviceSettingsProto* device_settings = - device_settings_service_->device_settings(); - if (policy_data && device_settings) { - UpdateValuesCache(*policy_data, *device_settings); - device_settings_ = *device_settings; - trusted_status_ = TRUSTED; - - // TODO(pastarmovj): Make those side effects responsibility of the - // respective subsystems. - ApplySideEffects(*device_settings); - - settings_loaded = true; - } else { - // Initial policy load is still pending. - trusted_status_ = TEMPORARILY_UNTRUSTED; - } +void DeviceSettingsProvider::OnRetrievePolicyCompleted( + SignedSettings::ReturnCode code, + const em::PolicyFetchResponse& policy_data) { + VLOG(1) << "OnRetrievePolicyCompleted. Error code: " << code + << ", trusted status : " << trusted_status_ + << ", ownership status : " << ownership_status_; + switch (code) { + case SignedSettings::SUCCESS: { + DCHECK(policy_data.has_policy_data()); + policy_.ParseFromString(policy_data.policy_data()); + signed_settings_cache::Store(policy(), + g_browser_process->local_state()); + UpdateValuesCache(); + trusted_status_ = TRUSTED; + // TODO(pastarmovj): Make those side effects responsibility of the + // respective subsystems. + ApplySideEffects(); break; } - case DeviceSettingsService::STORE_NO_POLICY: + case SignedSettings::NOT_FOUND: if (MitigateMissingPolicy()) break; - // fall through. - case DeviceSettingsService::STORE_KEY_UNAVAILABLE: - VLOG(1) << "No policies present yet, will use the temp storage."; + case SignedSettings::KEY_UNAVAILABLE: { + if (ownership_status_ != OwnershipService::OWNERSHIP_TAKEN) + NOTREACHED() << "No policies present yet, will use the temp storage."; trusted_status_ = PERMANENTLY_UNTRUSTED; break; - case DeviceSettingsService::STORE_POLICY_ERROR: - case DeviceSettingsService::STORE_VALIDATION_ERROR: - case DeviceSettingsService::STORE_INVALID_POLICY: - case DeviceSettingsService::STORE_OPERATION_FAILED: - LOG(ERROR) << "Failed to retrieve cros policies. Reason: " - << device_settings_service_->status(); + } + case SignedSettings::BAD_SIGNATURE: + case SignedSettings::OPERATION_FAILED: { + LOG(ERROR) << "Failed to retrieve cros policies. Reason:" << code; + if (retries_left_ > 0) { + trusted_status_ = TEMPORARILY_UNTRUSTED; + retries_left_ -= 1; + Reload(); + return; + } + LOG(ERROR) << "No retries left"; trusted_status_ = PERMANENTLY_UNTRUSTED; break; + } } - // Notify the observers we are done. std::vector<base::Closure> callbacks; callbacks.swap(callbacks_); for (size_t i = 0; i < callbacks.size(); ++i) callbacks[i].Run(); - - return settings_loaded; -} - -void DeviceSettingsProvider::StoreDeviceSettings() { - // Mute all previous callbacks to guarantee the |pending_changes_| queue is - // processed serially. - store_callback_factory_.InvalidateWeakPtrs(); - - device_settings_service_->SignAndStore( - scoped_ptr<em::ChromeDeviceSettingsProto>( - new em::ChromeDeviceSettingsProto(device_settings_)), - base::Bind(&DeviceSettingsProvider::UpdateAndProceedStoring, - store_callback_factory_.GetWeakPtr())); -} - -void DeviceSettingsProvider::AttemptMigration() { - if (device_settings_service_->HasPrivateOwnerKey()) { - PrefValueMap::const_iterator i; - for (i = migration_values_.begin(); i != migration_values_.end(); ++i) - DoSet(i->first, *i->second); - migration_values_.Clear(); - } } } // namespace chromeos diff --git a/chrome/browser/chromeos/settings/device_settings_provider.h b/chrome/browser/chromeos/settings/device_settings_provider.h index cf625df..03735b5 100644 --- a/chrome/browser/chromeos/settings/device_settings_provider.h +++ b/chrome/browser/chromeos/settings/device_settings_provider.h @@ -5,20 +5,18 @@ #ifndef CHROME_BROWSER_CHROMEOS_SETTINGS_DEVICE_SETTINGS_PROVIDER_H_ #define CHROME_BROWSER_CHROMEOS_SETTINGS_DEVICE_SETTINGS_PROVIDER_H_ -#include <deque> #include <string> #include <utility> #include <vector> #include "base/basictypes.h" #include "base/callback_forward.h" -#include "base/gtest_prod_util.h" -#include "base/memory/weak_ptr.h" #include "chrome/browser/chromeos/settings/cros_settings_provider.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" -#include "chrome/browser/policy/proto/chrome_device_policy.pb.h" -#include "chrome/browser/prefs/pref_value_map.h" +#include "chrome/browser/chromeos/settings/ownership_service.h" +#include "chrome/browser/chromeos/settings/signed_settings_migration_helper.h" +#include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "chrome/browser/prefs/pref_value_map.h" +#include "content/public/browser/notification_registrar.h" namespace base { class Value; @@ -30,12 +28,12 @@ class ChromeDeviceSettingsProto; namespace chromeos { -// CrosSettingsProvider implementation that works with device settings. +// CrosSettingsProvider implementation that works with SignedSettings. class DeviceSettingsProvider : public CrosSettingsProvider, - public DeviceSettingsService::Observer { + public content::NotificationObserver { public: DeviceSettingsProvider(const NotifyObserversCallback& notify_cb, - DeviceSettingsService* device_settings_service); + SignedSettingsHelper* signed_settings_helper); virtual ~DeviceSettingsProvider(); // CrosSettingsProvider implementation. @@ -43,26 +41,35 @@ class DeviceSettingsProvider : public CrosSettingsProvider, virtual TrustedStatus PrepareTrustedValues( const base::Closure& callback) OVERRIDE; virtual bool HandlesSetting(const std::string& path) const OVERRIDE; + virtual void Reload() OVERRIDE; private: // CrosSettingsProvider implementation: virtual void DoSet(const std::string& path, const base::Value& value) OVERRIDE; - // DeviceSettingsService::Observer implementation: - virtual void OwnershipStatusChanged() OVERRIDE; - virtual void DeviceSettingsUpdated() OVERRIDE; + // content::NotificationObserver implementation: + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + const enterprise_management::PolicyData policy() const; // Populates in-memory cache from the local_state cache that is used to store - // device settings before the device is owned and to speed up policy + // signed settings before the device is owned and to speed up policy // availability before the policy blob is fetched on boot. void RetrieveCachedData(); - // Stores a value from the |pending_changes_| queue in the device settings. + // Stores a value from the |pending_changes_| queue in the signed settings. // If the device is not owned yet the data ends up only in the local_state // cache and is serialized once ownership is acquired. void SetInPolicy(); + // Finalizes stores to the policy file if the cache is dirty. + void FinishSetInPolicy( + SignedSettings::ReturnCode code, + const enterprise_management::PolicyFetchResponse& policy); + // Decode the various groups of policies. void DecodeLoginPolicies( const enterprise_management::ChromeDeviceSettingsProto& policy, @@ -80,21 +87,18 @@ class DeviceSettingsProvider : public CrosSettingsProvider, const enterprise_management::ChromeDeviceSettingsProto& policy, PrefValueMap* new_values_cache) const; - // Parses the policy data and fills in |values_cache_|. - void UpdateValuesCache( - const enterprise_management::PolicyData& policy_data, - const enterprise_management::ChromeDeviceSettingsProto& settings); + // Parses the policy cache and fills the cache of base::Value objects. + void UpdateValuesCache(); // Applies the metrics policy and if not set migrates the legacy file. - void ApplyMetricsSetting(bool use_file, bool new_value); + void ApplyMetricsSetting(bool use_file, bool new_value) const; // Applies the data roaming policy. - void ApplyRoamingSetting(bool new_value); + void ApplyRoamingSetting(bool new_value) const; // Applies any changes of the policies that are not handled by the respective // subsystems. - void ApplySideEffects( - const enterprise_management::ChromeDeviceSettingsProto& settings); + void ApplySideEffects() const; // In case of missing policy blob we should verify if this is upgrade of // machine owned from pre version 12 OS and the user never touched the device @@ -102,55 +106,58 @@ class DeviceSettingsProvider : public CrosSettingsProvider, // comes and changes that. bool MitigateMissingPolicy(); + // Called right before boolean property is changed. + void OnBooleanPropertyChange(const std::string& path, bool new_value); + // Checks if the current cache value can be trusted for being representative // for the disk cache. TrustedStatus RequestTrustedEntity(); - // Invokes UpdateFromService() to synchronize with |device_settings_service_|, - // then triggers the next store operation if applicable. - void UpdateAndProceedStoring(); - - // Re-reads state from |device_settings_service_|, adjusts - // |trusted_status_| and calls UpdateValuesCache() if applicable. Returns true - // if new settings have been loaded. - bool UpdateFromService(); - - // Sends |device_settings_| to |device_settings_service_| for signing and - // storage in session_manager. - void StoreDeviceSettings(); - - // Checks the current ownership status to see whether the device owner is - // logged in and writes the data accumulated in |migration_values_| to proper - // device settings. - void AttemptMigration(); + // Called right after signed value was checked. + void OnPropertyRetrieve(const std::string& path, + const base::Value* value, + bool use_default_value); + + // Callback of StorePolicyOp for ordinary policy stores. + void OnStorePolicyCompleted(SignedSettings::ReturnCode code); + + // Callback of RetrievePolicyOp for ordinary policy [re]loads. + void OnRetrievePolicyCompleted( + SignedSettings::ReturnCode code, + const enterprise_management::PolicyFetchResponse& policy); + + // These setters are for test use only. + void set_ownership_status(OwnershipService::Status status) { + ownership_status_ = status; + } + void set_trusted_status(TrustedStatus status) { + trusted_status_ = status; + } + void set_retries_left(int retries) { + retries_left_ = retries; + } // Pending callbacks that need to be invoked after settings verification. std::vector<base::Closure> callbacks_; - DeviceSettingsService* device_settings_service_; - mutable PrefValueMap migration_values_; + SignedSettingsHelper* signed_settings_helper_; + OwnershipService::Status ownership_status_; + mutable scoped_ptr<SignedSettingsMigrationHelper> migration_helper_; + + content::NotificationRegistrar registrar_; + + // In order to guard against occasional failure to fetch a property + // we allow for some number of retries. + int retries_left_; + enterprise_management::PolicyData policy_; TrustedStatus trusted_status_; - DeviceSettingsService::OwnershipStatus ownership_status_; - - // The device settings as currently reported through the CrosSettingsProvider - // interface. This may be different from the actual current device settings - // (which can be obtained from |device_settings_service_|) in case the device - // does not have an owner yet or there are pending changes that have not yet - // been written to session_manager. - enterprise_management::ChromeDeviceSettingsProto device_settings_; - - // A cache of values, indexed by the settings keys served through the - // CrosSettingsProvider interface. This is always kept in sync with the raw - // data found in |device_settings_|. + PrefValueMap values_cache_; // This is a queue for set requests, because those need to be sequential. typedef std::pair<std::string, base::Value*> PendingQueueElement; - std::deque<PendingQueueElement> pending_changes_; - - // Weak pointer factory for creating store operation callbacks. - base::WeakPtrFactory<DeviceSettingsProvider> store_callback_factory_; + std::vector<PendingQueueElement> pending_changes_; friend class DeviceSettingsProviderTest; FRIEND_TEST_ALL_PREFIXES(DeviceSettingsProviderTest, diff --git a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc index 8943eee3e..e05c24c 100644 --- a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc +++ b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc @@ -7,14 +7,13 @@ #include <string> #include "base/bind.h" -#include "base/callback.h" #include "base/message_loop.h" #include "base/values.h" #include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/login/mock_user_manager.h" #include "chrome/browser/chromeos/settings/cros_settings_names.h" -#include "chrome/browser/chromeos/settings/device_settings_test_helper.h" -#include "chrome/browser/chromeos/settings/mock_owner_key_util.h" -#include "chrome/browser/policy/policy_builder.h" +#include "chrome/browser/chromeos/settings/mock_signed_settings_helper.h" +#include "chrome/browser/chromeos/settings/ownership_service.h" #include "chrome/browser/policy/proto/chrome_device_policy.pb.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "chrome/test/base/testing_browser_process.h" @@ -24,82 +23,96 @@ #include "testing/gtest/include/gtest/gtest.h" namespace em = enterprise_management; - namespace chromeos { using ::testing::AnyNumber; using ::testing::Mock; +using ::testing::Return; +using ::testing::SaveArg; using ::testing::_; class DeviceSettingsProviderTest: public testing::Test { - public: +public: MOCK_METHOD1(SettingChanged, void(const std::string&)); MOCK_METHOD0(GetTrustedCallback, void(void)); - protected: +protected: DeviceSettingsProviderTest() : message_loop_(MessageLoop::TYPE_UI), ui_thread_(content::BrowserThread::UI, &message_loop_), file_thread_(content::BrowserThread::FILE, &message_loop_), - local_state_(static_cast<TestingBrowserProcess*>(g_browser_process)), - owner_key_util_(new MockOwnerKeyUtil()) {} + local_state_(static_cast<TestingBrowserProcess*>(g_browser_process)) { + } + + virtual ~DeviceSettingsProviderTest() { + } virtual void SetUp() OVERRIDE { - policy_.payload().mutable_metrics_enabled()->set_metrics_enabled(false); - policy_.Build(); + PrepareEmptyPolicy(); - device_settings_test_helper_.set_policy_blob(policy_.GetBlob()); + EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)) + .WillRepeatedly( + MockSignedSettingsHelperRetrievePolicy(SignedSettings::SUCCESS, + policy_blob_)); + EXPECT_CALL(signed_settings_helper_, StartStorePolicyOp(_,_)) + .WillRepeatedly(DoAll( + SaveArg<0>(&policy_blob_), + MockSignedSettingsHelperStorePolicy(SignedSettings::SUCCESS))); - device_settings_service_.Initialize(&device_settings_test_helper_, - owner_key_util_); + EXPECT_CALL(*mock_user_manager_.user_manager(), IsCurrentUserOwner()) + .WillRepeatedly(Return(true)); EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); provider_.reset( new DeviceSettingsProvider( base::Bind(&DeviceSettingsProviderTest::SettingChanged, base::Unretained(this)), - &device_settings_service_)); + &signed_settings_helper_)); + provider_->set_ownership_status(OwnershipService::OWNERSHIP_TAKEN); + + // To prevent flooding the logs. + provider_->set_retries_left(1); + provider_->Reload(); Mock::VerifyAndClearExpectations(this); } - virtual void TearDown() OVERRIDE { - device_settings_service_.Shutdown(); + void PrepareEmptyPolicy() { + em::PolicyData policy; + em::ChromeDeviceSettingsProto pol; + // Set metrics to disabled to prevent us from running into code that is not + // mocked. + pol.mutable_metrics_enabled()->set_metrics_enabled(false); + policy.set_policy_type(chromeos::kDevicePolicyType); + policy.set_username("me@owner"); + policy.set_policy_value(pol.SerializeAsString()); + // Wipe the signed settings store. + policy_blob_.set_policy_data(policy.SerializeAsString()); + policy_blob_.set_policy_data_signature("false"); } + em::PolicyFetchResponse policy_blob_; + + scoped_ptr<DeviceSettingsProvider> provider_; + MessageLoop message_loop_; content::TestBrowserThread ui_thread_; content::TestBrowserThread file_thread_; - ScopedStubCrosEnabler stub_cros_enabler_; - ScopedTestingLocalState local_state_; - DeviceSettingsTestHelper device_settings_test_helper_; - scoped_refptr<MockOwnerKeyUtil> owner_key_util_; - - DeviceSettingsService device_settings_service_; - - policy::DevicePolicyBuilder policy_; - - scoped_ptr<DeviceSettingsProvider> provider_; + MockSignedSettingsHelper signed_settings_helper_; - private: - DISALLOW_COPY_AND_ASSIGN(DeviceSettingsProviderTest); + ScopedStubCrosEnabler stub_cros_enabler_; + ScopedMockUserManagerEnabler mock_user_manager_; }; TEST_F(DeviceSettingsProviderTest, InitializationTest) { - owner_key_util_->SetPublicKeyFromPrivateKey(policy_.signing_key()); - - // Have the service load a settings blob. - EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); - device_settings_service_.Load(); - device_settings_test_helper_.Flush(); - Mock::VerifyAndClearExpectations(this); - // Verify that the policy blob has been correctly parsed and trusted. // The trusted flag should be set before the call to PrepareTrustedValues. EXPECT_EQ(CrosSettingsProvider::TRUSTED, - provider_->PrepareTrustedValues(base::Closure())); + provider_->PrepareTrustedValues( + base::Bind(&DeviceSettingsProviderTest::GetTrustedCallback, + base::Unretained(this)))); const base::Value* value = provider_->Get(kStatsReportingPref); ASSERT_TRUE(value); bool bool_value; @@ -108,13 +121,16 @@ TEST_F(DeviceSettingsProviderTest, InitializationTest) { } TEST_F(DeviceSettingsProviderTest, InitializationTestUnowned) { - // Have the service check the key. - device_settings_service_.Load(); - device_settings_test_helper_.Flush(); + // No calls to the SignedSettingsHelper should occur in this case! + Mock::VerifyAndClear(&signed_settings_helper_); + provider_->set_ownership_status(OwnershipService::OWNERSHIP_NONE); + provider_->Reload(); // The trusted flag should be set before the call to PrepareTrustedValues. EXPECT_EQ(CrosSettingsProvider::TRUSTED, - provider_->PrepareTrustedValues(base::Closure())); + provider_->PrepareTrustedValues( + base::Bind(&DeviceSettingsProviderTest::GetTrustedCallback, + base::Unretained(this)))); const base::Value* value = provider_->Get(kReleaseChannel); ASSERT_TRUE(value); std::string string_value; @@ -122,38 +138,26 @@ TEST_F(DeviceSettingsProviderTest, InitializationTestUnowned) { EXPECT_TRUE(string_value.empty()); // Sets should succeed though and be readable from the cache. - EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); EXPECT_CALL(*this, SettingChanged(kReleaseChannel)).Times(1); base::StringValue new_value("stable-channel"); provider_->Set(kReleaseChannel, new_value); - Mock::VerifyAndClearExpectations(this); - - // This shouldn't trigger a write. - device_settings_test_helper_.set_policy_blob(std::string()); - device_settings_test_helper_.Flush(); - EXPECT_EQ(std::string(), device_settings_test_helper_.policy_blob()); - - // Verify the change has been applied. + // Do one more reload here to make sure we don't flip randomly between stores. + provider_->Reload(); + // Verify the change has not been applied. const base::Value* saved_value = provider_->Get(kReleaseChannel); ASSERT_TRUE(saved_value); EXPECT_TRUE(saved_value->GetAsString(&string_value)); ASSERT_EQ("stable-channel", string_value); + Mock::VerifyAndClearExpectations(this); } TEST_F(DeviceSettingsProviderTest, SetPrefFailed) { + EXPECT_CALL(*this, SettingChanged(kStatsReportingPref)).Times(1); // If we are not the owner no sets should work. - owner_key_util_->SetPublicKeyFromPrivateKey(policy_.signing_key()); - + EXPECT_CALL(*mock_user_manager_.user_manager(), IsCurrentUserOwner()) + .WillOnce(Return(false)); base::FundamentalValue value(true); - EXPECT_CALL(*this, SettingChanged(kStatsReportingPref)).Times(1); provider_->Set(kStatsReportingPref, value); - Mock::VerifyAndClearExpectations(this); - - // This shouldn't trigger a write. - device_settings_test_helper_.set_policy_blob(std::string()); - device_settings_test_helper_.Flush(); - EXPECT_EQ(std::string(), device_settings_test_helper_.policy_blob()); - // Verify the change has not been applied. const base::Value* saved_value = provider_->Get(kStatsReportingPref); ASSERT_TRUE(saved_value); @@ -163,26 +167,10 @@ TEST_F(DeviceSettingsProviderTest, SetPrefFailed) { } TEST_F(DeviceSettingsProviderTest, SetPrefSucceed) { - owner_key_util_->SetPrivateKey(policy_.signing_key()); - device_settings_service_.SetUsername(policy_.policy_data().username()); - device_settings_test_helper_.Flush(); - - base::FundamentalValue value(true); - EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); EXPECT_CALL(*this, SettingChanged(kStatsReportingPref)).Times(1); + base::FundamentalValue value(true); provider_->Set(kStatsReportingPref, value); - Mock::VerifyAndClearExpectations(this); - - // Process the store. - device_settings_test_helper_.set_policy_blob(std::string()); - device_settings_test_helper_.Flush(); - - // Verify that the device policy has been adjusted. - ASSERT_TRUE(device_settings_service_.device_settings()); - EXPECT_TRUE(device_settings_service_.device_settings()-> - metrics_enabled().metrics_enabled()); - - // Verify the change has been applied. + // Verify the change has not been applied. const base::Value* saved_value = provider_->Get(kStatsReportingPref); ASSERT_TRUE(saved_value); bool bool_value; @@ -190,64 +178,84 @@ TEST_F(DeviceSettingsProviderTest, SetPrefSucceed) { EXPECT_TRUE(bool_value); } -TEST_F(DeviceSettingsProviderTest, PolicyRetrievalFailedBadSignature) { - owner_key_util_->SetPublicKeyFromPrivateKey(policy_.signing_key()); - policy_.policy().set_policy_data_signature("bad signature"); - device_settings_test_helper_.set_policy_blob(policy_.GetBlob()); - - device_settings_service_.Load(); - device_settings_test_helper_.Flush(); - - // Verify that the cached settings blob is not "trusted". - EXPECT_EQ(DeviceSettingsService::STORE_VALIDATION_ERROR, - device_settings_service_.status()); +TEST_F(DeviceSettingsProviderTest, PolicyRetrievalFailedBadSingature) { + // No calls to the SignedSettingsHelper should occur in this case! + Mock::VerifyAndClear(&signed_settings_helper_); + EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)) + .WillRepeatedly( + MockSignedSettingsHelperRetrievePolicy( + SignedSettings::BAD_SIGNATURE, + policy_blob_)); + provider_->Reload(); + // Verify that the cache policy blob is not "trusted". EXPECT_EQ(CrosSettingsProvider::PERMANENTLY_UNTRUSTED, - provider_->PrepareTrustedValues(base::Closure())); + provider_->PrepareTrustedValues( + base::Bind(&DeviceSettingsProviderTest::GetTrustedCallback, + base::Unretained(this)))); } -TEST_F(DeviceSettingsProviderTest, PolicyRetrievalNoPolicy) { - owner_key_util_->SetPublicKeyFromPrivateKey(policy_.signing_key()); - device_settings_test_helper_.set_policy_blob(std::string()); - - device_settings_service_.Load(); - device_settings_test_helper_.Flush(); - - // Verify that the cached settings blob is not "trusted". - EXPECT_EQ(DeviceSettingsService::STORE_NO_POLICY, - device_settings_service_.status()); +TEST_F(DeviceSettingsProviderTest, PolicyRetrievalOperationFailedPermanently) { + // No calls to the SignedSettingsHelper should occur in this case! + Mock::VerifyAndClear(&signed_settings_helper_); + EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)) + .WillRepeatedly( + MockSignedSettingsHelperRetrievePolicy( + SignedSettings::OPERATION_FAILED, + policy_blob_)); + provider_->Reload(); + // Verify that the cache policy blob is not "trusted". EXPECT_EQ(CrosSettingsProvider::PERMANENTLY_UNTRUSTED, - provider_->PrepareTrustedValues(base::Closure())); + provider_->PrepareTrustedValues( + base::Bind(&DeviceSettingsProviderTest::GetTrustedCallback, + base::Unretained(this)))); } -TEST_F(DeviceSettingsProviderTest, PolicyFailedPermanentlyNotification) { - owner_key_util_->SetPublicKeyFromPrivateKey(policy_.signing_key()); - device_settings_test_helper_.set_policy_blob(std::string()); +TEST_F(DeviceSettingsProviderTest, PolicyRetrievalOperationFailedOnce) { + // No calls to the SignedSettingsHelper should occur in this case! + Mock::VerifyAndClear(&signed_settings_helper_); + EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)) + .WillOnce( + MockSignedSettingsHelperRetrievePolicy( + SignedSettings::OPERATION_FAILED, + policy_blob_)) + .WillRepeatedly( + MockSignedSettingsHelperRetrievePolicy( + SignedSettings::SUCCESS, + policy_blob_)); + // Should be trusted after an automatic reload. + provider_->Reload(); + // Verify that the cache policy blob is not "trusted". + EXPECT_EQ(CrosSettingsProvider::TRUSTED, + provider_->PrepareTrustedValues( + base::Bind(&DeviceSettingsProviderTest::GetTrustedCallback, + base::Unretained(this)))); +} +TEST_F(DeviceSettingsProviderTest, PolicyFailedPermanentlyNotification) { + Mock::VerifyAndClear(&signed_settings_helper_); + EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)) + .WillRepeatedly( + MockSignedSettingsHelperRetrievePolicy( + SignedSettings::OPERATION_FAILED, + policy_blob_)); + + provider_->set_trusted_status(CrosSettingsProvider::TEMPORARILY_UNTRUSTED); EXPECT_CALL(*this, GetTrustedCallback()); EXPECT_EQ(CrosSettingsProvider::TEMPORARILY_UNTRUSTED, provider_->PrepareTrustedValues( base::Bind(&DeviceSettingsProviderTest::GetTrustedCallback, base::Unretained(this)))); - - device_settings_service_.Load(); - device_settings_test_helper_.Flush(); - Mock::VerifyAndClearExpectations(this); - - EXPECT_EQ(CrosSettingsProvider::PERMANENTLY_UNTRUSTED, - provider_->PrepareTrustedValues(base::Closure())); + provider_->Reload(); } TEST_F(DeviceSettingsProviderTest, PolicyLoadNotification) { + provider_->set_trusted_status(CrosSettingsProvider::TEMPORARILY_UNTRUSTED); EXPECT_CALL(*this, GetTrustedCallback()); - EXPECT_EQ(CrosSettingsProvider::TEMPORARILY_UNTRUSTED, provider_->PrepareTrustedValues( base::Bind(&DeviceSettingsProviderTest::GetTrustedCallback, base::Unretained(this)))); - - device_settings_service_.Load(); - device_settings_test_helper_.Flush(); - Mock::VerifyAndClearExpectations(this); + provider_->Reload(); } } // namespace chromeos diff --git a/chrome/browser/chromeos/settings/owner_manager.cc b/chrome/browser/chromeos/settings/owner_manager.cc index 60e69a3..385af76 100644 --- a/chrome/browser/chromeos/settings/owner_manager.cc +++ b/chrome/browser/chromeos/settings/owner_manager.cc @@ -12,7 +12,7 @@ #include "base/file_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/boot_times_loader.h" -#include "chrome/browser/chromeos/settings/device_settings_cache.h" +#include "chrome/browser/chromeos/settings/signed_settings_cache.h" #include "chrome/common/chrome_notification_types.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" diff --git a/chrome/browser/chromeos/settings/session_manager_observer.cc b/chrome/browser/chromeos/settings/session_manager_observer.cc index fba6894..6bb828c 100644 --- a/chrome/browser/chromeos/settings/session_manager_observer.cc +++ b/chrome/browser/chromeos/settings/session_manager_observer.cc @@ -5,8 +5,8 @@ #include "chrome/browser/chromeos/settings/session_manager_observer.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/chromeos/settings/device_settings_cache.h" #include "chrome/browser/chromeos/settings/signed_settings.h" +#include "chrome/browser/chromeos/settings/signed_settings_cache.h" #include "chrome/common/chrome_notification_types.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "content/public/browser/browser_thread.h" @@ -60,7 +60,7 @@ void SessionManagerObserver::OwnerKeySet(bool success) { // Now owner is assigned and key is generated and we should persist // those settings into signed storage. if (success && g_browser_process && g_browser_process->local_state()) - device_settings_cache::Finalize(g_browser_process->local_state()); + signed_settings_cache::Finalize(g_browser_process->local_state()); // Whether we exported the public key or not, send a notification // indicating that we're done with this attempt. diff --git a/chrome/browser/chromeos/settings/signed_settings_cache.cc b/chrome/browser/chromeos/settings/signed_settings_cache.cc new file mode 100644 index 0000000..811f428 --- /dev/null +++ b/chrome/browser/chromeos/settings/signed_settings_cache.cc @@ -0,0 +1,133 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/settings/signed_settings_cache.h" + +#include <string> + +#include "base/base64.h" +#include "base/bind.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/settings/ownership_service.h" +#include "chrome/browser/chromeos/settings/signed_settings_helper.h" +#include "chrome/browser/policy/proto/device_management_backend.pb.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/common/pref_names.h" + +using content::BrowserThread; + +namespace em = enterprise_management; + +namespace chromeos { + +namespace { + +void OnStorePolicyCompleted(SignedSettings::ReturnCode code) { + if (code != SignedSettings::SUCCESS) + LOG(ERROR) << "Couldn't save temp store to the policy blob. code: " << code; + else + CrosSettings::Get()->ReloadProviders(); +} + +void FinishFinalize(PrefService* local_state, + SignedSettings::ReturnCode code, + const em::PolicyFetchResponse& policy) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + if (code != SignedSettings::SUCCESS) { + LOG(ERROR) << "Can't finalize temp store error code:" << code; + return; + } + + if (local_state) { + std::string encoded = + local_state->GetString(prefs::kSignedSettingsCache); + std::string policy_string; + if (!base::Base64Decode(encoded, &policy_string)) { + LOG(ERROR) << "Can't decode policy from base64 on finalizing."; + return; + } + + em::PolicyData merging_policy_data; + if (!merging_policy_data.ParseFromString(policy_string)) { + LOG(ERROR) << "Can't decode policy from string on finalizing."; + return; + } + + em::PolicyFetchResponse policy_envelope = policy; + DCHECK(policy_envelope.has_policy_data()); + em::PolicyData base_policy_data; + base_policy_data.ParseFromString(policy_envelope.policy_data()); + // Merge only the policy value as we should never ever rewrite the other + // fields of the PolicyData protobuf. + base_policy_data.set_policy_value(merging_policy_data.policy_value()); + policy_envelope.set_policy_data(base_policy_data.SerializeAsString()); + DCHECK(base_policy_data.has_username()); + policy_envelope.clear_policy_data_signature(); + SignedSettingsHelper::Get()->StartStorePolicyOp( + policy_envelope, base::Bind(&OnStorePolicyCompleted)); + } +} + +// Reload the initial policy blob, and if successful apply the settings from +// temp storage, and write them back the blob in FinishFinalize. +void ReloadSignedSettingsAndFinalize( + PrefService* local_state, + OwnershipService::Status status, + bool current_user_is_owner) { + if (current_user_is_owner) { + SignedSettingsHelper::Get()->StartRetrievePolicyOp( + base::Bind(FinishFinalize, local_state)); + } +} + +} // namespace + +namespace signed_settings_cache { + +void RegisterPrefs(PrefService* local_state) { + local_state->RegisterStringPref(prefs::kSignedSettingsCache, + "invalid", + PrefService::UNSYNCABLE_PREF); +} + +bool Store(const em::PolicyData& policy, PrefService* local_state) { + if (local_state) { + std::string policy_string = policy.SerializeAsString(); + std::string encoded; + if (!base::Base64Encode(policy_string, &encoded)) { + LOG(ERROR) << "Can't encode policy in base64."; + return false; + } + local_state->SetString(prefs::kSignedSettingsCache, encoded); + return true; + } + return false; +} + +bool Retrieve(em::PolicyData *policy, PrefService* local_state) { + if (local_state) { + std::string encoded = + local_state->GetString(prefs::kSignedSettingsCache); + std::string policy_string; + if (!base::Base64Decode(encoded, &policy_string)) { + // This is normal and happens on first boot. + VLOG(1) << "Can't decode policy from base64."; + return false; + } + return policy->ParseFromString(policy_string); + } + return false; +} + +void Finalize(PrefService* local_state) { + // First we have to make sure the owner is really logged in because the key + // notification is generated on every cloud policy key rotation too. + OwnershipService::GetSharedInstance()->GetStatusAsync( + base::Bind(&ReloadSignedSettingsAndFinalize, local_state)); +} + +} // namespace signed_settings_cache + +} // namespace chromeos diff --git a/chrome/browser/chromeos/settings/device_settings_cache.h b/chrome/browser/chromeos/settings/signed_settings_cache.h index 8f6f7cf..ab9da59 100644 --- a/chrome/browser/chromeos/settings/device_settings_cache.h +++ b/chrome/browser/chromeos/settings/signed_settings_cache.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_SETTINGS_DEVICE_SETTINGS_CACHE_H_ -#define CHROME_BROWSER_CHROMEOS_SETTINGS_DEVICE_SETTINGS_CACHE_H_ +#ifndef CHROME_BROWSER_CHROMEOS_SETTINGS_SIGNED_SETTINGS_CACHE_H_ +#define CHROME_BROWSER_CHROMEOS_SETTINGS_SIGNED_SETTINGS_CACHE_H_ namespace enterprise_management { class PolicyData; @@ -13,11 +13,11 @@ class PrefService; namespace chromeos { -// There is need (metrics at OOBE stage) to store settings (that normally would -// go into DeviceSettings storage) before owner has been assigned (hence no key -// is available). This set of functions serves as a transient storage in that -// case. -namespace device_settings_cache { +// There is need (metrics at OOBE stage) to store settings +// (that normally would go into SignedSettings storage) +// before owner has been assigned (hence no key is available). +// This set of functions serves as a transient storage in that case. +namespace signed_settings_cache { // Registers required pref section. void RegisterPrefs(PrefService* local_state); @@ -29,11 +29,11 @@ bool Store(const enterprise_management::PolicyData &policy, bool Retrieve(enterprise_management::PolicyData *policy, PrefService* local_state); -// Call this after owner has been assigned to persist settings into -// DeviceSettings storage. +// Call this after owner has been assigned to persist settings +// into SignedSettings storage. void Finalize(PrefService* local_state); -} // namespace device_settings_cache +} // namespace signed_settings_cache } // namespace chromeos -#endif // CHROME_BROWSER_CHROMEOS_SETTINGS_DEVICE_SETTINGS_CACHE_H_ +#endif // CHROME_BROWSER_CHROMEOS_SETTINGS_SIGNED_SETTINGS_CACHE_H_ diff --git a/chrome/browser/chromeos/settings/device_settings_cache_unittest.cc b/chrome/browser/chromeos/settings/signed_settings_cache_unittest.cc index d47021b5..de8bbc5 100644 --- a/chrome/browser/chromeos/settings/device_settings_cache_unittest.cc +++ b/chrome/browser/chromeos/settings/signed_settings_cache_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/settings/device_settings_cache.h" +#include "chrome/browser/chromeos/settings/signed_settings_cache.h" #include "chrome/browser/policy/proto/chrome_device_policy.pb.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" @@ -14,7 +14,7 @@ namespace em = enterprise_management; namespace chromeos { -class DeviceSettingsCacheTest : public testing::Test { +class SignedSettingsCacheTest : public testing::Test { protected: virtual void SetUp() { // prepare some data. @@ -23,18 +23,18 @@ class DeviceSettingsCacheTest : public testing::Test { pol.mutable_allow_new_users()->set_allow_new_users(false); policy_.set_policy_value(pol.SerializeAsString()); - device_settings_cache::RegisterPrefs(&local_state_); + signed_settings_cache::RegisterPrefs(&local_state_); } TestingPrefService local_state_; em::PolicyData policy_; }; -TEST_F(DeviceSettingsCacheTest, Basic) { - EXPECT_TRUE(device_settings_cache::Store(policy_, &local_state_)); +TEST_F(SignedSettingsCacheTest, Basic) { + EXPECT_TRUE(signed_settings_cache::Store(policy_, &local_state_)); em::PolicyData policy_out; - EXPECT_TRUE(device_settings_cache::Retrieve(&policy_out, &local_state_)); + EXPECT_TRUE(signed_settings_cache::Retrieve(&policy_out, &local_state_)); EXPECT_TRUE(policy_out.has_policy_type()); EXPECT_TRUE(policy_out.has_policy_value()); @@ -45,13 +45,13 @@ TEST_F(DeviceSettingsCacheTest, Basic) { EXPECT_FALSE(pol.allow_new_users().allow_new_users()); } -TEST_F(DeviceSettingsCacheTest, CorruptData) { - EXPECT_TRUE(device_settings_cache::Store(policy_, &local_state_)); +TEST_F(SignedSettingsCacheTest, CorruptData) { + EXPECT_TRUE(signed_settings_cache::Store(policy_, &local_state_)); - local_state_.SetString(prefs::kDeviceSettingsCache, "blaaa"); + local_state_.SetString(prefs::kSignedSettingsCache, "blaaa"); em::PolicyData policy_out; - EXPECT_FALSE(device_settings_cache::Retrieve(&policy_out, &local_state_)); + EXPECT_FALSE(signed_settings_cache::Retrieve(&policy_out, &local_state_)); } } // namespace chromeos diff --git a/chrome/browser/chromeos/settings/signed_settings_migration_helper.cc b/chrome/browser/chromeos/settings/signed_settings_migration_helper.cc new file mode 100644 index 0000000..566f2b3 --- /dev/null +++ b/chrome/browser/chromeos/settings/signed_settings_migration_helper.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/settings/signed_settings_migration_helper.h" + +#include "base/bind.h" +#include "base/values.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/common/chrome_notification_types.h" +#include "content/public/browser/notification_service.h" + +namespace chromeos { + +SignedSettingsMigrationHelper::SignedSettingsMigrationHelper() + : ALLOW_THIS_IN_INITIALIZER_LIST(ptr_factory_(this)) { + registrar_.Add(this, chrome::NOTIFICATION_OWNERSHIP_CHECKED, + content::NotificationService::AllSources()); +} + +SignedSettingsMigrationHelper::~SignedSettingsMigrationHelper() { + registrar_.RemoveAll(); + migration_values_.Clear(); +} + +void SignedSettingsMigrationHelper::AddMigrationValue(const std::string& path, + base::Value* value) { + migration_values_.SetValue(path, value); +} + +void SignedSettingsMigrationHelper::MigrateValues(void) { + ptr_factory_.InvalidateWeakPtrs(); + OwnershipService::GetSharedInstance()->GetStatusAsync( + base::Bind(&SignedSettingsMigrationHelper::DoMigrateValues, + ptr_factory_.GetWeakPtr())); +} + +// NotificationObserver overrides: +void SignedSettingsMigrationHelper::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + if (type == chrome::NOTIFICATION_OWNERSHIP_CHECKED) + MigrateValues(); +} + +void SignedSettingsMigrationHelper::DoMigrateValues( + OwnershipService::Status status, + bool current_user_is_owner) { + // We can call StartStorePropertyOp in two cases - either if the owner is + // currently logged in and the policy can be updated immediately or if there + // is no owner yet in which case the value will be temporarily stored in the + // SignedSettingsCache until the device is owned. If none of these + // cases is met then we will wait for user change notification and retry. + if (current_user_is_owner || status != OwnershipService::OWNERSHIP_TAKEN) { + std::map<std::string, base::Value*>::const_iterator i; + for (i = migration_values_.begin(); i != migration_values_.end(); ++i) { + // Queue all values for storing. + CrosSettings::Get()->Set(i->first, *i->second); + } + migration_values_.Clear(); + } +} + +} // namespace chromeos + diff --git a/chrome/browser/chromeos/settings/signed_settings_migration_helper.h b/chrome/browser/chromeos/settings/signed_settings_migration_helper.h new file mode 100644 index 0000000..13d5bfb --- /dev/null +++ b/chrome/browser/chromeos/settings/signed_settings_migration_helper.h @@ -0,0 +1,59 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_SETTINGS_SIGNED_SETTINGS_MIGRATION_HELPER_H_ +#define CHROME_BROWSER_CHROMEOS_SETTINGS_SIGNED_SETTINGS_MIGRATION_HELPER_H_ + +#include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/settings/ownership_service.h" +#include "chrome/browser/chromeos/settings/signed_settings_helper.h" +#include "chrome/browser/prefs/pref_value_map.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" + +namespace base { +class Value; +} + +namespace chromeos { + +// This class provides the means to migrate settings to the signed settings +// store. It does one of three things - store the settings in the policy blob +// immediately if the current user is the owner. Uses the +// SignedSettingsCache if there is no owner yet, or waits for an +// OWNERSHIP_CHECKED notification to delay the storing until the owner has +// logged in. +class SignedSettingsMigrationHelper : public content::NotificationObserver { + public: + SignedSettingsMigrationHelper(); + virtual ~SignedSettingsMigrationHelper(); + + // Adds a value to be migrated. The class takes ownership of the |value|. + void AddMigrationValue(const std::string& path, base::Value* value); + + // Initiates values migration. If the device is already owned this will + // happen immediately if not it will wait for ownership login and finish the + // migration then. + void MigrateValues(void); + + // NotificationObserver overrides: + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + private: + // Does the actual migration when ownership has been confirmed. + void DoMigrateValues(OwnershipService::Status status, + bool current_user_is_owner); + + content::NotificationRegistrar registrar_; + base::WeakPtrFactory<SignedSettingsMigrationHelper> ptr_factory_; + PrefValueMap migration_values_; + + DISALLOW_COPY_AND_ASSIGN(SignedSettingsMigrationHelper); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_SETTINGS_SIGNED_SETTINGS_MIGRATION_HELPER_H_ diff --git a/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc b/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc index 83c9d75..facadc3 100644 --- a/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc +++ b/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc @@ -73,6 +73,9 @@ bool StubCrosSettingsProvider::HandlesSetting(const std::string& path) const { return std::find(kHandledSettings, end, path) != end; } +void StubCrosSettingsProvider::Reload() { +} + void StubCrosSettingsProvider::DoSet(const std::string& path, const base::Value& value) { values_.SetValue(path, value.DeepCopy()); diff --git a/chrome/browser/chromeos/settings/stub_cros_settings_provider.h b/chrome/browser/chromeos/settings/stub_cros_settings_provider.h index 9d88bf7..13a10cc 100644 --- a/chrome/browser/chromeos/settings/stub_cros_settings_provider.h +++ b/chrome/browser/chromeos/settings/stub_cros_settings_provider.h @@ -26,6 +26,7 @@ class StubCrosSettingsProvider : public CrosSettingsProvider { virtual TrustedStatus PrepareTrustedValues( const base::Closure& callback) OVERRIDE; virtual bool HandlesSetting(const std::string& path) const OVERRIDE; + virtual void Reload() OVERRIDE; private: // CrosSettingsProvider implementation: diff --git a/chrome/browser/chromeos/settings/system_settings_provider.cc b/chrome/browser/chromeos/settings/system_settings_provider.cc index 75a8656..5148c74 100644 --- a/chrome/browser/chromeos/settings/system_settings_provider.cc +++ b/chrome/browser/chromeos/settings/system_settings_provider.cc @@ -60,6 +60,11 @@ bool SystemSettingsProvider::HandlesSetting(const std::string& path) const { return path == kSystemTimezone; } +void SystemSettingsProvider::Reload() { + // TODO(pastarmovj): We can actually cache the timezone here to make returning + // it faster. +} + void SystemSettingsProvider::TimezoneChanged(const icu::TimeZone& timezone) { // Fires system setting change notification. timezone_value_.reset(base::Value::CreateStringValue( diff --git a/chrome/browser/chromeos/settings/system_settings_provider.h b/chrome/browser/chromeos/settings/system_settings_provider.h index 578a1c5..49ef2aa 100644 --- a/chrome/browser/chromeos/settings/system_settings_provider.h +++ b/chrome/browser/chromeos/settings/system_settings_provider.h @@ -30,6 +30,7 @@ class SystemSettingsProvider : public CrosSettingsProvider, virtual TrustedStatus PrepareTrustedValues( const base::Closure& callback) OVERRIDE; virtual bool HandlesSetting(const std::string& path) const OVERRIDE; + virtual void Reload() OVERRIDE; // TimezoneSettings::Observer implementation. virtual void TimezoneChanged(const icu::TimeZone& timezone) OVERRIDE; diff --git a/chrome/browser/policy/device_policy_cache.cc b/chrome/browser/policy/device_policy_cache.cc index 8f6fac2..d81567b 100644 --- a/chrome/browser/policy/device_policy_cache.cc +++ b/chrome/browser/policy/device_policy_cache.cc @@ -15,6 +15,9 @@ #include "base/logging.h" #include "base/metrics/histogram.h" #include "base/values.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/settings/ownership_service.h" +#include "chrome/browser/chromeos/settings/signed_settings_helper.h" #include "chrome/browser/policy/app_pack_updater.h" #include "chrome/browser/policy/cloud_policy_data_store.h" #include "chrome/browser/policy/enterprise_install_attributes.h" @@ -36,6 +39,69 @@ namespace em = enterprise_management; namespace { +// Stores policy, updates the owner key if required and reports the status +// through a callback. +class StorePolicyOperation : public chromeos::OwnerManager::KeyUpdateDelegate { + public: + typedef base::Callback<void(chromeos::SignedSettings::ReturnCode)> Callback; + + StorePolicyOperation(chromeos::SignedSettingsHelper* signed_settings_helper, + const em::PolicyFetchResponse& policy, + const Callback& callback) + : signed_settings_helper_(signed_settings_helper), + policy_(policy), + callback_(callback), + weak_ptr_factory_(this) { + signed_settings_helper_->StartStorePolicyOp( + policy, + base::Bind(&StorePolicyOperation::OnStorePolicyCompleted, + weak_ptr_factory_.GetWeakPtr())); + } + virtual ~StorePolicyOperation() { + } + + void OnStorePolicyCompleted(chromeos::SignedSettings::ReturnCode code) { + if (code != chromeos::SignedSettings::SUCCESS) { + callback_.Run(code); + delete this; + return; + } + + if (policy_.has_new_public_key()) { + // The session manager has successfully done a key rotation. Replace the + // owner key also in chrome. + const std::string& new_key = policy_.new_public_key(); + const std::vector<uint8> new_key_data(new_key.c_str(), + new_key.c_str() + new_key.size()); + chromeos::OwnershipService::GetSharedInstance()->StartUpdateOwnerKey( + new_key_data, this); + return; + } else { + chromeos::CrosSettings::Get()->ReloadProviders(); + callback_.Run(chromeos::SignedSettings::SUCCESS); + delete this; + return; + } + } + + // OwnerManager::KeyUpdateDelegate implementation: + virtual void OnKeyUpdated() OVERRIDE { + chromeos::CrosSettings::Get()->ReloadProviders(); + callback_.Run(chromeos::SignedSettings::SUCCESS); + delete this; + } + + private: + + chromeos::SignedSettingsHelper* signed_settings_helper_; + em::PolicyFetchResponse policy_; + Callback callback_; + + base::WeakPtrFactory<StorePolicyOperation> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(StorePolicyOperation); +}; + // Decodes a protobuf integer to an IntegerValue. The caller assumes ownership // of the return Value*. Returns NULL in case the input value is out of bounds. Value* DecodeIntegerValue(google::protobuf::int64 value) { @@ -73,30 +139,29 @@ DevicePolicyCache::DevicePolicyCache( EnterpriseInstallAttributes* install_attributes) : data_store_(data_store), install_attributes_(install_attributes), - device_settings_service_(chromeos::DeviceSettingsService::Get()), + signed_settings_helper_(chromeos::SignedSettingsHelper::Get()), ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), policy_fetch_pending_(false) { - device_settings_service_->AddObserver(this); } DevicePolicyCache::DevicePolicyCache( CloudPolicyDataStore* data_store, EnterpriseInstallAttributes* install_attributes, - chromeos::DeviceSettingsService* device_settings_service) + chromeos::SignedSettingsHelper* signed_settings_helper) : data_store_(data_store), install_attributes_(install_attributes), - device_settings_service_(device_settings_service), + signed_settings_helper_(signed_settings_helper), ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), policy_fetch_pending_(false) { - device_settings_service_->AddObserver(this); } DevicePolicyCache::~DevicePolicyCache() { - device_settings_service_->RemoveObserver(this); } void DevicePolicyCache::Load() { - DeviceSettingsUpdated(); + signed_settings_helper_->StartRetrievePolicyOp( + base::Bind(&DevicePolicyCache::OnRetrievePolicyCompleted, + weak_ptr_factory_.GetWeakPtr())); } bool DevicePolicyCache::SetPolicy(const em::PolicyFetchResponse& policy) { @@ -140,11 +205,11 @@ bool DevicePolicyCache::SetPolicy(const em::PolicyFetchResponse& policy) { set_last_policy_refresh_time(base::Time::NowFromSystemTime()); // Start a store operation. - policy_fetch_pending_ = true; - device_settings_service_->Store( - policy.SerializeAsString(), + StorePolicyOperation::Callback callback = base::Bind(&DevicePolicyCache::PolicyStoreOpCompleted, - weak_ptr_factory_.GetWeakPtr())); + weak_ptr_factory_.GetWeakPtr()); + new StorePolicyOperation(signed_settings_helper_, policy, callback); + policy_fetch_pending_ = true; return true; } @@ -160,27 +225,17 @@ void DevicePolicyCache::SetFetchingDone() { CloudPolicyCacheBase::SetFetchingDone(); } -void DevicePolicyCache::OwnershipStatusChanged() {} - -void DevicePolicyCache::DeviceSettingsUpdated() { +void DevicePolicyCache::OnRetrievePolicyCompleted( + chromeos::SignedSettings::ReturnCode code, + const em::PolicyFetchResponse& policy) { DCHECK(CalledOnValidThread()); - chromeos::DeviceSettingsService::Status status = - device_settings_service_->status(); - const em::PolicyData* policy_data = device_settings_service_->policy_data(); - if (status == chromeos::DeviceSettingsService::STORE_SUCCESS && - !policy_data) { - // Initial policy load is still pending. - return; - } - if (!IsReady()) { std::string device_token; - InstallInitialPolicy(status, policy_data, &device_token); + InstallInitialPolicy(code, policy, &device_token); SetTokenAndFlagReady(device_token); } else { // In other words, IsReady() == true - if (status != chromeos::DeviceSettingsService::STORE_SUCCESS || - !policy_data) { - if (status == chromeos::DeviceSettingsService::STORE_VALIDATION_ERROR) { + if (code != chromeos::SignedSettings::SUCCESS) { + if (code == chromeos::SignedSettings::BAD_SIGNATURE) { UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyFetchBadSignature, kMetricPolicySize); InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, @@ -192,16 +247,14 @@ void DevicePolicyCache::DeviceSettingsUpdated() { CloudPolicySubsystem::POLICY_LOCAL_ERROR); } } else { - em::PolicyFetchResponse policy_response; - CHECK(policy_data->SerializeToString( - policy_response.mutable_policy_data())); - bool ok = SetPolicyInternal(policy_response, NULL, false); + bool ok = SetPolicyInternal(policy, NULL, false); if (ok) { UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyFetchOK, kMetricPolicySize); } } } + CheckFetchingDone(); } bool DevicePolicyCache::DecodePolicyData(const em::PolicyData& policy_data, @@ -215,14 +268,13 @@ bool DevicePolicyCache::DecodePolicyData(const em::PolicyData& policy_data, return true; } -void DevicePolicyCache::PolicyStoreOpCompleted() { +void DevicePolicyCache::PolicyStoreOpCompleted( + chromeos::SignedSettings::ReturnCode code) { DCHECK(CalledOnValidThread()); - chromeos::DeviceSettingsService::Status status = - device_settings_service_->status(); - if (status != chromeos::DeviceSettingsService::STORE_SUCCESS) { + if (code != chromeos::SignedSettings::SUCCESS) { UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyStoreFailed, kMetricPolicySize); - if (status == chromeos::DeviceSettingsService::STORE_VALIDATION_ERROR) { + if (code == chromeos::SignedSettings::BAD_SIGNATURE) { UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyFetchBadSignature, kMetricPolicySize); InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, @@ -238,21 +290,24 @@ void DevicePolicyCache::PolicyStoreOpCompleted() { } UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyStoreSucceeded, kMetricPolicySize); - - CheckFetchingDone(); + signed_settings_helper_->StartRetrievePolicyOp( + base::Bind(&DevicePolicyCache::OnRetrievePolicyCompleted, + weak_ptr_factory_.GetWeakPtr())); } void DevicePolicyCache::InstallInitialPolicy( - chromeos::DeviceSettingsService::Status status, - const em::PolicyData* policy_data, + chromeos::SignedSettings::ReturnCode code, + const em::PolicyFetchResponse& policy, std::string* device_token) { - if (status == chromeos::DeviceSettingsService::STORE_NO_POLICY || - status == chromeos::DeviceSettingsService::STORE_KEY_UNAVAILABLE) { + if (code == chromeos::SignedSettings::NOT_FOUND || + code == chromeos::SignedSettings::KEY_UNAVAILABLE || + !policy.has_policy_data()) { InformNotifier(CloudPolicySubsystem::UNENROLLED, CloudPolicySubsystem::NO_DETAILS); return; } - if (!policy_data) { + em::PolicyData policy_data; + if (!policy_data.ParseFromString(policy.policy_data())) { LOG(WARNING) << "Failed to parse PolicyData protobuf."; UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyLoadFailed, kMetricPolicySize); @@ -260,8 +315,8 @@ void DevicePolicyCache::InstallInitialPolicy( CloudPolicySubsystem::POLICY_LOCAL_ERROR); return; } - if (!policy_data->has_request_token() || - policy_data->request_token().empty()) { + if (!policy_data.has_request_token() || + policy_data.request_token().empty()) { SetUnmanagedInternal(base::Time::NowFromSystemTime()); InformNotifier(CloudPolicySubsystem::UNMANAGED, CloudPolicySubsystem::NO_DETAILS); @@ -270,7 +325,7 @@ void DevicePolicyCache::InstallInitialPolicy( // SetPolicyInternal() here. return; } - if (!policy_data->has_username() || !policy_data->has_device_id()) { + if (!policy_data.has_username() || !policy_data.has_device_id()) { UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyLoadFailed, kMetricPolicySize); InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, @@ -279,17 +334,26 @@ void DevicePolicyCache::InstallInitialPolicy( } UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyLoadSucceeded, kMetricPolicySize); - data_store_->set_user_name(policy_data->username()); - data_store_->set_device_id(policy_data->device_id()); - *device_token = policy_data->request_token(); + data_store_->set_user_name(policy_data.username()); + data_store_->set_device_id(policy_data.device_id()); + *device_token = policy_data.request_token(); base::Time timestamp; - em::PolicyFetchResponse policy_response; - CHECK(policy_data->SerializeToString(policy_response.mutable_policy_data())); - if (SetPolicyInternal(policy_response, ×tamp, true)) + if (SetPolicyInternal(policy, ×tamp, true)) set_last_policy_refresh_time(timestamp); } void DevicePolicyCache::SetTokenAndFlagReady(const std::string& device_token) { + // Make sure that we only start device policy fetches once device settings are + // available in order to ensure the first device policy fetch uploads the + // configured reporting bits. + if (chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED == + chromeos::CrosSettings::Get()->PrepareTrustedValues( + base::Bind(&DevicePolicyCache::SetTokenAndFlagReady, + weak_ptr_factory_.GetWeakPtr(), + device_token))) { + return; + } + // We need to call SetDeviceToken unconditionally to indicate the cache has // finished loading. data_store_->SetDeviceToken(device_token, true); diff --git a/chrome/browser/policy/device_policy_cache.h b/chrome/browser/policy/device_policy_cache.h index 0f52fd8..573a514 100644 --- a/chrome/browser/policy/device_policy_cache.h +++ b/chrome/browser/policy/device_policy_cache.h @@ -6,9 +6,19 @@ #define CHROME_BROWSER_POLICY_DEVICE_POLICY_CACHE_H_ #include "base/memory/weak_ptr.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" +#include "chrome/browser/chromeos/settings/signed_settings.h" #include "chrome/browser/policy/cloud_policy_cache_base.h" +namespace chromeos { +class SignedSettingsHelper; +} // namespace chromeos + +namespace enterprise_management { +class ChromeDeviceSettingsProto; +class PolicyData; +class PolicyFetchResponse; +} // namespace enterprise_management + namespace policy { class CloudPolicyDataStore; @@ -16,9 +26,8 @@ class EnterpriseInstallAttributes; class PolicyMap; // CloudPolicyCacheBase implementation that persists policy information -// to ChromeOS' session manager (via DeviceSettingsService). -class DevicePolicyCache : public CloudPolicyCacheBase, - public chromeos::DeviceSettingsService::Observer { +// to ChromeOS' session manager (via SignedSettingsHelper). +class DevicePolicyCache : public CloudPolicyCacheBase { public: DevicePolicyCache(CloudPolicyDataStore* data_store, EnterpriseInstallAttributes* install_attributes); @@ -31,28 +40,27 @@ class DevicePolicyCache : public CloudPolicyCacheBase, virtual void SetUnmanaged() OVERRIDE; virtual void SetFetchingDone() OVERRIDE; - // DeviceSettingsService::Observer implementation: - virtual void OwnershipStatusChanged() OVERRIDE; - virtual void DeviceSettingsUpdated() OVERRIDE; + void OnRetrievePolicyCompleted( + chromeos::SignedSettings::ReturnCode code, + const enterprise_management::PolicyFetchResponse& policy); private: friend class DevicePolicyCacheTest; friend class DevicePolicyCacheTestHelper; - // Alternate c'tor allowing tests to mock out the DeviceSettingsService + // Alternate c'tor allowing tests to mock out the SignedSettingsHelper // singleton. DevicePolicyCache( CloudPolicyDataStore* data_store, EnterpriseInstallAttributes* install_attributes, - chromeos::DeviceSettingsService* device_settings_service); + chromeos::SignedSettingsHelper* signed_settings_helper); // CloudPolicyCacheBase implementation: virtual bool DecodePolicyData( const enterprise_management::PolicyData& policy_data, PolicyMap* policies) OVERRIDE; - // Handles completion of policy store operations. - void PolicyStoreOpCompleted(); + 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. @@ -61,8 +69,8 @@ class DevicePolicyCache : public CloudPolicyCacheBase, // Tries to install the initial device policy retrieved from signed settings. // Fills in |device_token| if it could be extracted from the loaded protobuf. void InstallInitialPolicy( - chromeos::DeviceSettingsService::Status status, - const enterprise_management::PolicyData* policy_data, + chromeos::SignedSettings::ReturnCode code, + const enterprise_management::PolicyFetchResponse& policy, std::string* device_token); // Ensures that CrosSettings has established trust on the reporting prefs and @@ -104,7 +112,7 @@ class DevicePolicyCache : public CloudPolicyCacheBase, CloudPolicyDataStore* data_store_; EnterpriseInstallAttributes* install_attributes_; - chromeos::DeviceSettingsService* device_settings_service_; + chromeos::SignedSettingsHelper* signed_settings_helper_; base::WeakPtrFactory<DevicePolicyCache> weak_ptr_factory_; diff --git a/chrome/browser/policy/device_policy_cache_unittest.cc b/chrome/browser/policy/device_policy_cache_unittest.cc index 169398a..4762ab4 100644 --- a/chrome/browser/policy/device_policy_cache_unittest.cc +++ b/chrome/browser/policy/device_policy_cache_unittest.cc @@ -4,92 +4,106 @@ #include "chrome/browser/policy/device_policy_cache.h" -#include <vector> - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/file_path.h" -#include "base/memory/ref_counted.h" -#include "base/threading/sequenced_worker_pool.h" #include "chrome/browser/chromeos/cros/cryptohome_library.h" -#include "chrome/browser/chromeos/settings/device_settings_test_helper.h" -#include "chrome/browser/chromeos/settings/mock_owner_key_util.h" +#include "chrome/browser/chromeos/settings/mock_signed_settings_helper.h" #include "chrome/browser/policy/cloud_policy_data_store.h" #include "chrome/browser/policy/enterprise_install_attributes.h" -#include "chrome/browser/policy/policy_builder.h" #include "chrome/browser/policy/proto/chrome_device_policy.pb.h" -#include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "content/public/test/test_browser_thread.h" #include "policy/policy_constants.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -using ::testing::Mock; - namespace em = enterprise_management; namespace policy { namespace { +// Test registration user name. +const char kTestUser[] = "test@example.com"; + +using ::chromeos::SignedSettings; +using ::testing::InSequence; +using ::testing::Mock; +using ::testing::SaveArg; +using ::testing::_; + class MockCloudPolicyCacheObserver : public CloudPolicyCacheBase::Observer { public: - virtual ~MockCloudPolicyCacheObserver() {} - MOCK_METHOD1(OnCacheGoingAway, void(CloudPolicyCacheBase*)); MOCK_METHOD1(OnCacheUpdate, void(CloudPolicyCacheBase*)); }; +void CreatePolicy(em::PolicyFetchResponse* policy, + const std::string& user, + em::ChromeDeviceSettingsProto& settings) { + // This method omits a few fields which currently aren't needed by tests: + // timestamp, machine_name, public key info. + em::PolicyData signed_response; + 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)); + policy->set_policy_data(serialized_signed_response); +} + +void CreateRefreshRatePolicy(em::PolicyFetchResponse* policy, + const std::string& user, + int refresh_rate) { + em::ChromeDeviceSettingsProto settings; + settings.mutable_device_policy_refresh_rate()-> + set_device_policy_refresh_rate(refresh_rate); + CreatePolicy(policy, user, settings); +} + +void CreateProxyPolicy(em::PolicyFetchResponse* policy, + const std::string& user, + const std::string& proxy_mode, + const std::string& proxy_server, + const std::string& proxy_pac_url, + const std::string& proxy_bypass_list) { + em::ChromeDeviceSettingsProto settings; + em::DeviceProxySettingsProto* proxy_settings = + settings.mutable_device_proxy_settings(); + proxy_settings->set_proxy_mode(proxy_mode); + proxy_settings->set_proxy_server(proxy_server); + proxy_settings->set_proxy_pac_url(proxy_pac_url); + proxy_settings->set_proxy_bypass_list(proxy_bypass_list); + CreatePolicy(policy, user, settings); +} + } // namespace class DevicePolicyCacheTest : public testing::Test { protected: DevicePolicyCacheTest() : cryptohome_(chromeos::CryptohomeLibrary::GetImpl(true)), - owner_key_util_(new chromeos::MockOwnerKeyUtil()), install_attributes_(cryptohome_.get()), message_loop_(MessageLoop::TYPE_UI), ui_thread_(content::BrowserThread::UI, &message_loop_), file_thread_(content::BrowserThread::FILE, &message_loop_) {} - virtual void SetUp() OVERRIDE { - policy_.payload().mutable_device_policy_refresh_rate()-> - set_device_policy_refresh_rate(120); - policy_.Build(); - device_settings_test_helper_.set_policy_blob(policy_.GetBlob()); - - owner_key_util_->SetPublicKeyFromPrivateKey(policy_.signing_key()); - - device_settings_service_.Initialize(&device_settings_test_helper_, - owner_key_util_); - - data_store_.reset(CloudPolicyDataStore::CreateForDevicePolicies()); + virtual void SetUp() { + data_store_.reset(CloudPolicyDataStore::CreateForUserPolicies()); cache_.reset(new DevicePolicyCache(data_store_.get(), &install_attributes_, - &device_settings_service_)); + &signed_settings_helper_)); cache_->AddObserver(&observer_); } - virtual void TearDown() OVERRIDE { - device_settings_test_helper_.Flush(); - device_settings_service_.Shutdown(); - + virtual void TearDown() { cache_->RemoveObserver(&observer_); cache_.reset(); } - void Startup() { - EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())); - device_settings_service_.Load(); - device_settings_test_helper_.Flush(); - cache_->Load(); - Mock::VerifyAndClearExpectations(&observer_); - } - - void MakeEnterpriseDevice() { + void MakeEnterpriseDevice(const char* registration_user) { ASSERT_EQ(EnterpriseInstallAttributes::LOCK_SUCCESS, install_attributes_.LockDevice( - policy_.policy_data().username(), + registration_user, DEVICE_MODE_ENTERPRISE, std::string())); } @@ -99,16 +113,11 @@ class DevicePolicyCacheTest : public testing::Test { } MockCloudPolicyCacheObserver observer_; - scoped_ptr<chromeos::CryptohomeLibrary> cryptohome_; - scoped_refptr<chromeos::MockOwnerKeyUtil> owner_key_util_; - chromeos::DeviceSettingsTestHelper device_settings_test_helper_; - chromeos::DeviceSettingsService device_settings_service_; EnterpriseInstallAttributes install_attributes_; - scoped_ptr<CloudPolicyDataStore> data_store_; + chromeos::MockSignedSettingsHelper signed_settings_helper_; scoped_ptr<DevicePolicyCache> cache_; - DevicePolicyBuilder policy_; MessageLoop message_loop_; content::TestBrowserThread ui_thread_; @@ -118,134 +127,192 @@ class DevicePolicyCacheTest : public testing::Test { DISALLOW_COPY_AND_ASSIGN(DevicePolicyCacheTest); }; -TEST_F(DevicePolicyCacheTest, ColdStartup) { - EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())).Times(0); - cache_->Load(); - Mock::VerifyAndClearExpectations(&observer_); - +TEST_F(DevicePolicyCacheTest, Startup) { + em::PolicyFetchResponse policy; + CreateRefreshRatePolicy(&policy, kTestUser, 120); + EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)).WillOnce( + MockSignedSettingsHelperRetrievePolicy(SignedSettings::SUCCESS, + policy)); EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())); - device_settings_service_.Load(); - device_settings_test_helper_.Flush(); - Mock::VerifyAndClearExpectations(&observer_); - - base::FundamentalValue expected(120); - EXPECT_TRUE(Value::Equals(&expected, - GetPolicy(key::kDevicePolicyRefreshRate))); -} - -TEST_F(DevicePolicyCacheTest, WarmStartup) { - Startup(); - + cache_->Load(); + Mock::VerifyAndClearExpectations(&signed_settings_helper_); base::FundamentalValue expected(120); EXPECT_TRUE(Value::Equals(&expected, GetPolicy(key::kDevicePolicyRefreshRate))); } TEST_F(DevicePolicyCacheTest, SetPolicy) { - MakeEnterpriseDevice(); - Startup(); + InSequence s; + + MakeEnterpriseDevice(kTestUser); + // Startup. + em::PolicyFetchResponse policy; + CreateRefreshRatePolicy(&policy, kTestUser, 120); + EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)).WillOnce( + MockSignedSettingsHelperRetrievePolicy(SignedSettings::SUCCESS, + policy)); + EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())); + cache_->Load(); + Mock::VerifyAndClearExpectations(&signed_settings_helper_); + Mock::VerifyAndClearExpectations(&observer_); base::FundamentalValue expected(120); EXPECT_TRUE(Value::Equals(&expected, GetPolicy(key::kDevicePolicyRefreshRate))); // Set new policy information. - policy_.payload().mutable_device_policy_refresh_rate()-> - set_device_policy_refresh_rate(300); - policy_.Build(); + chromeos::SignedSettingsHelper::StorePolicyCallback store_callback; + em::PolicyFetchResponse new_policy; + CreateRefreshRatePolicy(&new_policy, kTestUser, 300); + EXPECT_CALL(signed_settings_helper_, StartStorePolicyOp(_, _)).WillOnce( + SaveArg<1>(&store_callback)); EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())).Times(0); - EXPECT_TRUE(cache_->SetPolicy(policy_.policy())); + EXPECT_TRUE(cache_->SetPolicy(new_policy)); cache_->SetFetchingDone(); + Mock::VerifyAndClearExpectations(&signed_settings_helper_); Mock::VerifyAndClearExpectations(&observer_); + ASSERT_FALSE(store_callback.is_null()); + chromeos::SignedSettingsHelper::RetrievePolicyCallback retrieve_callback; + EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)).WillOnce( + SaveArg<0>(&retrieve_callback)); EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())).Times(0); - device_settings_test_helper_.FlushStore(); + store_callback.Run(chromeos::SignedSettings::SUCCESS); + Mock::VerifyAndClearExpectations(&signed_settings_helper_); Mock::VerifyAndClearExpectations(&observer_); + ASSERT_FALSE(retrieve_callback.is_null()); // Cache update notification should only fire in the retrieve callback. EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())); - device_settings_test_helper_.Flush(); - Mock::VerifyAndClearExpectations(&observer_); - + retrieve_callback.Run(chromeos::SignedSettings::SUCCESS, new_policy); base::FundamentalValue updated_expected(300); EXPECT_TRUE(Value::Equals(&updated_expected, GetPolicy(key::kDevicePolicyRefreshRate))); + Mock::VerifyAndClearExpectations(&observer_); cache_->RemoveObserver(&observer_); } TEST_F(DevicePolicyCacheTest, SetPolicyOtherUserSameDomain) { - MakeEnterpriseDevice(); - Startup(); + InSequence s; - // Set new policy information. This should succeed as the domain is the same. - policy_.policy_data().set_username("another_user@example.com"); - policy_.Build(); + MakeEnterpriseDevice(kTestUser); + // Startup. + em::PolicyFetchResponse policy; + CreateRefreshRatePolicy(&policy, kTestUser, 120); + EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)).WillOnce( + MockSignedSettingsHelperRetrievePolicy(SignedSettings::SUCCESS, + policy)); EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())); - EXPECT_TRUE(cache_->SetPolicy(policy_.policy())); - device_settings_test_helper_.Flush(); + cache_->Load(); + Mock::VerifyAndClearExpectations(&signed_settings_helper_); + + // Set new policy information. This should succeed as the domain is the same. + chromeos::SignedSettingsHelper::StorePolicyCallback store_callback; + em::PolicyFetchResponse new_policy; + CreateRefreshRatePolicy(&new_policy, "another_user@example.com", 300); + EXPECT_CALL(signed_settings_helper_, StartStorePolicyOp(_, _)).WillOnce( + SaveArg<1>(&store_callback)); + EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())).Times(1); + EXPECT_TRUE(cache_->SetPolicy(new_policy)); + cache_->SetFetchingDone(); + store_callback.Run(chromeos::SignedSettings::OPERATION_FAILED); + Mock::VerifyAndClearExpectations(&signed_settings_helper_); Mock::VerifyAndClearExpectations(&observer_); - EXPECT_EQ(policy_.GetBlob(), device_settings_test_helper_.policy_blob()); } TEST_F(DevicePolicyCacheTest, SetPolicyOtherUserOtherDomain) { - MakeEnterpriseDevice(); - Startup(); + InSequence s; + + MakeEnterpriseDevice(kTestUser); + + // Startup. + em::PolicyFetchResponse policy; + CreateRefreshRatePolicy(&policy, kTestUser, 120); + EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)).WillOnce( + MockSignedSettingsHelperRetrievePolicy(SignedSettings::SUCCESS, + policy)); + EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())); + cache_->Load(); + Mock::VerifyAndClearExpectations(&signed_settings_helper_); // Set new policy information. This should fail because the user is from // different domain. - policy_.policy_data().set_username("foreign_user@hackers.com"); - policy_.Build(); - EXPECT_NE(policy_.GetBlob(), device_settings_test_helper_.policy_blob()); + em::PolicyFetchResponse new_policy; + CreateRefreshRatePolicy(&new_policy, "foreign_user@hackers.com", 300); + EXPECT_CALL(signed_settings_helper_, StartStorePolicyOp(_, _)).Times(0); + EXPECT_FALSE(cache_->SetPolicy(new_policy)); + Mock::VerifyAndClearExpectations(&signed_settings_helper_); - EXPECT_FALSE(cache_->SetPolicy(policy_.policy())); - device_settings_test_helper_.Flush(); - EXPECT_NE(policy_.GetBlob(), device_settings_test_helper_.policy_blob()); + base::FundamentalValue expected(120); + EXPECT_TRUE(Value::Equals(&expected, + GetPolicy(key::kDevicePolicyRefreshRate))); } TEST_F(DevicePolicyCacheTest, SetPolicyNonEnterpriseDevice) { - Startup(); + InSequence s; + + // Startup. + em::PolicyFetchResponse policy; + CreateRefreshRatePolicy(&policy, kTestUser, 120); + EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)).WillOnce( + MockSignedSettingsHelperRetrievePolicy(SignedSettings::SUCCESS, + policy)); + EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())); + cache_->Load(); + Mock::VerifyAndClearExpectations(&signed_settings_helper_); // Set new policy information. This should fail due to invalid user. - device_settings_test_helper_.set_policy_blob(std::string()); + em::PolicyFetchResponse new_policy; + CreateRefreshRatePolicy(&new_policy, kTestUser, 120); + EXPECT_CALL(signed_settings_helper_, StartStorePolicyOp(_, _)).Times(0); + EXPECT_FALSE(cache_->SetPolicy(new_policy)); + Mock::VerifyAndClearExpectations(&signed_settings_helper_); - EXPECT_FALSE(cache_->SetPolicy(policy_.policy())); - device_settings_test_helper_.Flush(); - EXPECT_TRUE(device_settings_test_helper_.policy_blob().empty()); + base::FundamentalValue expected(120); + EXPECT_TRUE(Value::Equals(&expected, + GetPolicy(key::kDevicePolicyRefreshRate))); } TEST_F(DevicePolicyCacheTest, SetProxyPolicy) { - MakeEnterpriseDevice(); - - em::DeviceProxySettingsProto proxy_settings; - proxy_settings.set_proxy_mode("direct"); - proxy_settings.set_proxy_server("http://proxy:8080"); - proxy_settings.set_proxy_pac_url("http://proxy:8080/pac.js"); - proxy_settings.set_proxy_bypass_list("127.0.0.1,example.com"); - policy_.payload().mutable_device_proxy_settings()->CopyFrom(proxy_settings); - policy_.Build(); - device_settings_test_helper_.set_policy_blob(policy_.GetBlob()); - Startup(); - + MakeEnterpriseDevice(kTestUser); + + // Startup. + em::PolicyFetchResponse policy; + CreateProxyPolicy(&policy, kTestUser, "direct", "http://proxy:8080", + "http://proxy:8080/pac.js", "127.0.0.1,example.com"); + EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)).WillOnce( + MockSignedSettingsHelperRetrievePolicy(SignedSettings::SUCCESS, + policy)); + EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())); + cache_->Load(); + Mock::VerifyAndClearExpectations(&signed_settings_helper_); DictionaryValue expected; - expected.SetString(key::kProxyMode, proxy_settings.proxy_mode()); - expected.SetString(key::kProxyServer, proxy_settings.proxy_server()); - expected.SetString(key::kProxyPacUrl, proxy_settings.proxy_pac_url()); - expected.SetString(key::kProxyBypassList, proxy_settings.proxy_bypass_list()); - EXPECT_TRUE(Value::Equals(&expected, GetPolicy(key::kProxySettings))); + expected.SetString(key::kProxyMode, "direct"); + expected.SetString(key::kProxyServer, "http://proxy:8080"); + expected.SetString(key::kProxyPacUrl, "http://proxy:8080/pac.js"); + expected.SetString(key::kProxyBypassList, "127.0.0.1,example.com"); + EXPECT_TRUE(Value::Equals(&expected, + GetPolicy(key::kProxySettings))); } TEST_F(DevicePolicyCacheTest, SetDeviceNetworkConfigurationPolicy) { - MakeEnterpriseDevice(); + MakeEnterpriseDevice(kTestUser); + // Startup. std::string fake_config("{ 'NetworkConfigurations': [] }"); - policy_.payload().mutable_open_network_configuration()-> - set_open_network_configuration(fake_config); - policy_.Build(); - device_settings_test_helper_.set_policy_blob(policy_.GetBlob()); - Startup(); - + em::PolicyFetchResponse policy; + em::ChromeDeviceSettingsProto settings; + settings.mutable_open_network_configuration()->set_open_network_configuration( + fake_config); + CreatePolicy(&policy, kTestUser, settings); + EXPECT_CALL(signed_settings_helper_, StartRetrievePolicyOp(_)).WillOnce( + MockSignedSettingsHelperRetrievePolicy(SignedSettings::SUCCESS, + policy)); + EXPECT_CALL(observer_, OnCacheUpdate(cache_.get())); + cache_->Load(); + Mock::VerifyAndClearExpectations(&signed_settings_helper_); StringValue expected_config(fake_config); EXPECT_TRUE( Value::Equals(&expected_config, diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 72daab2..1e2a824 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc @@ -95,7 +95,7 @@ #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/chromeos/preferences.h" #include "chrome/browser/chromeos/proxy_config_service_impl.h" -#include "chrome/browser/chromeos/settings/device_settings_cache.h" +#include "chrome/browser/chromeos/settings/signed_settings_cache.h" #include "chrome/browser/chromeos/status/data_promo_notification.h" #include "chrome/browser/policy/auto_enrollment_client.h" #include "chrome/browser/policy/device_status_collector.h" @@ -179,7 +179,7 @@ void RegisterLocalState(PrefService* local_state) { chromeos::ProxyConfigServiceImpl::RegisterPrefs(local_state); chromeos::UserManager::RegisterPrefs(local_state); chromeos::ServicesCustomizationDocument::RegisterPrefs(local_state); - chromeos::device_settings_cache::RegisterPrefs(local_state); + chromeos::signed_settings_cache::RegisterPrefs(local_state); chromeos::WallpaperManager::RegisterPrefs(local_state); chromeos::WizardController::RegisterPrefs(local_state); policy::AutoEnrollmentClient::RegisterPrefs(local_state); |