1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/user_manager/user_manager_base.h"
6 
7 #include <stddef.h>
8 #include <memory>
9 #include <set>
10 #include <utility>
11 
12 #include "base/bind.h"
13 #include "base/callback_helpers.h"
14 #include "base/command_line.h"
15 #include "base/compiler_specific.h"
16 #include "base/format_macros.h"
17 #include "base/location.h"
18 #include "base/logging.h"
19 #include "base/macros.h"
20 #include "base/metrics/histogram_macros.h"
21 #include "base/single_thread_task_runner.h"
22 #include "base/strings/string_util.h"
23 #include "base/strings/stringprintf.h"
24 #include "base/strings/utf_string_conversions.h"
25 #include "base/values.h"
26 #include "components/prefs/pref_registry_simple.h"
27 #include "components/prefs/pref_service.h"
28 #include "components/prefs/scoped_user_pref_update.h"
29 #include "components/user_manager/known_user.h"
30 #include "components/user_manager/remove_user_delegate.h"
31 #include "components/user_manager/user_type.h"
32 #include "google_apis/gaia/gaia_auth_util.h"
33 
34 namespace user_manager {
35 namespace {
36 
37 // A dictionary that maps user IDs to the displayed name.
38 const char kUserDisplayName[] = "UserDisplayName";
39 
40 // A dictionary that maps user IDs to the user's given name.
41 const char kUserGivenName[] = "UserGivenName";
42 
43 // A dictionary that maps user IDs to the displayed (non-canonical) emails.
44 const char kUserDisplayEmail[] = "UserDisplayEmail";
45 
46 // A dictionary that maps user IDs to OAuth token presence flag.
47 const char kUserOAuthTokenStatus[] = "OAuthTokenStatus";
48 
49 // A dictionary that maps user IDs to a flag indicating whether online
50 // authentication against GAIA should be enforced during the next sign-in.
51 const char kUserForceOnlineSignin[] = "UserForceOnlineSignin";
52 
53 // A dictionary that maps user ID to the user type.
54 const char kUserType[] = "UserType";
55 
56 // A string pref containing the ID of the last user who logged in if it was
57 // a user with gaia account (regular) or an empty string if it was another type
58 // of user (guest, kiosk, public account, etc.).
59 const char kLastLoggedInGaiaUser[] = "LastLoggedInRegularUser";
60 
61 // A string pref containing the ID of the last active user.
62 // In case of browser crash, this pref will be used to set active user after
63 // session restore.
64 const char kLastActiveUser[] = "LastActiveUser";
65 
66 // Upper bound for a histogram metric reporting the amount of time between
67 // one regular user logging out and a different regular user logging in.
68 const int kLogoutToLoginDelayMaxSec = 1800;
69 
70 // This reads integer value from kUserType Local State preference and
71 // interprets it as UserType. It is used in initial users load.
GetStoredUserType(const base::DictionaryValue * prefs_user_types,const AccountId & account_id)72 UserType GetStoredUserType(const base::DictionaryValue* prefs_user_types,
73                            const AccountId& account_id) {
74   const base::Value* stored_user_type = prefs_user_types->FindKey(
75       account_id.HasAccountIdKey() ? account_id.GetAccountIdKey()
76                                    : account_id.GetUserEmail());
77   if (!stored_user_type || !stored_user_type->is_int())
78     return USER_TYPE_REGULAR;
79 
80   int int_user_type = stored_user_type->GetInt();
81   if (int_user_type < 0 || int_user_type >= NUM_USER_TYPES ||
82       int_user_type == 2) {
83     LOG(ERROR) << "Bad user type " << int_user_type;
84     return USER_TYPE_REGULAR;
85   }
86   return static_cast<UserType>(int_user_type);
87 }
88 
89 }  // namespace
90 
91 // static
RegisterPrefs(PrefRegistrySimple * registry)92 void UserManagerBase::RegisterPrefs(PrefRegistrySimple* registry) {
93   registry->RegisterListPref(kRegularUsersPref);
94   registry->RegisterStringPref(kLastLoggedInGaiaUser, std::string());
95   registry->RegisterDictionaryPref(kUserDisplayName);
96   registry->RegisterDictionaryPref(kUserGivenName);
97   registry->RegisterDictionaryPref(kUserDisplayEmail);
98   registry->RegisterDictionaryPref(kUserOAuthTokenStatus);
99   registry->RegisterDictionaryPref(kUserForceOnlineSignin);
100   registry->RegisterDictionaryPref(kUserType);
101   registry->RegisterStringPref(kLastActiveUser, std::string());
102 
103   known_user::RegisterPrefs(registry);
104 }
105 
UserManagerBase(scoped_refptr<base::SingleThreadTaskRunner> task_runner)106 UserManagerBase::UserManagerBase(
107     scoped_refptr<base::SingleThreadTaskRunner> task_runner)
108     : task_runner_(std::move(task_runner)) {}
109 
~UserManagerBase()110 UserManagerBase::~UserManagerBase() {
111   // Can't use STLDeleteElements because of the private destructor of User.
112   for (UserList::iterator it = users_.begin(); it != users_.end();
113        it = users_.erase(it)) {
114     DeleteUser(*it);
115   }
116   // These are pointers to the same User instances that were in users_ list.
117   logged_in_users_.clear();
118   lru_logged_in_users_.clear();
119 
120   DeleteUser(active_user_);
121 }
122 
Shutdown()123 void UserManagerBase::Shutdown() {
124   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
125 }
126 
GetUsers() const127 const UserList& UserManagerBase::GetUsers() const {
128   const_cast<UserManagerBase*>(this)->EnsureUsersLoaded();
129   return users_;
130 }
131 
GetLoggedInUsers() const132 const UserList& UserManagerBase::GetLoggedInUsers() const {
133   return logged_in_users_;
134 }
135 
GetLRULoggedInUsers() const136 const UserList& UserManagerBase::GetLRULoggedInUsers() const {
137   return lru_logged_in_users_;
138 }
139 
GetOwnerAccountId() const140 const AccountId& UserManagerBase::GetOwnerAccountId() const {
141   return owner_account_id_;
142 }
143 
UserLoggedIn(const AccountId & account_id,const std::string & username_hash,bool browser_restart,bool is_child)144 void UserManagerBase::UserLoggedIn(const AccountId& account_id,
145                                    const std::string& username_hash,
146                                    bool browser_restart,
147                                    bool is_child) {
148   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
149 
150   if (!last_session_active_account_id_initialized_) {
151     last_session_active_account_id_ =
152         AccountId::FromUserEmail(GetLocalState()->GetString(kLastActiveUser));
153     last_session_active_account_id_initialized_ = true;
154   }
155 
156   User* user = FindUserInListAndModify(account_id);
157 
158   const UserType user_type =
159       CalculateUserType(account_id, user, browser_restart, is_child);
160   if (active_user_ && user) {
161     user->set_is_logged_in(true);
162     user->set_username_hash(username_hash);
163     logged_in_users_.push_back(user);
164     lru_logged_in_users_.push_back(user);
165 
166     // Reset the new user flag if the user already exists.
167     SetIsCurrentUserNew(false);
168     NotifyUserAddedToSession(user, true /* user switch pending */);
169 
170     return;
171   }
172 
173   if (IsDemoApp(account_id)) {
174     DemoAccountLoggedIn();
175   } else {
176     switch (user_type) {
177       case USER_TYPE_REGULAR:  // fallthrough
178       case USER_TYPE_CHILD:    // fallthrough
179       case USER_TYPE_ACTIVE_DIRECTORY:
180         if (account_id != GetOwnerAccountId() && !user &&
181             (AreEphemeralUsersEnabled() || browser_restart)) {
182           RegularUserLoggedInAsEphemeral(account_id, user_type);
183         } else {
184           RegularUserLoggedIn(account_id, user_type);
185         }
186         break;
187 
188       case USER_TYPE_GUEST:
189         GuestUserLoggedIn();
190         break;
191 
192       case USER_TYPE_PUBLIC_ACCOUNT:
193         PublicAccountUserLoggedIn(
194             user ? user : User::CreatePublicAccountUser(account_id));
195         break;
196 
197       case USER_TYPE_SUPERVISED:
198         NOTREACHED() << "Supervised users are not supported anymore";
199         break;
200 
201       case USER_TYPE_KIOSK_APP:
202       case USER_TYPE_ARC_KIOSK_APP:
203       case USER_TYPE_WEB_KIOSK_APP:
204         KioskAppLoggedIn(user);
205         break;
206 
207       default:
208         NOTREACHED() << "Unhandled usert type " << user_type;
209     }
210   }
211 
212   DCHECK(active_user_);
213   active_user_->set_is_logged_in(true);
214   active_user_->set_is_active(true);
215   active_user_->set_username_hash(username_hash);
216 
217   logged_in_users_.push_back(active_user_);
218   SetLRUUser(active_user_);
219 
220   if (!primary_user_) {
221     primary_user_ = active_user_;
222     if (primary_user_->HasGaiaAccount())
223       SendGaiaUserLoginMetrics(account_id);
224   } else if (primary_user_ != active_user_) {
225     // This is only needed for tests where a new user session is created
226     // for non-existent user. The new user is created and automatically set
227     // to active and there will be no pending user switch in such case.
228     SetIsCurrentUserNew(true);
229     NotifyUserAddedToSession(active_user_, false /* user switch pending */);
230   }
231 
232   UMA_HISTOGRAM_ENUMERATION(
233       "UserManager.LoginUserType", active_user_->GetType(), NUM_USER_TYPES);
234 
235   GetLocalState()->SetString(
236       kLastLoggedInGaiaUser,
237       active_user_->HasGaiaAccount() ? account_id.GetUserEmail() : "");
238 
239   NotifyOnLogin();
240   PerformPostUserLoggedInActions(browser_restart);
241 }
242 
SwitchActiveUser(const AccountId & account_id)243 void UserManagerBase::SwitchActiveUser(const AccountId& account_id) {
244   User* user = FindUserAndModify(account_id);
245   if (!user) {
246     NOTREACHED() << "Switching to a non-existing user";
247     return;
248   }
249   if (user == active_user_) {
250     NOTREACHED() << "Switching to a user who is already active";
251     return;
252   }
253   if (!user->is_logged_in()) {
254     NOTREACHED() << "Switching to a user that is not logged in";
255     return;
256   }
257   if (!user->HasGaiaAccount()) {
258     NOTREACHED() <<
259         "Switching to a user without gaia account (non-regular one)";
260     return;
261   }
262   if (user->username_hash().empty()) {
263     NOTREACHED() << "Switching to a user that doesn't have username_hash set";
264     return;
265   }
266 
267   DCHECK(active_user_);
268   active_user_->set_is_active(false);
269   user->set_is_active(true);
270   active_user_ = user;
271 
272   // Move the user to the front.
273   SetLRUUser(active_user_);
274 
275   NotifyActiveUserHashChanged(active_user_->username_hash());
276   NotifyActiveUserChanged(active_user_);
277   CallUpdateLoginState();
278 }
279 
SwitchToLastActiveUser()280 void UserManagerBase::SwitchToLastActiveUser() {
281   if (!last_session_active_account_id_.is_valid())
282     return;
283 
284   if (AccountId::FromUserEmail(
285           GetActiveUser()->GetAccountId().GetUserEmail()) !=
286       last_session_active_account_id_)
287     SwitchActiveUser(last_session_active_account_id_);
288 
289   // Make sure that this function gets run only once.
290   last_session_active_account_id_.clear();
291 }
292 
OnSessionStarted()293 void UserManagerBase::OnSessionStarted() {
294   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
295 
296   CallUpdateLoginState();
297   GetLocalState()->CommitPendingWrite();
298 }
299 
RemoveUser(const AccountId & account_id,RemoveUserDelegate * delegate)300 void UserManagerBase::RemoveUser(const AccountId& account_id,
301                                  RemoveUserDelegate* delegate) {
302   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
303 
304   if (!CanUserBeRemoved(FindUser(account_id)))
305     return;
306 
307   RemoveUserInternal(account_id, delegate);
308 }
309 
RemoveUserInternal(const AccountId & account_id,RemoveUserDelegate * delegate)310 void UserManagerBase::RemoveUserInternal(const AccountId& account_id,
311                                          RemoveUserDelegate* delegate) {
312   RemoveNonOwnerUserInternal(account_id, delegate);
313 }
314 
RemoveNonOwnerUserInternal(const AccountId & account_id,RemoveUserDelegate * delegate)315 void UserManagerBase::RemoveNonOwnerUserInternal(const AccountId& account_id,
316                                                  RemoveUserDelegate* delegate) {
317   // If account_id points to AccountId in User object, it will become deleted
318   // after RemoveUserFromList(), which could lead to use-after-free in observer.
319   // TODO(https://crbug.com/928534): Update user removal flow to prevent this.
320   const AccountId account_id_copy(account_id);
321 
322   if (delegate)
323     delegate->OnBeforeUserRemoved(account_id);
324   AsyncRemoveCryptohome(account_id);
325   RemoveUserFromList(account_id);
326 
327   if (delegate)
328     delegate->OnUserRemoved(account_id_copy);
329 }
330 
RemoveUserFromList(const AccountId & account_id)331 void UserManagerBase::RemoveUserFromList(const AccountId& account_id) {
332   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
333   RemoveNonCryptohomeData(account_id);
334   known_user::RemovePrefs(account_id);
335   if (user_loading_stage_ == STAGE_LOADED) {
336     // After the User object is deleted from memory in DeleteUser() here,
337     // the account_id reference will be invalid if the reference points
338     // to the account_id in the User object.
339     DeleteUser(
340         RemoveRegularOrSupervisedUserFromList(account_id, true /* notify */));
341   } else {
342     NOTREACHED() << "Users are not loaded yet.";
343     return;
344   }
345 
346   // Make sure that new data is persisted to Local State.
347   GetLocalState()->CommitPendingWrite();
348 }
349 
IsKnownUser(const AccountId & account_id) const350 bool UserManagerBase::IsKnownUser(const AccountId& account_id) const {
351   return FindUser(account_id) != nullptr;
352 }
353 
FindUser(const AccountId & account_id) const354 const User* UserManagerBase::FindUser(const AccountId& account_id) const {
355   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
356   if (active_user_ && active_user_->GetAccountId() == account_id)
357     return active_user_;
358   return FindUserInList(account_id);
359 }
360 
FindUserAndModify(const AccountId & account_id)361 User* UserManagerBase::FindUserAndModify(const AccountId& account_id) {
362   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
363   if (active_user_ && active_user_->GetAccountId() == account_id)
364     return active_user_;
365   return FindUserInListAndModify(account_id);
366 }
367 
GetActiveUser() const368 const User* UserManagerBase::GetActiveUser() const {
369   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
370   return active_user_;
371 }
372 
GetActiveUser()373 User* UserManagerBase::GetActiveUser() {
374   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
375   return active_user_;
376 }
377 
GetPrimaryUser() const378 const User* UserManagerBase::GetPrimaryUser() const {
379   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
380   return primary_user_;
381 }
382 
SaveUserOAuthStatus(const AccountId & account_id,User::OAuthTokenStatus oauth_token_status)383 void UserManagerBase::SaveUserOAuthStatus(
384     const AccountId& account_id,
385     User::OAuthTokenStatus oauth_token_status) {
386   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
387 
388   DVLOG(1) << "Saving user OAuth token status in Local State";
389   User* user = FindUserAndModify(account_id);
390   if (user)
391     user->set_oauth_token_status(oauth_token_status);
392 
393   // Do not update local state if data stored or cached outside the user's
394   // cryptohome is to be treated as ephemeral.
395   if (IsUserNonCryptohomeDataEphemeral(account_id))
396     return;
397 
398   {
399     DictionaryPrefUpdate oauth_status_update(GetLocalState(),
400                                              kUserOAuthTokenStatus);
401     oauth_status_update->SetKey(
402         account_id.GetUserEmail(),
403         base::Value(static_cast<int>(oauth_token_status)));
404   }
405   GetLocalState()->CommitPendingWrite();
406 }
407 
SaveForceOnlineSignin(const AccountId & account_id,bool force_online_signin)408 void UserManagerBase::SaveForceOnlineSignin(const AccountId& account_id,
409                                             bool force_online_signin) {
410   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
411 
412   User* const user = FindUserAndModify(account_id);
413   if (user)
414     user->set_force_online_signin(force_online_signin);
415 
416   // Do not update local state if data stored or cached outside the user's
417   // cryptohome is to be treated as ephemeral.
418   if (IsUserNonCryptohomeDataEphemeral(account_id))
419     return;
420 
421   {
422     DictionaryPrefUpdate force_online_update(GetLocalState(),
423                                              kUserForceOnlineSignin);
424     force_online_update->SetKey(account_id.GetUserEmail(),
425                                 base::Value(force_online_signin));
426   }
427   GetLocalState()->CommitPendingWrite();
428 }
429 
SaveUserDisplayName(const AccountId & account_id,const base::string16 & display_name)430 void UserManagerBase::SaveUserDisplayName(const AccountId& account_id,
431                                           const base::string16& display_name) {
432   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
433 
434   if (User* user = FindUserAndModify(account_id)) {
435     user->set_display_name(display_name);
436 
437     // Do not update local state if data stored or cached outside the user's
438     // cryptohome is to be treated as ephemeral.
439     if (!IsUserNonCryptohomeDataEphemeral(account_id)) {
440       DictionaryPrefUpdate display_name_update(GetLocalState(),
441                                                kUserDisplayName);
442       display_name_update->SetKey(account_id.GetUserEmail(),
443                                   base::Value(display_name));
444     }
445   }
446 }
447 
GetUserDisplayName(const AccountId & account_id) const448 base::string16 UserManagerBase::GetUserDisplayName(
449     const AccountId& account_id) const {
450   const User* user = FindUser(account_id);
451   return user ? user->display_name() : base::string16();
452 }
453 
SaveUserDisplayEmail(const AccountId & account_id,const std::string & display_email)454 void UserManagerBase::SaveUserDisplayEmail(const AccountId& account_id,
455                                            const std::string& display_email) {
456   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
457 
458   User* user = FindUserAndModify(account_id);
459   if (!user) {
460     LOG(ERROR) << "User not found: " << account_id.GetUserEmail();
461     return;  // Ignore if there is no such user.
462   }
463 
464   user->set_display_email(display_email);
465 
466   // Do not update local state if data stored or cached outside the user's
467   // cryptohome is to be treated as ephemeral.
468   if (IsUserNonCryptohomeDataEphemeral(account_id))
469     return;
470 
471   DictionaryPrefUpdate display_email_update(GetLocalState(), kUserDisplayEmail);
472   display_email_update->SetKey(account_id.GetUserEmail(),
473                                base::Value(display_email));
474 }
475 
SaveUserType(const User * user)476 void UserManagerBase::SaveUserType(const User* user) {
477   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
478 
479   CHECK(user);
480   // Do not update local state if data stored or cached outside the user's
481   // cryptohome is to be treated as ephemeral.
482   if (IsUserNonCryptohomeDataEphemeral(user->GetAccountId()))
483     return;
484 
485   DictionaryPrefUpdate user_type_update(GetLocalState(), kUserType);
486   user_type_update->SetKey(user->GetAccountId().GetAccountIdKey(),
487                            base::Value(static_cast<int>(user->GetType())));
488   GetLocalState()->CommitPendingWrite();
489 }
490 
UpdateUserAccountData(const AccountId & account_id,const UserAccountData & account_data)491 void UserManagerBase::UpdateUserAccountData(
492     const AccountId& account_id,
493     const UserAccountData& account_data) {
494   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
495 
496   SaveUserDisplayName(account_id, account_data.display_name());
497 
498   if (User* user = FindUserAndModify(account_id)) {
499     base::string16 given_name = account_data.given_name();
500     user->set_given_name(given_name);
501     if (!IsUserNonCryptohomeDataEphemeral(account_id)) {
502       DictionaryPrefUpdate given_name_update(GetLocalState(), kUserGivenName);
503       given_name_update->SetKey(account_id.GetUserEmail(),
504                                 base::Value(given_name));
505     }
506   }
507 
508   UpdateUserAccountLocale(account_id, account_data.locale());
509 }
510 
ParseUserList(const base::ListValue & users_list,const std::set<AccountId> & existing_users,std::vector<AccountId> * users_vector,std::set<AccountId> * users_set)511 void UserManagerBase::ParseUserList(const base::ListValue& users_list,
512                                     const std::set<AccountId>& existing_users,
513                                     std::vector<AccountId>* users_vector,
514                                     std::set<AccountId>* users_set) {
515   users_vector->clear();
516   users_set->clear();
517   for (size_t i = 0; i < users_list.GetSize(); ++i) {
518     std::string email;
519     if (!users_list.GetString(i, &email) || email.empty()) {
520       LOG(ERROR) << "Corrupt entry in user list at index " << i << ".";
521       continue;
522     }
523 
524     const AccountId account_id = known_user::GetAccountId(
525         email, std::string() /* id */, AccountType::UNKNOWN);
526 
527     if (existing_users.find(account_id) != existing_users.end() ||
528         !users_set->insert(account_id).second) {
529       LOG(ERROR) << "Duplicate user: " << email;
530       continue;
531     }
532     users_vector->push_back(account_id);
533   }
534 }
535 
IsCurrentUserOwner() const536 bool UserManagerBase::IsCurrentUserOwner() const {
537   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
538   return !owner_account_id_.empty() && active_user_ &&
539          active_user_->GetAccountId() == owner_account_id_;
540 }
541 
IsCurrentUserNew() const542 bool UserManagerBase::IsCurrentUserNew() const {
543   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
544   return is_current_user_new_;
545 }
546 
IsCurrentUserNonCryptohomeDataEphemeral() const547 bool UserManagerBase::IsCurrentUserNonCryptohomeDataEphemeral() const {
548   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
549   return IsUserLoggedIn() &&
550          IsUserNonCryptohomeDataEphemeral(GetActiveUser()->GetAccountId());
551 }
552 
IsCurrentUserCryptohomeDataEphemeral() const553 bool UserManagerBase::IsCurrentUserCryptohomeDataEphemeral() const {
554   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
555   return IsUserLoggedIn() &&
556          IsUserCryptohomeDataEphemeral(GetActiveUser()->GetAccountId());
557 }
558 
CanCurrentUserLock() const559 bool UserManagerBase::CanCurrentUserLock() const {
560   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
561   return IsUserLoggedIn() && active_user_->can_lock();
562 }
563 
IsUserLoggedIn() const564 bool UserManagerBase::IsUserLoggedIn() const {
565   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
566   return active_user_;
567 }
568 
IsLoggedInAsUserWithGaiaAccount() const569 bool UserManagerBase::IsLoggedInAsUserWithGaiaAccount() const {
570   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
571   return IsUserLoggedIn() && active_user_->HasGaiaAccount();
572 }
573 
IsLoggedInAsChildUser() const574 bool UserManagerBase::IsLoggedInAsChildUser() const {
575   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
576   return IsUserLoggedIn() && active_user_->GetType() == USER_TYPE_CHILD;
577 }
578 
IsLoggedInAsPublicAccount() const579 bool UserManagerBase::IsLoggedInAsPublicAccount() const {
580   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
581   return IsUserLoggedIn() &&
582          active_user_->GetType() == USER_TYPE_PUBLIC_ACCOUNT;
583 }
584 
IsLoggedInAsGuest() const585 bool UserManagerBase::IsLoggedInAsGuest() const {
586   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
587   return IsUserLoggedIn() && active_user_->GetType() == USER_TYPE_GUEST;
588 }
589 
IsLoggedInAsKioskApp() const590 bool UserManagerBase::IsLoggedInAsKioskApp() const {
591   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
592   return IsUserLoggedIn() && active_user_->GetType() == USER_TYPE_KIOSK_APP;
593 }
594 
IsLoggedInAsArcKioskApp() const595 bool UserManagerBase::IsLoggedInAsArcKioskApp() const {
596   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
597   return IsUserLoggedIn() && active_user_->GetType() == USER_TYPE_ARC_KIOSK_APP;
598 }
599 
IsLoggedInAsWebKioskApp() const600 bool UserManagerBase::IsLoggedInAsWebKioskApp() const {
601   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
602   return IsUserLoggedIn() && active_user_->GetType() == USER_TYPE_WEB_KIOSK_APP;
603 }
604 
IsLoggedInAsAnyKioskApp() const605 bool UserManagerBase::IsLoggedInAsAnyKioskApp() const {
606   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
607   return IsUserLoggedIn() && active_user_->IsKioskType();
608 }
609 
IsLoggedInAsStub() const610 bool UserManagerBase::IsLoggedInAsStub() const {
611   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
612   return IsUserLoggedIn() && IsStubAccountId(active_user_->GetAccountId());
613 }
614 
IsUserNonCryptohomeDataEphemeral(const AccountId & account_id) const615 bool UserManagerBase::IsUserNonCryptohomeDataEphemeral(
616     const AccountId& account_id) const {
617   // Data belonging to the guest and stub users is always ephemeral.
618   if (IsGuestAccountId(account_id) || IsStubAccountId(account_id))
619     return true;
620 
621   // Data belonging to the owner, anyone found on the user list and obsolete
622   // device local accounts whose data has not been removed yet is not ephemeral.
623   if (account_id == GetOwnerAccountId() || UserExistsInList(account_id) ||
624       IsDeviceLocalAccountMarkedForRemoval(account_id)) {
625     return false;
626   }
627 
628   // Data belonging to the currently logged-in user is ephemeral when:
629   // a) The user logged into a regular gaia account while the ephemeral users
630   //    policy was enabled.
631   //    - or -
632   // b) The user logged into any other account type.
633   if (IsUserLoggedIn() && (account_id == GetActiveUser()->GetAccountId()) &&
634       (is_current_user_ephemeral_regular_user_ ||
635        !IsLoggedInAsUserWithGaiaAccount())) {
636     return true;
637   }
638 
639   // Data belonging to any other user is ephemeral when:
640   // a) Going through the regular login flow and the ephemeral users policy is
641   //    enabled.
642   //    - or -
643   // b) The browser is restarting after a crash.
644   return AreEphemeralUsersEnabled() || HasBrowserRestarted();
645 }
646 
IsUserCryptohomeDataEphemeral(const AccountId & account_id) const647 bool UserManagerBase::IsUserCryptohomeDataEphemeral(
648     const AccountId& account_id) const {
649   // Don't consider stub users data as ephemeral.
650   if (IsStubAccountId(account_id))
651     return false;
652 
653   // Data belonging to the guest and demo users is always ephemeral.
654   if (IsGuestAccountId(account_id) || IsDemoApp(account_id))
655     return true;
656 
657   // Data belonging to the public accounts is always ephemeral.
658   const User* user = FindUser(account_id);
659   if (user && user->GetType() == USER_TYPE_PUBLIC_ACCOUNT)
660     return true;
661 
662   // Ephemeral users.
663   if (AreEphemeralUsersEnabled() && user &&
664       user->GetType() == USER_TYPE_REGULAR &&
665       FindUserInList(account_id) == nullptr) {
666     return true;
667   }
668 
669   return false;
670 }
671 
AddObserver(UserManager::Observer * obs)672 void UserManagerBase::AddObserver(UserManager::Observer* obs) {
673   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
674   observer_list_.AddObserver(obs);
675 }
676 
RemoveObserver(UserManager::Observer * obs)677 void UserManagerBase::RemoveObserver(UserManager::Observer* obs) {
678   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
679   observer_list_.RemoveObserver(obs);
680 }
681 
AddSessionStateObserver(UserManager::UserSessionStateObserver * obs)682 void UserManagerBase::AddSessionStateObserver(
683     UserManager::UserSessionStateObserver* obs) {
684   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
685   session_state_observer_list_.AddObserver(obs);
686 }
687 
RemoveSessionStateObserver(UserManager::UserSessionStateObserver * obs)688 void UserManagerBase::RemoveSessionStateObserver(
689     UserManager::UserSessionStateObserver* obs) {
690   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
691   session_state_observer_list_.RemoveObserver(obs);
692 }
693 
NotifyLocalStateChanged()694 void UserManagerBase::NotifyLocalStateChanged() {
695   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
696   for (auto& observer : observer_list_)
697     observer.LocalStateChanged(this);
698 }
699 
NotifyUserImageChanged(const User & user)700 void UserManagerBase::NotifyUserImageChanged(const User& user) {
701   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
702   for (auto& observer : observer_list_)
703     observer.OnUserImageChanged(user);
704 }
705 
NotifyUserProfileImageUpdateFailed(const User & user)706 void UserManagerBase::NotifyUserProfileImageUpdateFailed(const User& user) {
707   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
708   for (auto& observer : observer_list_)
709     observer.OnUserProfileImageUpdateFailed(user);
710 }
711 
NotifyUserProfileImageUpdated(const User & user,const gfx::ImageSkia & profile_image)712 void UserManagerBase::NotifyUserProfileImageUpdated(
713     const User& user,
714     const gfx::ImageSkia& profile_image) {
715   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
716   for (auto& observer : observer_list_)
717     observer.OnUserProfileImageUpdated(user, profile_image);
718 }
719 
NotifyUsersSignInConstraintsChanged()720 void UserManagerBase::NotifyUsersSignInConstraintsChanged() {
721   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
722   for (auto& observer : observer_list_)
723     observer.OnUsersSignInConstraintsChanged();
724 }
725 
CanUserBeRemoved(const User * user) const726 bool UserManagerBase::CanUserBeRemoved(const User* user) const {
727   // Only regular users are allowed to be manually removed.
728   if (!user || !(user->HasGaiaAccount() || user->IsActiveDirectoryUser()))
729     return false;
730 
731   // Sanity check: we must not remove single user unless it's an enterprise
732   // device. This check may seem redundant at a first sight because
733   // this single user must be an owner and we perform special check later
734   // in order not to remove an owner. However due to non-instant nature of
735   // ownership assignment this later check may sometimes fail.
736   // See http://crosbug.com/12723
737   if (users_.size() < 2 && !IsEnterpriseManaged())
738     return false;
739 
740   // Sanity check: do not allow any of the the logged in users to be removed.
741   for (UserList::const_iterator it = logged_in_users_.begin();
742        it != logged_in_users_.end();
743        ++it) {
744     if ((*it)->GetAccountId() == user->GetAccountId())
745       return false;
746   }
747 
748   return true;
749 }
750 
GetEphemeralUsersEnabled() const751 bool UserManagerBase::GetEphemeralUsersEnabled() const {
752   return ephemeral_users_enabled_;
753 }
754 
SetEphemeralUsersEnabled(bool enabled)755 void UserManagerBase::SetEphemeralUsersEnabled(bool enabled) {
756   ephemeral_users_enabled_ = enabled;
757 }
758 
SetIsCurrentUserNew(bool is_new)759 void UserManagerBase::SetIsCurrentUserNew(bool is_new) {
760   is_current_user_new_ = is_new;
761 }
762 
SetOwnerId(const AccountId & owner_account_id)763 void UserManagerBase::SetOwnerId(const AccountId& owner_account_id) {
764   owner_account_id_ = owner_account_id;
765   CallUpdateLoginState();
766 }
767 
GetPendingUserSwitchID() const768 const AccountId& UserManagerBase::GetPendingUserSwitchID() const {
769   return pending_user_switch_;
770 }
771 
SetPendingUserSwitchId(const AccountId & account_id)772 void UserManagerBase::SetPendingUserSwitchId(const AccountId& account_id) {
773   pending_user_switch_ = account_id;
774 }
775 
EnsureUsersLoaded()776 void UserManagerBase::EnsureUsersLoaded() {
777   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
778   if (!GetLocalState())
779     return;
780 
781   if (user_loading_stage_ != STAGE_NOT_LOADED)
782     return;
783   user_loading_stage_ = STAGE_LOADING;
784 
785   PrefService* local_state = GetLocalState();
786   const base::ListValue* prefs_regular_users =
787       local_state->GetList(kRegularUsersPref);
788 
789   const base::DictionaryValue* prefs_display_names =
790       local_state->GetDictionary(kUserDisplayName);
791   const base::DictionaryValue* prefs_given_names =
792       local_state->GetDictionary(kUserGivenName);
793   const base::DictionaryValue* prefs_display_emails =
794       local_state->GetDictionary(kUserDisplayEmail);
795   const base::DictionaryValue* prefs_user_types =
796       local_state->GetDictionary(kUserType);
797 
798   // Load public sessions first.
799   std::set<AccountId> device_local_accounts_set;
800   LoadDeviceLocalAccounts(&device_local_accounts_set);
801 
802   // Load regular users and supervised users.
803   std::vector<AccountId> regular_users;
804   std::set<AccountId> regular_users_set;
805   ParseUserList(*prefs_regular_users, device_local_accounts_set, &regular_users,
806                 &regular_users_set);
807   for (std::vector<AccountId>::const_iterator it = regular_users.begin();
808        it != regular_users.end(); ++it) {
809     if (IsSupervisedAccountId(*it))
810       continue;
811     User* user =
812         User::CreateRegularUser(*it, GetStoredUserType(prefs_user_types, *it));
813     user->set_oauth_token_status(LoadUserOAuthStatus(*it));
814     user->set_force_online_signin(LoadForceOnlineSignin(*it));
815     user->set_using_saml(known_user::IsUsingSAML(*it));
816     users_.push_back(user);
817   }
818 
819   for (auto* user : users_) {
820     auto& account_id = user->GetAccountId();
821     base::string16 display_name;
822     if (prefs_display_names->GetStringWithoutPathExpansion(
823             account_id.GetUserEmail(), &display_name)) {
824       user->set_display_name(display_name);
825     }
826 
827     base::string16 given_name;
828     if (prefs_given_names->GetStringWithoutPathExpansion(
829             account_id.GetUserEmail(), &given_name)) {
830       user->set_given_name(given_name);
831     }
832 
833     std::string display_email;
834     if (prefs_display_emails->GetStringWithoutPathExpansion(
835             account_id.GetUserEmail(), &display_email)) {
836       user->set_display_email(display_email);
837     }
838   }
839   user_loading_stage_ = STAGE_LOADED;
840 
841   PerformPostUserListLoadingActions();
842 }
843 
GetUsersAndModify()844 UserList& UserManagerBase::GetUsersAndModify() {
845   EnsureUsersLoaded();
846   return users_;
847 }
848 
FindUserInList(const AccountId & account_id) const849 const User* UserManagerBase::FindUserInList(const AccountId& account_id) const {
850   const UserList& users = GetUsers();
851   for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
852     if ((*it)->GetAccountId() == account_id)
853       return *it;
854   }
855   return nullptr;
856 }
857 
UserExistsInList(const AccountId & account_id) const858 bool UserManagerBase::UserExistsInList(const AccountId& account_id) const {
859   const base::ListValue* user_list =
860       GetLocalState()->GetList(kRegularUsersPref);
861   for (size_t i = 0; i < user_list->GetSize(); ++i) {
862     std::string email;
863     if (user_list->GetString(i, &email) && (account_id.GetUserEmail() == email))
864       return true;
865   }
866   return false;
867 }
868 
FindUserInListAndModify(const AccountId & account_id)869 User* UserManagerBase::FindUserInListAndModify(const AccountId& account_id) {
870   UserList& users = GetUsersAndModify();
871   for (UserList::iterator it = users.begin(); it != users.end(); ++it) {
872     if ((*it)->GetAccountId() == account_id)
873       return *it;
874   }
875   return nullptr;
876 }
877 
GuestUserLoggedIn()878 void UserManagerBase::GuestUserLoggedIn() {
879   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
880   active_user_ = User::CreateGuestUser(GetGuestAccountId());
881 }
882 
AddUserRecord(User * user)883 void UserManagerBase::AddUserRecord(User* user) {
884   // Add the user to the front of the user list.
885   ListPrefUpdate prefs_users_update(GetLocalState(), kRegularUsersPref);
886   prefs_users_update->Insert(
887       0, std::make_unique<base::Value>(user->GetAccountId().GetUserEmail()));
888   users_.insert(users_.begin(), user);
889 }
890 
RegularUserLoggedIn(const AccountId & account_id,const UserType user_type)891 void UserManagerBase::RegularUserLoggedIn(const AccountId& account_id,
892                                           const UserType user_type) {
893   // Remove the user from the user list.
894   active_user_ =
895       RemoveRegularOrSupervisedUserFromList(account_id, false /* notify */);
896 
897   if (active_user_ && active_user_->GetType() != user_type)
898     active_user_->UpdateType(user_type);
899 
900   // If the user was not found on the user list, create a new user.
901   SetIsCurrentUserNew(!active_user_);
902   if (IsCurrentUserNew()) {
903     active_user_ = User::CreateRegularUser(account_id, user_type);
904     SaveUserType(active_user_);
905 
906     active_user_->set_oauth_token_status(LoadUserOAuthStatus(account_id));
907     SaveUserDisplayName(active_user_->GetAccountId(),
908                         base::UTF8ToUTF16(active_user_->GetAccountName(true)));
909   } else {
910     SaveUserType(active_user_);
911   }
912 
913   AddUserRecord(active_user_);
914   known_user::SetIsEphemeralUser(active_user_->GetAccountId(), false);
915 
916   // Make sure that new data is persisted to Local State.
917   GetLocalState()->CommitPendingWrite();
918 }
919 
RegularUserLoggedInAsEphemeral(const AccountId & account_id,const UserType user_type)920 void UserManagerBase::RegularUserLoggedInAsEphemeral(
921     const AccountId& account_id,
922     const UserType user_type) {
923   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
924   SetIsCurrentUserNew(true);
925   is_current_user_ephemeral_regular_user_ = true;
926   active_user_ = User::CreateRegularUser(account_id, user_type);
927   known_user::SetIsEphemeralUser(active_user_->GetAccountId(), true);
928 }
929 
NotifyActiveUserChanged(User * active_user)930 void UserManagerBase::NotifyActiveUserChanged(User* active_user) {
931   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
932   for (auto& observer : session_state_observer_list_)
933     observer.ActiveUserChanged(active_user);
934 }
935 
NotifyOnLogin()936 void UserManagerBase::NotifyOnLogin() {
937   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
938 
939   NotifyActiveUserHashChanged(active_user_->username_hash());
940   NotifyActiveUserChanged(active_user_);
941   CallUpdateLoginState();
942 }
943 
LoadUserOAuthStatus(const AccountId & account_id) const944 User::OAuthTokenStatus UserManagerBase::LoadUserOAuthStatus(
945     const AccountId& account_id) const {
946   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
947 
948   const base::DictionaryValue* prefs_oauth_status =
949       GetLocalState()->GetDictionary(kUserOAuthTokenStatus);
950   int oauth_token_status = User::OAUTH_TOKEN_STATUS_UNKNOWN;
951   if (prefs_oauth_status &&
952       prefs_oauth_status->GetIntegerWithoutPathExpansion(
953           account_id.GetUserEmail(), &oauth_token_status)) {
954     User::OAuthTokenStatus status =
955         static_cast<User::OAuthTokenStatus>(oauth_token_status);
956     return status;
957   }
958   return User::OAUTH_TOKEN_STATUS_UNKNOWN;
959 }
960 
LoadForceOnlineSignin(const AccountId & account_id) const961 bool UserManagerBase::LoadForceOnlineSignin(const AccountId& account_id) const {
962   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
963 
964   const base::DictionaryValue* prefs_force_online =
965       GetLocalState()->GetDictionary(kUserForceOnlineSignin);
966   bool force_online_signin = false;
967   if (prefs_force_online) {
968     prefs_force_online->GetBooleanWithoutPathExpansion(
969         account_id.GetUserEmail(), &force_online_signin);
970   }
971   return force_online_signin;
972 }
973 
RemoveNonCryptohomeData(const AccountId & account_id)974 void UserManagerBase::RemoveNonCryptohomeData(const AccountId& account_id) {
975   PrefService* prefs = GetLocalState();
976   DictionaryPrefUpdate prefs_display_name_update(prefs, kUserDisplayName);
977   prefs_display_name_update->RemoveKey(account_id.GetUserEmail());
978 
979   DictionaryPrefUpdate prefs_given_name_update(prefs, kUserGivenName);
980   prefs_given_name_update->RemoveKey(account_id.GetUserEmail());
981 
982   DictionaryPrefUpdate prefs_display_email_update(prefs, kUserDisplayEmail);
983   prefs_display_email_update->RemoveKey(account_id.GetUserEmail());
984 
985   DictionaryPrefUpdate prefs_oauth_update(prefs, kUserOAuthTokenStatus);
986   prefs_oauth_update->RemoveKey(account_id.GetUserEmail());
987 
988   DictionaryPrefUpdate prefs_force_online_update(prefs, kUserForceOnlineSignin);
989   prefs_force_online_update->RemoveKey(account_id.GetUserEmail());
990 
991   known_user::RemovePrefs(account_id);
992 
993   const AccountId last_active_user =
994       AccountId::FromUserEmail(GetLocalState()->GetString(kLastActiveUser));
995   if (account_id == last_active_user)
996     GetLocalState()->SetString(kLastActiveUser, std::string());
997 }
998 
RemoveRegularOrSupervisedUserFromList(const AccountId & account_id,bool notify)999 User* UserManagerBase::RemoveRegularOrSupervisedUserFromList(
1000     const AccountId& account_id,
1001     bool notify) {
1002   ListPrefUpdate prefs_users_update(GetLocalState(), kRegularUsersPref);
1003   prefs_users_update->Clear();
1004   User* user = nullptr;
1005   for (UserList::iterator it = users_.begin(); it != users_.end();) {
1006     if ((*it)->GetAccountId() == account_id) {
1007       user = *it;
1008       it = users_.erase(it);
1009     } else {
1010       if ((*it)->HasGaiaAccount() || (*it)->IsActiveDirectoryUser()) {
1011         const std::string user_email = (*it)->GetAccountId().GetUserEmail();
1012         prefs_users_update->AppendString(user_email);
1013       }
1014       ++it;
1015     }
1016   }
1017   if (notify) {
1018     OnUserRemoved(account_id);
1019     NotifyLocalStateChanged();
1020   }
1021   return user;
1022 }
1023 
NotifyUserAddedToSession(const User * added_user,bool user_switch_pending)1024 void UserManagerBase::NotifyUserAddedToSession(const User* added_user,
1025                                                bool user_switch_pending) {
1026   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
1027   for (auto& observer : session_state_observer_list_)
1028     observer.UserAddedToSession(added_user);
1029 }
1030 
NotifyActiveUserHashChanged(const std::string & hash)1031 void UserManagerBase::NotifyActiveUserHashChanged(const std::string& hash) {
1032   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
1033   for (auto& observer : session_state_observer_list_)
1034     observer.ActiveUserHashChanged(hash);
1035 }
1036 
Initialize()1037 void UserManagerBase::Initialize() {
1038   UserManager::Initialize();
1039   if (!HasBrowserRestarted())
1040     known_user::CleanEphemeralUsers();
1041   CallUpdateLoginState();
1042 }
1043 
CallUpdateLoginState()1044 void UserManagerBase::CallUpdateLoginState() {
1045   UpdateLoginState(active_user_, primary_user_, IsCurrentUserOwner());
1046 }
1047 
SetLRUUser(User * user)1048 void UserManagerBase::SetLRUUser(User* user) {
1049   GetLocalState()->SetString(kLastActiveUser,
1050                              user->GetAccountId().GetUserEmail());
1051   GetLocalState()->CommitPendingWrite();
1052 
1053   UserList::iterator it =
1054       std::find(lru_logged_in_users_.begin(), lru_logged_in_users_.end(), user);
1055   if (it != lru_logged_in_users_.end())
1056     lru_logged_in_users_.erase(it);
1057   lru_logged_in_users_.insert(lru_logged_in_users_.begin(), user);
1058 }
1059 
SendGaiaUserLoginMetrics(const AccountId & account_id)1060 void UserManagerBase::SendGaiaUserLoginMetrics(const AccountId& account_id) {
1061   // If this isn't the first time Chrome was run after the system booted,
1062   // assume that Chrome was restarted because a previous session ended.
1063   if (IsFirstExecAfterBoot())
1064     return;
1065 
1066   const std::string last_email =
1067       GetLocalState()->GetString(kLastLoggedInGaiaUser);
1068   const base::TimeDelta time_to_login =
1069       base::TimeTicks::Now() - manager_creation_time_;
1070   if (!last_email.empty() &&
1071       account_id != AccountId::FromUserEmail(last_email) &&
1072       time_to_login.InSeconds() <= kLogoutToLoginDelayMaxSec) {
1073     UMA_HISTOGRAM_CUSTOM_COUNTS("UserManager.LogoutToLoginDelay",
1074                                 time_to_login.InSeconds(), 1,
1075                                 kLogoutToLoginDelayMaxSec, 50);
1076   }
1077 }
1078 
UpdateUserAccountLocale(const AccountId & account_id,const std::string & locale)1079 void UserManagerBase::UpdateUserAccountLocale(const AccountId& account_id,
1080                                               const std::string& locale) {
1081   std::unique_ptr<std::string> resolved_locale(new std::string());
1082   if (!locale.empty() && locale != GetApplicationLocale()) {
1083     // std::move will nullptr out |resolved_locale|, so cache the underlying
1084     // ptr.
1085     std::string* raw_resolved_locale = resolved_locale.get();
1086     ScheduleResolveLocale(
1087         locale,
1088         base::BindOnce(&UserManagerBase::DoUpdateAccountLocale,
1089                        weak_factory_.GetWeakPtr(), account_id,
1090                        std::move(resolved_locale)),
1091         raw_resolved_locale);
1092   } else {
1093     resolved_locale.reset(new std::string(locale));
1094     DoUpdateAccountLocale(account_id, std::move(resolved_locale));
1095   }
1096 }
1097 
DoUpdateAccountLocale(const AccountId & account_id,std::unique_ptr<std::string> resolved_locale)1098 void UserManagerBase::DoUpdateAccountLocale(
1099     const AccountId& account_id,
1100     std::unique_ptr<std::string> resolved_locale) {
1101   User* user = FindUserAndModify(account_id);
1102   if (user && resolved_locale)
1103     user->SetAccountLocale(*resolved_locale);
1104 }
1105 
DeleteUser(User * user)1106 void UserManagerBase::DeleteUser(User* user) {
1107   const bool is_active_user = (user == active_user_);
1108   delete user;
1109   if (is_active_user)
1110     active_user_ = nullptr;
1111 }
1112 
1113 }  // namespace user_manager
1114