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/accessibility/accessibility_events.h"
24 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/browser_process_platform_part.h"
26 #include "chrome/browser/chrome_notification_types.h"
27 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
28 #include "chrome/browser/chromeos/boot_times_loader.h"
29 #include "chrome/browser/chromeos/customization_document.h"
30 #include "chrome/browser/chromeos/first_run/first_run.h"
31 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
32 #include "chrome/browser/chromeos/login/helper.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/ui/login_display_host.h"
36 #include "chrome/browser/chromeos/login/user_flow.h"
37 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
38 #include "chrome/browser/chromeos/login/wizard_controller.h"
39 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
40 #include "chrome/browser/chromeos/policy/device_local_account.h"
41 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
42 #include "chrome/browser/chromeos/profiles/profile_helper.h"
43 #include "chrome/browser/chromeos/settings/cros_settings.h"
44 #include "chrome/browser/prefs/session_startup_pref.h"
45 #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
46 #include "chrome/common/chrome_switches.h"
47 #include "chrome/common/chrome_version_info.h"
48 #include "chrome/common/pref_names.h"
49 #include "chrome/common/url_constants.h"
50 #include "chrome/grit/generated_resources.h"
51 #include "chromeos/chromeos_switches.h"
52 #include "chromeos/dbus/dbus_thread_manager.h"
53 #include "chromeos/dbus/power_manager_client.h"
54 #include "chromeos/dbus/session_manager_client.h"
55 #include "chromeos/login/auth/user_context.h"
56 #include "chromeos/login/user_names.h"
57 #include "chromeos/settings/cros_settings_names.h"
58 #include "components/google/core/browser/google_util.h"
59 #include "components/policy/core/common/cloud/cloud_policy_core.h"
60 #include "components/policy/core/common/cloud/cloud_policy_store.h"
61 #include "components/policy/core/common/policy_map.h"
62 #include "components/policy/core/common/policy_service.h"
63 #include "components/policy/core/common/policy_types.h"
64 #include "components/user_manager/user_manager.h"
65 #include "components/user_manager/user_type.h"
66 #include "content/public/browser/browser_thread.h"
67 #include "content/public/browser/notification_service.h"
68 #include "content/public/browser/notification_types.h"
69 #include "content/public/browser/user_metrics.h"
70 #include "google_apis/gaia/gaia_auth_util.h"
71 #include "google_apis/gaia/google_service_auth_error.h"
72 #include "net/http/http_auth_cache.h"
73 #include "net/http/http_network_session.h"
74 #include "net/http/http_transaction_factory.h"
75 #include "net/url_request/url_request_context.h"
76 #include "net/url_request/url_request_context_getter.h"
77 #include "policy/policy_constants.h"
78 #include "ui/accessibility/ax_enums.h"
79 #include "ui/base/l10n/l10n_util.h"
80 #include "ui/views/widget/widget.h"
86 // URL for account creation.
87 const char kCreateAccountURL[] =
88 "https://accounts.google.com/NewAccount?service=mail";
90 // ChromeVox tutorial URL (used in place of "getting started" url when
91 // accessibility is enabled).
92 const char kChromeVoxTutorialURLPattern[] =
93 "http://www.chromevox.com/tutorial/index.html?lang=%s";
95 // Delay for transferring the auth cache to the system profile.
96 const long int kAuthCacheTransferDelayMs = 2000;
98 // Delay for restarting the ui if safe-mode login has failed.
99 const long int kSafeModeRestartUiDelayMs = 30000;
101 // Makes a call to the policy subsystem to reload the policy when we detect
102 // authentication change.
103 void RefreshPoliciesOnUIThread() {
104 if (g_browser_process->policy_service())
105 g_browser_process->policy_service()->RefreshPolicies(base::Closure());
108 // Copies any authentication details that were entered in the login profile in
109 // the mail profile to make sure all subsystems of Chrome can access the network
110 // with the provided authentication which are possibly for a proxy server.
111 void TransferContextAuthenticationsOnIOThread(
112 net::URLRequestContextGetter* default_profile_context_getter,
113 net::URLRequestContextGetter* browser_process_context_getter) {
114 net::HttpAuthCache* new_cache =
115 browser_process_context_getter->GetURLRequestContext()->
116 http_transaction_factory()->GetSession()->http_auth_cache();
117 net::HttpAuthCache* old_cache =
118 default_profile_context_getter->GetURLRequestContext()->
119 http_transaction_factory()->GetSession()->http_auth_cache();
120 new_cache->UpdateAllFrom(*old_cache);
121 VLOG(1) << "Main request context populated with authentication data.";
122 // Last but not least tell the policy subsystem to refresh now as it might
123 // have been stuck until now too.
124 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
125 base::Bind(&RefreshPoliciesOnUIThread));
131 ExistingUserController* ExistingUserController::current_controller_ = NULL;
133 ////////////////////////////////////////////////////////////////////////////////
134 // ExistingUserController, public:
136 ExistingUserController::ExistingUserController(LoginDisplayHost* host)
137 : auth_status_consumer_(NULL),
139 login_display_(host_->CreateLoginDisplay(this)),
140 num_login_attempts_(0),
141 cros_settings_(CrosSettings::Get()),
143 offline_failed_(false),
144 is_login_in_progress_(false),
145 password_changed_(false),
146 auth_mode_(LoginPerformer::AUTH_MODE_EXTENSION),
147 do_auto_enrollment_(false),
148 signin_screen_ready_(false),
149 network_state_helper_(new login::NetworkStateHelper) {
150 DCHECK(current_controller_ == NULL);
151 current_controller_ = this;
154 chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
155 content::NotificationService::AllSources());
157 chrome::NOTIFICATION_USER_LIST_CHANGED,
158 content::NotificationService::AllSources());
160 chrome::NOTIFICATION_AUTH_SUPPLIED,
161 content::NotificationService::AllSources());
163 chrome::NOTIFICATION_SESSION_STARTED,
164 content::NotificationService::AllSources());
165 show_user_names_subscription_ = cros_settings_->AddSettingsObserver(
166 kAccountsPrefShowUserNamesOnSignIn,
167 base::Bind(&ExistingUserController::DeviceSettingsChanged,
168 base::Unretained(this)));
169 allow_new_user_subscription_ = cros_settings_->AddSettingsObserver(
170 kAccountsPrefAllowNewUser,
171 base::Bind(&ExistingUserController::DeviceSettingsChanged,
172 base::Unretained(this)));
173 allow_guest_subscription_ = cros_settings_->AddSettingsObserver(
174 kAccountsPrefAllowGuest,
175 base::Bind(&ExistingUserController::DeviceSettingsChanged,
176 base::Unretained(this)));
177 allow_supervised_user_subscription_ = cros_settings_->AddSettingsObserver(
178 kAccountsPrefSupervisedUsersEnabled,
179 base::Bind(&ExistingUserController::DeviceSettingsChanged,
180 base::Unretained(this)));
181 users_subscription_ = cros_settings_->AddSettingsObserver(
183 base::Bind(&ExistingUserController::DeviceSettingsChanged,
184 base::Unretained(this)));
185 local_account_auto_login_id_subscription_ =
186 cros_settings_->AddSettingsObserver(
187 kAccountsPrefDeviceLocalAccountAutoLoginId,
188 base::Bind(&ExistingUserController::ConfigurePublicSessionAutoLogin,
189 base::Unretained(this)));
190 local_account_auto_login_delay_subscription_ =
191 cros_settings_->AddSettingsObserver(
192 kAccountsPrefDeviceLocalAccountAutoLoginDelay,
193 base::Bind(&ExistingUserController::ConfigurePublicSessionAutoLogin,
194 base::Unretained(this)));
197 void ExistingUserController::Init(const user_manager::UserList& users) {
198 time_init_ = base::Time::Now();
199 UpdateLoginDisplay(users);
200 ConfigurePublicSessionAutoLogin();
203 void ExistingUserController::UpdateLoginDisplay(
204 const user_manager::UserList& users) {
205 bool show_users_on_signin;
206 user_manager::UserList filtered_users;
208 cros_settings_->GetBoolean(kAccountsPrefShowUserNamesOnSignIn,
209 &show_users_on_signin);
210 for (user_manager::UserList::const_iterator it = users.begin();
213 // TODO(xiyuan): Clean user profile whose email is not in whitelist.
214 bool meets_supervised_requirements =
215 (*it)->GetType() != user_manager::USER_TYPE_SUPERVISED ||
216 user_manager::UserManager::Get()->AreSupervisedUsersAllowed();
217 bool meets_whitelist_requirements =
218 LoginUtils::IsWhitelisted((*it)->email(), NULL) ||
219 (*it)->GetType() != user_manager::USER_TYPE_REGULAR;
221 // Public session accounts are always shown on login screen.
222 bool meets_show_users_requirements =
223 show_users_on_signin ||
224 (*it)->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT;
225 if (meets_supervised_requirements &&
226 meets_whitelist_requirements &&
227 meets_show_users_requirements) {
228 filtered_users.push_back(*it);
232 // If no user pods are visible, fallback to single new user pod which will
233 // have guest session link.
235 cros_settings_->GetBoolean(kAccountsPrefAllowGuest, &show_guest);
236 show_users_on_signin |= !filtered_users.empty();
237 show_guest &= !filtered_users.empty();
238 bool show_new_user = true;
239 login_display_->set_parent_window(GetNativeWindow());
240 login_display_->Init(
241 filtered_users, show_guest, show_users_on_signin, show_new_user);
242 host_->OnPreferencesChanged();
245 void ExistingUserController::DoAutoEnrollment() {
246 do_auto_enrollment_ = true;
249 void ExistingUserController::ResumeLogin() {
250 // This means the user signed-in, then auto-enrollment used his credentials
251 // to enroll and succeeded.
252 resume_login_callback_.Run();
253 resume_login_callback_.Reset();
256 ////////////////////////////////////////////////////////////////////////////////
257 // ExistingUserController, content::NotificationObserver implementation:
260 void ExistingUserController::Observe(
262 const content::NotificationSource& source,
263 const content::NotificationDetails& details) {
264 if (type == chrome::NOTIFICATION_SESSION_STARTED) {
265 // Stop listening to any notification once session has started.
266 // Sign in screen objects are marked for deletion with DeleteSoon so
267 // make sure no object would be used after session has started.
268 // http://crbug.com/125276
269 registrar_.RemoveAll();
272 if (type == chrome::NOTIFICATION_USER_LIST_CHANGED) {
273 DeviceSettingsChanged();
276 if (type == chrome::NOTIFICATION_AUTH_SUPPLIED) {
277 // Possibly the user has authenticated against a proxy server and we might
278 // need the credentials for enrollment and other system requests from the
279 // main |g_browser_process| request context (see bug
280 // http://crosbug.com/24861). So we transfer any credentials to the global
281 // request context here.
282 // The issue we have here is that the NOTIFICATION_AUTH_SUPPLIED is sent
283 // just after the UI is closed but before the new credentials were stored
284 // in the profile. Therefore we have to give it some time to make sure it
285 // has been updated before we copy it.
286 VLOG(1) << "Authentication was entered manually, possibly for proxyauth.";
287 scoped_refptr<net::URLRequestContextGetter> browser_process_context_getter =
288 g_browser_process->system_request_context();
289 Profile* signin_profile = ProfileHelper::GetSigninProfile();
290 scoped_refptr<net::URLRequestContextGetter> signin_profile_context_getter =
291 signin_profile->GetRequestContext();
292 DCHECK(browser_process_context_getter.get());
293 DCHECK(signin_profile_context_getter.get());
294 content::BrowserThread::PostDelayedTask(
295 content::BrowserThread::IO, FROM_HERE,
296 base::Bind(&TransferContextAuthenticationsOnIOThread,
297 signin_profile_context_getter,
298 browser_process_context_getter),
299 base::TimeDelta::FromMilliseconds(kAuthCacheTransferDelayMs));
301 if (type != chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED)
303 login_display_->OnUserImageChanged(
304 *content::Details<user_manager::User>(details).ptr());
307 ////////////////////////////////////////////////////////////////////////////////
308 // ExistingUserController, private:
310 ExistingUserController::~ExistingUserController() {
311 LoginUtils::Get()->DelegateDeleted(this);
313 if (current_controller_ == this) {
314 current_controller_ = NULL;
316 NOTREACHED() << "More than one controller are alive.";
318 DCHECK(login_display_.get());
321 ////////////////////////////////////////////////////////////////////////////////
322 // ExistingUserController, LoginDisplay::Delegate implementation:
325 void ExistingUserController::CancelPasswordChangedFlow() {
326 login_performer_.reset(NULL);
327 login_display_->SetUIEnabled(true);
328 StartPublicSessionAutoLoginTimer();
331 void ExistingUserController::CreateAccount() {
332 content::RecordAction(base::UserMetricsAction("Login.CreateAccount"));
333 guest_mode_url_ = google_util::AppendGoogleLocaleParam(
334 GURL(kCreateAccountURL), g_browser_process->GetApplicationLocale());
338 void ExistingUserController::CompleteLogin(const UserContext& user_context) {
339 login_display_->set_signin_completed(true);
341 // Complete login event was generated already from UI. Ignore notification.
345 // Stop the auto-login timer when attempting login.
346 StopPublicSessionAutoLoginTimer();
348 // Disable UI while loading user profile.
349 login_display_->SetUIEnabled(false);
351 if (!time_init_.is_null()) {
352 base::TimeDelta delta = base::Time::Now() - time_init_;
353 UMA_HISTOGRAM_MEDIUM_TIMES("Login.PromptToCompleteLoginTime", delta);
354 time_init_ = base::Time(); // Reset to null.
357 host_->OnCompleteLogin();
359 // Do an ownership check now to avoid auto-enrolling if the device has
360 // already been owned.
361 DeviceSettingsService::Get()->GetOwnershipStatusAsync(
362 base::Bind(&ExistingUserController::CompleteLoginInternal,
363 weak_factory_.GetWeakPtr(),
367 void ExistingUserController::CompleteLoginInternal(
368 const UserContext& user_context,
369 DeviceSettingsService::OwnershipStatus ownership_status) {
370 // Auto-enrollment must have made a decision by now. It's too late to enroll
371 // if the protocol isn't done at this point.
372 if (do_auto_enrollment_ &&
373 ownership_status == DeviceSettingsService::OWNERSHIP_NONE) {
374 VLOG(1) << "Forcing auto-enrollment before completing login";
375 // The only way to get out of the enrollment screen from now on is to either
376 // complete enrollment, or opt-out of it. So this controller shouldn't force
377 // enrollment again if it is reused for another sign-in.
378 do_auto_enrollment_ = false;
379 auto_enrollment_username_ = user_context.GetUserID();
380 resume_login_callback_ = base::Bind(
381 &ExistingUserController::PerformLogin,
382 weak_factory_.GetWeakPtr(),
383 user_context, LoginPerformer::AUTH_MODE_EXTENSION);
384 ShowEnrollmentScreen(true, user_context.GetUserID());
385 // Enable UI for the enrollment screen. SetUIEnabled(true) will post a
386 // request to show the sign-in screen again when invoked at the sign-in
387 // screen; invoke SetUIEnabled() after navigating to the enrollment screen.
388 login_display_->SetUIEnabled(true);
390 PerformLogin(user_context, LoginPerformer::AUTH_MODE_EXTENSION);
394 base::string16 ExistingUserController::GetConnectedNetworkName() {
395 return network_state_helper_->GetCurrentNetworkName();
398 bool ExistingUserController::IsSigninInProgress() const {
399 return is_login_in_progress_;
402 void ExistingUserController::Login(const UserContext& user_context,
403 const SigninSpecifics& specifics) {
404 if (user_context.GetUserType() == user_manager::USER_TYPE_GUEST) {
405 if (!specifics.guest_mode_url.empty()) {
406 guest_mode_url_ = GURL(specifics.guest_mode_url);
407 if (specifics.guest_mode_url_append_locale)
408 guest_mode_url_ = google_util::AppendGoogleLocaleParam(
409 guest_mode_url_, g_browser_process->GetApplicationLocale());
413 } else if (user_context.GetUserType() ==
414 user_manager::USER_TYPE_PUBLIC_ACCOUNT) {
415 LoginAsPublicSession(user_context);
417 } else if (user_context.GetUserType() ==
418 user_manager::USER_TYPE_RETAIL_MODE) {
419 LoginAsRetailModeUser();
421 } else if (user_context.GetUserType() == user_manager::USER_TYPE_KIOSK_APP) {
422 LoginAsKioskApp(user_context.GetUserID(), specifics.kiosk_diagnostic_mode);
426 if (!user_context.HasCredentials())
429 // Stop the auto-login timer when attempting login.
430 StopPublicSessionAutoLoginTimer();
432 // Disable clicking on other windows.
433 login_display_->SetUIEnabled(false);
435 if (last_login_attempt_username_ != user_context.GetUserID()) {
436 last_login_attempt_username_ = user_context.GetUserID();
437 num_login_attempts_ = 0;
438 // Also reset state variables, which are used to determine password change.
439 offline_failed_ = false;
440 online_succeeded_for_.clear();
442 num_login_attempts_++;
443 PerformLogin(user_context, LoginPerformer::AUTH_MODE_INTERNAL);
446 void ExistingUserController::PerformLogin(
447 const UserContext& user_context,
448 LoginPerformer::AuthorizationMode auth_mode) {
449 ChromeUserManager::Get()->GetUserFlow(last_login_attempt_username_)->set_host(
452 BootTimesLoader::Get()->RecordLoginAttempted();
454 // Disable UI while loading user profile.
455 login_display_->SetUIEnabled(false);
457 // Use the same LoginPerformer for subsequent login as it has state
458 // such as Authenticator instance.
459 if (!login_performer_.get() || num_login_attempts_ <= 1) {
460 // Only one instance of LoginPerformer should exist at a time.
461 login_performer_.reset(NULL);
462 login_performer_.reset(new LoginPerformer(this));
465 is_login_in_progress_ = true;
466 if (gaia::ExtractDomainName(user_context.GetUserID()) ==
467 chromeos::login::kSupervisedUserDomain) {
468 login_performer_->LoginAsSupervisedUser(user_context);
470 login_performer_->PerformLogin(user_context, auth_mode);
472 SendAccessibilityAlert(
473 l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNING_IN));
476 void ExistingUserController::LoginAsRetailModeUser() {
477 // Stop the auto-login timer when attempting login.
478 StopPublicSessionAutoLoginTimer();
480 // Disable clicking on other windows.
481 login_display_->SetUIEnabled(false);
482 // TODO(rkc): Add a CHECK to make sure retail mode logins are allowed once
483 // the enterprise policy wiring is done for retail mode.
485 // Only one instance of LoginPerformer should exist at a time.
486 login_performer_.reset(NULL);
487 login_performer_.reset(new LoginPerformer(this));
488 is_login_in_progress_ = true;
489 login_performer_->LoginRetailMode();
490 SendAccessibilityAlert(
491 l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNIN_DEMOUSER));
494 void ExistingUserController::LoginAsGuest() {
495 if (is_login_in_progress_ ||
496 user_manager::UserManager::Get()->IsUserLoggedIn()) {
500 // Stop the auto-login timer when attempting login.
501 StopPublicSessionAutoLoginTimer();
503 // Disable clicking on other windows.
504 login_display_->SetUIEnabled(false);
506 CrosSettingsProvider::TrustedStatus status =
507 cros_settings_->PrepareTrustedValues(
508 base::Bind(&ExistingUserController::LoginAsGuest,
509 weak_factory_.GetWeakPtr()));
510 // Must not proceed without signature verification.
511 if (status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) {
512 login_display_->ShowError(IDS_LOGIN_ERROR_OWNER_KEY_LOST, 1,
513 HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT);
514 // Reenable clicking on other windows and status area.
515 login_display_->SetUIEnabled(true);
516 StartPublicSessionAutoLoginTimer();
517 display_email_.clear();
519 } else if (status != CrosSettingsProvider::TRUSTED) {
520 // Value of AllowNewUser setting is still not verified.
521 // Another attempt will be invoked after verification completion.
526 cros_settings_->GetBoolean(kAccountsPrefAllowGuest, &allow_guest);
528 // Disallowed. The UI should normally not show the guest pod but if for some
529 // reason this has been made available to the user here is the time to tell
531 login_display_->ShowError(IDS_LOGIN_ERROR_WHITELIST, 1,
532 HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT);
533 // Reenable clicking on other windows and status area.
534 login_display_->SetUIEnabled(true);
535 StartPublicSessionAutoLoginTimer();
536 display_email_.clear();
540 // Only one instance of LoginPerformer should exist at a time.
541 login_performer_.reset(NULL);
542 login_performer_.reset(new LoginPerformer(this));
543 is_login_in_progress_ = true;
544 login_performer_->LoginOffTheRecord();
545 SendAccessibilityAlert(
546 l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNIN_OFFRECORD));
549 void ExistingUserController::MigrateUserData(const std::string& old_password) {
550 // LoginPerformer instance has state of the user so it should exist.
551 if (login_performer_.get())
552 login_performer_->RecoverEncryptedData(old_password);
555 void ExistingUserController::LoginAsPublicSession(
556 const UserContext& user_context) {
557 if (is_login_in_progress_ ||
558 user_manager::UserManager::Get()->IsUserLoggedIn()) {
562 // Stop the auto-login timer when attempting login.
563 StopPublicSessionAutoLoginTimer();
565 // Disable clicking on other windows.
566 login_display_->SetUIEnabled(false);
568 CrosSettingsProvider::TrustedStatus status =
569 cros_settings_->PrepareTrustedValues(
570 base::Bind(&ExistingUserController::LoginAsPublicSession,
571 weak_factory_.GetWeakPtr(),
573 // If device policy is permanently unavailable, logging into public accounts
575 if (status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) {
576 login_display_->ShowError(IDS_LOGIN_ERROR_OWNER_KEY_LOST, 1,
577 HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT);
578 // Re-enable clicking on other windows.
579 login_display_->SetUIEnabled(true);
583 // If device policy is not verified yet, this function will be called again
584 // when verification finishes.
585 if (status != CrosSettingsProvider::TRUSTED)
588 // If there is no public account with the given user ID, logging in is not
590 const user_manager::User* user =
591 user_manager::UserManager::Get()->FindUser(user_context.GetUserID());
592 if (!user || user->GetType() != user_manager::USER_TYPE_PUBLIC_ACCOUNT) {
593 // Re-enable clicking on other windows.
594 login_display_->SetUIEnabled(true);
595 StartPublicSessionAutoLoginTimer();
599 UserContext new_user_context = user_context;
600 std::string locale = user_context.GetPublicSessionLocale();
601 if (locale.empty()) {
602 // When performing auto-login, no locale is chosen by the user. Check
603 // whether a list of recommended locales was set by policy. If so, use its
604 // first entry. Otherwise, |locale| will remain blank, indicating that the
605 // public session should use the current UI locale.
606 const policy::PolicyMap::Entry* entry = g_browser_process->platform_part()->
607 browser_policy_connector_chromeos()->
608 GetDeviceLocalAccountPolicyService()->
609 GetBrokerForUser(user_context.GetUserID())->core()->store()->
610 policy_map().Get(policy::key::kSessionLocales);
611 base::ListValue const* list = NULL;
613 entry->level == policy::POLICY_LEVEL_RECOMMENDED &&
615 entry->value->GetAsList(&list)) {
616 if (list->GetString(0, &locale))
617 new_user_context.SetPublicSessionLocale(locale);
621 if (!locale.empty() &&
622 new_user_context.GetPublicSessionInputMethod().empty()) {
623 // When |locale| is set, a suitable keyboard layout should be chosen. In
624 // most cases, this will already be the case because the UI shows a list of
625 // keyboard layouts suitable for the |locale| and ensures that one of them
626 // us selected. However, it is still possible that |locale| is set but no
627 // keyboard layout was chosen:
628 // * The list of keyboard layouts is updated asynchronously. If the user
629 // enters the public session before the list of keyboard layouts for the
630 // |locale| has been retrieved, the UI will indicate that no keyboard
631 // layout was chosen.
632 // * During auto-login, the |locale| is set in this method and a suitable
633 // keyboard layout must be chosen next.
635 // The list of suitable keyboard layouts is constructed asynchronously. Once
636 // it has been retrieved, |SetPublicSessionKeyboardLayoutAndLogin| will
637 // select the first layout from the list and continue login.
638 GetKeyboardLayoutsForLocale(
640 &ExistingUserController::SetPublicSessionKeyboardLayoutAndLogin,
641 weak_factory_.GetWeakPtr(),
647 // The user chose a locale and a suitable keyboard layout or left both unset.
648 // Login can continue immediately.
649 LoginAsPublicSessionInternal(new_user_context);
652 void ExistingUserController::LoginAsKioskApp(const std::string& app_id,
653 bool diagnostic_mode) {
654 host_->StartAppLaunch(app_id, diagnostic_mode);
657 void ExistingUserController::OnSigninScreenReady() {
658 signin_screen_ready_ = true;
659 StartPublicSessionAutoLoginTimer();
662 void ExistingUserController::OnStartEnterpriseEnrollment() {
663 if (KioskAppManager::Get()->IsConsumerKioskDeviceWithAutoLaunch()) {
664 LOG(WARNING) << "Enterprise enrollment is not available after kiosk auto "
669 DeviceSettingsService::Get()->GetOwnershipStatusAsync(
670 base::Bind(&ExistingUserController::OnEnrollmentOwnershipCheckCompleted,
671 weak_factory_.GetWeakPtr()));
674 void ExistingUserController::OnStartKioskEnableScreen() {
675 KioskAppManager::Get()->GetConsumerKioskAutoLaunchStatus(
677 &ExistingUserController::OnConsumerKioskAutoLaunchCheckCompleted,
678 weak_factory_.GetWeakPtr()));
681 void ExistingUserController::OnStartKioskAutolaunchScreen() {
682 ShowKioskAutolaunchScreen();
685 void ExistingUserController::ResyncUserData() {
686 // LoginPerformer instance has state of the user so it should exist.
687 if (login_performer_.get())
688 login_performer_->ResyncEncryptedData();
691 void ExistingUserController::SetDisplayEmail(const std::string& email) {
692 display_email_ = email;
695 void ExistingUserController::ShowWrongHWIDScreen() {
696 scoped_ptr<base::DictionaryValue> params;
697 host_->StartWizard(WizardController::kWrongHWIDScreenName, params.Pass());
700 void ExistingUserController::Signout() {
704 void ExistingUserController::OnConsumerKioskAutoLaunchCheckCompleted(
705 KioskAppManager::ConsumerKioskAutoLaunchStatus status) {
706 if (status == KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE)
707 ShowKioskEnableScreen();
710 void ExistingUserController::OnEnrollmentOwnershipCheckCompleted(
711 DeviceSettingsService::OwnershipStatus status) {
712 if (status == DeviceSettingsService::OWNERSHIP_NONE) {
713 ShowEnrollmentScreen(false, std::string());
714 } else if (status == DeviceSettingsService::OWNERSHIP_TAKEN) {
715 // On a device that is already owned we might want to allow users to
716 // re-enroll if the policy information is invalid.
717 CrosSettingsProvider::TrustedStatus trusted_status =
718 CrosSettings::Get()->PrepareTrustedValues(
720 &ExistingUserController::OnEnrollmentOwnershipCheckCompleted,
721 weak_factory_.GetWeakPtr(), status));
722 if (trusted_status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) {
723 ShowEnrollmentScreen(false, std::string());
726 // OwnershipService::GetStatusAsync is supposed to return either
727 // OWNERSHIP_NONE or OWNERSHIP_TAKEN.
732 void ExistingUserController::ShowEnrollmentScreen(bool is_auto_enrollment,
733 const std::string& user) {
734 scoped_ptr<base::DictionaryValue> params;
735 if (is_auto_enrollment) {
736 params.reset(new base::DictionaryValue());
737 params->SetBoolean("is_auto_enrollment", true);
738 params->SetString("user", user);
740 host_->StartWizard(WizardController::kEnrollmentScreenName,
744 void ExistingUserController::ShowResetScreen() {
745 scoped_ptr<base::DictionaryValue> params;
746 host_->StartWizard(WizardController::kResetScreenName, params.Pass());
749 void ExistingUserController::ShowKioskEnableScreen() {
750 scoped_ptr<base::DictionaryValue> params;
751 host_->StartWizard(WizardController::kKioskEnableScreenName, params.Pass());
754 void ExistingUserController::ShowKioskAutolaunchScreen() {
755 scoped_ptr<base::DictionaryValue> params;
756 host_->StartWizard(WizardController::kKioskAutolaunchScreenName,
760 void ExistingUserController::ShowTPMError() {
761 login_display_->SetUIEnabled(false);
762 login_display_->ShowErrorScreen(LoginDisplay::TPM_ERROR);
765 ////////////////////////////////////////////////////////////////////////////////
766 // ExistingUserController, LoginPerformer::Delegate implementation:
769 void ExistingUserController::OnAuthFailure(const AuthFailure& failure) {
770 is_login_in_progress_ = false;
771 offline_failed_ = true;
773 guest_mode_url_ = GURL::EmptyGURL();
774 std::string error = failure.GetErrorString();
776 if (ChromeUserManager::Get()
777 ->GetUserFlow(last_login_attempt_username_)
778 ->HandleLoginFailure(failure)) {
779 login_display_->SetUIEnabled(true);
783 if (failure.reason() == AuthFailure::OWNER_REQUIRED) {
784 ShowError(IDS_LOGIN_ERROR_OWNER_REQUIRED, error);
785 content::BrowserThread::PostDelayedTask(
786 content::BrowserThread::UI, FROM_HERE,
787 base::Bind(&SessionManagerClient::StopSession,
788 base::Unretained(DBusThreadManager::Get()->
789 GetSessionManagerClient())),
790 base::TimeDelta::FromMilliseconds(kSafeModeRestartUiDelayMs));
791 } else if (failure.reason() == AuthFailure::TPM_ERROR) {
793 } else if (!online_succeeded_for_.empty()) {
794 ShowGaiaPasswordChanged(online_succeeded_for_);
796 // Check networking after trying to login in case user is
797 // cached locally or the local admin account.
798 bool is_known_user = user_manager::UserManager::Get()->IsKnownUser(
799 last_login_attempt_username_);
800 if (!network_state_helper_->IsConnected()) {
802 ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error);
804 ShowError(IDS_LOGIN_ERROR_OFFLINE_FAILED_NETWORK_NOT_CONNECTED, error);
806 // TODO(nkostylev): Cleanup rest of ClientLogin related code.
807 if (failure.reason() == AuthFailure::NETWORK_AUTH_FAILED &&
808 failure.error().state() ==
809 GoogleServiceAuthError::HOSTED_NOT_ALLOWED) {
810 ShowError(IDS_LOGIN_ERROR_AUTHENTICATING_HOSTED, error);
813 ShowError(IDS_LOGIN_ERROR_AUTHENTICATING_NEW, error);
815 ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error);
818 // Reenable clicking on other windows and status area.
819 login_display_->SetUIEnabled(true);
820 login_display_->ClearAndEnablePassword();
821 StartPublicSessionAutoLoginTimer();
824 // Reset user flow to default, so that special flow will not affect next
826 ChromeUserManager::Get()->ResetUserFlow(last_login_attempt_username_);
828 if (auth_status_consumer_)
829 auth_status_consumer_->OnAuthFailure(failure);
831 // Clear the recorded displayed email so it won't affect any future attempts.
832 display_email_.clear();
835 void ExistingUserController::OnAuthSuccess(const UserContext& user_context) {
836 is_login_in_progress_ = false;
837 offline_failed_ = false;
838 login_display_->set_signin_completed(true);
840 // Login performer will be gone so cache this value to use
841 // once profile is loaded.
842 password_changed_ = login_performer_->password_changed();
843 auth_mode_ = login_performer_->auth_mode();
845 ChromeUserManager::Get()
846 ->GetUserFlow(user_context.GetUserID())
847 ->HandleLoginSuccess(user_context);
849 StopPublicSessionAutoLoginTimer();
851 const bool has_auth_cookies =
852 login_performer_->auth_mode() == LoginPerformer::AUTH_MODE_EXTENSION &&
853 user_context.GetAuthCode().empty();
855 // LoginPerformer instance will delete itself once online auth result is OK.
856 // In case of failure it'll bring up ScreenLock and ask for
857 // correct password/display error message.
858 // Even in case when following online,offline protocol and returning
859 // requests_pending = false, let LoginPerformer delete itself.
860 login_performer_->set_delegate(NULL);
861 ignore_result(login_performer_.release());
863 // Will call OnProfilePrepared() in the end.
864 LoginUtils::Get()->PrepareProfile(user_context,
866 false, // Start session for user.
869 // Update user's displayed email.
870 if (!display_email_.empty()) {
871 user_manager::UserManager::Get()->SaveUserDisplayEmail(
872 user_context.GetUserID(), display_email_);
873 display_email_.clear();
877 void ExistingUserController::OnProfilePrepared(Profile* profile) {
878 // Reenable clicking on other windows and status area.
879 login_display_->SetUIEnabled(true);
881 user_manager::UserManager* user_manager = user_manager::UserManager::Get();
882 if (user_manager->IsCurrentUserNew() &&
883 user_manager->IsLoggedInAsSupervisedUser()) {
884 // Supervised users should launch into empty desktop on first run.
885 CommandLine::ForCurrentProcess()->AppendSwitch(::switches::kSilentLaunch);
888 if (user_manager->IsCurrentUserNew() &&
889 !ChromeUserManager::Get()
890 ->GetCurrentUserFlow()
891 ->ShouldSkipPostLoginScreens() &&
892 !WizardController::default_controller()->skip_post_login_screens()) {
893 // Don't specify start URLs if the administrator has configured the start
895 if (!SessionStartupPref::TypeIsManaged(profile->GetPrefs()))
896 InitializeStartUrls();
898 // Mark the device as registered., i.e. the second part of OOBE as
900 if (!StartupUtils::IsDeviceRegistered())
901 StartupUtils::MarkDeviceRegistered(base::Closure());
903 if (CommandLine::ForCurrentProcess()->HasSwitch(
904 chromeos::switches::kOobeSkipPostLogin)) {
905 LoginUtils::Get()->DoBrowserLaunch(profile, host_);
908 ActivateWizard(WizardController::kTermsOfServiceScreenName);
911 LoginUtils::Get()->DoBrowserLaunch(profile, host_);
914 // Inform |auth_status_consumer_| about successful login.
915 if (auth_status_consumer_)
916 auth_status_consumer_->OnAuthSuccess(UserContext());
919 void ExistingUserController::OnOffTheRecordAuthSuccess() {
920 is_login_in_progress_ = false;
921 offline_failed_ = false;
923 // Mark the device as registered., i.e. the second part of OOBE as completed.
924 if (!StartupUtils::IsDeviceRegistered())
925 StartupUtils::MarkDeviceRegistered(base::Closure());
927 LoginUtils::Get()->CompleteOffTheRecordLogin(guest_mode_url_);
929 if (auth_status_consumer_)
930 auth_status_consumer_->OnOffTheRecordAuthSuccess();
933 void ExistingUserController::OnPasswordChangeDetected() {
934 is_login_in_progress_ = false;
935 offline_failed_ = false;
937 // Must not proceed without signature verification.
938 if (CrosSettingsProvider::TRUSTED != cros_settings_->PrepareTrustedValues(
939 base::Bind(&ExistingUserController::OnPasswordChangeDetected,
940 weak_factory_.GetWeakPtr()))) {
941 // Value of owner email is still not verified.
942 // Another attempt will be invoked after verification completion.
946 if (ChromeUserManager::Get()
947 ->GetUserFlow(last_login_attempt_username_)
948 ->HandlePasswordChangeDetected()) {
952 // True if user has already made an attempt to enter old password and failed.
953 bool show_invalid_old_password_error =
954 login_performer_->password_changed_callback_count() > 1;
956 // Note: We allow owner using "full sync" mode which will recreate
957 // cryptohome and deal with owner private key being lost. This also allows
958 // us to recover from a lost owner password/homedir.
959 // TODO(gspencer): We shouldn't have to erase stateful data when
960 // doing this. See http://crosbug.com/9115 http://crosbug.com/7792
961 login_display_->ShowPasswordChangedDialog(show_invalid_old_password_error);
963 if (auth_status_consumer_)
964 auth_status_consumer_->OnPasswordChangeDetected();
966 display_email_.clear();
969 void ExistingUserController::WhiteListCheckFailed(const std::string& email) {
970 is_login_in_progress_ = false;
971 offline_failed_ = false;
973 ShowError(IDS_LOGIN_ERROR_WHITELIST, email);
975 // Reenable clicking on other windows and status area.
976 login_display_->SetUIEnabled(true);
977 login_display_->ShowSigninUI(email);
979 if (auth_status_consumer_) {
980 auth_status_consumer_->OnAuthFailure(
981 AuthFailure(AuthFailure::WHITELIST_CHECK_FAILED));
984 display_email_.clear();
986 StartPublicSessionAutoLoginTimer();
989 void ExistingUserController::PolicyLoadFailed() {
990 ShowError(IDS_LOGIN_ERROR_OWNER_KEY_LOST, "");
992 // Reenable clicking on other windows and status area.
993 is_login_in_progress_ = false;
994 offline_failed_ = false;
995 login_display_->SetUIEnabled(true);
997 display_email_.clear();
999 // Policy load failure stops login attempts -- restart the timer.
1000 StartPublicSessionAutoLoginTimer();
1003 void ExistingUserController::OnOnlineChecked(const std::string& username,
1005 if (success && last_login_attempt_username_ == username) {
1006 online_succeeded_for_ = username;
1007 // Wait for login attempt to end, if it hasn't yet.
1008 if (offline_failed_ && !is_login_in_progress_)
1009 ShowGaiaPasswordChanged(username);
1013 ////////////////////////////////////////////////////////////////////////////////
1014 // ExistingUserController, private:
1016 void ExistingUserController::DeviceSettingsChanged() {
1017 if (host_ != NULL) {
1018 // Signed settings or user list changed. Notify views and update them.
1019 UpdateLoginDisplay(user_manager::UserManager::Get()->GetUsers());
1020 ConfigurePublicSessionAutoLogin();
1025 void ExistingUserController::ActivateWizard(const std::string& screen_name) {
1026 scoped_ptr<base::DictionaryValue> params;
1027 host_->StartWizard(screen_name, params.Pass());
1030 LoginPerformer::AuthorizationMode ExistingUserController::auth_mode() const {
1031 if (login_performer_)
1032 return login_performer_->auth_mode();
1037 bool ExistingUserController::password_changed() const {
1038 if (login_performer_)
1039 return login_performer_->password_changed();
1041 return password_changed_;
1044 void ExistingUserController::ConfigurePublicSessionAutoLogin() {
1045 std::string auto_login_account_id;
1046 cros_settings_->GetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
1047 &auto_login_account_id);
1048 const std::vector<policy::DeviceLocalAccount> device_local_accounts =
1049 policy::GetDeviceLocalAccounts(cros_settings_);
1051 public_session_auto_login_username_.clear();
1052 for (std::vector<policy::DeviceLocalAccount>::const_iterator
1053 it = device_local_accounts.begin();
1054 it != device_local_accounts.end(); ++it) {
1055 if (it->account_id == auto_login_account_id) {
1056 public_session_auto_login_username_ = it->user_id;
1061 const user_manager::User* user = user_manager::UserManager::Get()->FindUser(
1062 public_session_auto_login_username_);
1063 if (!user || user->GetType() != user_manager::USER_TYPE_PUBLIC_ACCOUNT)
1064 public_session_auto_login_username_.clear();
1066 if (!cros_settings_->GetInteger(
1067 kAccountsPrefDeviceLocalAccountAutoLoginDelay,
1068 &public_session_auto_login_delay_)) {
1069 public_session_auto_login_delay_ = 0;
1072 if (!public_session_auto_login_username_.empty())
1073 StartPublicSessionAutoLoginTimer();
1075 StopPublicSessionAutoLoginTimer();
1078 void ExistingUserController::ResetPublicSessionAutoLoginTimer() {
1079 // Only restart the auto-login timer if it's already running.
1080 if (auto_login_timer_ && auto_login_timer_->IsRunning()) {
1081 StopPublicSessionAutoLoginTimer();
1082 StartPublicSessionAutoLoginTimer();
1086 void ExistingUserController::OnPublicSessionAutoLoginTimerFire() {
1087 CHECK(signin_screen_ready_ &&
1088 !is_login_in_progress_ &&
1089 !public_session_auto_login_username_.empty());
1090 // TODO(bartfab): Set the UI language and initial locale.
1091 LoginAsPublicSession(UserContext(user_manager::USER_TYPE_PUBLIC_ACCOUNT,
1092 public_session_auto_login_username_));
1095 void ExistingUserController::StopPublicSessionAutoLoginTimer() {
1096 if (auto_login_timer_)
1097 auto_login_timer_->Stop();
1100 void ExistingUserController::StartPublicSessionAutoLoginTimer() {
1101 if (!signin_screen_ready_ ||
1102 is_login_in_progress_ ||
1103 public_session_auto_login_username_.empty()) {
1107 // Start the auto-login timer.
1108 if (!auto_login_timer_)
1109 auto_login_timer_.reset(new base::OneShotTimer<ExistingUserController>);
1111 auto_login_timer_->Start(
1113 base::TimeDelta::FromMilliseconds(
1114 public_session_auto_login_delay_),
1116 &ExistingUserController::OnPublicSessionAutoLoginTimerFire,
1117 weak_factory_.GetWeakPtr()));
1120 gfx::NativeWindow ExistingUserController::GetNativeWindow() const {
1121 return host_->GetNativeWindow();
1124 void ExistingUserController::InitializeStartUrls() const {
1125 std::vector<std::string> start_urls;
1127 const base::ListValue *urls;
1128 user_manager::UserManager* user_manager = user_manager::UserManager::Get();
1129 bool can_show_getstarted_guide =
1130 user_manager->GetActiveUser()->GetType() ==
1131 user_manager::USER_TYPE_REGULAR &&
1132 !user_manager->IsCurrentUserNonCryptohomeDataEphemeral();
1133 if (user_manager->IsLoggedInAsDemoUser()) {
1134 if (CrosSettings::Get()->GetList(kStartUpUrls, &urls)) {
1135 // The retail mode user will get start URLs from a special policy if it is
1137 for (base::ListValue::const_iterator it = urls->begin();
1138 it != urls->end(); ++it) {
1140 if ((*it)->GetAsString(&url))
1141 start_urls.push_back(url);
1144 can_show_getstarted_guide = false;
1145 // Skip the default first-run behavior for public accounts.
1146 } else if (!user_manager->IsLoggedInAsPublicAccount()) {
1147 if (AccessibilityManager::Get()->IsSpokenFeedbackEnabled()) {
1148 const char* url = kChromeVoxTutorialURLPattern;
1149 PrefService* prefs = g_browser_process->local_state();
1150 const std::string current_locale =
1151 base::StringToLowerASCII(prefs->GetString(prefs::kApplicationLocale));
1152 std::string vox_url = base::StringPrintf(url, current_locale.c_str());
1153 start_urls.push_back(vox_url);
1154 can_show_getstarted_guide = false;
1158 // Only show getting started guide for a new user.
1159 const bool should_show_getstarted_guide = user_manager->IsCurrentUserNew();
1161 if (can_show_getstarted_guide && should_show_getstarted_guide) {
1162 // Don't open default Chrome window if we're going to launch the first-run
1163 // app. Because we dont' want the first-run app to be hidden in the
1165 CommandLine::ForCurrentProcess()->AppendSwitch(::switches::kSilentLaunch);
1166 first_run::MaybeLaunchDialogAfterSessionStart();
1168 for (size_t i = 0; i < start_urls.size(); ++i) {
1169 CommandLine::ForCurrentProcess()->AppendArg(start_urls[i]);
1174 void ExistingUserController::ShowError(int error_id,
1175 const std::string& details) {
1176 // TODO(dpolukhin): show detailed error info. |details| string contains
1177 // low level error info that is not localized and even is not user friendly.
1178 // For now just ignore it because error_text contains all required information
1179 // for end users, developers can see details string in Chrome logs.
1181 HelpAppLauncher::HelpTopic help_topic_id;
1182 bool is_offline = !network_state_helper_->IsConnected();
1183 switch (login_performer_->error().state()) {
1184 case GoogleServiceAuthError::CONNECTION_FAILED:
1185 help_topic_id = HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT_OFFLINE;
1187 case GoogleServiceAuthError::ACCOUNT_DISABLED:
1188 help_topic_id = HelpAppLauncher::HELP_ACCOUNT_DISABLED;
1190 case GoogleServiceAuthError::HOSTED_NOT_ALLOWED:
1191 help_topic_id = HelpAppLauncher::HELP_HOSTED_ACCOUNT;
1194 help_topic_id = is_offline ?
1195 HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT_OFFLINE :
1196 HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT;
1200 if (error_id == IDS_LOGIN_ERROR_AUTHENTICATING) {
1201 if (num_login_attempts_ > 1) {
1202 const user_manager::User* user =
1203 user_manager::UserManager::Get()->FindUser(
1204 last_login_attempt_username_);
1205 if (user && (user->GetType() == user_manager::USER_TYPE_SUPERVISED))
1206 error_id = IDS_LOGIN_ERROR_AUTHENTICATING_2ND_TIME_SUPERVISED;
1210 login_display_->ShowError(error_id, num_login_attempts_, help_topic_id);
1213 void ExistingUserController::ShowGaiaPasswordChanged(
1214 const std::string& username) {
1215 // Invalidate OAuth token, since it can't be correct after password is
1217 user_manager::UserManager::Get()->SaveUserOAuthStatus(
1218 username, user_manager::User::OAUTH2_TOKEN_STATUS_INVALID);
1220 login_display_->SetUIEnabled(true);
1221 login_display_->ShowGaiaPasswordChanged(username);
1224 void ExistingUserController::SendAccessibilityAlert(
1225 const std::string& alert_text) {
1226 AccessibilityAlertInfo event(ProfileHelper::GetSigninProfile(), alert_text);
1227 SendControlAccessibilityNotification(
1228 ui::AX_EVENT_VALUE_CHANGED, &event);
1231 void ExistingUserController::SetPublicSessionKeyboardLayoutAndLogin(
1232 const UserContext& user_context,
1233 scoped_ptr<base::ListValue> keyboard_layouts) {
1234 UserContext new_user_context = user_context;
1235 std::string keyboard_layout;
1236 for (size_t i = 0; i < keyboard_layouts->GetSize(); ++i) {
1237 base::DictionaryValue* entry = NULL;
1238 keyboard_layouts->GetDictionary(i, &entry);
1239 bool selected = false;
1240 entry->GetBoolean("selected", &selected);
1242 entry->GetString("value", &keyboard_layout);
1246 DCHECK(!keyboard_layout.empty());
1247 new_user_context.SetPublicSessionInputMethod(keyboard_layout);
1249 LoginAsPublicSessionInternal(new_user_context);
1252 void ExistingUserController::LoginAsPublicSessionInternal(
1253 const UserContext& user_context) {
1254 // Only one instance of LoginPerformer should exist at a time.
1255 login_performer_.reset(NULL);
1256 login_performer_.reset(new LoginPerformer(this));
1257 is_login_in_progress_ = true;
1258 login_performer_->LoginAsPublicSession(user_context);
1259 SendAccessibilityAlert(
1260 l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNIN_PUBLIC_ACCOUNT));
1263 } // namespace chromeos