0

Make sure that cached values of signed settings are trusted.

Verify them at least once since startup.

BUG=chromium-os:8645
TEST=Manual

Review URL: http://codereview.chromium.org/5185001

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@67846 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
dilmah@chromium.org
2010-12-01 13:08:56 +00:00
parent a6a6052d8b
commit e8f8da26a2
12 changed files with 497 additions and 158 deletions

@@ -58,7 +58,7 @@ using __gnu_cxx::hash_set;
namespace __gnu_cxx {
// The GNU C++ library provides identiy hash functions for many integral types,
// The GNU C++ library provides identity hash functions for many integral types,
// but not for |long long|. This hash function will truncate if |size_t| is
// narrower than |long long|. This is probably good enough for what we will
// use it for.

@@ -17,7 +17,7 @@
namespace chromeos {
AccountsOptionsHandler::AccountsOptionsHandler()
: CrosOptionsPageUIHandler(new UserCrosSettingsProvider()) {
: CrosOptionsPageUIHandler(new UserCrosSettingsProvider) {
}
AccountsOptionsHandler::~AccountsOptionsHandler() {

@@ -126,7 +126,8 @@ ExistingUserController::ExistingUserController(
selected_view_index_(kNotSelected),
num_login_attempts_(0),
bubble_(NULL),
user_settings_(new UserCrosSettingsProvider()) {
user_settings_(new UserCrosSettingsProvider),
method_factory_(this) {
if (delete_scheduled_instance_)
delete_scheduled_instance_->Delete();
@@ -302,8 +303,19 @@ void ExistingUserController::WhiteListCheckFailed(const std::string& email) {
void ExistingUserController::LoginOffTheRecord() {
// Check allow_guest in case this call is fired from key accelerator.
if (!UserCrosSettingsProvider::cached_allow_guest())
// Must not proceed without signature verification.
bool trusted_setting_available = user_settings_->RequestTrustedAllowGuest(
method_factory_.NewRunnableMethod(
&ExistingUserController::LoginOffTheRecord));
if (!trusted_setting_available) {
// Value of AllowGuest setting is still not verified.
// Another attempt will be invoked again after verification completion.
return;
}
if (!UserCrosSettingsProvider::cached_allow_guest()) {
// Disallowed.
return;
}
// Disable clicking on other windows.
SendSetLoginState(false);
@@ -356,11 +368,10 @@ void ExistingUserController::ActivateWizard(const std::string& screen_name) {
void ExistingUserController::RemoveUser(UserController* source) {
ClearErrors();
// TODO(xiyuan): Wait for the cached settings update before using them.
if (UserCrosSettingsProvider::cached_owner() == source->user().email()) {
// Owner is not allowed to be removed from the device.
return;
}
// Owner is not allowed to be removed from the device.
// It must be enforced at upper levels.
DCHECK(user_settings_->RequestTrustedOwner(NULL));
DCHECK(source->user().email() != UserCrosSettingsProvider::cached_owner());
UserManager::Get()->RemoveUser(source->user().email());
@@ -548,9 +559,18 @@ void ExistingUserController::OnPasswordChangeDetected(
return;
}
// Must not proceed without signature verification.
bool trusted_setting_available = user_settings_->RequestTrustedOwner(
method_factory_.NewRunnableMethod(
&ExistingUserController::OnPasswordChangeDetected,
credentials));
if (!trusted_setting_available) {
// Value of owner email is still not verified.
// Another attempt will be invoked after verification completion.
return;
}
// TODO(altimofeev): remove this constrain when full sync for the owner will
// be correctly handled.
// TODO(xiyuan): Wait for the cached settings update before using them.
bool full_sync_disabled = (UserCrosSettingsProvider::cached_owner() ==
controllers_[selected_view_index_]->user().email());

@@ -166,9 +166,12 @@ class ExistingUserController : public WmMessageListener::Observer,
// Help application used for help dialogs.
scoped_ptr<HelpAppLauncher> help_app_;
// A user settings provider instance to trigger settings cache update.
// Triggers prefetching of user settings.
scoped_ptr<UserCrosSettingsProvider> user_settings_;
// Factory of callbacks.
ScopedRunnableMethodFactory<ExistingUserController> method_factory_;
DISALLOW_COPY_AND_ASSIGN(ExistingUserController);
};

@@ -21,7 +21,8 @@ namespace {
LoginPerformer::LoginPerformer(Delegate* delegate)
: last_login_failure_(LoginFailure::None()),
delegate_(delegate) {}
delegate_(delegate),
method_factory_(this) {}
////////////////////////////////////////////////////////////////////////////////
// LoginPerformer, LoginStatusConsumer implementation:
@@ -100,6 +101,18 @@ void LoginPerformer::Login(const std::string& username,
const std::string& password) {
username_ = username;
password_ = password;
// Must not proceed without signature verification.
UserCrosSettingsProvider user_settings;
bool trusted_setting_available = user_settings.RequestTrustedAllowNewUser(
method_factory_.NewRunnableMethod(
&LoginPerformer::Login,
username,
password));
if (!trusted_setting_available) {
// Value of AllowNewUser setting is still not verified.
// Another attempt will be invoked after verification completion.
return;
}
if (UserCrosSettingsProvider::cached_allow_new_user()) {
// Starts authentication if guest login is allowed.
StartAuthentication();

@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/ref_counted.h"
#include "base/task.h"
#include "chrome/browser/chromeos/login/authenticator.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/browser/chromeos/login/signed_settings_helper.h"
@@ -107,6 +108,8 @@ class LoginPerformer : public LoginStatusConsumer,
// Notifications receiver.
Delegate* delegate_;
ScopedRunnableMethodFactory<LoginPerformer> method_factory_;
DISALLOW_COPY_AND_ASSIGN(LoginPerformer);
};

@@ -73,8 +73,16 @@ void OwnerManager::GenerateKeysAndExportPublic() {
}
void OwnerManager::ExportKey() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
VLOG(1) << "Exporting public key";
if (!utils_->ExportPublicKeyViaDbus(private_key_.get(), this)) {
if (utils_->ExportPublicKeyViaDbus(private_key_.get(), this)) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableMethod(this,
&OwnerManager::SendNotification,
NotificationType::OWNERSHIP_TAKEN,
NotificationService::NoDetails()));
} else {
private_key_.reset(NULL);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,

@@ -148,7 +148,8 @@ UserController::UserController(Delegate* delegate, bool is_guest)
existing_user_view_(NULL),
guest_user_view_(NULL),
label_view_(NULL),
unselected_label_view_(NULL) {
unselected_label_view_(NULL),
method_factory_(this) {
registrar_.Add(
this,
NotificationType::LOGIN_USER_IMAGE_CHANGED,
@@ -163,9 +164,7 @@ UserController::UserController(Delegate* delegate,
is_guest_(false),
// Empty 'cached_owner()' means that owner hasn't been cached yet, not
// that owner has an empty email.
is_owner_(
!user.email().empty() &&
UserCrosSettingsProvider::cached_owner() == user.email()),
is_owner_(user.email() == UserCrosSettingsProvider::cached_owner()),
show_name_tooltip_(false),
user_(user),
delegate_(delegate),
@@ -179,7 +178,9 @@ UserController::UserController(Delegate* delegate,
existing_user_view_(NULL),
guest_user_view_(NULL),
label_view_(NULL),
unselected_label_view_(NULL) {
unselected_label_view_(NULL),
method_factory_(this) {
DCHECK(!user.email().empty());
registrar_.Add(
this,
NotificationType::LOGIN_USER_IMAGE_CHANGED,
@@ -552,6 +553,19 @@ void UserController::NavigateAway() {
}
void UserController::OnRemoveUser() {
// Must not proceed without signature verification.
UserCrosSettingsProvider user_settings;
bool trusted_owner_available = user_settings.RequestTrustedOwner(
method_factory_.NewRunnableMethod(&UserController::OnRemoveUser));
if (!trusted_owner_available) {
// Value of owner email is still not verified.
// Another attempt will be invoked after verification completion.
return;
}
if (user().email() == UserCrosSettingsProvider::cached_owner()) {
// Owner is not allowed to be removed from the device.
return;
}
delegate_->RemoveUser(this);
}

@@ -9,6 +9,7 @@
#include <string>
#include "base/string16.h"
#include "base/task.h"
#include "chrome/browser/chromeos/login/new_user_view.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/login/user_view.h"
@@ -19,7 +20,6 @@
#include "views/controls/button/button.h"
#include "views/controls/textfield/textfield.h"
#include "views/widget/widget_delegate.h"
namespace views {
class WidgetGtk;
}
@@ -231,6 +231,8 @@ class UserController : public views::ButtonListener,
NotificationRegistrar registrar_;
ScopedRunnableMethodFactory<UserController> method_factory_;
DISALLOW_COPY_AND_ASSIGN(UserController);
};

@@ -4,21 +4,87 @@
#include "chrome/browser/chromeos/user_cros_settings_provider.h"
#include <map>
#include <set>
#include "base/hash_tables.h"
#include "base/logging.h"
#include "base/singleton.h"
#include "base/string_util.h"
#include "base/task.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/login_library.h"
#include "chrome/browser/chromeos/cros_settings.h"
#include "chrome/browser/chromeos/cros_settings_names.h"
#include "chrome/browser/chromeos/login/ownership_service.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
namespace chromeos {
namespace {
const char kTrueIncantation[] = "true";
const char kFalseIncantation[] = "false";
const char kTrustedSuffix[] = "/trusted";
// For all our boolean settings following is applicable:
// true is default permissive value and false is safe prohibitic value.
const char* kBooleanSettings[] = {
kAccountsPrefAllowNewUser,
kAccountsPrefAllowGuest,
kAccountsPrefShowUserNamesOnSignIn
};
const char* kStringSettings[] = {
kDeviceOwner
};
const char* kListSettings[] = {
kAccountsPrefUsers
};
bool IsControlledBooleanSetting(const std::string& pref_path) {
return std::find(kBooleanSettings,
kBooleanSettings + arraysize(kBooleanSettings),
pref_path) !=
kBooleanSettings + arraysize(kBooleanSettings);
}
bool IsControlledStringSetting(const std::string& pref_path) {
return std::find(kStringSettings,
kStringSettings + arraysize(kStringSettings),
pref_path) !=
kStringSettings + arraysize(kStringSettings);
}
bool IsControlledListSetting(const std::string& pref_path) {
return std::find(kListSettings,
kListSettings + arraysize(kListSettings),
pref_path) !=
kListSettings + arraysize(kListSettings);
}
void RegisterSetting(PrefService* local_state, const std::string& pref_path) {
local_state->RegisterBooleanPref((pref_path + kTrustedSuffix).c_str(),
false);
if (IsControlledBooleanSetting(pref_path)) {
local_state->RegisterBooleanPref(pref_path.c_str(), true);
} else if (IsControlledStringSetting(pref_path)) {
local_state->RegisterStringPref(pref_path.c_str(), "");
} else {
DCHECK(IsControlledListSetting(pref_path));
local_state->RegisterListPref(pref_path.c_str());
}
}
Value* CreateSettingsBooleanValue(bool value, bool managed) {
DictionaryValue* dict = new DictionaryValue;
dict->Set("value", Value::CreateBooleanValue(value));
@@ -26,16 +92,30 @@ Value* CreateSettingsBooleanValue(bool value, bool managed) {
return dict;
}
// static
void UpdateCacheBool(const char* name, bool value) {
enum UseValue {
USE_VALUE_SUPPLIED,
USE_VALUE_DEFAULT
};
void UpdateCacheBool(const std::string& name,
bool value,
UseValue use_value) {
PrefService* prefs = g_browser_process->local_state();
prefs->SetBoolean(name, value);
if (use_value == USE_VALUE_DEFAULT)
prefs->ClearPref(name.c_str());
else
prefs->SetBoolean(name.c_str(), value);
prefs->ScheduleSavePersistentPrefs();
}
void UpdateCacheString(const char* name, const std::string& value) {
void UpdateCacheString(const std::string& name,
const std::string& value,
UseValue use_value) {
PrefService* prefs = g_browser_process->local_state();
prefs->SetString(name, value);
if (use_value == USE_VALUE_DEFAULT)
prefs->ClearPref(name.c_str());
else
prefs->SetString(name.c_str(), value);
prefs->ScheduleSavePersistentPrefs();
}
@@ -74,43 +154,333 @@ bool GetUserWhitelist(ListValue* user_list) {
return true;
}
class UserCrosSettingsTrust : public SignedSettingsHelper::Callback,
public NotificationObserver {
public:
static UserCrosSettingsTrust* GetSharedInstance() {
return Singleton<UserCrosSettingsTrust>::get();
}
// Working horse for UserCrosSettingsProvider::RequestTrusted* family.
bool RequestTrustedEntity(const std::string& name, Task* callback) {
if (GetOwnershipStatus() == OWNERSHIP_NONE)
return true;
if (GetOwnershipStatus() == OWNERSHIP_TAKEN) {
DCHECK(g_browser_process);
PrefService* prefs = g_browser_process->local_state();
DCHECK(prefs);
if (prefs->GetBoolean((name + kTrustedSuffix).c_str()))
return true;
}
if (callback)
callbacks_[name].push_back(callback);
return false;
}
void Set(const std::string& path, Value* in_value) {
if (!UserManager::Get()->current_user_is_owner()) {
LOG(WARNING) << "Changing settings from non-owner, setting=" << path;
// Revert UI change.
CrosSettings::Get()->FireObservers(path.c_str());
return;
}
if (IsControlledBooleanSetting(path)) {
bool bool_value = false;
if (in_value->GetAsBoolean(&bool_value)) {
std::string value = bool_value ? kTrueIncantation : kFalseIncantation;
SignedSettingsHelper::Get()->StartStorePropertyOp(path, value, this);
UpdateCacheBool(path, bool_value, USE_VALUE_SUPPLIED);
VLOG(1) << "Set cros setting " << path << "=" << value;
}
} else if (path == kDeviceOwner) {
VLOG(1) << "Setting owner is not supported. Please use "
"'UpdateCachedOwner' instead.";
} else if (path == kAccountsPrefUsers) {
VLOG(1) << "Setting user whitelist is not implemented. Please use "
"whitelist/unwhitelist instead.";
} else {
LOG(WARNING) << "Try to set unhandled cros setting " << path;
}
}
private:
// Listed in upgrade order.
enum OwnershipStatus {
OWNERSHIP_UNKNOWN = 0,
OWNERSHIP_NONE,
OWNERSHIP_TAKEN
};
// Used to discriminate different sources of ownership status info.
enum OwnershipSource {
SOURCE_FETCH, // Info comes from FetchOwnershipStatus method.
SOURCE_OBSERVE // Info comes from Observe method.
};
// upper bound for number of retries to fetch a signed setting.
static const int kNumRetriesLimit = 9;
UserCrosSettingsTrust() : ownership_status_(OWNERSHIP_UNKNOWN),
retries_left_(kNumRetriesLimit) {
notification_registrar_.Add(this,
NotificationType::OWNERSHIP_TAKEN,
NotificationService::AllSources());
// Start getting ownership status.
BrowserThread::PostTask(
BrowserThread::FILE,
FROM_HERE,
NewRunnableMethod(this, &UserCrosSettingsTrust::FetchOwnershipStatus));
}
~UserCrosSettingsTrust() {
if (BrowserThread::CurrentlyOn(BrowserThread::UI) &&
CrosLibrary::Get()->EnsureLoaded()) {
// Cancels all pending callbacks from us.
SignedSettingsHelper::Get()->CancelCallback(this);
}
}
void FetchOwnershipStatus() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
OwnershipStatus status =
OwnershipService::GetSharedInstance()->IsAlreadyOwned() ?
OWNERSHIP_TAKEN : OWNERSHIP_NONE;
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
NewRunnableMethod(this, &UserCrosSettingsTrust::SetOwnershipStatus,
status, SOURCE_FETCH));
}
void SetOwnershipStatus(OwnershipStatus new_status,
OwnershipSource source) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(new_status == OWNERSHIP_TAKEN || new_status == OWNERSHIP_NONE);
if (source == SOURCE_FETCH) {
DCHECK(ownership_status_ != OWNERSHIP_NONE);
if (ownership_status_ == OWNERSHIP_TAKEN) {
// OWNERSHIP_TAKEN notification was observed earlier.
return;
}
}
ownership_status_ = new_status;
if (source == SOURCE_FETCH) {
// Start prefetching Boolean and String preferences.
for (size_t i = 0; i < arraysize(kBooleanSettings); ++i)
StartFetchingSetting(kBooleanSettings[i]);
for (size_t i = 0; i < arraysize(kStringSettings); ++i)
StartFetchingSetting(kStringSettings[i]);
} else if (source == SOURCE_OBSERVE) {
DCHECK(new_status == OWNERSHIP_TAKEN);
if (CrosLibrary::Get()->EnsureLoaded()) {
// TODO(dilmah,cmasone): We would not need following piece of code as
// long as failure callback from SignedSettings will allow us to
// discriminate missing settings from failed signature verification.
// Otherwise we must set default values for boolean settings.
UserManager::Get()->set_current_user_is_owner(true);
for (size_t i = 0; i < arraysize(kBooleanSettings); ++i)
Set(kBooleanSettings[i], Value::CreateBooleanValue(true));
}
}
}
// Returns ownership status.
// Called on UI thread unlike OwnershipService::IsAlreadyOwned.
OwnershipStatus GetOwnershipStatus() {
return ownership_status_;
}
void StartFetchingSetting(const std::string& name) {
DCHECK(g_browser_process);
PrefService* prefs = g_browser_process->local_state();
if (!prefs)
return;
// Do not trust before fetching complete.
prefs->ClearPref((name + kTrustedSuffix).c_str());
prefs->ScheduleSavePersistentPrefs();
if (CrosLibrary::Get()->EnsureLoaded()) {
SignedSettingsHelper::Get()->StartRetrieveProperty(name, this);
}
}
// Implementation of SignedSettingsHelper::Callback.
virtual void OnRetrievePropertyCompleted(bool success,
const std::string& name,
const std::string& value) {
if (!IsControlledBooleanSetting(name) && !IsControlledStringSetting(name)) {
NOTREACHED();
return;
}
DCHECK(GetOwnershipStatus() != OWNERSHIP_UNKNOWN);
PrefService* prefs = g_browser_process->local_state();
if (!success && GetOwnershipStatus() == OWNERSHIP_TAKEN) {
LOG(ERROR) << "On owned device: failed to retrieve cros "
"setting, name=" << name;
if (retries_left_ > 0) {
retries_left_ -= 1;
StartFetchingSetting(name);
return;
}
LOG(ERROR) << "No retries left";
if (IsControlledBooleanSetting(name)) {
// For boolean settings we can just set safe (false) values
// and continue as trusted.
UpdateCacheBool(name, false, USE_VALUE_SUPPLIED);
} else {
prefs->ClearPref((name + kTrustedSuffix).c_str());
return;
}
} else {
DCHECK(success || GetOwnershipStatus() == OWNERSHIP_NONE);
if (success)
VLOG(1) << "Retrieved cros setting " << name << "=" << value;
else
VLOG(1) << "We are disowned. Going default for cros setting " << name;
if (IsControlledBooleanSetting(name)) {
// Our boolean settings are true by default (if not explicitly present).
UpdateCacheBool(name, (value == kTrueIncantation),
success ? USE_VALUE_SUPPLIED : USE_VALUE_DEFAULT);
} else if (IsControlledStringSetting(name)) {
UpdateCacheString(name, value,
success ? USE_VALUE_SUPPLIED : USE_VALUE_DEFAULT);
}
}
prefs->SetBoolean((name + kTrustedSuffix).c_str(), true);
{
DCHECK(GetOwnershipStatus() != OWNERSHIP_UNKNOWN);
std::vector<Task*>& callbacks_vector = callbacks_[name];
for (size_t i = 0; i < callbacks_vector.size(); ++i)
MessageLoop::current()->PostTask(FROM_HERE, callbacks_vector[i]);
callbacks_vector.clear();
}
if (success)
CrosSettings::Get()->FireObservers(name.c_str());
}
// Implementation of SignedSettingsHelper::Callback.
virtual void OnStorePropertyCompleted(bool success,
const std::string& name,
const std::string& value) {
VLOG(1) << "Store cros setting " << name << "=" << value << ", success="
<< success;
// Reload the setting if store op fails.
if (!success)
SignedSettingsHelper::Get()->StartRetrieveProperty(name, this);
}
// Implementation of SignedSettingsHelper::Callback.
virtual void OnWhitelistCompleted(bool success, const std::string& email) {
VLOG(1) << "Add " << email << " to whitelist, success=" << success;
// Reload the whitelist on settings op failure.
if (!success)
CrosSettings::Get()->FireObservers(kAccountsPrefUsers);
}
// Implementation of SignedSettingsHelper::Callback.
virtual void OnUnwhitelistCompleted(bool success, const std::string& email) {
VLOG(1) << "Remove " << email << " from whitelist, success=" << success;
// Reload the whitelist on settings op failure.
if (!success)
CrosSettings::Get()->FireObservers(kAccountsPrefUsers);
}
// NotificationObserver implementation.
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type.value == NotificationType::OWNERSHIP_TAKEN) {
SetOwnershipStatus(OWNERSHIP_TAKEN, SOURCE_OBSERVE);
notification_registrar_.RemoveAll();
} else {
NOTREACHED();
}
}
// Pending callbacks that need to be invoked after settings verification.
base::hash_map< std::string, std::vector< Task* > > callbacks_;
NotificationRegistrar notification_registrar_;
OwnershipStatus ownership_status_;
// In order to guard against occasional failure to fetch a property
// we allow for some number of retries.
int retries_left_;
friend class SignedSettingsHelper;
friend struct DefaultSingletonTraits<UserCrosSettingsTrust>;
DISALLOW_COPY_AND_ASSIGN(UserCrosSettingsTrust);
};
} // namespace
UserCrosSettingsProvider::UserCrosSettingsProvider() {
StartFetchingBoolSetting(kAccountsPrefAllowGuest);
StartFetchingBoolSetting(kAccountsPrefAllowNewUser);
StartFetchingBoolSetting(kAccountsPrefShowUserNamesOnSignIn);
StartFetchingStringSetting(kDeviceOwner);
}
} // namespace chromeos
UserCrosSettingsProvider::~UserCrosSettingsProvider() {
// Cancels all pending callbacks from us.
SignedSettingsHelper::Get()->CancelCallback(this);
// We want to use NewRunnableMethod with this class but need to disable
// reference counting since it is singleton.
DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::UserCrosSettingsTrust);
namespace chromeos {
UserCrosSettingsProvider::UserCrosSettingsProvider() {
// Trigger prefetching of settings.
UserCrosSettingsTrust::GetSharedInstance();
}
// static
void UserCrosSettingsProvider::RegisterPrefs(PrefService* local_state) {
// Cached signed settings values
local_state->RegisterBooleanPref(kAccountsPrefAllowGuest, true);
local_state->RegisterBooleanPref(kAccountsPrefAllowNewUser, true);
local_state->RegisterBooleanPref(kAccountsPrefShowUserNamesOnSignIn, true);
local_state->RegisterListPref(kAccountsPrefUsers);
local_state->RegisterStringPref(kDeviceOwner, "");
for (size_t i = 0; i < arraysize(kBooleanSettings); ++i)
RegisterSetting(local_state, kBooleanSettings[i]);
for (size_t i = 0; i < arraysize(kStringSettings); ++i)
RegisterSetting(local_state, kStringSettings[i]);
for (size_t i = 0; i < arraysize(kListSettings); ++i)
RegisterSetting(local_state, kListSettings[i]);
}
bool UserCrosSettingsProvider::RequestTrustedAllowGuest(Task* callback) {
return UserCrosSettingsTrust::GetSharedInstance()->RequestTrustedEntity(
kAccountsPrefAllowGuest, callback);
}
bool UserCrosSettingsProvider::RequestTrustedAllowNewUser(Task* callback) {
return UserCrosSettingsTrust::GetSharedInstance()->RequestTrustedEntity(
kAccountsPrefAllowNewUser, callback);
}
bool UserCrosSettingsProvider::RequestTrustedShowUsersOnSignin(Task* callback) {
return UserCrosSettingsTrust::GetSharedInstance()->RequestTrustedEntity(
kAccountsPrefShowUserNamesOnSignIn, callback);
}
bool UserCrosSettingsProvider::RequestTrustedOwner(Task* callback) {
return UserCrosSettingsTrust::GetSharedInstance()->RequestTrustedEntity(
kDeviceOwner, callback);
}
// static
bool UserCrosSettingsProvider::cached_allow_guest() {
// Trigger prefetching if singleton object still does not exist.
UserCrosSettingsTrust::GetSharedInstance();
return g_browser_process->local_state()->GetBoolean(kAccountsPrefAllowGuest);
}
// static
bool UserCrosSettingsProvider::cached_allow_new_user() {
// Trigger prefetching if singleton object still does not exist.
UserCrosSettingsTrust::GetSharedInstance();
return g_browser_process->local_state()->GetBoolean(
kAccountsPrefAllowNewUser);
}
// static
bool UserCrosSettingsProvider::cached_show_users_on_signin() {
// Trigger prefetching if singleton object still does not exist.
UserCrosSettingsTrust::GetSharedInstance();
return g_browser_process->local_state()->GetBoolean(
kAccountsPrefShowUserNamesOnSignIn);
}
@@ -132,6 +502,8 @@ const ListValue* UserCrosSettingsProvider::cached_whitelist() {
// static
std::string UserCrosSettingsProvider::cached_owner() {
// Trigger prefetching if singleton object still does not exist.
UserCrosSettingsTrust::GetSharedInstance();
if (!g_browser_process || !g_browser_process->local_state())
return std::string();
return g_browser_process->local_state()->GetString(kDeviceOwner);
@@ -154,41 +526,12 @@ bool UserCrosSettingsProvider::IsEmailInCachedWhitelist(
void UserCrosSettingsProvider::DoSet(const std::string& path,
Value* in_value) {
if (!UserManager::Get()->current_user_is_owner()) {
LOG(WARNING) << "Changing settings from non-owner, setting=" << path;
// Revert UI change.
CrosSettings::Get()->FireObservers(path.c_str());
return;
}
if (path == kAccountsPrefAllowGuest ||
path == kAccountsPrefAllowNewUser ||
path == kAccountsPrefShowUserNamesOnSignIn) {
bool bool_value = false;
if (in_value->GetAsBoolean(&bool_value)) {
std::string value = bool_value ? "true" : "false";
SignedSettingsHelper::Get()->StartStorePropertyOp(path, value, this);
UpdateCacheBool(path.c_str(), bool_value);
VLOG(1) << "Set cros setting " << path << "=" << value;
}
} else if (path == kDeviceOwner) {
VLOG(1) << "Setting owner is not supported. Please use 'UpdateCachedOwner' "
"instead.";
} else if (path == kAccountsPrefUsers) {
VLOG(1) << "Setting user whitelist is not implemented. Please use "
"whitelist/unwhitelist instead.";
} else {
LOG(WARNING) << "Try to set unhandled cros setting " << path;
}
UserCrosSettingsTrust::GetSharedInstance()->Set(path, in_value);
}
bool UserCrosSettingsProvider::Get(const std::string& path,
Value** out_value) const {
if (path == kAccountsPrefAllowGuest ||
path == kAccountsPrefAllowNewUser ||
path == kAccountsPrefShowUserNamesOnSignIn) {
if (IsControlledBooleanSetting(path)) {
*out_value = CreateSettingsBooleanValue(
g_browser_process->local_state()->GetBoolean(path.c_str()),
!UserManager::Get()->current_user_is_owner());
@@ -207,56 +550,9 @@ bool UserCrosSettingsProvider::HandlesSetting(const std::string& path) {
return ::StartsWithASCII(path, "cros.accounts.", true);
}
void UserCrosSettingsProvider::OnWhitelistCompleted(bool success,
const std::string& email) {
VLOG(1) << "Add " << email << " to whitelist, success=" << success;
// Reload the whitelist on settings op failure.
if (!success)
CrosSettings::Get()->FireObservers(kAccountsPrefUsers);
}
void UserCrosSettingsProvider::OnUnwhitelistCompleted(bool success,
const std::string& email) {
VLOG(1) << "Remove " << email << " from whitelist, success=" << success;
// Reload the whitelist on settings op failure.
if (!success)
CrosSettings::Get()->FireObservers(kAccountsPrefUsers);
}
void UserCrosSettingsProvider::OnStorePropertyCompleted(
bool success, const std::string& name, const std::string& value) {
VLOG(1) << "Store cros setting " << name << "=" << value << ", success="
<< success;
// Reload the setting if store op fails.
if (!success)
SignedSettingsHelper::Get()->StartRetrieveProperty(name, this);
}
void UserCrosSettingsProvider::OnRetrievePropertyCompleted(
bool success, const std::string& name, const std::string& value) {
if (!success) {
LOG(WARNING) << "Failed to retrieve cros setting, name=" << name;
return;
}
VLOG(1) << "Retrieved cros setting " << name << "=" << value;
if (bool_settings_.count(name)) {
UpdateCacheBool(name.c_str(), value == "true" ? true : false);
}
if (string_settings_.count(name)) {
UpdateCacheString(name.c_str(), value);
}
CrosSettings::Get()->FireObservers(name.c_str());
}
void UserCrosSettingsProvider::WhitelistUser(const std::string& email) {
SignedSettingsHelper::Get()->StartWhitelistOp(email, true, this);
SignedSettingsHelper::Get()->StartWhitelistOp(
email, true, UserCrosSettingsTrust::GetSharedInstance());
PrefService* prefs = g_browser_process->local_state();
ListValue* cached_whitelist = prefs->GetMutableList(kAccountsPrefUsers);
@@ -265,7 +561,8 @@ void UserCrosSettingsProvider::WhitelistUser(const std::string& email) {
}
void UserCrosSettingsProvider::UnwhitelistUser(const std::string& email) {
SignedSettingsHelper::Get()->StartWhitelistOp(email, false, this);
SignedSettingsHelper::Get()->StartWhitelistOp(
email, false, UserCrosSettingsTrust::GetSharedInstance());
PrefService* prefs = g_browser_process->local_state();
ListValue* cached_whitelist = prefs->GetMutableList(kAccountsPrefUsers);
@@ -276,25 +573,7 @@ void UserCrosSettingsProvider::UnwhitelistUser(const std::string& email) {
// static
void UserCrosSettingsProvider::UpdateCachedOwner(const std::string& email) {
UpdateCacheString(kDeviceOwner, email);
}
void UserCrosSettingsProvider::StartFetchingBoolSetting(
const std::string& name) {
bool_settings_.insert(name);
StartFetchingSetting(name);
}
void UserCrosSettingsProvider::StartFetchingStringSetting(
const std::string& name) {
string_settings_.insert(name);
StartFetchingSetting(name);
}
void UserCrosSettingsProvider::StartFetchingSetting(
const std::string& name) {
if (CrosLibrary::Get()->EnsureLoaded())
SignedSettingsHelper::Get()->StartRetrieveProperty(name, this);
UpdateCacheString(kDeviceOwner, email, USE_VALUE_SUPPLIED);
}
} // namespace chromeos

@@ -9,24 +9,33 @@
#include <string>
#include "base/basictypes.h"
#include "base/hash_tables.h"
#include "chrome/browser/chromeos/cros_settings_provider.h"
#include "chrome/browser/chromeos/login/signed_settings_helper.h"
class ListValue;
class PrefService;
class Task;
namespace chromeos {
class UserCrosSettingsProvider : public CrosSettingsProvider,
public SignedSettingsHelper::Callback {
class UserCrosSettingsProvider : public CrosSettingsProvider {
public:
UserCrosSettingsProvider();
virtual ~UserCrosSettingsProvider();
virtual ~UserCrosSettingsProvider() {}
// Registers cached users settings in preferences.
static void RegisterPrefs(PrefService* local_state);
// Methods to use when trusted (signature verified) values are required.
// Return true if subsequent call to corresponding cached_* getter shall
// return trusted value.
// Return false if trusted values are unavailable at a moment.
// In latter case passed task will be posted when ready.
bool RequestTrustedAllowGuest(Task* callback);
bool RequestTrustedAllowNewUser(Task* callback);
bool RequestTrustedShowUsersOnSignin(Task* callback);
bool RequestTrustedOwner(Task* callback);
// Helper functions to access cached settings.
static bool cached_allow_guest();
static bool cached_allow_new_user();
@@ -43,14 +52,6 @@ class UserCrosSettingsProvider : public CrosSettingsProvider,
virtual bool Get(const std::string& path, Value** out_value) const;
virtual bool HandlesSetting(const std::string& path);
// SignedSettingsHelper::Callback overrides.
virtual void OnWhitelistCompleted(bool success, const std::string& email);
virtual void OnUnwhitelistCompleted(bool success, const std::string& email);
virtual void OnStorePropertyCompleted(
bool success, const std::string& name, const std::string& value);
virtual void OnRetrievePropertyCompleted(
bool success, const std::string& name, const std::string& value);
void WhitelistUser(const std::string& email);
void UnwhitelistUser(const std::string& email);
@@ -61,13 +62,6 @@ class UserCrosSettingsProvider : public CrosSettingsProvider,
// CrosSettingsProvider implementation.
virtual void DoSet(const std::string& path, Value* value);
void StartFetchingBoolSetting(const std::string& name);
void StartFetchingStringSetting(const std::string& name);
void StartFetchingSetting(const std::string& name);
base::hash_set<std::string> bool_settings_;
base::hash_set<std::string> string_settings_;
DISALLOW_COPY_AND_ASSIGN(UserCrosSettingsProvider);
};

@@ -1243,6 +1243,9 @@ class NotificationType {
// os device has failed.
OWNER_KEY_FETCH_ATTEMPT_FAILED,
// Sent after device was successfully owned.
OWNERSHIP_TAKEN,
// This is sent to a ChromeOS settings observer when a system setting is
// changed. The source is the CrosSettings and the details a std::string of
// the changed setting.