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:
@@ -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.
|
||||
|
Reference in New Issue
Block a user