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