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