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