Home | History | Annotate | Download | only in login
      1 // Copyright (c) 2012 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/chromeos/login/existing_user_controller.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/callback.h"
     12 #include "base/command_line.h"
     13 #include "base/logging.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "base/message_loop/message_loop.h"
     16 #include "base/metrics/histogram.h"
     17 #include "base/prefs/pref_service.h"
     18 #include "base/strings/string_util.h"
     19 #include "base/strings/stringprintf.h"
     20 #include "base/strings/utf_string_conversions.h"
     21 #include "base/values.h"
     22 #include "base/version.h"
     23 #include "chrome/browser/accessibility/accessibility_events.h"
     24 #include "chrome/browser/browser_process.h"
     25 #include "chrome/browser/chrome_notification_types.h"
     26 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
     27 #include "chrome/browser/chromeos/boot_times_loader.h"
     28 #include "chrome/browser/chromeos/customization_document.h"
     29 #include "chrome/browser/chromeos/first_run/first_run.h"
     30 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
     31 #include "chrome/browser/chromeos/login/helper.h"
     32 #include "chrome/browser/chromeos/login/login_display_host.h"
     33 #include "chrome/browser/chromeos/login/login_utils.h"
     34 #include "chrome/browser/chromeos/login/startup_utils.h"
     35 #include "chrome/browser/chromeos/login/user_manager.h"
     36 #include "chrome/browser/chromeos/login/wizard_controller.h"
     37 #include "chrome/browser/chromeos/policy/device_local_account.h"
     38 #include "chrome/browser/chromeos/profiles/profile_helper.h"
     39 #include "chrome/browser/chromeos/settings/cros_settings.h"
     40 #include "chrome/browser/google/google_util.h"
     41 #include "chrome/browser/prefs/session_startup_pref.h"
     42 #include "chrome/common/chrome_switches.h"
     43 #include "chrome/common/chrome_version_info.h"
     44 #include "chrome/common/pref_names.h"
     45 #include "chrome/common/url_constants.h"
     46 #include "chromeos/chromeos_switches.h"
     47 #include "chromeos/dbus/dbus_thread_manager.h"
     48 #include "chromeos/dbus/power_manager_client.h"
     49 #include "chromeos/dbus/session_manager_client.h"
     50 #include "chromeos/settings/cros_settings_names.h"
     51 #include "components/policy/core/common/policy_service.h"
     52 #include "content/public/browser/browser_thread.h"
     53 #include "content/public/browser/notification_service.h"
     54 #include "content/public/browser/notification_types.h"
     55 #include "content/public/browser/user_metrics.h"
     56 #include "google_apis/gaia/gaia_auth_util.h"
     57 #include "google_apis/gaia/google_service_auth_error.h"
     58 #include "grit/generated_resources.h"
     59 #include "net/http/http_auth_cache.h"
     60 #include "net/http/http_network_session.h"
     61 #include "net/http/http_transaction_factory.h"
     62 #include "net/url_request/url_request_context.h"
     63 #include "net/url_request/url_request_context_getter.h"
     64 #include "ui/base/accessibility/accessibility_types.h"
     65 #include "ui/base/l10n/l10n_util.h"
     66 #include "ui/views/widget/widget.h"
     67 
     68 namespace chromeos {
     69 
     70 namespace {
     71 
     72 // URL for account creation.
     73 const char kCreateAccountURL[] =
     74     "https://accounts.google.com/NewAccount?service=mail";
     75 
     76 // ChromeVox tutorial URL (used in place of "getting started" url when
     77 // accessibility is enabled).
     78 const char kChromeVoxTutorialURLPattern[] =
     79     "http://www.chromevox.com/tutorial/index.html?lang=%s";
     80 
     81 // Delay for transferring the auth cache to the system profile.
     82 const long int kAuthCacheTransferDelayMs = 2000;
     83 
     84 // Delay for restarting the ui if safe-mode login has failed.
     85 const long int kSafeModeRestartUiDelayMs = 30000;
     86 
     87 // Makes a call to the policy subsystem to reload the policy when we detect
     88 // authentication change.
     89 void RefreshPoliciesOnUIThread() {
     90   if (g_browser_process->policy_service())
     91     g_browser_process->policy_service()->RefreshPolicies(base::Closure());
     92 }
     93 
     94 // Copies any authentication details that were entered in the login profile in
     95 // the mail profile to make sure all subsystems of Chrome can access the network
     96 // with the provided authentication which are possibly for a proxy server.
     97 void TransferContextAuthenticationsOnIOThread(
     98     net::URLRequestContextGetter* default_profile_context_getter,
     99     net::URLRequestContextGetter* browser_process_context_getter) {
    100   net::HttpAuthCache* new_cache =
    101       browser_process_context_getter->GetURLRequestContext()->
    102       http_transaction_factory()->GetSession()->http_auth_cache();
    103   net::HttpAuthCache* old_cache =
    104       default_profile_context_getter->GetURLRequestContext()->
    105       http_transaction_factory()->GetSession()->http_auth_cache();
    106   new_cache->UpdateAllFrom(*old_cache);
    107   VLOG(1) << "Main request context populated with authentication data.";
    108   // Last but not least tell the policy subsystem to refresh now as it might
    109   // have been stuck until now too.
    110   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
    111                                    base::Bind(&RefreshPoliciesOnUIThread));
    112 }
    113 
    114 }  // namespace
    115 
    116 // static
    117 ExistingUserController* ExistingUserController::current_controller_ = NULL;
    118 
    119 ////////////////////////////////////////////////////////////////////////////////
    120 // ExistingUserController, public:
    121 
    122 ExistingUserController::ExistingUserController(LoginDisplayHost* host)
    123     : login_status_consumer_(NULL),
    124       host_(host),
    125       login_display_(host_->CreateLoginDisplay(this)),
    126       num_login_attempts_(0),
    127       cros_settings_(CrosSettings::Get()),
    128       weak_factory_(this),
    129       offline_failed_(false),
    130       is_login_in_progress_(false),
    131       password_changed_(false),
    132       do_auto_enrollment_(false),
    133       signin_screen_ready_(false),
    134       network_state_helper_(new login::NetworkStateHelper) {
    135   DCHECK(current_controller_ == NULL);
    136   current_controller_ = this;
    137 
    138   registrar_.Add(this,
    139                  chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
    140                  content::NotificationService::AllSources());
    141   registrar_.Add(this,
    142                  chrome::NOTIFICATION_USER_LIST_CHANGED,
    143                  content::NotificationService::AllSources());
    144   registrar_.Add(this,
    145                  chrome::NOTIFICATION_AUTH_SUPPLIED,
    146                  content::NotificationService::AllSources());
    147   registrar_.Add(this,
    148                  chrome::NOTIFICATION_SESSION_STARTED,
    149                  content::NotificationService::AllSources());
    150   show_user_names_subscription_ = cros_settings_->AddSettingsObserver(
    151       kAccountsPrefShowUserNamesOnSignIn,
    152       base::Bind(&ExistingUserController::DeviceSettingsChanged,
    153                  base::Unretained(this)));
    154   allow_new_user_subscription_ = cros_settings_->AddSettingsObserver(
    155       kAccountsPrefAllowNewUser,
    156       base::Bind(&ExistingUserController::DeviceSettingsChanged,
    157                  base::Unretained(this)));
    158   allow_guest_subscription_ = cros_settings_->AddSettingsObserver(
    159       kAccountsPrefAllowGuest,
    160       base::Bind(&ExistingUserController::DeviceSettingsChanged,
    161                  base::Unretained(this)));
    162   users_subscription_ = cros_settings_->AddSettingsObserver(
    163       kAccountsPrefUsers,
    164       base::Bind(&ExistingUserController::DeviceSettingsChanged,
    165                  base::Unretained(this)));
    166   local_account_auto_login_id_subscription_ =
    167       cros_settings_->AddSettingsObserver(
    168           kAccountsPrefDeviceLocalAccountAutoLoginId,
    169           base::Bind(&ExistingUserController::ConfigurePublicSessionAutoLogin,
    170                      base::Unretained(this)));
    171   local_account_auto_login_delay_subscription_ =
    172       cros_settings_->AddSettingsObserver(
    173           kAccountsPrefDeviceLocalAccountAutoLoginDelay,
    174           base::Bind(&ExistingUserController::ConfigurePublicSessionAutoLogin,
    175                      base::Unretained(this)));
    176 }
    177 
    178 void ExistingUserController::Init(const UserList& users) {
    179   time_init_ = base::Time::Now();
    180   UpdateLoginDisplay(users);
    181   ConfigurePublicSessionAutoLogin();
    182 
    183   DBusThreadManager::Get()->GetSessionManagerClient()->EmitLoginPromptReady();
    184 }
    185 
    186 void ExistingUserController::UpdateLoginDisplay(const UserList& users) {
    187   bool show_users_on_signin;
    188   UserList filtered_users;
    189 
    190   cros_settings_->GetBoolean(kAccountsPrefShowUserNamesOnSignIn,
    191                              &show_users_on_signin);
    192   if (show_users_on_signin) {
    193     for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
    194       // TODO(xiyuan): Clean user profile whose email is not in whitelist.
    195       bool meets_locally_managed_requirements =
    196           (*it)->GetType() != User::USER_TYPE_LOCALLY_MANAGED ||
    197           UserManager::Get()->AreLocallyManagedUsersAllowed();
    198       bool meets_whitelist_requirements =
    199           LoginUtils::IsWhitelisted((*it)->email(), NULL) ||
    200           (*it)->GetType() != User::USER_TYPE_REGULAR;
    201       if (meets_locally_managed_requirements && meets_whitelist_requirements) {
    202         filtered_users.push_back(*it);
    203       }
    204     }
    205   }
    206 
    207   // If no user pods are visible, fallback to single new user pod which will
    208   // have guest session link.
    209   bool show_guest;
    210   cros_settings_->GetBoolean(kAccountsPrefAllowGuest, &show_guest);
    211   bool show_users;
    212   cros_settings_->GetBoolean(kAccountsPrefShowUserNamesOnSignIn, &show_users);
    213   show_guest &= !filtered_users.empty();
    214   bool show_new_user = true;
    215   login_display_->set_parent_window(GetNativeWindow());
    216   login_display_->Init(filtered_users, show_guest, show_users, show_new_user);
    217   host_->OnPreferencesChanged();
    218 }
    219 
    220 void ExistingUserController::DoAutoEnrollment() {
    221   do_auto_enrollment_ = true;
    222 }
    223 
    224 void ExistingUserController::ResumeLogin() {
    225   // This means the user signed-in, then auto-enrollment used his credentials
    226   // to enroll and succeeded.
    227   resume_login_callback_.Run();
    228   resume_login_callback_.Reset();
    229 }
    230 
    231 ////////////////////////////////////////////////////////////////////////////////
    232 // ExistingUserController, content::NotificationObserver implementation:
    233 //
    234 
    235 void ExistingUserController::Observe(
    236     int type,
    237     const content::NotificationSource& source,
    238     const content::NotificationDetails& details) {
    239   if (type == chrome::NOTIFICATION_SESSION_STARTED) {
    240     // Stop listening to any notification once session has started.
    241     // Sign in screen objects are marked for deletion with DeleteSoon so
    242     // make sure no object would be used after session has started.
    243     // http://crbug.com/125276
    244     registrar_.RemoveAll();
    245     return;
    246   }
    247   if (type == chrome::NOTIFICATION_USER_LIST_CHANGED) {
    248     DeviceSettingsChanged();
    249     return;
    250   }
    251   if (type == chrome::NOTIFICATION_AUTH_SUPPLIED) {
    252     // Possibly the user has authenticated against a proxy server and we might
    253     // need the credentials for enrollment and other system requests from the
    254     // main |g_browser_process| request context (see bug
    255     // http://crosbug.com/24861). So we transfer any credentials to the global
    256     // request context here.
    257     // The issue we have here is that the NOTIFICATION_AUTH_SUPPLIED is sent
    258     // just after the UI is closed but before the new credentials were stored
    259     // in the profile. Therefore we have to give it some time to make sure it
    260     // has been updated before we copy it.
    261     VLOG(1) << "Authentication was entered manually, possibly for proxyauth.";
    262     scoped_refptr<net::URLRequestContextGetter> browser_process_context_getter =
    263         g_browser_process->system_request_context();
    264     Profile* signin_profile = ProfileHelper::GetSigninProfile();
    265     scoped_refptr<net::URLRequestContextGetter> signin_profile_context_getter =
    266         signin_profile->GetRequestContext();
    267     DCHECK(browser_process_context_getter.get());
    268     DCHECK(signin_profile_context_getter.get());
    269     content::BrowserThread::PostDelayedTask(
    270         content::BrowserThread::IO, FROM_HERE,
    271         base::Bind(&TransferContextAuthenticationsOnIOThread,
    272                    signin_profile_context_getter,
    273                    browser_process_context_getter),
    274         base::TimeDelta::FromMilliseconds(kAuthCacheTransferDelayMs));
    275   }
    276   if (type != chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED)
    277     return;
    278   login_display_->OnUserImageChanged(*content::Details<User>(details).ptr());
    279 }
    280 
    281 ////////////////////////////////////////////////////////////////////////////////
    282 // ExistingUserController, private:
    283 
    284 ExistingUserController::~ExistingUserController() {
    285   LoginUtils::Get()->DelegateDeleted(this);
    286 
    287   if (current_controller_ == this) {
    288     current_controller_ = NULL;
    289   } else {
    290     NOTREACHED() << "More than one controller are alive.";
    291   }
    292   DCHECK(login_display_.get());
    293 }
    294 
    295 ////////////////////////////////////////////////////////////////////////////////
    296 // ExistingUserController, LoginDisplay::Delegate implementation:
    297 //
    298 
    299 void ExistingUserController::CancelPasswordChangedFlow() {
    300   login_performer_.reset(NULL);
    301   login_display_->SetUIEnabled(true);
    302   StartPublicSessionAutoLoginTimer();
    303 }
    304 
    305 void ExistingUserController::CreateAccount() {
    306   content::RecordAction(content::UserMetricsAction("Login.CreateAccount"));
    307   guest_mode_url_ =
    308       google_util::AppendGoogleLocaleParam(GURL(kCreateAccountURL));
    309   LoginAsGuest();
    310 }
    311 
    312 void ExistingUserController::CompleteLogin(const UserContext& user_context) {
    313   login_display_->set_signin_completed(true);
    314   if (!host_) {
    315     // Complete login event was generated already from UI. Ignore notification.
    316     return;
    317   }
    318 
    319   // Stop the auto-login timer when attempting login.
    320   StopPublicSessionAutoLoginTimer();
    321 
    322   // Disable UI while loading user profile.
    323   login_display_->SetUIEnabled(false);
    324 
    325   if (!time_init_.is_null()) {
    326     base::TimeDelta delta = base::Time::Now() - time_init_;
    327     UMA_HISTOGRAM_MEDIUM_TIMES("Login.PromptToCompleteLoginTime", delta);
    328     time_init_ = base::Time();  // Reset to null.
    329   }
    330 
    331   host_->OnCompleteLogin();
    332 
    333   // Do an ownership check now to avoid auto-enrolling if the device has
    334   // already been owned.
    335   DeviceSettingsService::Get()->GetOwnershipStatusAsync(
    336       base::Bind(&ExistingUserController::CompleteLoginInternal,
    337                  weak_factory_.GetWeakPtr(),
    338                  user_context));
    339 }
    340 
    341 void ExistingUserController::CompleteLoginInternal(
    342     const UserContext& user_context,
    343     DeviceSettingsService::OwnershipStatus ownership_status) {
    344   // Auto-enrollment must have made a decision by now. It's too late to enroll
    345   // if the protocol isn't done at this point.
    346   if (do_auto_enrollment_ &&
    347       ownership_status == DeviceSettingsService::OWNERSHIP_NONE) {
    348     VLOG(1) << "Forcing auto-enrollment before completing login";
    349     // The only way to get out of the enrollment screen from now on is to either
    350     // complete enrollment, or opt-out of it. So this controller shouldn't force
    351     // enrollment again if it is reused for another sign-in.
    352     do_auto_enrollment_ = false;
    353     auto_enrollment_username_ = user_context.username;
    354     resume_login_callback_ = base::Bind(
    355         &ExistingUserController::PerformLogin,
    356         weak_factory_.GetWeakPtr(),
    357         user_context, LoginPerformer::AUTH_MODE_EXTENSION);
    358     ShowEnrollmentScreen(true, user_context.username);
    359     // Enable UI for the enrollment screen. SetUIEnabled(true) will post a
    360     // request to show the sign-in screen again when invoked at the sign-in
    361     // screen; invoke SetUIEnabled() after navigating to the enrollment screen.
    362     login_display_->SetUIEnabled(true);
    363   } else {
    364     PerformLogin(user_context, LoginPerformer::AUTH_MODE_EXTENSION);
    365   }
    366 }
    367 
    368 base::string16 ExistingUserController::GetConnectedNetworkName() {
    369   return network_state_helper_->GetCurrentNetworkName();
    370 }
    371 
    372 bool ExistingUserController::IsSigninInProgress() const {
    373   return is_login_in_progress_;
    374 }
    375 
    376 void ExistingUserController::Login(const UserContext& user_context) {
    377   if ((user_context.username.empty() || user_context.password.empty()) &&
    378       user_context.auth_code.empty())
    379     return;
    380 
    381   // Stop the auto-login timer when attempting login.
    382   StopPublicSessionAutoLoginTimer();
    383 
    384   // Disable clicking on other windows.
    385   login_display_->SetUIEnabled(false);
    386 
    387   BootTimesLoader::Get()->RecordLoginAttempted();
    388 
    389   if (last_login_attempt_username_ != user_context.username) {
    390     last_login_attempt_username_ = user_context.username;
    391     num_login_attempts_ = 0;
    392     // Also reset state variables, which are used to determine password change.
    393     offline_failed_ = false;
    394     online_succeeded_for_.clear();
    395   }
    396   num_login_attempts_++;
    397   PerformLogin(user_context, LoginPerformer::AUTH_MODE_INTERNAL);
    398 }
    399 
    400 void ExistingUserController::PerformLogin(
    401     const UserContext& user_context,
    402     LoginPerformer::AuthorizationMode auth_mode) {
    403   UserManager::Get()->GetUserFlow(last_login_attempt_username_)->
    404       set_host(host_);
    405 
    406   // Disable UI while loading user profile.
    407   login_display_->SetUIEnabled(false);
    408 
    409   // Use the same LoginPerformer for subsequent login as it has state
    410   // such as Authenticator instance.
    411   if (!login_performer_.get() || num_login_attempts_ <= 1) {
    412     LoginPerformer::Delegate* delegate = this;
    413     if (login_performer_delegate_.get())
    414       delegate = login_performer_delegate_.get();
    415     // Only one instance of LoginPerformer should exist at a time.
    416     login_performer_.reset(NULL);
    417     login_performer_.reset(new LoginPerformer(delegate));
    418   }
    419 
    420   is_login_in_progress_ = true;
    421   if (gaia::ExtractDomainName(user_context.username) ==
    422           UserManager::kLocallyManagedUserDomain) {
    423     login_performer_->LoginAsLocallyManagedUser(
    424         UserContext(user_context.username,
    425                     user_context.password,
    426                     std::string()));  // auth_code
    427   } else {
    428     login_performer_->PerformLogin(user_context, auth_mode);
    429   }
    430   SendAccessibilityAlert(
    431       l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNING_IN));
    432 }
    433 
    434 void ExistingUserController::LoginAsRetailModeUser() {
    435   // Stop the auto-login timer when attempting login.
    436   StopPublicSessionAutoLoginTimer();
    437 
    438   // Disable clicking on other windows.
    439   login_display_->SetUIEnabled(false);
    440   // TODO(rkc): Add a CHECK to make sure retail mode logins are allowed once
    441   // the enterprise policy wiring is done for retail mode.
    442 
    443   // Only one instance of LoginPerformer should exist at a time.
    444   login_performer_.reset(NULL);
    445   login_performer_.reset(new LoginPerformer(this));
    446   is_login_in_progress_ = true;
    447   login_performer_->LoginRetailMode();
    448   SendAccessibilityAlert(
    449       l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNIN_DEMOUSER));
    450 }
    451 
    452 void ExistingUserController::LoginAsGuest() {
    453   if (is_login_in_progress_ || UserManager::Get()->IsUserLoggedIn())
    454     return;
    455 
    456   // Stop the auto-login timer when attempting login.
    457   StopPublicSessionAutoLoginTimer();
    458 
    459   // Disable clicking on other windows.
    460   login_display_->SetUIEnabled(false);
    461 
    462   CrosSettingsProvider::TrustedStatus status =
    463       cros_settings_->PrepareTrustedValues(
    464           base::Bind(&ExistingUserController::LoginAsGuest,
    465                      weak_factory_.GetWeakPtr()));
    466   // Must not proceed without signature verification.
    467   if (status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) {
    468     login_display_->ShowError(IDS_LOGIN_ERROR_OWNER_KEY_LOST, 1,
    469                               HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT);
    470     // Reenable clicking on other windows and status area.
    471     login_display_->SetUIEnabled(true);
    472     StartPublicSessionAutoLoginTimer();
    473     display_email_.clear();
    474     return;
    475   } else if (status != CrosSettingsProvider::TRUSTED) {
    476     // Value of AllowNewUser setting is still not verified.
    477     // Another attempt will be invoked after verification completion.
    478     return;
    479   }
    480 
    481   bool allow_guest;
    482   cros_settings_->GetBoolean(kAccountsPrefAllowGuest, &allow_guest);
    483   if (!allow_guest) {
    484     // Disallowed. The UI should normally not show the guest pod but if for some
    485     // reason this has been made available to the user here is the time to tell
    486     // this nicely.
    487     login_display_->ShowError(IDS_LOGIN_ERROR_WHITELIST, 1,
    488                               HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT);
    489     // Reenable clicking on other windows and status area.
    490     login_display_->SetUIEnabled(true);
    491     StartPublicSessionAutoLoginTimer();
    492     display_email_.clear();
    493     return;
    494   }
    495 
    496   // Only one instance of LoginPerformer should exist at a time.
    497   login_performer_.reset(NULL);
    498   login_performer_.reset(new LoginPerformer(this));
    499   is_login_in_progress_ = true;
    500   login_performer_->LoginOffTheRecord();
    501   SendAccessibilityAlert(
    502       l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNIN_OFFRECORD));
    503 }
    504 
    505 void ExistingUserController::MigrateUserData(const std::string& old_password) {
    506   // LoginPerformer instance has state of the user so it should exist.
    507   if (login_performer_.get())
    508     login_performer_->RecoverEncryptedData(old_password);
    509 }
    510 
    511 void ExistingUserController::LoginAsPublicAccount(
    512     const std::string& username) {
    513   if (is_login_in_progress_ || UserManager::Get()->IsUserLoggedIn())
    514     return;
    515 
    516   // Stop the auto-login timer when attempting login.
    517   StopPublicSessionAutoLoginTimer();
    518 
    519   // Disable clicking on other windows.
    520   login_display_->SetUIEnabled(false);
    521 
    522   CrosSettingsProvider::TrustedStatus status =
    523       cros_settings_->PrepareTrustedValues(
    524           base::Bind(&ExistingUserController::LoginAsPublicAccount,
    525                      weak_factory_.GetWeakPtr(),
    526                      username));
    527   // If device policy is permanently unavailable, logging into public accounts
    528   // is not possible.
    529   if (status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) {
    530     login_display_->ShowError(IDS_LOGIN_ERROR_OWNER_KEY_LOST, 1,
    531                               HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT);
    532     // Re-enable clicking on other windows.
    533     login_display_->SetUIEnabled(true);
    534     return;
    535   }
    536 
    537   // If device policy is not verified yet, this function will be called again
    538   // when verification finishes.
    539   if (status != CrosSettingsProvider::TRUSTED)
    540     return;
    541 
    542   // If there is no public account with the given |username|, logging in is not
    543   // possible.
    544   const User* user = UserManager::Get()->FindUser(username);
    545   if (!user || user->GetType() != User::USER_TYPE_PUBLIC_ACCOUNT) {
    546     // Re-enable clicking on other windows.
    547     login_display_->SetUIEnabled(true);
    548     StartPublicSessionAutoLoginTimer();
    549     return;
    550   }
    551 
    552   // Only one instance of LoginPerformer should exist at a time.
    553   login_performer_.reset(NULL);
    554   login_performer_.reset(new LoginPerformer(this));
    555   is_login_in_progress_ = true;
    556   login_performer_->LoginAsPublicAccount(username);
    557   SendAccessibilityAlert(
    558       l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNIN_PUBLIC_ACCOUNT));
    559 }
    560 
    561 void ExistingUserController::LoginAsKioskApp(const std::string& app_id) {
    562   host_->StartAppLaunch(app_id);
    563 }
    564 
    565 void ExistingUserController::OnSigninScreenReady() {
    566   signin_screen_ready_ = true;
    567   StartPublicSessionAutoLoginTimer();
    568 }
    569 
    570 void ExistingUserController::OnUserSelected(const std::string& username) {
    571   login_performer_.reset(NULL);
    572   num_login_attempts_ = 0;
    573 }
    574 
    575 void ExistingUserController::OnStartEnterpriseEnrollment() {
    576   DeviceSettingsService::Get()->GetOwnershipStatusAsync(
    577       base::Bind(&ExistingUserController::OnEnrollmentOwnershipCheckCompleted,
    578                  weak_factory_.GetWeakPtr()));
    579 }
    580 
    581 void ExistingUserController::OnStartKioskEnableScreen() {
    582   KioskAppManager::Get()->GetConsumerKioskModeStatus(
    583       base::Bind(&ExistingUserController::OnConsumerKioskModeCheckCompleted,
    584                  weak_factory_.GetWeakPtr()));
    585 }
    586 
    587 void ExistingUserController::OnStartDeviceReset() {
    588   ShowResetScreen();
    589 }
    590 
    591 void ExistingUserController::OnStartKioskAutolaunchScreen() {
    592   ShowKioskAutolaunchScreen();
    593 }
    594 
    595 void ExistingUserController::ResyncUserData() {
    596   // LoginPerformer instance has state of the user so it should exist.
    597   if (login_performer_.get())
    598     login_performer_->ResyncEncryptedData();
    599 }
    600 
    601 void ExistingUserController::SetDisplayEmail(const std::string& email) {
    602   display_email_ = email;
    603 }
    604 
    605 void ExistingUserController::ShowWrongHWIDScreen() {
    606   scoped_ptr<DictionaryValue> params;
    607   host_->StartWizard(WizardController::kWrongHWIDScreenName, params.Pass());
    608   login_display_->OnFadeOut();
    609 }
    610 
    611 void ExistingUserController::Signout() {
    612   NOTREACHED();
    613 }
    614 
    615 void ExistingUserController::OnConsumerKioskModeCheckCompleted(
    616     KioskAppManager::ConsumerKioskModeStatus status) {
    617   if (status == KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE)
    618     ShowKioskEnableScreen();
    619 }
    620 
    621 void ExistingUserController::OnEnrollmentOwnershipCheckCompleted(
    622     DeviceSettingsService::OwnershipStatus status) {
    623   if (status == DeviceSettingsService::OWNERSHIP_NONE) {
    624     ShowEnrollmentScreen(false, std::string());
    625   } else if (status == DeviceSettingsService::OWNERSHIP_TAKEN) {
    626     // On a device that is already owned we might want to allow users to
    627     // re-enroll if the policy information is invalid.
    628     CrosSettingsProvider::TrustedStatus trusted_status =
    629         CrosSettings::Get()->PrepareTrustedValues(
    630             base::Bind(
    631                 &ExistingUserController::OnEnrollmentOwnershipCheckCompleted,
    632                 weak_factory_.GetWeakPtr(), status));
    633     if (trusted_status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) {
    634       ShowEnrollmentScreen(false, std::string());
    635     }
    636   } else {
    637     // OwnershipService::GetStatusAsync is supposed to return either
    638     // OWNERSHIP_NONE or OWNERSHIP_TAKEN.
    639     NOTREACHED();
    640   }
    641 }
    642 
    643 void ExistingUserController::ShowEnrollmentScreen(bool is_auto_enrollment,
    644                                                   const std::string& user) {
    645   scoped_ptr<DictionaryValue> params;
    646   if (is_auto_enrollment) {
    647     params.reset(new DictionaryValue());
    648     params->SetBoolean("is_auto_enrollment", true);
    649     params->SetString("user", user);
    650   }
    651   host_->StartWizard(WizardController::kEnrollmentScreenName,
    652                      params.Pass());
    653   login_display_->OnFadeOut();
    654 }
    655 
    656 void ExistingUserController::ShowResetScreen() {
    657   scoped_ptr<DictionaryValue> params;
    658   host_->StartWizard(WizardController::kResetScreenName, params.Pass());
    659   login_display_->OnFadeOut();
    660 }
    661 
    662 void ExistingUserController::ShowKioskEnableScreen() {
    663   scoped_ptr<DictionaryValue> params;
    664   host_->StartWizard(WizardController::kKioskEnableScreenName, params.Pass());
    665   login_display_->OnFadeOut();
    666 }
    667 
    668 void ExistingUserController::ShowKioskAutolaunchScreen() {
    669   scoped_ptr<DictionaryValue> params;
    670   host_->StartWizard(WizardController::kKioskAutolaunchScreenName,
    671                      params.Pass());
    672   login_display_->OnFadeOut();
    673 }
    674 
    675 void ExistingUserController::ShowTPMError() {
    676   login_display_->SetUIEnabled(false);
    677   login_display_->ShowErrorScreen(LoginDisplay::TPM_ERROR);
    678 }
    679 
    680 ////////////////////////////////////////////////////////////////////////////////
    681 // ExistingUserController, LoginPerformer::Delegate implementation:
    682 //
    683 
    684 void ExistingUserController::OnLoginFailure(const LoginFailure& failure) {
    685   is_login_in_progress_ = false;
    686   offline_failed_ = true;
    687 
    688   guest_mode_url_ = GURL::EmptyGURL();
    689   std::string error = failure.GetErrorString();
    690 
    691   if (UserManager::Get()->GetUserFlow(last_login_attempt_username_)->
    692           HandleLoginFailure(failure)) {
    693     login_display_->SetUIEnabled(true);
    694     return;
    695   }
    696 
    697   if (failure.reason() == LoginFailure::OWNER_REQUIRED) {
    698     ShowError(IDS_LOGIN_ERROR_OWNER_REQUIRED, error);
    699     content::BrowserThread::PostDelayedTask(
    700         content::BrowserThread::UI, FROM_HERE,
    701         base::Bind(&SessionManagerClient::StopSession,
    702                    base::Unretained(DBusThreadManager::Get()->
    703                                     GetSessionManagerClient())),
    704         base::TimeDelta::FromMilliseconds(kSafeModeRestartUiDelayMs));
    705   } else if (failure.reason() == LoginFailure::TPM_ERROR) {
    706     ShowTPMError();
    707   } else if (!online_succeeded_for_.empty()) {
    708     ShowGaiaPasswordChanged(online_succeeded_for_);
    709   } else {
    710     // Check networking after trying to login in case user is
    711     // cached locally or the local admin account.
    712     bool is_known_user =
    713         UserManager::Get()->IsKnownUser(last_login_attempt_username_);
    714     if (!network_state_helper_->IsConnected()) {
    715       if (is_known_user)
    716         ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error);
    717       else
    718         ShowError(IDS_LOGIN_ERROR_OFFLINE_FAILED_NETWORK_NOT_CONNECTED, error);
    719     } else {
    720       // TODO(nkostylev): Cleanup rest of ClientLogin related code.
    721       if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED &&
    722           failure.error().state() ==
    723               GoogleServiceAuthError::HOSTED_NOT_ALLOWED) {
    724         ShowError(IDS_LOGIN_ERROR_AUTHENTICATING_HOSTED, error);
    725       } else {
    726         if (!is_known_user)
    727           ShowError(IDS_LOGIN_ERROR_AUTHENTICATING_NEW, error);
    728         else
    729           ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error);
    730       }
    731     }
    732     // Reenable clicking on other windows and status area.
    733     login_display_->SetUIEnabled(true);
    734     login_display_->ClearAndEnablePassword();
    735     StartPublicSessionAutoLoginTimer();
    736   }
    737 
    738   // Reset user flow to default, so that special flow will not affect next
    739   // attempt.
    740   UserManager::Get()->ResetUserFlow(last_login_attempt_username_);
    741 
    742   if (login_status_consumer_)
    743     login_status_consumer_->OnLoginFailure(failure);
    744 
    745   // Clear the recorded displayed email so it won't affect any future attempts.
    746   display_email_.clear();
    747 }
    748 
    749 void ExistingUserController::OnLoginSuccess(const UserContext& user_context) {
    750   is_login_in_progress_ = false;
    751   offline_failed_ = false;
    752   login_display_->set_signin_completed(true);
    753 
    754   StopPublicSessionAutoLoginTimer();
    755 
    756   bool has_cookies =
    757       login_performer_->auth_mode() == LoginPerformer::AUTH_MODE_EXTENSION &&
    758       user_context.auth_code.empty();
    759 
    760   // Login performer will be gone so cache this value to use
    761   // once profile is loaded.
    762   password_changed_ = login_performer_->password_changed();
    763 
    764   // LoginPerformer instance will delete itself once online auth result is OK.
    765   // In case of failure it'll bring up ScreenLock and ask for
    766   // correct password/display error message.
    767   // Even in case when following online,offline protocol and returning
    768   // requests_pending = false, let LoginPerformer delete itself.
    769   login_performer_->set_delegate(NULL);
    770   ignore_result(login_performer_.release());
    771 
    772   // Will call OnProfilePrepared() in the end.
    773   LoginUtils::Get()->PrepareProfile(user_context,
    774                                     display_email_,
    775                                     has_cookies,
    776                                     false,          // Start session for user.
    777                                     this);
    778 
    779   display_email_.clear();
    780 
    781   // Notify LoginDisplay to allow it provide visual feedback to user.
    782   login_display_->OnLoginSuccess(user_context.username);
    783 }
    784 
    785 void ExistingUserController::OnProfilePrepared(Profile* profile) {
    786   // Reenable clicking on other windows and status area.
    787   login_display_->SetUIEnabled(true);
    788 
    789   UserManager* user_manager = UserManager::Get();
    790   if (user_manager->IsCurrentUserNew() &&
    791       user_manager->IsLoggedInAsLocallyManagedUser()) {
    792     // Supervised users should launch into empty desktop on first run.
    793     CommandLine::ForCurrentProcess()->AppendSwitch(::switches::kSilentLaunch);
    794   }
    795 
    796   if (user_manager->IsCurrentUserNew() &&
    797       !user_manager->GetCurrentUserFlow()->ShouldSkipPostLoginScreens() &&
    798       !WizardController::default_controller()->skip_post_login_screens()) {
    799     // Don't specify start URLs if the administrator has configured the start
    800     // URLs via policy.
    801     if (!SessionStartupPref::TypeIsManaged(profile->GetPrefs()))
    802       InitializeStartUrls();
    803 
    804     // Mark the device as registered., i.e. the second part of OOBE as
    805     // completed.
    806     if (!StartupUtils::IsDeviceRegistered())
    807       StartupUtils::MarkDeviceRegistered();
    808 
    809     if (CommandLine::ForCurrentProcess()->HasSwitch(
    810           chromeos::switches::kOobeSkipPostLogin)) {
    811       LoginUtils::Get()->DoBrowserLaunch(profile, host_);
    812       host_ = NULL;
    813     } else {
    814       ActivateWizard(WizardController::kTermsOfServiceScreenName);
    815     }
    816   } else {
    817     LoginUtils::Get()->DoBrowserLaunch(profile, host_);
    818     host_ = NULL;
    819   }
    820   // Inform |login_status_consumer_| about successful login.
    821   if (login_status_consumer_)
    822     login_status_consumer_->OnLoginSuccess(UserContext());
    823   login_display_->OnFadeOut();
    824 }
    825 
    826 void ExistingUserController::OnOffTheRecordLoginSuccess() {
    827   is_login_in_progress_ = false;
    828   offline_failed_ = false;
    829 
    830   // Mark the device as registered., i.e. the second part of OOBE as completed.
    831   if (!StartupUtils::IsDeviceRegistered())
    832     StartupUtils::MarkDeviceRegistered();
    833 
    834   LoginUtils::Get()->CompleteOffTheRecordLogin(guest_mode_url_);
    835 
    836   if (login_status_consumer_)
    837     login_status_consumer_->OnOffTheRecordLoginSuccess();
    838 }
    839 
    840 void ExistingUserController::OnPasswordChangeDetected() {
    841   is_login_in_progress_ = false;
    842   offline_failed_ = false;
    843 
    844   // Must not proceed without signature verification.
    845   if (CrosSettingsProvider::TRUSTED != cros_settings_->PrepareTrustedValues(
    846       base::Bind(&ExistingUserController::OnPasswordChangeDetected,
    847                  weak_factory_.GetWeakPtr()))) {
    848     // Value of owner email is still not verified.
    849     // Another attempt will be invoked after verification completion.
    850     return;
    851   }
    852 
    853   if (UserManager::Get()->GetUserFlow(last_login_attempt_username_)->
    854           HandlePasswordChangeDetected()) {
    855     return;
    856   }
    857 
    858   // True if user has already made an attempt to enter old password and failed.
    859   bool show_invalid_old_password_error =
    860       login_performer_->password_changed_callback_count() > 1;
    861 
    862   // Note: We allow owner using "full sync" mode which will recreate
    863   // cryptohome and deal with owner private key being lost. This also allows
    864   // us to recover from a lost owner password/homedir.
    865   // TODO(gspencer): We shouldn't have to erase stateful data when
    866   // doing this.  See http://crosbug.com/9115 http://crosbug.com/7792
    867   login_display_->ShowPasswordChangedDialog(show_invalid_old_password_error);
    868 
    869   if (login_status_consumer_)
    870     login_status_consumer_->OnPasswordChangeDetected();
    871 
    872   display_email_.clear();
    873 }
    874 
    875 void ExistingUserController::WhiteListCheckFailed(const std::string& email) {
    876   is_login_in_progress_ = false;
    877   offline_failed_ = false;
    878 
    879   ShowError(IDS_LOGIN_ERROR_WHITELIST, email);
    880 
    881   // Reenable clicking on other windows and status area.
    882   login_display_->SetUIEnabled(true);
    883   login_display_->ShowSigninUI(email);
    884 
    885   if (login_status_consumer_) {
    886     login_status_consumer_->OnLoginFailure(LoginFailure(
    887           LoginFailure::WHITELIST_CHECK_FAILED));
    888   }
    889 
    890   display_email_.clear();
    891 
    892   StartPublicSessionAutoLoginTimer();
    893 }
    894 
    895 void ExistingUserController::PolicyLoadFailed() {
    896   ShowError(IDS_LOGIN_ERROR_OWNER_KEY_LOST, "");
    897 
    898   // Reenable clicking on other windows and status area.
    899   is_login_in_progress_ = false;
    900   offline_failed_ = false;
    901   login_display_->SetUIEnabled(true);
    902 
    903   display_email_.clear();
    904 
    905   // Policy load failure stops login attempts -- restart the timer.
    906   StartPublicSessionAutoLoginTimer();
    907 }
    908 
    909 void ExistingUserController::OnOnlineChecked(const std::string& username,
    910                                              bool success) {
    911   if (success && last_login_attempt_username_ == username) {
    912     online_succeeded_for_ = username;
    913     // Wait for login attempt to end, if it hasn't yet.
    914     if (offline_failed_ && !is_login_in_progress_)
    915       ShowGaiaPasswordChanged(username);
    916   }
    917 }
    918 
    919 ////////////////////////////////////////////////////////////////////////////////
    920 // ExistingUserController, private:
    921 
    922 void ExistingUserController::DeviceSettingsChanged() {
    923   if (host_ != NULL) {
    924     // Signed settings or user list changed. Notify views and update them.
    925     UpdateLoginDisplay(chromeos::UserManager::Get()->GetUsers());
    926     ConfigurePublicSessionAutoLogin();
    927     return;
    928   }
    929 }
    930 
    931 void ExistingUserController::ActivateWizard(const std::string& screen_name) {
    932   scoped_ptr<DictionaryValue> params;
    933   host_->StartWizard(screen_name, params.Pass());
    934 }
    935 
    936 void ExistingUserController::ConfigurePublicSessionAutoLogin() {
    937   std::string auto_login_account_id;
    938   cros_settings_->GetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
    939                             &auto_login_account_id);
    940   const std::vector<policy::DeviceLocalAccount> device_local_accounts =
    941       policy::GetDeviceLocalAccounts(cros_settings_);
    942 
    943   public_session_auto_login_username_.clear();
    944   for (std::vector<policy::DeviceLocalAccount>::const_iterator
    945            it = device_local_accounts.begin();
    946        it != device_local_accounts.end(); ++it) {
    947     if (it->account_id == auto_login_account_id) {
    948       public_session_auto_login_username_ = it->user_id;
    949       break;
    950     }
    951   }
    952 
    953   const User* user =
    954       UserManager::Get()->FindUser(public_session_auto_login_username_);
    955   if (!user || user->GetType() != User::USER_TYPE_PUBLIC_ACCOUNT)
    956     public_session_auto_login_username_.clear();
    957 
    958   if (!cros_settings_->GetInteger(
    959           kAccountsPrefDeviceLocalAccountAutoLoginDelay,
    960           &public_session_auto_login_delay_)) {
    961     public_session_auto_login_delay_ = 0;
    962   }
    963 
    964   if (!public_session_auto_login_username_.empty())
    965     StartPublicSessionAutoLoginTimer();
    966   else
    967     StopPublicSessionAutoLoginTimer();
    968 }
    969 
    970 void ExistingUserController::ResetPublicSessionAutoLoginTimer() {
    971   // Only restart the auto-login timer if it's already running.
    972   if (auto_login_timer_ && auto_login_timer_->IsRunning()) {
    973     StopPublicSessionAutoLoginTimer();
    974     StartPublicSessionAutoLoginTimer();
    975   }
    976 }
    977 
    978 void ExistingUserController::OnPublicSessionAutoLoginTimerFire() {
    979   CHECK(signin_screen_ready_ &&
    980         !is_login_in_progress_ &&
    981         !public_session_auto_login_username_.empty());
    982   LoginAsPublicAccount(public_session_auto_login_username_);
    983 }
    984 
    985 void ExistingUserController::StopPublicSessionAutoLoginTimer() {
    986   if (auto_login_timer_)
    987     auto_login_timer_->Stop();
    988 }
    989 
    990 void ExistingUserController::StartPublicSessionAutoLoginTimer() {
    991   if (!signin_screen_ready_ ||
    992       is_login_in_progress_ ||
    993       public_session_auto_login_username_.empty()) {
    994     return;
    995   }
    996 
    997   // Start the auto-login timer.
    998   if (!auto_login_timer_)
    999     auto_login_timer_.reset(new base::OneShotTimer<ExistingUserController>);
   1000 
   1001   auto_login_timer_->Start(
   1002       FROM_HERE,
   1003       base::TimeDelta::FromMilliseconds(
   1004           public_session_auto_login_delay_),
   1005       base::Bind(
   1006           &ExistingUserController::OnPublicSessionAutoLoginTimerFire,
   1007           weak_factory_.GetWeakPtr()));
   1008 }
   1009 
   1010 gfx::NativeWindow ExistingUserController::GetNativeWindow() const {
   1011   return host_->GetNativeWindow();
   1012 }
   1013 
   1014 void ExistingUserController::InitializeStartUrls() const {
   1015   std::vector<std::string> start_urls;
   1016 
   1017   const base::ListValue *urls;
   1018   bool can_show_getstarted_guide =
   1019     UserManager::Get()->IsLoggedInAsRegularUser();
   1020   if (UserManager::Get()->IsLoggedInAsDemoUser()) {
   1021     if (CrosSettings::Get()->GetList(kStartUpUrls, &urls)) {
   1022       // The retail mode user will get start URLs from a special policy if it is
   1023       // set.
   1024       for (base::ListValue::const_iterator it = urls->begin();
   1025            it != urls->end(); ++it) {
   1026         std::string url;
   1027         if ((*it)->GetAsString(&url))
   1028           start_urls.push_back(url);
   1029       }
   1030     }
   1031     can_show_getstarted_guide = false;
   1032   // Skip the default first-run behavior for public accounts.
   1033   } else if (!UserManager::Get()->IsLoggedInAsPublicAccount()) {
   1034     if (AccessibilityManager::Get()->IsSpokenFeedbackEnabled()) {
   1035       const char* url = kChromeVoxTutorialURLPattern;
   1036       PrefService* prefs = g_browser_process->local_state();
   1037       const std::string current_locale =
   1038           StringToLowerASCII(prefs->GetString(prefs::kApplicationLocale));
   1039       std::string vox_url = base::StringPrintf(url, current_locale.c_str());
   1040       start_urls.push_back(vox_url);
   1041       can_show_getstarted_guide = false;
   1042     }
   1043   }
   1044 
   1045   ServicesCustomizationDocument* customization =
   1046       ServicesCustomizationDocument::GetInstance();
   1047   if (!ServicesCustomizationDocument::WasApplied() &&
   1048       customization->IsReady()) {
   1049     // Since we don't use OEM start URL anymore, just mark as applied.
   1050     customization->ApplyCustomization();
   1051   }
   1052 
   1053   // Only show getting started guide for a new user.
   1054   const bool should_show_getstarted_guide =
   1055       UserManager::Get()->IsCurrentUserNew();
   1056 
   1057   if (can_show_getstarted_guide && should_show_getstarted_guide) {
   1058     // Don't open default Chrome window if we're going to launch the first-run
   1059     // app. Because we dont' want the first-run app to be hidden in the
   1060     // background.
   1061     CommandLine::ForCurrentProcess()->AppendSwitch(::switches::kSilentLaunch);
   1062     first_run::MaybeLaunchDialogAfterSessionStart();
   1063   } else {
   1064     for (size_t i = 0; i < start_urls.size(); ++i) {
   1065       CommandLine::ForCurrentProcess()->AppendArg(start_urls[i]);
   1066     }
   1067   }
   1068 }
   1069 
   1070 void ExistingUserController::ShowError(int error_id,
   1071                                        const std::string& details) {
   1072   // TODO(dpolukhin): show detailed error info. |details| string contains
   1073   // low level error info that is not localized and even is not user friendly.
   1074   // For now just ignore it because error_text contains all required information
   1075   // for end users, developers can see details string in Chrome logs.
   1076   VLOG(1) << details;
   1077   HelpAppLauncher::HelpTopic help_topic_id;
   1078   bool is_offline = !network_state_helper_->IsConnected();
   1079   switch (login_performer_->error().state()) {
   1080     case GoogleServiceAuthError::CONNECTION_FAILED:
   1081       help_topic_id = HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT_OFFLINE;
   1082       break;
   1083     case GoogleServiceAuthError::ACCOUNT_DISABLED:
   1084       help_topic_id = HelpAppLauncher::HELP_ACCOUNT_DISABLED;
   1085       break;
   1086     case GoogleServiceAuthError::HOSTED_NOT_ALLOWED:
   1087       help_topic_id = HelpAppLauncher::HELP_HOSTED_ACCOUNT;
   1088       break;
   1089     default:
   1090       help_topic_id = is_offline ?
   1091           HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT_OFFLINE :
   1092           HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT;
   1093       break;
   1094   }
   1095 
   1096   login_display_->ShowError(error_id, num_login_attempts_, help_topic_id);
   1097 }
   1098 
   1099 void ExistingUserController::ShowGaiaPasswordChanged(
   1100     const std::string& username) {
   1101   // Invalidate OAuth token, since it can't be correct after password is
   1102   // changed.
   1103   UserManager::Get()->SaveUserOAuthStatus(
   1104       username,
   1105       User::OAUTH2_TOKEN_STATUS_INVALID);
   1106 
   1107   login_display_->SetUIEnabled(true);
   1108   login_display_->ShowGaiaPasswordChanged(username);
   1109 }
   1110 
   1111 void ExistingUserController::SendAccessibilityAlert(
   1112     const std::string& alert_text) {
   1113   AccessibilityAlertInfo event(ProfileHelper::GetSigninProfile(), alert_text);
   1114   SendControlAccessibilityNotification(
   1115       ui::AccessibilityTypes::EVENT_VALUE_CHANGED, &event);
   1116 }
   1117 
   1118 }  // namespace chromeos
   1119