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