Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(608)

Unified Diff: chrome/browser/chromeos/login/user_manager_impl.cc

Issue 11419184: Add public accounts to UserManager (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Made comment easier to understand. Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/login/user_manager_impl.cc
diff --git a/chrome/browser/chromeos/login/user_manager_impl.cc b/chrome/browser/chromeos/login/user_manager_impl.cc
index 14882c0688b8835c871a5ca38420c6e5a69598a6..c5359766ea762e7d8573fc786f4bb17d5b9c4573 100644
--- a/chrome/browser/chromeos/login/user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/user_manager_impl.cc
@@ -4,6 +4,10 @@
#include "chrome/browser/chromeos/login/user_manager_impl.h"
+#include <cstddef>
+#include <set>
+#include <vector>
+
#include "ash/shell.h"
#include "base/bind.h"
#include "base/chromeos/chromeos_version.h"
@@ -23,7 +27,6 @@
#include "chrome/browser/chromeos/login/remove_user_delegate.h"
#include "chrome/browser/chromeos/login/user_image_manager_impl.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
-#include "chrome/browser/chromeos/settings/cros_settings.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"
@@ -44,8 +47,18 @@ namespace chromeos {
namespace {
-// A vector pref of the users who have logged into the device.
-const char kLoggedInUsers[] = "LoggedInUsers";
+// A vector pref of the the regular users known on this device, arranged in LRU
+// order.
+const char kRegularUsers[] = "LoggedInUsers";
+
+// A vector pref of the public accounts defined on this device.
+const char kPublicAccounts[] = "PublicAccounts";
+
+// A string pref that gets set when a public account is removed but a user is
+// currently logged into that account, requiring the account's data to be
+// removed after logout.
+const char kPublicAccountPendingDataRemoval[] =
+ "PublicAccountPendingDataRemoval";
// A dictionary that maps usernames to the displayed name.
const char kUserDisplayName[] = "UserDisplayName";
@@ -97,11 +110,47 @@ void RemoveUserInternal(const std::string& user_email,
delegate->OnUserRemoved(user_email);
}
+// Helper function that copies users from |users_list| to |users_vector| and
+// |users_set|. Duplicates and users already present in |existing_users| are
+// skipped. The |logged_in_user| is also skipped and the return value
+// indicates whether that user was found in |users_list|.
+bool ParseUserList(const ListValue& users_list,
+ const std::set<std::string>& existing_users,
+ const std::string& logged_in_user,
+ std::vector<std::string>* users_vector,
+ std::set<std::string>* users_set) {
+ users_vector->clear();
+ users_set->clear();
+ bool logged_in_user_on_list = false;
+ for (size_t i = 0; i < users_list.GetSize(); ++i) {
+ std::string email;
+ if (!users_list.GetString(i, &email) || email.empty()) {
+ LOG(ERROR) << "Corrupt entry in user list at index " << i << ".";
+ continue;
+ }
+ if (existing_users.find(email) != existing_users.end() ||
+ !users_set->insert(email).second) {
+ LOG(ERROR) << "Duplicate user: " << email;
+ continue;
+ }
+ if (email == logged_in_user) {
+ logged_in_user_on_list = true;
+ continue;
+ }
+ users_vector->push_back(email);
+ }
+ users_set->erase(logged_in_user);
+ return logged_in_user_on_list;
+}
+
} // namespace
// static
void UserManager::RegisterPrefs(PrefService* local_state) {
- local_state->RegisterListPref(kLoggedInUsers, PrefService::UNSYNCABLE_PREF);
+ local_state->RegisterListPref(kRegularUsers, PrefService::UNSYNCABLE_PREF);
+ local_state->RegisterListPref(kPublicAccounts, PrefService::UNSYNCABLE_PREF);
+ local_state->RegisterStringPref(kPublicAccountPendingDataRemoval, "",
+ PrefService::UNSYNCABLE_PREF);
local_state->RegisterDictionaryPref(kUserOAuthTokenStatus,
PrefService::UNSYNCABLE_PREF);
local_state->RegisterDictionaryPref(kUserDisplayName,
@@ -111,7 +160,9 @@ void UserManager::RegisterPrefs(PrefService* local_state) {
}
UserManagerImpl::UserManagerImpl()
- : logged_in_user_(NULL),
+ : cros_settings_(CrosSettings::Get()),
+ users_loaded_(false),
+ logged_in_user_(NULL),
session_started_(false),
is_current_user_owner_(false),
is_current_user_new_(false),
@@ -137,6 +188,12 @@ UserManagerImpl::~UserManagerImpl() {
delete logged_in_user_;
}
+void UserManagerImpl::Shutdown() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ cros_settings_->RemoveSettingsObserver(kAccountsPrefDeviceLocalAccounts,
+ this);
+}
+
UserImageManager* UserManagerImpl::GetUserImageManager() {
return user_image_manager_.get();
}
@@ -168,35 +225,19 @@ void UserManagerImpl::UserLoggedIn(const std::string& email,
EnsureUsersLoaded();
- // Clear the prefs view of the users.
- PrefService* prefs = g_browser_process->local_state();
- ListPrefUpdate prefs_users_update(prefs, kLoggedInUsers);
- prefs_users_update->Clear();
+ // Remove the user from the user list.
+ logged_in_user_ = RemoveRegularUserFromList(email);
- // Make sure this user is first.
- prefs_users_update->Append(new base::StringValue(email));
- UserList::iterator logged_in_user = users_.end();
- for (UserList::iterator it = users_.begin(); it != users_.end(); ++it) {
- std::string user_email = (*it)->email();
- // Skip the most recent user.
- if (email != user_email)
- prefs_users_update->Append(new base::StringValue(user_email));
- else
- logged_in_user = it;
- }
+ // Add the user to the front of the persistent user list.
+ ListPrefUpdate prefs_users_update(g_browser_process->local_state(),
+ kRegularUsers);
+ prefs_users_update->Insert(0, new base::StringValue(email));
- if (logged_in_user == users_.end()) {
+ // If the user was not found on the user list, create a new user.
+ if (!logged_in_user_) {
is_current_user_new_ = true;
logged_in_user_ = User::CreateRegularUser(email);
logged_in_user_->set_oauth_token_status(LoadUserOAuthStatus(email));
- } else {
- logged_in_user_ = *logged_in_user;
- users_.erase(logged_in_user);
- }
- // This user must be in the front of the user list.
- users_.insert(users_.begin(), logged_in_user_);
-
- if (is_current_user_new_) {
SaveUserDisplayName(logged_in_user_->email(),
UTF8ToUTF16(logged_in_user_->GetAccountName(true)));
WallpaperManager::Get()->SetInitialUserWallpaper(email, true);
@@ -209,8 +250,8 @@ void UserManagerImpl::UserLoggedIn(const std::string& email,
WallpaperManager::Get()->EnsureLoggedInUserWallpaperLoaded();
}
- // Make sure we persist new user data to Local State.
- prefs->CommitPendingWrite();
+ // Make sure that new data is persisted to Local State.
+ g_browser_process->local_state()->CommitPendingWrite();
NotifyOnLogin();
}
@@ -253,7 +294,7 @@ void UserManagerImpl::SessionStarted() {
content::NotificationService::AllSources(),
content::NotificationService::NoDetails());
if (is_current_user_new_) {
- // Make sure we persist new user data to Local State.
+ // Make sure that the new user's data is persisted to Local State.
g_browser_process->local_state()->CommitPendingWrite();
}
}
@@ -262,7 +303,8 @@ void UserManagerImpl::RemoveUser(const std::string& email,
RemoveUserDelegate* delegate) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!IsKnownUser(email))
+ const User* user = FindUser(email);
+ if (!user || user->GetType() != User::USER_TYPE_REGULAR)
return;
// Sanity check: we must not remove single user. This check may seem
@@ -283,7 +325,10 @@ void UserManagerImpl::RemoveUser(const std::string& email,
void UserManagerImpl::RemoveUserFromList(const std::string& email) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
EnsureUsersLoaded();
- RemoveUserFromListInternal(email);
+ RemoveNonCryptohomeData(email);
+ delete RemoveRegularUserFromList(email);
+ // Make sure that new data is persisted to Local State.
+ g_browser_process->local_state()->CommitPendingWrite();
}
bool UserManagerImpl::IsKnownUser(const std::string& email) const {
@@ -429,13 +474,18 @@ void UserManagerImpl::Observe(int type,
}
}
break;
+ case chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED:
+ DCHECK_EQ(*content::Details<const std::string>(details).ptr(),
+ kAccountsPrefDeviceLocalAccounts);
+ RetrieveTrustedDevicePolicies();
+ break;
default:
NOTREACHED();
}
}
void UserManagerImpl::OnStateChanged() {
- DCHECK(IsUserLoggedIn() && !IsLoggedInAsGuest());
+ DCHECK(IsLoggedInAsRegularUser());
GoogleServiceAuthError::State state =
observed_sync_service_->GetAuthError().state();
if (state != GoogleServiceAuthError::NONE &&
@@ -484,6 +534,12 @@ bool UserManagerImpl::IsUserLoggedIn() const {
return logged_in_user_;
}
+bool UserManagerImpl::IsLoggedInAsRegularUser() const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return IsUserLoggedIn() &&
+ logged_in_user_->GetType() == User::USER_TYPE_REGULAR;
+}
+
bool UserManagerImpl::IsLoggedInAsDemoUser() const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return IsUserLoggedIn() &&
@@ -553,46 +609,56 @@ void UserManagerImpl::NotifyLocalStateChanged() {
void UserManagerImpl::EnsureUsersLoaded() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!users_.empty())
- return;
if (!g_browser_process)
return;
+ if (users_loaded_)
+ return;
+ users_loaded_ = true;
+
PrefService* local_state = g_browser_process->local_state();
- const ListValue* prefs_users =
- local_state->GetList(kLoggedInUsers);
+ const ListValue* prefs_regular_users = local_state->GetList(kRegularUsers);
+ const ListValue* prefs_public_accounts =
+ local_state->GetList(kPublicAccounts);
const DictionaryValue* prefs_display_names =
local_state->GetDictionary(kUserDisplayName);
const DictionaryValue* prefs_display_emails =
local_state->GetDictionary(kUserDisplayEmail);
- if (!prefs_users)
- return;
-
- for (ListValue::const_iterator it = prefs_users->begin();
- it != prefs_users->end(); ++it) {
- std::string email;
- if ((*it)->GetAsString(&email)) {
- User* user = User::CreateRegularUser(email);
- user->set_oauth_token_status(LoadUserOAuthStatus(email));
- users_.push_back(user);
-
- string16 display_name;
- if (prefs_display_names &&
- prefs_display_names->GetStringWithoutPathExpansion(
- email, &display_name)) {
- user->set_display_name(display_name);
- }
+ // Load regular users.
+ std::vector<std::string> regular_users;
+ std::set<std::string> regular_users_set;
+ ParseUserList(*prefs_regular_users, std::set<std::string>(), "",
+ &regular_users, &regular_users_set);
+ for (std::vector<std::string>::const_iterator it = regular_users.begin();
+ it != regular_users.end(); ++it) {
+ User* user = User::CreateRegularUser(*it);
+ user->set_oauth_token_status(LoadUserOAuthStatus(*it));
+ users_.push_back(user);
+
+ string16 display_name;
+ if (prefs_display_names->GetStringWithoutPathExpansion(*it,
+ &display_name)) {
+ user->set_display_name(display_name);
+ }
- std::string display_email;
- if (prefs_display_emails &&
- prefs_display_emails->GetStringWithoutPathExpansion(
- email, &display_email)) {
- user->set_display_email(display_email);
- }
+ std::string display_email;
+ if (prefs_display_emails->GetStringWithoutPathExpansion(*it,
+ &display_email)) {
+ user->set_display_email(display_email);
}
}
+ // Load public accounts.
+ std::vector<std::string> public_accounts;
+ std::set<std::string> public_accounts_set;
+ ParseUserList(*prefs_public_accounts, regular_users_set, "",
+ &public_accounts, &public_accounts_set);
+ for (std::vector<std::string>::const_iterator it = public_accounts.begin();
+ it != public_accounts.end(); ++it) {
+ users_.push_back(User::CreatePublicAccountUser(*it));
+ }
+
user_image_manager_->LoadUserImages(users_);
}
@@ -600,42 +666,53 @@ void UserManagerImpl::RetrieveTrustedDevicePolicies() {
ephemeral_users_enabled_ = false;
owner_email_ = "";
- CrosSettings* cros_settings = CrosSettings::Get();
// Schedule a callback if device policy has not yet been verified.
- if (CrosSettingsProvider::TRUSTED != cros_settings->PrepareTrustedValues(
+ if (CrosSettingsProvider::TRUSTED != cros_settings_->PrepareTrustedValues(
base::Bind(&UserManagerImpl::RetrieveTrustedDevicePolicies,
base::Unretained(this)))) {
return;
}
- cros_settings->GetBoolean(kAccountsPrefEphemeralUsersEnabled,
- &ephemeral_users_enabled_);
- cros_settings->GetString(kDeviceOwner, &owner_email_);
+ cros_settings_->GetBoolean(kAccountsPrefEphemeralUsersEnabled,
+ &ephemeral_users_enabled_);
+ cros_settings_->GetString(kDeviceOwner, &owner_email_);
+ const base::ListValue* public_accounts;
+ cros_settings_->GetList(kAccountsPrefDeviceLocalAccounts, &public_accounts);
+
+ EnsureUsersLoaded();
+
+ bool changed = UpdateAndCleanUpPublicAccounts(*public_accounts);
// If ephemeral users are enabled and we are on the login screen, take this
- // opportunity to clean up by removing all users except the owner.
+ // opportunity to clean up by removing all regular users except the owner.
if (ephemeral_users_enabled_ && !IsUserLoggedIn()) {
- scoped_ptr<base::ListValue> users(
- g_browser_process->local_state()->GetList(kLoggedInUsers)->DeepCopy());
-
- bool changed = false;
- for (base::ListValue::const_iterator user = users->begin();
- user != users->end(); ++user) {
- std::string user_email;
- (*user)->GetAsString(&user_email);
- if (user_email != owner_email_) {
- RemoveUserFromListInternal(user_email);
+ ListPrefUpdate prefs_users_update(g_browser_process->local_state(),
+ kRegularUsers);
+ prefs_users_update->Clear();
+ for (UserList::iterator it = users_.begin(); it != users_.end(); ) {
+ const std::string user_email = (*it)->email();
+ if ((*it)->GetType() == User::USER_TYPE_REGULAR &&
+ user_email != owner_email_) {
+ RemoveNonCryptohomeData(user_email);
+ delete *it;
+ it = users_.erase(it);
changed = true;
+ } else {
+ prefs_users_update->Append(new base::StringValue(user_email));
+ ++it;
}
}
+ }
- if (changed) {
- content::NotificationService::current()->Notify(
- chrome::NOTIFICATION_POLICY_USER_LIST_CHANGED,
- content::Source<UserManager>(this),
- content::NotificationService::NoDetails());
- }
+ if (changed) {
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_POLICY_USER_LIST_CHANGED,
+ content::Source<UserManager>(this),
+ content::NotificationService::NoDetails());
}
+
+ cros_settings_->AddSettingsObserver(kAccountsPrefDeviceLocalAccounts,
+ this);
}
bool UserManagerImpl::AreEphemeralUsersEnabled() const {
@@ -681,24 +758,11 @@ void UserManagerImpl::CheckOwnership() {
base::Unretained(this)));
}
-void UserManagerImpl::RemoveUserFromListInternal(const std::string& email) {
- // Clear the prefs view of the users.
- PrefService* prefs = g_browser_process->local_state();
- ListPrefUpdate prefs_users_update(prefs, kLoggedInUsers);
- prefs_users_update->Clear();
-
- UserList::iterator user_to_remove = users_.end();
- for (UserList::iterator it = users_.begin(); it != users_.end(); ++it) {
- std::string user_email = (*it)->email();
- // Skip user that we would like to delete.
- if (email != user_email)
- prefs_users_update->Append(new base::StringValue(user_email));
- else
- user_to_remove = it;
- }
-
+void UserManagerImpl::RemoveNonCryptohomeData(const std::string& email) {
WallpaperManager::Get()->RemoveUserWallpaperInfo(email);
+ user_image_manager_->DeleteUserImage(email);
+ PrefService* prefs = g_browser_process->local_state();
DictionaryPrefUpdate prefs_oauth_update(prefs, kUserOAuthTokenStatus);
int oauth_status;
prefs_oauth_update->GetIntegerWithoutPathExpansion(email, &oauth_status);
@@ -709,11 +773,112 @@ void UserManagerImpl::RemoveUserFromListInternal(const std::string& email) {
DictionaryPrefUpdate prefs_display_email_update(prefs, kUserDisplayEmail);
prefs_display_email_update->RemoveWithoutPathExpansion(email, NULL);
+}
+
+User *UserManagerImpl::RemoveRegularUserFromList(const std::string& email) {
+ ListPrefUpdate prefs_users_update(g_browser_process->local_state(),
+ kRegularUsers);
+ prefs_users_update->Clear();
+ User* user = NULL;
+ for (UserList::iterator it = users_.begin(); it != users_.end(); ) {
+ const std::string user_email = (*it)->email();
+ if (user_email == email) {
+ user = *it;
+ it = users_.erase(it);
+ } else {
+ if ((*it)->GetType() == User::USER_TYPE_REGULAR)
+ prefs_users_update->Append(new base::StringValue(user_email));
+ ++it;
+ }
+ }
+ return user;
+}
+
+bool UserManagerImpl::UpdateAndCleanUpPublicAccounts(
+ const base::ListValue& public_accounts) {
+ PrefService* local_state = g_browser_process->local_state();
- if (user_to_remove != users_.end()) {
- delete *user_to_remove;
- users_.erase(user_to_remove);
+ // Determine the currently logged-in user's email.
+ std::string logged_in_user_email;
+ if (IsUserLoggedIn())
+ logged_in_user_email = GetLoggedInUser()->email();
+
+ // If there is a public account whose data is pending removal and the user is
+ // not currently logged in with that account, take this opportunity to remove
+ // the data.
+ std::string public_account_pending_data_removal =
+ local_state->GetString(kPublicAccountPendingDataRemoval);
+ if (!public_account_pending_data_removal.empty() &&
+ public_account_pending_data_removal != logged_in_user_email) {
+ RemoveNonCryptohomeData(public_account_pending_data_removal);
+ local_state->ClearPref(kPublicAccountPendingDataRemoval);
}
+
+ // Split the current user list public accounts and regular users.
+ std::vector<std::string> old_public_accounts;
+ std::set<std::string> regular_users;
+ for (UserList::const_iterator it = users_.begin(); it != users_.end(); ++it) {
+ if ((*it)->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT)
+ old_public_accounts.push_back((*it)->email());
+ else
+ regular_users.insert((*it)->email());
+ }
+
+ // Get the new list of public accounts from policy.
+ std::vector<std::string> new_public_accounts;
+ std::set<std::string> new_public_accounts_set;
+ if (!ParseUserList(public_accounts, regular_users, logged_in_user_email,
+ &new_public_accounts, &new_public_accounts_set) &&
+ IsUserLoggedIn()) {
+ User* user = GetLoggedInUser();
+ // If the user is currently logged into a public account that has been
+ // removed from the list, mark the account's data as pending removal after
+ // logout.
+ if (user->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT) {
+ local_state->SetString(kPublicAccountPendingDataRemoval,
+ logged_in_user_email);
+ }
+ }
+
+ // Persist the new list of public accounts in a pref.
+ ListPrefUpdate prefs_public_accounts_update(local_state, kPublicAccounts);
+ scoped_ptr<base::ListValue> prefs_public_accounts(public_accounts.DeepCopy());
+ prefs_public_accounts_update->Swap(prefs_public_accounts.get());
+
+ // If the list of public accounts has not changed, return.
+ if (new_public_accounts.size() == old_public_accounts.size()) {
+ bool changed = false;
+ for (size_t i = 0; i < new_public_accounts.size(); ++i) {
+ if (new_public_accounts[i] != old_public_accounts[i]) {
+ changed = true;
+ break;
+ }
+ }
+ if (!changed)
+ return false;
+ }
+
+ // Remove the old public accounts from the user list.
+ for (UserList::iterator it = users_.begin(); it != users_.end(); ) {
+ if ((*it)->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT) {
+ delete *it;
+ it = users_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ // Add the new public accounts to the front of the user list.
+ for (std::vector<std::string>::const_reverse_iterator
+ it = new_public_accounts.rbegin();
+ it != new_public_accounts.rend(); ++it) {
+ users_.insert(users_.begin(), User::CreatePublicAccountUser(*it));
+ }
+
+ user_image_manager_->LoadUserImages(
+ UserList(users_.begin(), users_.begin() + new_public_accounts.size()));
+
+ return true;
}
} // namespace chromeos
« no previous file with comments | « chrome/browser/chromeos/login/user_manager_impl.h ('k') | chrome/browser/chromeos/login/user_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698