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