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
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// Record UMA for Easy sign-in outcome.
129void 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.
138void 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
151ExistingUserController* ExistingUserController::current_controller_ = NULL;
152
153////////////////////////////////////////////////////////////////////////////////
154// ExistingUserController, public:
155
156ExistingUserController::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
218void ExistingUserController::Init(const user_manager::UserList& users) {
219  time_init_ = base::Time::Now();
220  UpdateLoginDisplay(users);
221  ConfigurePublicSessionAutoLogin();
222}
223
224void 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
266void ExistingUserController::DoAutoEnrollment() {
267  do_auto_enrollment_ = true;
268}
269
270void 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
281void 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
331ExistingUserController::~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
346void ExistingUserController::CancelPasswordChangedFlow() {
347  login_performer_.reset(NULL);
348  login_display_->SetUIEnabled(true);
349  StartPublicSessionAutoLoginTimer();
350}
351
352void 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
359void 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
388void 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
415base::string16 ExistingUserController::GetConnectedNetworkName() {
416  return network_state_helper_->GetCurrentNetworkName();
417}
418
419bool ExistingUserController::IsSigninInProgress() const {
420  return is_login_in_progress_;
421}
422
423void 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
467void 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
500void 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
518void 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
573void 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
579void 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
676void ExistingUserController::LoginAsKioskApp(const std::string& app_id,
677                                             bool diagnostic_mode) {
678  host_->StartAppLaunch(app_id, diagnostic_mode);
679}
680
681void ExistingUserController::OnSigninScreenReady() {
682  signin_screen_ready_ = true;
683  StartPublicSessionAutoLoginTimer();
684}
685
686void 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
698void ExistingUserController::OnStartKioskEnableScreen() {
699  KioskAppManager::Get()->GetConsumerKioskAutoLaunchStatus(
700      base::Bind(
701          &ExistingUserController::OnConsumerKioskAutoLaunchCheckCompleted,
702          weak_factory_.GetWeakPtr()));
703}
704
705void ExistingUserController::OnStartKioskAutolaunchScreen() {
706  ShowKioskAutolaunchScreen();
707}
708
709void 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
715void ExistingUserController::SetDisplayEmail(const std::string& email) {
716  display_email_ = email;
717}
718
719void ExistingUserController::ShowWrongHWIDScreen() {
720  scoped_ptr<base::DictionaryValue> params;
721  host_->StartWizard(WizardController::kWrongHWIDScreenName, params.Pass());
722}
723
724void ExistingUserController::Signout() {
725  NOTREACHED();
726}
727
728void ExistingUserController::OnConsumerKioskAutoLaunchCheckCompleted(
729    KioskAppManager::ConsumerKioskAutoLaunchStatus status) {
730  if (status == KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE)
731    ShowKioskEnableScreen();
732}
733
734void 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
756void 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
768void ExistingUserController::ShowResetScreen() {
769  scoped_ptr<base::DictionaryValue> params;
770  host_->StartWizard(WizardController::kResetScreenName, params.Pass());
771}
772
773void ExistingUserController::ShowKioskEnableScreen() {
774  scoped_ptr<base::DictionaryValue> params;
775  host_->StartWizard(WizardController::kKioskEnableScreenName, params.Pass());
776}
777
778void ExistingUserController::ShowKioskAutolaunchScreen() {
779  scoped_ptr<base::DictionaryValue> params;
780  host_->StartWizard(WizardController::kKioskAutolaunchScreenName,
781                     params.Pass());
782}
783
784void ExistingUserController::ShowTPMError() {
785  login_display_->SetUIEnabled(false);
786  login_display_->ShowErrorScreen(LoginDisplay::TPM_ERROR);
787}
788
789////////////////////////////////////////////////////////////////////////////////
790// ExistingUserController, LoginPerformer::Delegate implementation:
791//
792
793void 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
863void 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
912void 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
954void 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
968void 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
1004void 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
1024void 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
1038void 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
1051void 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
1060void ExistingUserController::ActivateWizard(const std::string& screen_name) {
1061  scoped_ptr<base::DictionaryValue> params;
1062  host_->StartWizard(screen_name, params.Pass());
1063}
1064
1065LoginPerformer::AuthorizationMode ExistingUserController::auth_mode() const {
1066  if (login_performer_)
1067    return login_performer_->auth_mode();
1068
1069  return auth_mode_;
1070}
1071
1072bool ExistingUserController::password_changed() const {
1073  if (login_performer_)
1074    return login_performer_->password_changed();
1075
1076  return password_changed_;
1077}
1078
1079void 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
1113void 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
1121void 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
1130void ExistingUserController::StopPublicSessionAutoLoginTimer() {
1131  if (auto_login_timer_)
1132    auto_login_timer_->Stop();
1133}
1134
1135void 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
1155gfx::NativeWindow ExistingUserController::GetNativeWindow() const {
1156  return host_->GetNativeWindow();
1157}
1158
1159void 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
1209void 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
1248void 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
1259void 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
1266void 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
1287void 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