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