user_manager_screen_handler.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
1// Copyright 2013 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 "chrome/browser/ui/webui/signin/user_manager_screen_handler.h"
6
7#include "base/bind.h"
8#include "base/prefs/pref_service.h"
9#include "base/strings/utf_string_conversions.h"
10#include "base/value_conversions.h"
11#include "base/values.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h"
14#include "chrome/browser/profiles/profile.h"
15#include "chrome/browser/profiles/profile_avatar_icon_util.h"
16#include "chrome/browser/profiles/profile_info_cache.h"
17#include "chrome/browser/profiles/profile_info_cache_observer.h"
18#include "chrome/browser/profiles/profile_manager.h"
19#include "chrome/browser/profiles/profile_metrics.h"
20#include "chrome/browser/profiles/profile_window.h"
21#include "chrome/browser/profiles/profiles_state.h"
22#include "chrome/browser/signin/local_auth.h"
23#include "chrome/browser/ui/browser_dialogs.h"
24#include "chrome/browser/ui/browser_finder.h"
25#include "chrome/browser/ui/singleton_tabs.h"
26#include "chrome/common/pref_names.h"
27#include "chrome/common/url_constants.h"
28#include "content/public/browser/web_contents.h"
29#include "content/public/browser/web_ui.h"
30#include "google_apis/gaia/gaia_auth_fetcher.h"
31#include "google_apis/gaia/gaia_constants.h"
32#include "grit/browser_resources.h"
33#include "grit/chromium_strings.h"
34#include "grit/generated_resources.h"
35#include "grit/theme_resources.h"
36#include "third_party/skia/include/core/SkBitmap.h"
37#include "ui/base/l10n/l10n_util.h"
38#include "ui/base/resource/resource_bundle.h"
39#include "ui/base/webui/web_ui_util.h"
40#include "ui/gfx/image/image.h"
41#include "ui/gfx/image/image_skia.h"
42#include "ui/gfx/image/image_util.h"
43
44namespace {
45// User dictionary keys.
46const char kKeyUsername[] = "username";
47const char kKeyDisplayName[]= "displayName";
48const char kKeyEmailAddress[] = "emailAddress";
49const char kKeyProfilePath[] = "profilePath";
50const char kKeyPublicAccount[] = "publicAccount";
51const char kKeySupervisedUser[] = "supervisedUser";
52const char kKeySignedIn[] = "signedIn";
53const char kKeyCanRemove[] = "canRemove";
54const char kKeyIsOwner[] = "isOwner";
55const char kKeyIsDesktop[] = "isDesktopUser";
56const char kKeyAvatarUrl[] = "userImage";
57const char kKeyNeedsSignin[] = "needsSignin";
58
59// JS API callback names.
60const char kJsApiUserManagerInitialize[] = "userManagerInitialize";
61const char kJsApiUserManagerAddUser[] = "addUser";
62const char kJsApiUserManagerAuthLaunchUser[] = "authenticatedLaunchUser";
63const char kJsApiUserManagerLaunchGuest[] = "launchGuest";
64const char kJsApiUserManagerLaunchUser[] = "launchUser";
65const char kJsApiUserManagerRemoveUser[] = "removeUser";
66const char kJsApiUserManagerAttemptUnlock[] = "attemptUnlock";
67
68const size_t kAvatarIconSize = 180;
69
70void HandleAndDoNothing(const base::ListValue* args) {
71}
72
73// This callback is run if the only profile has been deleted, and a new
74// profile has been created to replace it.
75void OpenNewWindowForProfile(
76    chrome::HostDesktopType desktop_type,
77    Profile* profile,
78    Profile::CreateStatus status) {
79  if (status != Profile::CREATE_STATUS_INITIALIZED)
80    return;
81  profiles::FindOrCreateNewWindowForProfile(
82    profile,
83    chrome::startup::IS_PROCESS_STARTUP,
84    chrome::startup::IS_FIRST_RUN,
85    desktop_type,
86    false);
87}
88
89// This callback is run after switching to a new profile has finished. This
90// means either a new browser window has been opened, or an existing one
91// has been found, which means we can safely close the User Manager without
92// accidentally terminating the browser process. The task needs to be posted,
93// as HideUserManager will end up destroying its WebContents, which will
94// destruct the UserManagerScreenHandler as well.
95void OnSwitchToProfileComplete() {
96  base::MessageLoop::current()->PostTask(
97        FROM_HERE,
98        base::Bind(&chrome::HideUserManager));
99}
100
101std::string GetAvatarImageAtIndex(
102    size_t index, const ProfileInfoCache& info_cache) {
103  bool is_gaia_picture =
104      info_cache.IsUsingGAIAPictureOfProfileAtIndex(index) &&
105      info_cache.GetGAIAPictureOfProfileAtIndex(index);
106
107  // If the avatar is too small (i.e. the old-style low resolution avatar),
108  // it will be pixelated when displayed in the User Manager, so we should
109  // return the placeholder avatar instead.
110  gfx::Image avatar_image = info_cache.GetAvatarIconOfProfileAtIndex(index);
111  if (avatar_image.Width() <= profiles::kAvatarIconWidth ||
112      avatar_image.Height() <= profiles::kAvatarIconHeight ) {
113    avatar_image = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
114        profiles::GetPlaceholderAvatarIconResourceID());
115  }
116  gfx::Image resized_image = profiles::GetSizedAvatarIcon(
117      avatar_image, is_gaia_picture, kAvatarIconSize, kAvatarIconSize);
118  return webui::GetBitmapDataUrl(resized_image.AsBitmap());
119}
120
121size_t GetIndexOfProfileWithEmailAndName(const ProfileInfoCache& info_cache,
122                                         const base::string16& email,
123                                         const base::string16& name) {
124  for (size_t i = 0; i < info_cache.GetNumberOfProfiles(); ++i) {
125    if (info_cache.GetUserNameOfProfileAtIndex(i) == email &&
126        (name.empty() ||
127         profiles::GetAvatarNameForProfile(
128             info_cache.GetPathOfProfileAtIndex(i)) == name)) {
129      return i;
130    }
131  }
132  return std::string::npos;
133}
134
135extensions::ScreenlockPrivateEventRouter* GetScreenlockRouter(
136    const std::string& email) {
137  ProfileInfoCache& info_cache =
138      g_browser_process->profile_manager()->GetProfileInfoCache();
139  const size_t profile_index = GetIndexOfProfileWithEmailAndName(
140      info_cache, base::UTF8ToUTF16(email), base::string16());
141  Profile* profile = g_browser_process->profile_manager()
142      ->GetProfileByPath(info_cache.GetPathOfProfileAtIndex(profile_index));
143  return extensions::ScreenlockPrivateEventRouter::GetFactoryInstance()->Get(
144      profile);
145}
146
147bool IsGuestModeEnabled() {
148  PrefService* service = g_browser_process->local_state();
149  DCHECK(service);
150  return service->GetBoolean(prefs::kBrowserGuestModeEnabled);
151}
152
153}  // namespace
154
155// ProfileUpdateObserver ------------------------------------------------------
156
157class UserManagerScreenHandler::ProfileUpdateObserver
158    : public ProfileInfoCacheObserver {
159 public:
160  ProfileUpdateObserver(
161      ProfileManager* profile_manager, UserManagerScreenHandler* handler)
162      : profile_manager_(profile_manager),
163        user_manager_handler_(handler) {
164    DCHECK(profile_manager_);
165    DCHECK(user_manager_handler_);
166    profile_manager_->GetProfileInfoCache().AddObserver(this);
167  }
168
169  virtual ~ProfileUpdateObserver() {
170    DCHECK(profile_manager_);
171    profile_manager_->GetProfileInfoCache().RemoveObserver(this);
172  }
173
174 private:
175  // ProfileInfoCacheObserver implementation:
176  // If any change has been made to a profile, propagate it to all the
177  // visible user manager screens.
178  virtual void OnProfileAdded(const base::FilePath& profile_path) OVERRIDE {
179    user_manager_handler_->SendUserList();
180  }
181
182  virtual void OnProfileWasRemoved(
183      const base::FilePath& profile_path,
184      const base::string16& profile_name) OVERRIDE {
185    // TODO(noms): Change 'SendUserList' to 'removeUser' JS-call when
186    // UserManager is able to find pod belonging to removed user.
187    user_manager_handler_->SendUserList();
188  }
189
190  virtual void OnProfileNameChanged(
191      const base::FilePath& profile_path,
192      const base::string16& old_profile_name) OVERRIDE {
193    user_manager_handler_->SendUserList();
194  }
195
196  virtual void OnProfileAvatarChanged(
197      const base::FilePath& profile_path) OVERRIDE {
198    user_manager_handler_->SendUserList();
199  }
200
201  virtual void OnProfileSigninRequiredChanged(
202      const base::FilePath& profile_path) OVERRIDE {
203    user_manager_handler_->SendUserList();
204  }
205
206  ProfileManager* profile_manager_;
207
208  UserManagerScreenHandler* user_manager_handler_;  // Weak; owns us.
209
210  DISALLOW_COPY_AND_ASSIGN(ProfileUpdateObserver);
211};
212
213// UserManagerScreenHandler ---------------------------------------------------
214
215UserManagerScreenHandler::UserManagerScreenHandler()
216    : desktop_type_(chrome::GetActiveDesktop()) {
217  profileInfoCacheObserver_.reset(
218      new UserManagerScreenHandler::ProfileUpdateObserver(
219          g_browser_process->profile_manager(), this));
220}
221
222UserManagerScreenHandler::~UserManagerScreenHandler() {
223  ScreenlockBridge::Get()->SetLockHandler(NULL);
224}
225
226void UserManagerScreenHandler::ShowBannerMessage(
227    const base::string16& message) {
228  web_ui()->CallJavascriptFunction(
229      "login.AccountPickerScreen.showBannerMessage",
230      base::StringValue(message));
231}
232
233void UserManagerScreenHandler::ShowUserPodCustomIcon(
234    const std::string& user_email,
235    const ScreenlockBridge::UserPodCustomIconOptions& icon_options) {
236  scoped_ptr<base::DictionaryValue> icon = icon_options.ToDictionaryValue();
237  if (!icon || icon->empty())
238    return;
239  web_ui()->CallJavascriptFunction(
240      "login.AccountPickerScreen.showUserPodCustomIcon",
241      base::StringValue(user_email),
242      *icon);
243}
244
245void UserManagerScreenHandler::HideUserPodCustomIcon(
246    const std::string& user_email) {
247  web_ui()->CallJavascriptFunction(
248      "login.AccountPickerScreen.hideUserPodCustomIcon",
249      base::StringValue(user_email));
250}
251
252void UserManagerScreenHandler::EnableInput() {
253  // Nothing here because UI is not disabled when starting to authenticate.
254}
255
256void UserManagerScreenHandler::SetAuthType(
257    const std::string& user_email,
258    ScreenlockBridge::LockHandler::AuthType auth_type,
259    const base::string16& auth_value) {
260  if (GetAuthType(user_email) ==
261          ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD)
262    return;
263
264  user_auth_type_map_[user_email] = auth_type;
265  web_ui()->CallJavascriptFunction(
266      "login.AccountPickerScreen.setAuthType",
267      base::StringValue(user_email),
268      base::FundamentalValue(auth_type),
269      base::StringValue(auth_value));
270}
271
272ScreenlockBridge::LockHandler::AuthType UserManagerScreenHandler::GetAuthType(
273      const std::string& user_email) const {
274  UserAuthTypeMap::const_iterator it = user_auth_type_map_.find(user_email);
275  if (it == user_auth_type_map_.end())
276    return ScreenlockBridge::LockHandler::OFFLINE_PASSWORD;
277  return it->second;
278}
279
280void UserManagerScreenHandler::Unlock(const std::string& user_email) {
281  ProfileInfoCache& info_cache =
282      g_browser_process->profile_manager()->GetProfileInfoCache();
283  const size_t profile_index = GetIndexOfProfileWithEmailAndName(
284      info_cache, base::UTF8ToUTF16(user_email), base::string16());
285  DCHECK_LT(profile_index, info_cache.GetNumberOfProfiles());
286
287  authenticating_profile_index_ = profile_index;
288  ReportAuthenticationResult(true, ProfileMetrics::AUTH_LOCAL);
289}
290
291void UserManagerScreenHandler::HandleInitialize(const base::ListValue* args) {
292  SendUserList();
293  web_ui()->CallJavascriptFunction("cr.ui.Oobe.showUserManagerScreen",
294      base::FundamentalValue(IsGuestModeEnabled()));
295  desktop_type_ = chrome::GetHostDesktopTypeForNativeView(
296      web_ui()->GetWebContents()->GetNativeView());
297
298  ScreenlockBridge::Get()->SetLockHandler(this);
299}
300
301void UserManagerScreenHandler::HandleAddUser(const base::ListValue* args) {
302  profiles::CreateAndSwitchToNewProfile(desktop_type_,
303                                        base::Bind(&OnSwitchToProfileComplete),
304                                        ProfileMetrics::ADD_NEW_USER_MANAGER);
305}
306
307void UserManagerScreenHandler::HandleAuthenticatedLaunchUser(
308    const base::ListValue* args) {
309  base::string16 email_address;
310  if (!args->GetString(0, &email_address))
311    return;
312
313  base::string16 display_name;
314  if (!args->GetString(1, &display_name))
315    return;
316
317  std::string password;
318  if (!args->GetString(2, &password))
319    return;
320
321  ProfileInfoCache& info_cache =
322      g_browser_process->profile_manager()->GetProfileInfoCache();
323  size_t profile_index = GetIndexOfProfileWithEmailAndName(
324      info_cache, email_address, display_name);
325  if (profile_index >= info_cache.GetNumberOfProfiles()) {
326    NOTREACHED();
327    return;
328  }
329
330  authenticating_profile_index_ = profile_index;
331  if (!chrome::ValidateLocalAuthCredentials(profile_index, password)) {
332    // Make a second attempt via an on-line authentication call.  This handles
333    // profiles that are missing sign-in credentials and also cases where the
334    // password has been changed externally.
335    client_login_.reset(new GaiaAuthFetcher(
336        this,
337        GaiaConstants::kChromeSource,
338        web_ui()->GetWebContents()->GetBrowserContext()->GetRequestContext()));
339    std::string email_string;
340    args->GetString(0, &email_string);
341    client_login_->StartClientLogin(
342        email_string,
343        password,
344        GaiaConstants::kSyncService,
345        std::string(),
346        std::string(),
347        GaiaAuthFetcher::HostedAccountsAllowed);
348    password_attempt_ = password;
349    return;
350  }
351
352  ReportAuthenticationResult(true, ProfileMetrics::AUTH_LOCAL);
353}
354
355void UserManagerScreenHandler::HandleRemoveUser(const base::ListValue* args) {
356  DCHECK(args);
357  const base::Value* profile_path_value;
358  if (!args->Get(0, &profile_path_value))
359    return;
360
361  base::FilePath profile_path;
362  if (!base::GetValueAsFilePath(*profile_path_value, &profile_path))
363    return;
364
365  // This handler could have been called for a supervised user, for example
366  // because the user fiddled with the web inspector. Silently return in this
367  // case.
368  if (Profile::FromWebUI(web_ui())->IsSupervised())
369    return;
370
371  if (!profiles::IsMultipleProfilesEnabled())
372    return;
373
374  g_browser_process->profile_manager()->ScheduleProfileForDeletion(
375      profile_path,
376      base::Bind(&OpenNewWindowForProfile, desktop_type_));
377  ProfileMetrics::LogProfileDeleteUser(
378      ProfileMetrics::DELETE_PROFILE_USER_MANAGER);
379}
380
381void UserManagerScreenHandler::HandleLaunchGuest(const base::ListValue* args) {
382  if (IsGuestModeEnabled()) {
383    profiles::SwitchToGuestProfile(desktop_type_,
384                                   base::Bind(&OnSwitchToProfileComplete));
385    ProfileMetrics::LogProfileSwitchUser(ProfileMetrics::SWITCH_PROFILE_GUEST);
386  } else {
387    // The UI should have prevented the user from allowing the selection of
388    // guest mode.
389    NOTREACHED();
390  }
391}
392
393void UserManagerScreenHandler::HandleLaunchUser(const base::ListValue* args) {
394  base::string16 email_address;
395  base::string16 display_name;
396
397  if (!args->GetString(0, &email_address) ||
398      !args->GetString(1, &display_name)) {
399    NOTREACHED();
400    return;
401  }
402
403  ProfileInfoCache& info_cache =
404      g_browser_process->profile_manager()->GetProfileInfoCache();
405  size_t profile_index = GetIndexOfProfileWithEmailAndName(
406      info_cache, email_address, display_name);
407
408  if (profile_index >= info_cache.GetNumberOfProfiles()) {
409    NOTREACHED();
410    return;
411  }
412
413  // It's possible that a user breaks into the user-manager page using the
414  // JavaScript Inspector and causes a "locked" profile to call this
415  // unauthenticated version of "launch" instead of the proper one.  Thus,
416  // we have to validate in (secure) C++ code that it really is a profile
417  // not needing authentication.  If it is, just ignore the "launch" request.
418  if (info_cache.ProfileIsSigninRequiredAtIndex(profile_index))
419    return;
420  ProfileMetrics::LogProfileAuthResult(ProfileMetrics::AUTH_UNNECESSARY);
421
422  base::FilePath path = info_cache.GetPathOfProfileAtIndex(profile_index);
423  profiles::SwitchToProfile(path,
424                            desktop_type_,
425                            false,  /* reuse any existing windows */
426                            base::Bind(&OnSwitchToProfileComplete),
427                            ProfileMetrics::SWITCH_PROFILE_MANAGER);
428}
429
430void UserManagerScreenHandler::HandleAttemptUnlock(
431    const base::ListValue* args) {
432  std::string email;
433  CHECK(args->GetString(0, &email));
434  GetScreenlockRouter(email)->OnAuthAttempted(GetAuthType(email), "");
435}
436
437void UserManagerScreenHandler::HandleHardlockUserPod(
438    const base::ListValue* args) {
439  std::string email;
440  CHECK(args->GetString(0, &email));
441  SetAuthType(email,
442              ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD,
443              base::string16());
444  HideUserPodCustomIcon(email);
445}
446
447void UserManagerScreenHandler::OnClientLoginSuccess(
448    const ClientLoginResult& result) {
449  chrome::SetLocalAuthCredentials(authenticating_profile_index_,
450                                  password_attempt_);
451  ReportAuthenticationResult(true, ProfileMetrics::AUTH_ONLINE);
452}
453
454void UserManagerScreenHandler::OnClientLoginFailure(
455    const GoogleServiceAuthError& error) {
456  const GoogleServiceAuthError::State state = error.state();
457  // Some "error" results mean the password was correct but some other action
458  // should be taken.  For our purposes, we only care that the password was
459  // correct so count those as a success.
460  bool success = (state == GoogleServiceAuthError::NONE ||
461                  state == GoogleServiceAuthError::CAPTCHA_REQUIRED ||
462                  state == GoogleServiceAuthError::TWO_FACTOR ||
463                  state == GoogleServiceAuthError::ACCOUNT_DELETED ||
464                  state == GoogleServiceAuthError::ACCOUNT_DISABLED);
465  ReportAuthenticationResult(success,
466                             success ? ProfileMetrics::AUTH_ONLINE
467                                     : ProfileMetrics::AUTH_FAILED);
468}
469
470void UserManagerScreenHandler::RegisterMessages() {
471  web_ui()->RegisterMessageCallback(kJsApiUserManagerInitialize,
472      base::Bind(&UserManagerScreenHandler::HandleInitialize,
473                 base::Unretained(this)));
474  web_ui()->RegisterMessageCallback(kJsApiUserManagerAddUser,
475      base::Bind(&UserManagerScreenHandler::HandleAddUser,
476                 base::Unretained(this)));
477  web_ui()->RegisterMessageCallback(kJsApiUserManagerAuthLaunchUser,
478      base::Bind(&UserManagerScreenHandler::HandleAuthenticatedLaunchUser,
479                 base::Unretained(this)));
480  web_ui()->RegisterMessageCallback(kJsApiUserManagerLaunchGuest,
481      base::Bind(&UserManagerScreenHandler::HandleLaunchGuest,
482                 base::Unretained(this)));
483  web_ui()->RegisterMessageCallback(kJsApiUserManagerLaunchUser,
484      base::Bind(&UserManagerScreenHandler::HandleLaunchUser,
485                 base::Unretained(this)));
486  web_ui()->RegisterMessageCallback(kJsApiUserManagerRemoveUser,
487      base::Bind(&UserManagerScreenHandler::HandleRemoveUser,
488                 base::Unretained(this)));
489  web_ui()->RegisterMessageCallback(kJsApiUserManagerAttemptUnlock,
490      base::Bind(&UserManagerScreenHandler::HandleAttemptUnlock,
491                 base::Unretained(this)));
492
493  const content::WebUI::MessageCallback& kDoNothingCallback =
494      base::Bind(&HandleAndDoNothing);
495
496  // Unused callbacks from screen_account_picker.js
497  web_ui()->RegisterMessageCallback("accountPickerReady", kDoNothingCallback);
498  web_ui()->RegisterMessageCallback("loginUIStateChanged", kDoNothingCallback);
499  web_ui()->RegisterMessageCallback("hideCaptivePortal", kDoNothingCallback);
500  // Unused callbacks from display_manager.js
501  web_ui()->RegisterMessageCallback("showAddUser", kDoNothingCallback);
502  web_ui()->RegisterMessageCallback("loadWallpaper", kDoNothingCallback);
503  web_ui()->RegisterMessageCallback("updateCurrentScreen", kDoNothingCallback);
504  web_ui()->RegisterMessageCallback("loginVisible", kDoNothingCallback);
505  // Unused callbacks from user_pod_row.js
506  web_ui()->RegisterMessageCallback("focusPod", kDoNothingCallback);
507}
508
509void UserManagerScreenHandler::GetLocalizedValues(
510    base::DictionaryValue* localized_strings) {
511  // For Control Bar.
512  localized_strings->SetString("signedIn",
513      l10n_util::GetStringUTF16(IDS_SCREEN_LOCK_ACTIVE_USER));
514  localized_strings->SetString("signinButton",
515      l10n_util::GetStringUTF16(IDS_LOGIN_BUTTON));
516  localized_strings->SetString("addUser",
517      l10n_util::GetStringUTF16(IDS_ADD_USER_BUTTON));
518  localized_strings->SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL));
519  localized_strings->SetString("browseAsGuest",
520      l10n_util::GetStringUTF16(IDS_GO_INCOGNITO_BUTTON));
521  localized_strings->SetString("signOutUser",
522      l10n_util::GetStringUTF16(IDS_SCREEN_LOCK_SIGN_OUT));
523
524  // For AccountPickerScreen.
525  localized_strings->SetString("screenType", "login-add-user");
526  localized_strings->SetString("highlightStrength", "normal");
527  localized_strings->SetString("title",
528      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
529  localized_strings->SetString("passwordHint",
530      l10n_util::GetStringUTF16(IDS_LOGIN_POD_EMPTY_PASSWORD_TEXT));
531  localized_strings->SetString("podMenuButtonAccessibleName",
532      l10n_util::GetStringUTF16(IDS_LOGIN_POD_MENU_BUTTON_ACCESSIBLE_NAME));
533  localized_strings->SetString("podMenuRemoveItemAccessibleName",
534      l10n_util::GetStringUTF16(
535          IDS_LOGIN_POD_MENU_REMOVE_ITEM_ACCESSIBLE_NAME));
536  localized_strings->SetString("removeUser",
537      l10n_util::GetStringUTF16(IDS_LOGIN_POD_USER_REMOVE_WARNING_BUTTON));
538  localized_strings->SetString("passwordFieldAccessibleName",
539      l10n_util::GetStringUTF16(IDS_LOGIN_POD_PASSWORD_FIELD_ACCESSIBLE_NAME));
540  localized_strings->SetString("bootIntoWallpaper", "off");
541
542  // For AccountPickerScreen, the remove user warning overlay.
543  localized_strings->SetString("removeUserWarningButtonTitle",
544      l10n_util::GetStringUTF16(IDS_LOGIN_POD_USER_REMOVE_WARNING_BUTTON));
545  localized_strings->SetString("removeUserWarningText",
546      l10n_util::GetStringUTF16(IDS_LOGIN_POD_USER_REMOVE_WARNING));
547  localized_strings->SetString("removeSupervisedUserWarningText",
548      l10n_util::GetStringFUTF16(
549          IDS_LOGIN_POD_SUPERVISED_USER_REMOVE_WARNING,
550          base::UTF8ToUTF16(chrome::kSupervisedUserManagementDisplayURL)));
551
552  // Strings needed for the User Manager tutorial slides.
553  localized_strings->SetString("tutorialNext",
554      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_NEXT));
555  localized_strings->SetString("tutorialDone",
556      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_DONE));
557  localized_strings->SetString("slideWelcomeTitle",
558      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_INTRO_TITLE));
559  localized_strings->SetString("slideWelcomeText",
560      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_INTRO_TEXT));
561  localized_strings->SetString("slideYourChromeTitle",
562      l10n_util::GetStringUTF16(
563          IDS_USER_MANAGER_TUTORIAL_SLIDE_YOUR_CHROME_TITLE));
564  localized_strings->SetString("slideYourChromeText", l10n_util::GetStringUTF16(
565      IDS_USER_MANAGER_TUTORIAL_SLIDE_YOUR_CHROME_TEXT));
566  localized_strings->SetString("slideGuestsTitle",
567      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_GUEST_TITLE));
568  localized_strings->SetString("slideGuestsText",
569      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_GUEST_TEXT));
570  localized_strings->SetString("slideFriendsTitle",
571      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_FRIENDS_TITLE));
572  localized_strings->SetString("slideFriendsText",
573      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_FRIENDS_TEXT));
574  localized_strings->SetString("slideCompleteTitle",
575      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_OUTRO_TITLE));
576  localized_strings->SetString("slideCompleteText",
577      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_OUTRO_TEXT));
578  localized_strings->SetString("slideCompleteUserNotFound",
579      l10n_util::GetStringUTF16(
580          IDS_USER_MANAGER_TUTORIAL_SLIDE_OUTRO_USER_NOT_FOUND));
581  localized_strings->SetString("slideCompleteAddUser",
582      l10n_util::GetStringUTF16(
583          IDS_USER_MANAGER_TUTORIAL_SLIDE_OUTRO_ADD_USER));
584
585  // Strings needed for the user_pod_template public account div, but not ever
586  // actually displayed for desktop users.
587  localized_strings->SetString("publicAccountReminder", base::string16());
588  localized_strings->SetString("publicSessionLanguageAndInput",
589                               base::string16());
590  localized_strings->SetString("publicAccountEnter", base::string16());
591  localized_strings->SetString("publicAccountEnterAccessibleName",
592                               base::string16());
593  localized_strings->SetString("publicSessionSelectLanguage", base::string16());
594  localized_strings->SetString("publicSessionSelectKeyboard", base::string16());
595  localized_strings->SetString("signinBannerText", base::string16());
596  localized_strings->SetString("launchAppButton", base::string16());
597  localized_strings->SetString("multiProfilesRestrictedPolicyTitle",
598                               base::string16());
599  localized_strings->SetString("multiProfilesNotAllowedPolicyMsg",
600                                base::string16());
601  localized_strings->SetString("multiProfilesPrimaryOnlyPolicyMsg",
602                                base::string16());
603  localized_strings->SetString("multiProfilesOwnerPrimaryOnlyMsg",
604                                base::string16());
605}
606
607void UserManagerScreenHandler::SendUserList() {
608  base::ListValue users_list;
609  base::FilePath active_profile_path =
610      web_ui()->GetWebContents()->GetBrowserContext()->GetPath();
611  const ProfileInfoCache& info_cache =
612      g_browser_process->profile_manager()->GetProfileInfoCache();
613
614  user_auth_type_map_.clear();
615
616  // If the active user is a supervised user, then they may not perform
617  // certain actions (i.e. delete another user).
618  bool active_user_is_supervised = Profile::FromWebUI(web_ui())->IsSupervised();
619  for (size_t i = 0; i < info_cache.GetNumberOfProfiles(); ++i) {
620    base::DictionaryValue* profile_value = new base::DictionaryValue();
621
622    base::FilePath profile_path = info_cache.GetPathOfProfileAtIndex(i);
623    bool is_active_user = (profile_path == active_profile_path);
624
625    profile_value->SetString(
626        kKeyUsername, info_cache.GetUserNameOfProfileAtIndex(i));
627    profile_value->SetString(
628        kKeyEmailAddress, info_cache.GetUserNameOfProfileAtIndex(i));
629    // The profiles displayed in the User Manager are never guest profiles.
630    profile_value->SetString(
631        kKeyDisplayName,
632        profiles::GetAvatarNameForProfile(profile_path));
633    profile_value->SetString(kKeyProfilePath, profile_path.MaybeAsASCII());
634    profile_value->SetBoolean(kKeyPublicAccount, false);
635    profile_value->SetBoolean(
636        kKeySupervisedUser, info_cache.ProfileIsSupervisedAtIndex(i));
637    profile_value->SetBoolean(kKeySignedIn, is_active_user);
638    profile_value->SetBoolean(
639        kKeyNeedsSignin, info_cache.ProfileIsSigninRequiredAtIndex(i));
640    profile_value->SetBoolean(kKeyIsOwner, false);
641    profile_value->SetBoolean(kKeyCanRemove, !active_user_is_supervised);
642    profile_value->SetBoolean(kKeyIsDesktop, true);
643    profile_value->SetString(
644        kKeyAvatarUrl, GetAvatarImageAtIndex(i, info_cache));
645
646    // The row of user pods should display the active user first.
647    if (is_active_user)
648      users_list.Insert(0, profile_value);
649    else
650      users_list.Append(profile_value);
651  }
652
653  web_ui()->CallJavascriptFunction("login.AccountPickerScreen.loadUsers",
654      users_list, base::FundamentalValue(IsGuestModeEnabled()));
655}
656
657void UserManagerScreenHandler::ReportAuthenticationResult(
658    bool success,
659    ProfileMetrics::ProfileAuth auth) {
660  ProfileMetrics::LogProfileAuthResult(auth);
661  password_attempt_.clear();
662
663  if (success) {
664    ProfileInfoCache& info_cache =
665        g_browser_process->profile_manager()->GetProfileInfoCache();
666    info_cache.SetProfileSigninRequiredAtIndex(
667        authenticating_profile_index_, false);
668    base::FilePath path = info_cache.GetPathOfProfileAtIndex(
669        authenticating_profile_index_);
670    profiles::SwitchToProfile(path, desktop_type_, true,
671                              base::Bind(&OnSwitchToProfileComplete),
672                              ProfileMetrics::SWITCH_PROFILE_UNLOCK);
673  } else {
674    web_ui()->CallJavascriptFunction(
675        "cr.ui.Oobe.showSignInError",
676        base::FundamentalValue(0),
677        base::StringValue(
678            l10n_util::GetStringUTF8(IDS_LOGIN_ERROR_AUTHENTICATING)),
679        base::StringValue(""),
680        base::FundamentalValue(0));
681  }
682}
683