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