1 // Copyright (c) 2011 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/login_performer.h" 6 7 #include <string> 8 9 #include "base/logging.h" 10 #include "base/message_loop.h" 11 #include "base/metrics/histogram.h" 12 #include "base/utf_string_conversions.h" 13 #include "chrome/browser/browser_process.h" 14 #include "chrome/browser/chromeos/boot_times_loader.h" 15 #include "chrome/browser/chromeos/cros/cros_library.h" 16 #include "chrome/browser/chromeos/cros/screen_lock_library.h" 17 #include "chrome/browser/chromeos/cros_settings_names.h" 18 #include "chrome/browser/chromeos/login/login_utils.h" 19 #include "chrome/browser/chromeos/login/screen_locker.h" 20 #include "chrome/browser/chromeos/user_cros_settings_provider.h" 21 #include "chrome/browser/metrics/user_metrics.h" 22 #include "chrome/browser/prefs/pref_service.h" 23 #include "chrome/browser/profiles/profile.h" 24 #include "chrome/browser/profiles/profile_manager.h" 25 #include "chrome/common/pref_names.h" 26 #include "content/browser/browser_thread.h" 27 #include "content/common/notification_service.h" 28 #include "content/common/notification_type.h" 29 #include "grit/generated_resources.h" 30 #include "ui/base/l10n/l10n_util.h" 31 #include "ui/base/resource/resource_bundle.h" 32 33 namespace chromeos { 34 35 // Initialize default LoginPerformer. 36 // static 37 LoginPerformer* LoginPerformer::default_performer_ = NULL; 38 39 LoginPerformer::LoginPerformer(Delegate* delegate) 40 : last_login_failure_(LoginFailure::None()), 41 delegate_(delegate), 42 password_changed_(false), 43 screen_lock_requested_(false), 44 initial_online_auth_pending_(false), 45 method_factory_(this) { 46 DCHECK(default_performer_ == NULL) 47 << "LoginPerformer should have only one instance."; 48 default_performer_ = this; 49 } 50 51 LoginPerformer::~LoginPerformer() { 52 DVLOG(1) << "Deleting LoginPerformer"; 53 DCHECK(default_performer_ != NULL) << "Default instance should exist."; 54 default_performer_ = NULL; 55 } 56 57 //////////////////////////////////////////////////////////////////////////////// 58 // LoginPerformer, LoginStatusConsumer implementation: 59 60 void LoginPerformer::OnLoginFailure(const LoginFailure& failure) { 61 UserMetrics::RecordAction(UserMetricsAction("Login_Failure")); 62 UMA_HISTOGRAM_ENUMERATION("Login.FailureReason", failure.reason(), 63 LoginFailure::NUM_FAILURE_REASONS); 64 65 DVLOG(1) << "failure.reason " << failure.reason(); 66 DVLOG(1) << "failure.error.state " << failure.error().state(); 67 68 last_login_failure_ = failure; 69 if (delegate_) { 70 captcha_.clear(); 71 captcha_token_.clear(); 72 if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED && 73 failure.error().state() == GoogleServiceAuthError::CAPTCHA_REQUIRED) { 74 captcha_token_ = failure.error().captcha().token; 75 } 76 delegate_->OnLoginFailure(failure); 77 return; 78 } 79 80 // Consequent online login failure with blocking UI on. 81 // No difference between cases whether screen was locked by the user or 82 // by LoginPerformer except for the very first screen lock while waiting 83 // for online auth. Otherwise it will be SL active > timeout > screen unlock. 84 // Display recoverable error message using ScreenLocker, 85 // force sign out otherwise. 86 if (ScreenLocker::default_screen_locker() && !initial_online_auth_pending_) { 87 ResolveLockLoginFailure(); 88 return; 89 } 90 initial_online_auth_pending_ = false; 91 92 // Offline auth - OK, online auth - failed. 93 if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED) { 94 ResolveInitialNetworkAuthFailure(); 95 } else if (failure.reason() == LoginFailure::LOGIN_TIMED_OUT) { 96 VLOG(1) << "Online login timed out. " 97 << "Granting user access based on offline auth only."; 98 // ScreenLock is not active, it's ok to delete itself. 99 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 100 } else { 101 // COULD_NOT_MOUNT_CRYPTOHOME, COULD_NOT_MOUNT_TMPFS: 102 // happens during offline auth only. 103 // UNLOCK_FAILED is used during normal screen lock case. 104 // TODO(nkostylev) DATA_REMOVAL_FAILED - ? 105 NOTREACHED(); 106 } 107 } 108 109 void LoginPerformer::OnLoginSuccess( 110 const std::string& username, 111 const std::string& password, 112 const GaiaAuthConsumer::ClientLoginResult& credentials, 113 bool pending_requests) { 114 UserMetrics::RecordAction(UserMetricsAction("Login_Success")); 115 // 0 - Login success offline and online. It's a new user. or it's an 116 // existing user and offline auth took longer than online auth. 117 // 1 - Login success offline only. It's an existing user login. 118 UMA_HISTOGRAM_ENUMERATION("Login.SuccessReason", pending_requests, 2); 119 120 VLOG(1) << "LoginSuccess, pending_requests " << pending_requests; 121 if (delegate_) { 122 // After delegate_->OnLoginSuccess(...) is called, delegate_ releases 123 // LoginPerformer ownership. LP now manages it's lifetime on its own. 124 // 2 things could make it exist longer: 125 // 1. ScreenLock active (pending correct new password input) 126 // 2. Pending online auth request. 127 if (!pending_requests) 128 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 129 else 130 initial_online_auth_pending_ = true; 131 132 delegate_->OnLoginSuccess(username, 133 password, 134 credentials, 135 pending_requests); 136 return; 137 } else { 138 // Online login has succeeded. 139 DCHECK(!pending_requests) 140 << "Pending request w/o delegate_ should not happen!"; 141 // It is not guaranted, that profile creation has been finished yet. So use 142 // async version here. 143 credentials_ = credentials; 144 ProfileManager::CreateDefaultProfileAsync(this); 145 } 146 } 147 148 void LoginPerformer::OnProfileCreated(Profile* profile) { 149 CHECK(profile); 150 151 LoginUtils::Get()->FetchCookies(profile, credentials_); 152 LoginUtils::Get()->FetchTokens(profile, credentials_); 153 credentials_ = GaiaAuthConsumer::ClientLoginResult(); 154 155 // Don't unlock screen if it was locked while we're waiting 156 // for initial online auth. 157 if (ScreenLocker::default_screen_locker() && 158 !initial_online_auth_pending_) { 159 DVLOG(1) << "Online login OK - unlocking screen."; 160 RequestScreenUnlock(); 161 // Do not delete itself just yet, wait for unlock. 162 // See ResolveScreenUnlocked(). 163 return; 164 } 165 initial_online_auth_pending_ = false; 166 // There's nothing else that's holding LP from deleting itself - 167 // no ScreenLock, no pending requests. 168 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 169 } 170 171 void LoginPerformer::OnOffTheRecordLoginSuccess() { 172 UserMetrics::RecordAction( 173 UserMetricsAction("Login_GuestLoginSuccess")); 174 175 if (delegate_) 176 delegate_->OnOffTheRecordLoginSuccess(); 177 else 178 NOTREACHED(); 179 } 180 181 void LoginPerformer::OnPasswordChangeDetected( 182 const GaiaAuthConsumer::ClientLoginResult& credentials) { 183 cached_credentials_ = credentials; 184 if (delegate_) { 185 delegate_->OnPasswordChangeDetected(credentials); 186 } else { 187 last_login_failure_ = 188 LoginFailure::FromNetworkAuthFailure(GoogleServiceAuthError( 189 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); 190 password_changed_ = true; 191 DVLOG(1) << "Password change detected - locking screen."; 192 RequestScreenLock(); 193 } 194 } 195 196 //////////////////////////////////////////////////////////////////////////////// 197 // LoginPerformer, SignedSettingsHelper::Callback implementation: 198 199 void LoginPerformer::OnCheckWhitelistCompleted(SignedSettings::ReturnCode code, 200 const std::string& email) { 201 if (code == SignedSettings::SUCCESS) { 202 // Whitelist check passed, continue with authentication. 203 StartAuthentication(); 204 } else { 205 if (delegate_) 206 delegate_->WhiteListCheckFailed(email); 207 else 208 NOTREACHED(); 209 } 210 } 211 212 //////////////////////////////////////////////////////////////////////////////// 213 // LoginPerformer, NotificationObserver implementation: 214 // 215 216 void LoginPerformer::Observe(NotificationType type, 217 const NotificationSource& source, 218 const NotificationDetails& details) { 219 if (type != NotificationType::SCREEN_LOCK_STATE_CHANGED) 220 return; 221 222 bool is_screen_locked = *Details<bool>(details).ptr(); 223 if (is_screen_locked) { 224 if (screen_lock_requested_) { 225 screen_lock_requested_ = false; 226 ResolveScreenLocked(); 227 } 228 } else { 229 ResolveScreenUnlocked(); 230 } 231 } 232 233 //////////////////////////////////////////////////////////////////////////////// 234 // LoginPerformer, public: 235 236 void LoginPerformer::Login(const std::string& username, 237 const std::string& password) { 238 username_ = username; 239 password_ = password; 240 241 // Whitelist check is always performed during initial login and 242 // should not be performed when ScreenLock is active (pending online auth). 243 if (!ScreenLocker::default_screen_locker()) { 244 // Must not proceed without signature verification. 245 UserCrosSettingsProvider user_settings; 246 bool trusted_setting_available = user_settings.RequestTrustedAllowNewUser( 247 method_factory_.NewRunnableMethod(&LoginPerformer::Login, 248 username, 249 password)); 250 if (!trusted_setting_available) { 251 // Value of AllowNewUser setting is still not verified. 252 // Another attempt will be invoked after verification completion. 253 return; 254 } 255 } 256 257 if (ScreenLocker::default_screen_locker() || 258 UserCrosSettingsProvider::cached_allow_new_user()) { 259 // Starts authentication if guest login is allowed or online auth pending. 260 StartAuthentication(); 261 } else { 262 // Otherwise, do whitelist check first. 263 PrefService* local_state = g_browser_process->local_state(); 264 CHECK(local_state); 265 if (local_state->IsManagedPreference(kAccountsPrefUsers)) { 266 if (UserCrosSettingsProvider::IsEmailInCachedWhitelist(username)) { 267 StartAuthentication(); 268 } else { 269 if (delegate_) 270 delegate_->WhiteListCheckFailed(username); 271 else 272 NOTREACHED(); 273 } 274 } else { 275 // In case of signed settings: with current implementation we do not 276 // trust whitelist returned by PrefService. So make separate check. 277 SignedSettingsHelper::Get()->StartCheckWhitelistOp( 278 username, this); 279 } 280 } 281 } 282 283 void LoginPerformer::LoginOffTheRecord() { 284 authenticator_ = LoginUtils::Get()->CreateAuthenticator(this); 285 BrowserThread::PostTask( 286 BrowserThread::UI, FROM_HERE, 287 NewRunnableMethod(authenticator_.get(), 288 &Authenticator::LoginOffTheRecord)); 289 } 290 291 void LoginPerformer::RecoverEncryptedData(const std::string& old_password) { 292 BrowserThread::PostTask( 293 BrowserThread::UI, FROM_HERE, 294 NewRunnableMethod(authenticator_.get(), 295 &Authenticator::RecoverEncryptedData, 296 old_password, 297 cached_credentials_)); 298 cached_credentials_ = GaiaAuthConsumer::ClientLoginResult(); 299 } 300 301 void LoginPerformer::ResyncEncryptedData() { 302 BrowserThread::PostTask( 303 BrowserThread::UI, FROM_HERE, 304 NewRunnableMethod(authenticator_.get(), 305 &Authenticator::ResyncEncryptedData, 306 cached_credentials_)); 307 cached_credentials_ = GaiaAuthConsumer::ClientLoginResult(); 308 } 309 310 //////////////////////////////////////////////////////////////////////////////// 311 // LoginPerformer, private: 312 313 void LoginPerformer::RequestScreenLock() { 314 DVLOG(1) << "Screen lock requested"; 315 // Will receive notifications on screen unlock and delete itself. 316 registrar_.Add(this, 317 NotificationType::SCREEN_LOCK_STATE_CHANGED, 318 NotificationService::AllSources()); 319 if (ScreenLocker::default_screen_locker()) { 320 DVLOG(1) << "Screen already locked"; 321 ResolveScreenLocked(); 322 } else { 323 screen_lock_requested_ = true; 324 chromeos::CrosLibrary::Get()->GetScreenLockLibrary()-> 325 NotifyScreenLockRequested(); 326 } 327 } 328 329 void LoginPerformer::RequestScreenUnlock() { 330 DVLOG(1) << "Screen unlock requested"; 331 if (ScreenLocker::default_screen_locker()) { 332 chromeos::CrosLibrary::Get()->GetScreenLockLibrary()-> 333 NotifyScreenUnlockRequested(); 334 // Will unsubscribe from notifications once unlock is successful. 335 } else { 336 LOG(ERROR) << "Screen is not locked"; 337 NOTREACHED(); 338 } 339 } 340 341 void LoginPerformer::ResolveInitialNetworkAuthFailure() { 342 DVLOG(1) << "auth_error: " << last_login_failure_.error().state(); 343 344 switch (last_login_failure_.error().state()) { 345 case GoogleServiceAuthError::CONNECTION_FAILED: 346 case GoogleServiceAuthError::SERVICE_UNAVAILABLE: 347 case GoogleServiceAuthError::TWO_FACTOR: 348 case GoogleServiceAuthError::REQUEST_CANCELED: 349 // Offline auth already done. Online auth will be done next time 350 // or once user accesses web property. 351 VLOG(1) << "Granting user access based on offline auth only. " 352 << "Online login failed with " 353 << last_login_failure_.error().state(); 354 // Resolving initial online auth failure, no ScreenLock is active. 355 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 356 return; 357 case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: 358 // Offline auth OK, so it might be the case of changed password. 359 password_changed_ = true; 360 case GoogleServiceAuthError::USER_NOT_SIGNED_UP: 361 case GoogleServiceAuthError::ACCOUNT_DELETED: 362 case GoogleServiceAuthError::ACCOUNT_DISABLED: 363 // Access not granted. User has to sign out. 364 // Request screen lock & show error message there. 365 case GoogleServiceAuthError::CAPTCHA_REQUIRED: 366 // User is requested to enter CAPTCHA challenge. 367 captcha_token_ = last_login_failure_.error().captcha().token; 368 RequestScreenLock(); 369 return; 370 default: 371 // Unless there's new GoogleServiceAuthErrors state has been added. 372 NOTREACHED(); 373 return; 374 } 375 } 376 377 void LoginPerformer::ResolveLockLoginFailure() { 378 if (last_login_failure_.reason() == LoginFailure::LOGIN_TIMED_OUT) { 379 LOG(WARNING) << "Online login timed out - unlocking screen. " 380 << "Granting user access based on offline auth only."; 381 RequestScreenUnlock(); 382 return; 383 } else if (last_login_failure_.reason() == 384 LoginFailure::NETWORK_AUTH_FAILED) { 385 ResolveLockNetworkAuthFailure(); 386 return; 387 } else if (last_login_failure_.reason() == 388 LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME || 389 last_login_failure_.reason() == 390 LoginFailure::DATA_REMOVAL_FAILED) { 391 LOG(ERROR) << "Cryptohome error, forcing sign out."; 392 } else { 393 // COULD_NOT_MOUNT_TMPFS, UNLOCK_FAILED should not happen here. 394 NOTREACHED(); 395 } 396 ScreenLocker::default_screen_locker()->Signout(); 397 } 398 399 void LoginPerformer::ResolveLockNetworkAuthFailure() { 400 DCHECK(ScreenLocker::default_screen_locker()) 401 << "ScreenLocker instance doesn't exist."; 402 DCHECK(last_login_failure_.reason() == LoginFailure::NETWORK_AUTH_FAILED); 403 404 string16 msg; 405 bool sign_out_only = false; 406 407 DVLOG(1) << "auth_error: " << last_login_failure_.error().state(); 408 409 switch (last_login_failure_.error().state()) { 410 case GoogleServiceAuthError::CONNECTION_FAILED: 411 case GoogleServiceAuthError::SERVICE_UNAVAILABLE: 412 case GoogleServiceAuthError::TWO_FACTOR: 413 case GoogleServiceAuthError::REQUEST_CANCELED: 414 // Offline auth already done. Online auth will be done next time 415 // or once user accesses web property. 416 LOG(WARNING) << "Granting user access based on offline auth only. " 417 << "Online login failed with " 418 << last_login_failure_.error().state(); 419 RequestScreenUnlock(); 420 return; 421 case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: 422 // Password change detected. 423 msg = l10n_util::GetStringUTF16(IDS_LOGIN_ERROR_PASSWORD_CHANGED); 424 break; 425 case GoogleServiceAuthError::USER_NOT_SIGNED_UP: 426 case GoogleServiceAuthError::ACCOUNT_DELETED: 427 case GoogleServiceAuthError::ACCOUNT_DISABLED: 428 // Access not granted. User has to sign out. 429 // Show error message using existing screen lock. 430 msg = l10n_util::GetStringUTF16(IDS_LOGIN_ERROR_RESTRICTED); 431 sign_out_only = true; 432 break; 433 case GoogleServiceAuthError::CAPTCHA_REQUIRED: 434 // User is requested to enter CAPTCHA challenge. 435 captcha_token_ = last_login_failure_.error().captcha().token; 436 msg = l10n_util::GetStringUTF16(IDS_LOGIN_ERROR_PASSWORD_CHANGED); 437 ScreenLocker::default_screen_locker()->ShowCaptchaAndErrorMessage( 438 last_login_failure_.error().captcha().image_url, 439 UTF16ToWide(msg)); 440 return; 441 default: 442 // Unless there's new GoogleServiceAuthError state has been added. 443 NOTREACHED(); 444 break; 445 } 446 447 ScreenLocker::default_screen_locker()->ShowErrorMessage(UTF16ToWide(msg), 448 sign_out_only); 449 } 450 451 void LoginPerformer::ResolveScreenLocked() { 452 DVLOG(1) << "Screen locked"; 453 ResolveLockNetworkAuthFailure(); 454 } 455 456 void LoginPerformer::ResolveScreenUnlocked() { 457 DVLOG(1) << "Screen unlocked"; 458 registrar_.RemoveAll(); 459 // If screen was unlocked that was for a reason, should delete itself now. 460 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 461 } 462 463 void LoginPerformer::StartAuthentication() { 464 DVLOG(1) << "Auth started"; 465 BootTimesLoader::Get()->AddLoginTimeMarker("AuthStarted", false); 466 Profile* profile = g_browser_process->profile_manager()->GetDefaultProfile(); 467 if (delegate_) { 468 authenticator_ = LoginUtils::Get()->CreateAuthenticator(this); 469 BrowserThread::PostTask( 470 BrowserThread::UI, FROM_HERE, 471 NewRunnableMethod(authenticator_.get(), 472 &Authenticator::AuthenticateToLogin, 473 profile, 474 username_, 475 password_, 476 captcha_token_, 477 captcha_)); 478 } else { 479 DCHECK(authenticator_.get()) 480 << "Authenticator instance doesn't exist for login attempt retry."; 481 // At this point offline auth has been successful, 482 // retry online auth, using existing Authenticator instance. 483 BrowserThread::PostTask( 484 BrowserThread::UI, FROM_HERE, 485 NewRunnableMethod(authenticator_.get(), 486 &Authenticator::RetryAuth, 487 profile, 488 username_, 489 password_, 490 captcha_token_, 491 captcha_)); 492 } 493 password_.clear(); 494 } 495 496 } // namespace chromeos 497