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