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