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.
5 #include "chrome/browser/chromeos/login/existing_user_controller.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"
69 // URL for account creation.
70 const char kCreateAccountURL[] =
71 "https://accounts.google.com/NewAccount?service=mail";
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";
78 // Delay for transferring the auth cache to the system profile.
79 const long int kAuthCacheTransferDelayMs = 2000;
81 // Delay for restarting the ui if safe-mode login has failed.
82 const long int kSafeModeRestartUiDelayMs = 30000;
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());
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));
114 ExistingUserController* ExistingUserController::current_controller_ = NULL;
116 ////////////////////////////////////////////////////////////////////////////////
117 // ExistingUserController, public:
119 ExistingUserController::ExistingUserController(LoginDisplayHost* host)
120 : login_status_consumer_(NULL),
122 login_display_(host_->CreateLoginDisplay(this)),
123 num_login_attempts_(0),
124 cros_settings_(CrosSettings::Get()),
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;
136 chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
137 content::NotificationService::AllSources());
139 chrome::NOTIFICATION_USER_LIST_CHANGED,
140 content::NotificationService::AllSources());
142 chrome::NOTIFICATION_AUTH_SUPPLIED,
143 content::NotificationService::AllSources());
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(
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)));
175 void ExistingUserController::Init(const UserList& users) {
176 time_init_ = base::Time::Now();
177 UpdateLoginDisplay(users);
178 ConfigurePublicSessionAutoLogin();
180 DBusThreadManager::Get()->GetSessionManagerClient()->EmitLoginPromptReady();
183 void ExistingUserController::UpdateLoginDisplay(const UserList& users) {
184 bool show_users_on_signin;
185 UserList filtered_users;
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);
204 // If no user pods are visible, fallback to single new user pod which will
205 // have guest session link.
207 cros_settings_->GetBoolean(kAccountsPrefAllowGuest, &show_guest);
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();
217 void ExistingUserController::DoAutoEnrollment() {
218 do_auto_enrollment_ = true;
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();
228 ////////////////////////////////////////////////////////////////////////////////
229 // ExistingUserController, content::NotificationObserver implementation:
232 void ExistingUserController::Observe(
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();
244 if (type == chrome::NOTIFICATION_USER_LIST_CHANGED) {
245 DeviceSettingsChanged();
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));
273 if (type != chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED)
275 login_display_->OnUserImageChanged(*content::Details<User>(details).ptr());
278 ////////////////////////////////////////////////////////////////////////////////
279 // ExistingUserController, private:
281 ExistingUserController::~ExistingUserController() {
282 LoginUtils::Get()->DelegateDeleted(this);
284 if (current_controller_ == this) {
285 current_controller_ = NULL;
287 NOTREACHED() << "More than one controller are alive.";
289 DCHECK(login_display_.get());
292 ////////////////////////////////////////////////////////////////////////////////
293 // ExistingUserController, LoginDisplay::Delegate implementation:
296 void ExistingUserController::CancelPasswordChangedFlow() {
297 login_performer_.reset(NULL);
298 login_display_->SetUIEnabled(true);
299 StartPublicSessionAutoLoginTimer();
302 void ExistingUserController::CreateAccount() {
303 content::RecordAction(content::UserMetricsAction("Login.CreateAccount"));
305 google_util::AppendGoogleLocaleParam(GURL(kCreateAccountURL));
309 void ExistingUserController::CompleteLogin(const UserContext& user_context) {
310 login_display_->set_signin_completed(true);
312 // Complete login event was generated already from UI. Ignore notification.
316 // Stop the auto-login timer when attempting login.
317 StopPublicSessionAutoLoginTimer();
319 // Disable UI while loading user profile.
320 login_display_->SetUIEnabled(false);
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.
328 host_->OnCompleteLogin();
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(),
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);
361 PerformLogin(user_context, LoginPerformer::AUTH_MODE_EXTENSION);
365 string16 ExistingUserController::GetConnectedNetworkName() {
366 return network_state_helper_->GetCurrentNetworkName();
369 bool ExistingUserController::IsSigninInProgress() const {
370 return is_login_in_progress_;
373 void ExistingUserController::Login(const UserContext& user_context) {
374 if ((user_context.username.empty() || user_context.password.empty()) &&
375 user_context.auth_code.empty())
378 // Stop the auto-login timer when attempting login.
379 StopPublicSessionAutoLoginTimer();
381 // Disable clicking on other windows.
382 login_display_->SetUIEnabled(false);
384 BootTimesLoader::Get()->RecordLoginAttempted();
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();
393 num_login_attempts_++;
394 PerformLogin(user_context, LoginPerformer::AUTH_MODE_INTERNAL);
397 void ExistingUserController::PerformLogin(
398 const UserContext& user_context,
399 LoginPerformer::AuthorizationMode auth_mode) {
400 UserManager::Get()->GetUserFlow(last_login_attempt_username_)->
403 // Disable UI while loading user profile.
404 login_display_->SetUIEnabled(false);
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));
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
425 login_performer_->PerformLogin(user_context, auth_mode);
427 AccessibilityManager::Get()->MaybeSpeak(
428 l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNING_IN));
431 void ExistingUserController::LoginAsRetailModeUser() {
432 // Stop the auto-login timer when attempting login.
433 StopPublicSessionAutoLoginTimer();
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.
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));
449 void ExistingUserController::LoginAsGuest() {
450 if (is_login_in_progress_ || UserManager::Get()->IsUserLoggedIn())
453 // Stop the auto-login timer when attempting login.
454 StopPublicSessionAutoLoginTimer();
456 // Disable clicking on other windows.
457 login_display_->SetUIEnabled(false);
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();
472 } else if (status != CrosSettingsProvider::TRUSTED) {
473 // Value of AllowNewUser setting is still not verified.
474 // Another attempt will be invoked after verification completion.
479 cros_settings_->GetBoolean(kAccountsPrefAllowGuest, &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
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();
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));
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);
508 void ExistingUserController::LoginAsPublicAccount(
509 const std::string& username) {
510 if (is_login_in_progress_ || UserManager::Get()->IsUserLoggedIn())
513 // Stop the auto-login timer when attempting login.
514 StopPublicSessionAutoLoginTimer();
516 // Disable clicking on other windows.
517 login_display_->SetUIEnabled(false);
519 CrosSettingsProvider::TrustedStatus status =
520 cros_settings_->PrepareTrustedValues(
521 base::Bind(&ExistingUserController::LoginAsPublicAccount,
522 weak_factory_.GetWeakPtr(),
524 // If device policy is permanently unavailable, logging into public accounts
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);
534 // If device policy is not verified yet, this function will be called again
535 // when verification finishes.
536 if (status != CrosSettingsProvider::TRUSTED)
539 // If there is no public account with the given |username|, logging in is not
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();
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));
558 void ExistingUserController::LoginAsKioskApp(const std::string& app_id) {
559 host_->StartAppLaunch(app_id);
562 void ExistingUserController::OnSigninScreenReady() {
563 signin_screen_ready_ = true;
564 StartPublicSessionAutoLoginTimer();
567 void ExistingUserController::OnUserSelected(const std::string& username) {
568 login_performer_.reset(NULL);
569 num_login_attempts_ = 0;
572 void ExistingUserController::OnStartEnterpriseEnrollment() {
573 DeviceSettingsService::Get()->GetOwnershipStatusAsync(
574 base::Bind(&ExistingUserController::OnEnrollmentOwnershipCheckCompleted,
575 weak_factory_.GetWeakPtr()));
578 void ExistingUserController::OnStartKioskEnableScreen() {
579 KioskAppManager::Get()->GetConsumerKioskModeStatus(
580 base::Bind(&ExistingUserController::OnConsumerKioskModeCheckCompleted,
581 weak_factory_.GetWeakPtr()));
584 void ExistingUserController::OnStartDeviceReset() {
588 void ExistingUserController::OnStartKioskAutolaunchScreen() {
589 ShowKioskAutolaunchScreen();
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();
598 void ExistingUserController::SetDisplayEmail(const std::string& email) {
599 display_email_ = email;
602 void ExistingUserController::ShowWrongHWIDScreen() {
603 scoped_ptr<DictionaryValue> params;
604 host_->StartWizard(WizardController::kWrongHWIDScreenName, params.Pass());
605 login_display_->OnFadeOut();
608 void ExistingUserController::Signout() {
612 void ExistingUserController::OnConsumerKioskModeCheckCompleted(
613 KioskAppManager::ConsumerKioskModeStatus status) {
614 if (status == KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE)
615 ShowKioskEnableScreen();
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(
628 &ExistingUserController::OnEnrollmentOwnershipCheckCompleted,
629 weak_factory_.GetWeakPtr(), status));
630 if (trusted_status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) {
631 ShowEnrollmentScreen(false, std::string());
634 // OwnershipService::GetStatusAsync is supposed to return either
635 // OWNERSHIP_NONE or OWNERSHIP_TAKEN.
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);
648 host_->StartWizard(WizardController::kEnrollmentScreenName,
650 login_display_->OnFadeOut();
653 void ExistingUserController::ShowResetScreen() {
654 scoped_ptr<DictionaryValue> params;
655 host_->StartWizard(WizardController::kResetScreenName, params.Pass());
656 login_display_->OnFadeOut();
659 void ExistingUserController::ShowKioskEnableScreen() {
660 scoped_ptr<DictionaryValue> params;
661 host_->StartWizard(WizardController::kKioskEnableScreenName, params.Pass());
662 login_display_->OnFadeOut();
665 void ExistingUserController::ShowKioskAutolaunchScreen() {
666 scoped_ptr<DictionaryValue> params;
667 host_->StartWizard(WizardController::kKioskAutolaunchScreenName,
669 login_display_->OnFadeOut();
672 void ExistingUserController::ShowTPMError() {
673 login_display_->SetUIEnabled(false);
674 login_display_->ShowErrorScreen(LoginDisplay::TPM_ERROR);
677 ////////////////////////////////////////////////////////////////////////////////
678 // ExistingUserController, LoginPerformer::Delegate implementation:
681 void ExistingUserController::OnLoginFailure(const LoginFailure& failure) {
682 is_login_in_progress_ = false;
683 offline_failed_ = true;
685 guest_mode_url_ = GURL::EmptyGURL();
686 std::string error = failure.GetErrorString();
688 if (UserManager::Get()->GetUserFlow(last_login_attempt_username_)->
689 HandleLoginFailure(failure)) {
690 login_display_->SetUIEnabled(true);
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) {
704 } else if (!online_succeeded_for_.empty()) {
705 ShowGaiaPasswordChanged(online_succeeded_for_);
707 // Check networking after trying to login in case user is
708 // cached locally or the local admin account.
710 UserManager::Get()->IsKnownUser(last_login_attempt_username_);
711 if (!network_state_helper_->IsConnected()) {
713 ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error);
715 ShowError(IDS_LOGIN_ERROR_OFFLINE_FAILED_NETWORK_NOT_CONNECTED, error);
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);
724 ShowError(IDS_LOGIN_ERROR_AUTHENTICATING_NEW, error);
726 ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error);
729 // Reenable clicking on other windows and status area.
730 login_display_->SetUIEnabled(true);
731 login_display_->ClearAndEnablePassword();
732 StartPublicSessionAutoLoginTimer();
735 // Reset user flow to default, so that special flow will not affect next
737 UserManager::Get()->ResetUserFlow(last_login_attempt_username_);
739 if (login_status_consumer_)
740 login_status_consumer_->OnLoginFailure(failure);
742 // Clear the recorded displayed email so it won't affect any future attempts.
743 display_email_.clear();
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);
751 StopPublicSessionAutoLoginTimer();
754 login_performer_->auth_mode() == LoginPerformer::AUTH_MODE_EXTENSION &&
755 user_context.auth_code.empty();
757 // Login performer will be gone so cache this value to use
758 // once profile is loaded.
759 password_changed_ = login_performer_->password_changed();
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());
769 // Will call OnProfilePrepared() in the end.
770 LoginUtils::Get()->PrepareProfile(user_context,
773 false, // Start session for user.
776 display_email_.clear();
778 // Notify LoginDisplay to allow it provide visual feedback to user.
779 login_display_->OnLoginSuccess(user_context.username);
782 void ExistingUserController::OnProfilePrepared(Profile* profile) {
783 // Reenable clicking on other windows and status area.
784 login_display_->SetUIEnabled(true);
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);
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
798 if (!SessionStartupPref::TypeIsManaged(profile->GetPrefs()))
799 InitializeStartUrls();
801 // Mark the device as registered., i.e. the second part of OOBE as
803 if (!StartupUtils::IsDeviceRegistered())
804 StartupUtils::MarkDeviceRegistered();
806 if (CommandLine::ForCurrentProcess()->HasSwitch(
807 chromeos::switches::kOobeSkipPostLogin)) {
808 LoginUtils::Get()->DoBrowserLaunch(profile, host_);
811 ActivateWizard(WizardController::kTermsOfServiceScreenName);
814 LoginUtils::Get()->DoBrowserLaunch(profile, host_);
817 // Inform |login_status_consumer_| about successful login.
818 if (login_status_consumer_)
819 login_status_consumer_->OnLoginSuccess(UserContext());
820 login_display_->OnFadeOut();
823 void ExistingUserController::OnOffTheRecordLoginSuccess() {
824 is_login_in_progress_ = false;
825 offline_failed_ = false;
827 // Mark the device as registered., i.e. the second part of OOBE as completed.
828 if (!StartupUtils::IsDeviceRegistered())
829 StartupUtils::MarkDeviceRegistered();
831 LoginUtils::Get()->CompleteOffTheRecordLogin(guest_mode_url_);
833 if (login_status_consumer_)
834 login_status_consumer_->OnOffTheRecordLoginSuccess();
837 void ExistingUserController::OnPasswordChangeDetected() {
838 is_login_in_progress_ = false;
839 offline_failed_ = false;
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.
850 if (UserManager::Get()->GetUserFlow(last_login_attempt_username_)->
851 HandlePasswordChangeDetected()) {
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;
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);
866 if (login_status_consumer_)
867 login_status_consumer_->OnPasswordChangeDetected();
869 display_email_.clear();
872 void ExistingUserController::WhiteListCheckFailed(const std::string& email) {
873 is_login_in_progress_ = false;
874 offline_failed_ = false;
876 ShowError(IDS_LOGIN_ERROR_WHITELIST, email);
878 // Reenable clicking on other windows and status area.
879 login_display_->SetUIEnabled(true);
880 login_display_->ShowSigninUI(email);
882 if (login_status_consumer_) {
883 login_status_consumer_->OnLoginFailure(LoginFailure(
884 LoginFailure::WHITELIST_CHECK_FAILED));
887 display_email_.clear();
889 StartPublicSessionAutoLoginTimer();
892 void ExistingUserController::PolicyLoadFailed() {
893 ShowError(IDS_LOGIN_ERROR_OWNER_KEY_LOST, "");
895 // Reenable clicking on other windows and status area.
896 is_login_in_progress_ = false;
897 offline_failed_ = false;
898 login_display_->SetUIEnabled(true);
900 display_email_.clear();
902 // Policy load failure stops login attempts -- restart the timer.
903 StartPublicSessionAutoLoginTimer();
906 void ExistingUserController::OnOnlineChecked(const std::string& username,
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);
916 ////////////////////////////////////////////////////////////////////////////////
917 // ExistingUserController, private:
919 void ExistingUserController::DeviceSettingsChanged() {
921 // Signed settings or user list changed. Notify views and update them.
922 UpdateLoginDisplay(chromeos::UserManager::Get()->GetUsers());
923 ConfigurePublicSessionAutoLogin();
928 void ExistingUserController::ActivateWizard(const std::string& screen_name) {
929 scoped_ptr<DictionaryValue> params;
930 host_->StartWizard(screen_name, params.Pass());
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_);
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;
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();
955 if (!cros_settings_->GetInteger(
956 kAccountsPrefDeviceLocalAccountAutoLoginDelay,
957 &public_session_auto_login_delay_)) {
958 public_session_auto_login_delay_ = 0;
961 if (!public_session_auto_login_username_.empty())
962 StartPublicSessionAutoLoginTimer();
964 StopPublicSessionAutoLoginTimer();
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();
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_);
982 void ExistingUserController::StopPublicSessionAutoLoginTimer() {
983 if (auto_login_timer_)
984 auto_login_timer_->Stop();
987 void ExistingUserController::StartPublicSessionAutoLoginTimer() {
988 if (!signin_screen_ready_ ||
989 is_login_in_progress_ ||
990 public_session_auto_login_username_.empty()) {
994 // Start the auto-login timer.
995 if (!auto_login_timer_)
996 auto_login_timer_.reset(new base::OneShotTimer<ExistingUserController>);
998 auto_login_timer_->Start(
1000 base::TimeDelta::FromMilliseconds(
1001 public_session_auto_login_delay_),
1003 &ExistingUserController::OnPublicSessionAutoLoginTimerFire,
1004 weak_factory_.GetWeakPtr()));
1007 gfx::NativeWindow ExistingUserController::GetNativeWindow() const {
1008 return host_->GetNativeWindow();
1011 void ExistingUserController::InitializeStartUrls() const {
1012 std::vector<std::string> start_urls;
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
1020 for (base::ListValue::const_iterator it = urls->begin();
1021 it != urls->end(); ++it) {
1023 if ((*it)->GetAsString(&url))
1024 start_urls.push_back(url);
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;
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();
1049 // Only show getting started guide for a new user.
1050 const bool should_show_getstarted_guide =
1051 UserManager::Get()->IsCurrentUserNew();
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);
1058 for (size_t i = 0; i < start_urls.size(); ++i) {
1059 CommandLine::ForCurrentProcess()->AppendArg(start_urls[i]);
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.
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;
1077 case GoogleServiceAuthError::ACCOUNT_DISABLED:
1078 help_topic_id = HelpAppLauncher::HELP_ACCOUNT_DISABLED;
1080 case GoogleServiceAuthError::HOSTED_NOT_ALLOWED:
1081 help_topic_id = HelpAppLauncher::HELP_HOSTED_ACCOUNT;
1084 help_topic_id = is_offline ?
1085 HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT_OFFLINE :
1086 HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT;
1090 login_display_->ShowError(error_id, num_login_attempts_, help_topic_id);
1093 void ExistingUserController::ShowGaiaPasswordChanged(
1094 const std::string& username) {
1095 // Invalidate OAuth token, since it can't be correct after password is
1097 UserManager::Get()->SaveUserOAuthStatus(
1099 User::OAUTH2_TOKEN_STATUS_INVALID);
1101 login_display_->SetUIEnabled(true);
1102 login_display_->ShowGaiaPasswordChanged(username);
1105 } // namespace chromeos