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