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