| OLD | NEW |
| (Empty) |
| 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/parallel_authenticator.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/command_line.h" | |
| 9 #include "base/files/file_path.h" | |
| 10 #include "base/logging.h" | |
| 11 #include "base/strings/string_number_conversions.h" | |
| 12 #include "base/strings/string_util.h" | |
| 13 #include "chrome/browser/chrome_notification_types.h" | |
| 14 #include "chrome/browser/chromeos/boot_times_loader.h" | |
| 15 #include "chrome/browser/chromeos/login/authentication_notification_details.h" | |
| 16 #include "chrome/browser/chromeos/login/login_status_consumer.h" | |
| 17 #include "chrome/browser/chromeos/login/user.h" | |
| 18 #include "chrome/browser/chromeos/login/user_manager.h" | |
| 19 #include "chrome/browser/chromeos/settings/cros_settings.h" | |
| 20 #include "chrome/common/chrome_switches.h" | |
| 21 #include "chromeos/cryptohome/async_method_caller.h" | |
| 22 #include "chromeos/cryptohome/system_salt_getter.h" | |
| 23 #include "chromeos/dbus/cryptohome_client.h" | |
| 24 #include "chromeos/dbus/dbus_thread_manager.h" | |
| 25 #include "chromeos/login/login_state.h" | |
| 26 #include "content/public/browser/browser_thread.h" | |
| 27 #include "content/public/browser/notification_service.h" | |
| 28 #include "crypto/sha2.h" | |
| 29 #include "google_apis/gaia/gaia_auth_util.h" | |
| 30 #include "third_party/cros_system_api/dbus/service_constants.h" | |
| 31 | |
| 32 using content::BrowserThread; | |
| 33 | |
| 34 namespace chromeos { | |
| 35 | |
| 36 namespace { | |
| 37 | |
| 38 // Length of password hashed with SHA-256. | |
| 39 const int kPasswordHashLength = 32; | |
| 40 | |
| 41 // Records status and calls resolver->Resolve(). | |
| 42 void TriggerResolve(AuthAttemptState* attempt, | |
| 43 scoped_refptr<ParallelAuthenticator> resolver, | |
| 44 bool success, | |
| 45 cryptohome::MountError return_code) { | |
| 46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 47 attempt->RecordCryptohomeStatus(success, return_code); | |
| 48 resolver->Resolve(); | |
| 49 } | |
| 50 | |
| 51 // Records get hash status and calls resolver->Resolve(). | |
| 52 void TriggerResolveHash(AuthAttemptState* attempt, | |
| 53 scoped_refptr<ParallelAuthenticator> resolver, | |
| 54 bool success, | |
| 55 const std::string& username_hash) { | |
| 56 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 57 if (success) | |
| 58 attempt->RecordUsernameHash(username_hash); | |
| 59 else | |
| 60 attempt->RecordUsernameHashFailed(); | |
| 61 resolver->Resolve(); | |
| 62 } | |
| 63 | |
| 64 // Calls TriggerResolve while adding login time marker. | |
| 65 void TriggerResolveWithLoginTimeMarker( | |
| 66 const std::string& marker_name, | |
| 67 AuthAttemptState* attempt, | |
| 68 scoped_refptr<ParallelAuthenticator> resolver, | |
| 69 bool success, | |
| 70 cryptohome::MountError return_code) { | |
| 71 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(marker_name, false); | |
| 72 TriggerResolve(attempt, resolver, success, return_code); | |
| 73 } | |
| 74 | |
| 75 // Calls cryptohome's mount method. | |
| 76 void Mount(AuthAttemptState* attempt, | |
| 77 scoped_refptr<ParallelAuthenticator> resolver, | |
| 78 int flags, | |
| 79 const std::string& system_salt) { | |
| 80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 81 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( | |
| 82 "CryptohomeMount-Start", false); | |
| 83 // Set state that username_hash is requested here so that test implementation | |
| 84 // that returns directly would not generate 2 OnLoginSucces() calls. | |
| 85 attempt->UsernameHashRequested(); | |
| 86 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMount( | |
| 87 attempt->user_context.GetUserID(), | |
| 88 ParallelAuthenticator::HashPassword(attempt->user_context.GetPassword(), | |
| 89 system_salt), | |
| 90 flags, | |
| 91 base::Bind(&TriggerResolveWithLoginTimeMarker, | |
| 92 "CryptohomeMount-End", | |
| 93 attempt, | |
| 94 resolver)); | |
| 95 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername( | |
| 96 attempt->user_context.GetUserID(), | |
| 97 base::Bind(&TriggerResolveHash, | |
| 98 attempt, | |
| 99 resolver)); | |
| 100 } | |
| 101 | |
| 102 // Calls cryptohome's mount method for guest. | |
| 103 void MountGuest(AuthAttemptState* attempt, | |
| 104 scoped_refptr<ParallelAuthenticator> resolver) { | |
| 105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 106 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountGuest( | |
| 107 base::Bind(&TriggerResolveWithLoginTimeMarker, | |
| 108 "CryptohomeMount-End", | |
| 109 attempt, | |
| 110 resolver)); | |
| 111 } | |
| 112 | |
| 113 // Calls cryptohome's mount method for guest and also get the user hash from | |
| 114 // cryptohome. | |
| 115 void MountGuestAndGetHash(AuthAttemptState* attempt, | |
| 116 scoped_refptr<ParallelAuthenticator> resolver) { | |
| 117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 118 attempt->UsernameHashRequested(); | |
| 119 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountGuest( | |
| 120 base::Bind(&TriggerResolveWithLoginTimeMarker, | |
| 121 "CryptohomeMount-End", | |
| 122 attempt, | |
| 123 resolver)); | |
| 124 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername( | |
| 125 attempt->user_context.GetUserID(), | |
| 126 base::Bind(&TriggerResolveHash, | |
| 127 attempt, | |
| 128 resolver)); | |
| 129 } | |
| 130 | |
| 131 // Calls cryptohome's MountPublic method | |
| 132 void MountPublic(AuthAttemptState* attempt, | |
| 133 scoped_refptr<ParallelAuthenticator> resolver, | |
| 134 int flags) { | |
| 135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 136 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountPublic( | |
| 137 attempt->user_context.GetUserID(), | |
| 138 flags, | |
| 139 base::Bind(&TriggerResolveWithLoginTimeMarker, | |
| 140 "CryptohomeMountPublic-End", | |
| 141 attempt, | |
| 142 resolver)); | |
| 143 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername( | |
| 144 attempt->user_context.GetUserID(), | |
| 145 base::Bind(&TriggerResolveHash, | |
| 146 attempt, | |
| 147 resolver)); | |
| 148 } | |
| 149 | |
| 150 // Calls cryptohome's key migration method. | |
| 151 void Migrate(AuthAttemptState* attempt, | |
| 152 scoped_refptr<ParallelAuthenticator> resolver, | |
| 153 bool passing_old_hash, | |
| 154 const std::string& old_password, | |
| 155 const std::string& system_salt) { | |
| 156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 157 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( | |
| 158 "CryptohomeMigrate-Start", false); | |
| 159 cryptohome::AsyncMethodCaller* caller = | |
| 160 cryptohome::AsyncMethodCaller::GetInstance(); | |
| 161 if (passing_old_hash) { | |
| 162 caller->AsyncMigrateKey( | |
| 163 attempt->user_context.GetUserID(), | |
| 164 ParallelAuthenticator::HashPassword(old_password, system_salt), | |
| 165 ParallelAuthenticator::HashPassword(attempt->user_context.GetPassword(), | |
| 166 system_salt), | |
| 167 base::Bind(&TriggerResolveWithLoginTimeMarker, | |
| 168 "CryptohomeMount-End", | |
| 169 attempt, | |
| 170 resolver)); | |
| 171 } else { | |
| 172 caller->AsyncMigrateKey( | |
| 173 attempt->user_context.GetUserID(), | |
| 174 ParallelAuthenticator::HashPassword(attempt->user_context.GetPassword(), | |
| 175 system_salt), | |
| 176 ParallelAuthenticator::HashPassword(old_password, system_salt), | |
| 177 base::Bind(&TriggerResolveWithLoginTimeMarker, | |
| 178 "CryptohomeMount-End", | |
| 179 attempt, | |
| 180 resolver)); | |
| 181 } | |
| 182 } | |
| 183 | |
| 184 // Calls cryptohome's remove method. | |
| 185 void Remove(AuthAttemptState* attempt, | |
| 186 scoped_refptr<ParallelAuthenticator> resolver) { | |
| 187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 188 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( | |
| 189 "CryptohomeRemove-Start", false); | |
| 190 cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove( | |
| 191 attempt->user_context.GetUserID(), | |
| 192 base::Bind(&TriggerResolveWithLoginTimeMarker, | |
| 193 "CryptohomeRemove-End", | |
| 194 attempt, | |
| 195 resolver)); | |
| 196 } | |
| 197 | |
| 198 // Calls cryptohome's key check method. | |
| 199 void CheckKey(AuthAttemptState* attempt, | |
| 200 scoped_refptr<ParallelAuthenticator> resolver, | |
| 201 const std::string& system_salt) { | |
| 202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 203 cryptohome::AsyncMethodCaller::GetInstance()->AsyncCheckKey( | |
| 204 attempt->user_context.GetUserID(), | |
| 205 ParallelAuthenticator::HashPassword(attempt->user_context.GetPassword(), | |
| 206 system_salt), | |
| 207 base::Bind(&TriggerResolve, attempt, resolver)); | |
| 208 } | |
| 209 | |
| 210 } // namespace | |
| 211 | |
| 212 ParallelAuthenticator::ParallelAuthenticator(LoginStatusConsumer* consumer) | |
| 213 : Authenticator(consumer), | |
| 214 migrate_attempted_(false), | |
| 215 remove_attempted_(false), | |
| 216 resync_attempted_(false), | |
| 217 ephemeral_mount_attempted_(false), | |
| 218 check_key_attempted_(false), | |
| 219 already_reported_success_(false), | |
| 220 owner_is_verified_(false), | |
| 221 user_can_login_(false), | |
| 222 remove_user_data_on_failure_(false), | |
| 223 delayed_login_failure_(NULL) { | |
| 224 } | |
| 225 | |
| 226 void ParallelAuthenticator::AuthenticateToLogin( | |
| 227 Profile* profile, | |
| 228 const UserContext& user_context) { | |
| 229 std::string canonicalized = gaia::CanonicalizeEmail(user_context.GetUserID()); | |
| 230 authentication_profile_ = profile; | |
| 231 current_state_.reset( | |
| 232 new AuthAttemptState( | |
| 233 UserContext(canonicalized, | |
| 234 user_context.GetPassword(), | |
| 235 user_context.GetAuthCode()), | |
| 236 std::string(), // login_token, not used. | |
| 237 std::string(), // login_captcha, not used. | |
| 238 User::USER_TYPE_REGULAR, | |
| 239 !UserManager::Get()->IsKnownUser(canonicalized))); | |
| 240 // Reset the verified flag. | |
| 241 owner_is_verified_ = false; | |
| 242 | |
| 243 SystemSaltGetter::Get()->GetSystemSalt( | |
| 244 base::Bind(&Mount, | |
| 245 current_state_.get(), | |
| 246 scoped_refptr<ParallelAuthenticator>(this), | |
| 247 cryptohome::MOUNT_FLAGS_NONE)); | |
| 248 } | |
| 249 | |
| 250 void ParallelAuthenticator::CompleteLogin(Profile* profile, | |
| 251 const UserContext& user_context) { | |
| 252 std::string canonicalized = gaia::CanonicalizeEmail(user_context.GetUserID()); | |
| 253 authentication_profile_ = profile; | |
| 254 current_state_.reset( | |
| 255 new AuthAttemptState( | |
| 256 UserContext(canonicalized, | |
| 257 user_context.GetPassword(), | |
| 258 user_context.GetAuthCode(), | |
| 259 user_context.GetUserIDHash(), | |
| 260 user_context.IsUsingOAuth(), | |
| 261 user_context.GetAuthFlow()), | |
| 262 !UserManager::Get()->IsKnownUser(canonicalized))); | |
| 263 | |
| 264 // Reset the verified flag. | |
| 265 owner_is_verified_ = false; | |
| 266 | |
| 267 SystemSaltGetter::Get()->GetSystemSalt( | |
| 268 base::Bind(&Mount, | |
| 269 current_state_.get(), | |
| 270 scoped_refptr<ParallelAuthenticator>(this), | |
| 271 cryptohome::MOUNT_FLAGS_NONE)); | |
| 272 | |
| 273 // For login completion from extension, we just need to resolve the current | |
| 274 // auth attempt state, the rest of OAuth related tasks will be done in | |
| 275 // parallel. | |
| 276 BrowserThread::PostTask( | |
| 277 BrowserThread::UI, FROM_HERE, | |
| 278 base::Bind(&ParallelAuthenticator::ResolveLoginCompletionStatus, this)); | |
| 279 } | |
| 280 | |
| 281 void ParallelAuthenticator::AuthenticateToUnlock( | |
| 282 const UserContext& user_context) { | |
| 283 current_state_.reset( | |
| 284 new AuthAttemptState( | |
| 285 gaia::CanonicalizeEmail(user_context.GetUserID()), | |
| 286 user_context.GetPassword())); | |
| 287 remove_user_data_on_failure_ = false; | |
| 288 check_key_attempted_ = true; | |
| 289 SystemSaltGetter::Get()->GetSystemSalt( | |
| 290 base::Bind(&CheckKey, | |
| 291 current_state_.get(), | |
| 292 scoped_refptr<ParallelAuthenticator>(this))); | |
| 293 } | |
| 294 | |
| 295 void ParallelAuthenticator::LoginAsLocallyManagedUser( | |
| 296 const UserContext& user_context) { | |
| 297 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 298 // TODO(nkostylev): Pass proper value for |user_is_new| or remove (not used). | |
| 299 current_state_.reset( | |
| 300 new AuthAttemptState(user_context, | |
| 301 "", // login_token | |
| 302 "", // login_captcha | |
| 303 User::USER_TYPE_LOCALLY_MANAGED, | |
| 304 false)); | |
| 305 remove_user_data_on_failure_ = false; | |
| 306 SystemSaltGetter::Get()->GetSystemSalt( | |
| 307 base::Bind(&Mount, | |
| 308 current_state_.get(), | |
| 309 scoped_refptr<ParallelAuthenticator>(this), | |
| 310 cryptohome::MOUNT_FLAGS_NONE)); | |
| 311 } | |
| 312 | |
| 313 void ParallelAuthenticator::LoginRetailMode() { | |
| 314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 315 // Note: |kRetailModeUserEMail| is used in other places to identify a retail | |
| 316 // mode session. | |
| 317 current_state_.reset(new AuthAttemptState( | |
| 318 UserContext(UserManager::kRetailModeUserName, | |
| 319 std::string(), // password | |
| 320 std::string()), // auth_code | |
| 321 std::string(), // login_token | |
| 322 std::string(), // login_captcha | |
| 323 User::USER_TYPE_RETAIL_MODE, | |
| 324 false)); | |
| 325 remove_user_data_on_failure_ = false; | |
| 326 ephemeral_mount_attempted_ = true; | |
| 327 MountGuest(current_state_.get(), | |
| 328 scoped_refptr<ParallelAuthenticator>(this)); | |
| 329 } | |
| 330 | |
| 331 void ParallelAuthenticator::LoginOffTheRecord() { | |
| 332 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 333 current_state_.reset(new AuthAttemptState( | |
| 334 UserContext(UserManager::kGuestUserName, // username | |
| 335 std::string(), // password | |
| 336 std::string()), // auth_code | |
| 337 std::string(), // login_token | |
| 338 std::string(), // login_captcha | |
| 339 User::USER_TYPE_GUEST, | |
| 340 false)); | |
| 341 remove_user_data_on_failure_ = false; | |
| 342 ephemeral_mount_attempted_ = true; | |
| 343 MountGuest(current_state_.get(), | |
| 344 scoped_refptr<ParallelAuthenticator>(this)); | |
| 345 } | |
| 346 | |
| 347 void ParallelAuthenticator::LoginAsPublicAccount(const std::string& username) { | |
| 348 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 349 current_state_.reset(new AuthAttemptState( | |
| 350 UserContext(username, | |
| 351 std::string(), // password | |
| 352 std::string()), // auth_code | |
| 353 std::string(), // login_token | |
| 354 std::string(), // login_captcha | |
| 355 User::USER_TYPE_PUBLIC_ACCOUNT, | |
| 356 false)); | |
| 357 remove_user_data_on_failure_ = false; | |
| 358 ephemeral_mount_attempted_ = true; | |
| 359 SystemSaltGetter::Get()->GetSystemSalt( | |
| 360 base::Bind(&Mount, | |
| 361 current_state_.get(), | |
| 362 scoped_refptr<ParallelAuthenticator>(this), | |
| 363 cryptohome::CREATE_IF_MISSING | cryptohome::ENSURE_EPHEMERAL)); | |
| 364 } | |
| 365 | |
| 366 void ParallelAuthenticator::LoginAsKioskAccount( | |
| 367 const std::string& app_user_id, | |
| 368 bool use_guest_mount) { | |
| 369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 370 | |
| 371 const std::string user_id = | |
| 372 use_guest_mount ? UserManager::kGuestUserName : app_user_id; | |
| 373 current_state_.reset(new AuthAttemptState( | |
| 374 UserContext(user_id, | |
| 375 std::string(), // password | |
| 376 std::string()), // auth_code | |
| 377 std::string(), // login_token | |
| 378 std::string(), // login_captcha | |
| 379 User::USER_TYPE_KIOSK_APP, | |
| 380 false)); | |
| 381 | |
| 382 remove_user_data_on_failure_ = true; | |
| 383 if (!use_guest_mount) { | |
| 384 MountPublic(current_state_.get(), | |
| 385 scoped_refptr<ParallelAuthenticator>(this), | |
| 386 cryptohome::CREATE_IF_MISSING); | |
| 387 } else { | |
| 388 ephemeral_mount_attempted_ = true; | |
| 389 MountGuestAndGetHash(current_state_.get(), | |
| 390 scoped_refptr<ParallelAuthenticator>(this)); | |
| 391 } | |
| 392 } | |
| 393 | |
| 394 void ParallelAuthenticator::OnRetailModeLoginSuccess() { | |
| 395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 396 VLOG(1) << "Retail mode login success"; | |
| 397 // Send notification of success | |
| 398 AuthenticationNotificationDetails details(true); | |
| 399 content::NotificationService::current()->Notify( | |
| 400 chrome::NOTIFICATION_LOGIN_AUTHENTICATION, | |
| 401 content::NotificationService::AllSources(), | |
| 402 content::Details<AuthenticationNotificationDetails>(&details)); | |
| 403 if (consumer_) | |
| 404 consumer_->OnRetailModeLoginSuccess(current_state_->user_context); | |
| 405 } | |
| 406 | |
| 407 void ParallelAuthenticator::OnLoginSuccess() { | |
| 408 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 409 VLOG(1) << "Login success"; | |
| 410 // Send notification of success | |
| 411 AuthenticationNotificationDetails details(true); | |
| 412 content::NotificationService::current()->Notify( | |
| 413 chrome::NOTIFICATION_LOGIN_AUTHENTICATION, | |
| 414 content::NotificationService::AllSources(), | |
| 415 content::Details<AuthenticationNotificationDetails>(&details)); | |
| 416 { | |
| 417 base::AutoLock for_this_block(success_lock_); | |
| 418 already_reported_success_ = true; | |
| 419 } | |
| 420 if (consumer_) | |
| 421 consumer_->OnLoginSuccess(current_state_->user_context); | |
| 422 } | |
| 423 | |
| 424 void ParallelAuthenticator::OnOffTheRecordLoginSuccess() { | |
| 425 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 426 // Send notification of success | |
| 427 AuthenticationNotificationDetails details(true); | |
| 428 content::NotificationService::current()->Notify( | |
| 429 chrome::NOTIFICATION_LOGIN_AUTHENTICATION, | |
| 430 content::NotificationService::AllSources(), | |
| 431 content::Details<AuthenticationNotificationDetails>(&details)); | |
| 432 if (consumer_) | |
| 433 consumer_->OnOffTheRecordLoginSuccess(); | |
| 434 } | |
| 435 | |
| 436 void ParallelAuthenticator::OnPasswordChangeDetected() { | |
| 437 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 438 if (consumer_) | |
| 439 consumer_->OnPasswordChangeDetected(); | |
| 440 } | |
| 441 | |
| 442 void ParallelAuthenticator::OnLoginFailure(const LoginFailure& error) { | |
| 443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 444 | |
| 445 // OnLoginFailure will be called again with the same |error| | |
| 446 // after the cryptohome has been removed. | |
| 447 if (remove_user_data_on_failure_) { | |
| 448 delayed_login_failure_ = &error; | |
| 449 RemoveEncryptedData(); | |
| 450 return; | |
| 451 } | |
| 452 | |
| 453 // Send notification of failure | |
| 454 AuthenticationNotificationDetails details(false); | |
| 455 content::NotificationService::current()->Notify( | |
| 456 chrome::NOTIFICATION_LOGIN_AUTHENTICATION, | |
| 457 content::NotificationService::AllSources(), | |
| 458 content::Details<AuthenticationNotificationDetails>(&details)); | |
| 459 LOG(WARNING) << "Login failed: " << error.GetErrorString(); | |
| 460 if (consumer_) | |
| 461 consumer_->OnLoginFailure(error); | |
| 462 } | |
| 463 | |
| 464 void ParallelAuthenticator::RecoverEncryptedData( | |
| 465 const std::string& old_password) { | |
| 466 migrate_attempted_ = true; | |
| 467 current_state_->ResetCryptohomeStatus(); | |
| 468 SystemSaltGetter::Get()->GetSystemSalt( | |
| 469 base::Bind(&Migrate, | |
| 470 current_state_.get(), | |
| 471 scoped_refptr<ParallelAuthenticator>(this), | |
| 472 true, | |
| 473 old_password)); | |
| 474 } | |
| 475 | |
| 476 void ParallelAuthenticator::RemoveEncryptedData() { | |
| 477 remove_attempted_ = true; | |
| 478 current_state_->ResetCryptohomeStatus(); | |
| 479 BrowserThread::PostTask( | |
| 480 BrowserThread::UI, FROM_HERE, | |
| 481 base::Bind(&Remove, | |
| 482 current_state_.get(), | |
| 483 scoped_refptr<ParallelAuthenticator>(this))); | |
| 484 } | |
| 485 | |
| 486 void ParallelAuthenticator::ResyncEncryptedData() { | |
| 487 resync_attempted_ = true; | |
| 488 current_state_->ResetCryptohomeStatus(); | |
| 489 BrowserThread::PostTask( | |
| 490 BrowserThread::UI, FROM_HERE, | |
| 491 base::Bind(&Remove, | |
| 492 current_state_.get(), | |
| 493 scoped_refptr<ParallelAuthenticator>(this))); | |
| 494 } | |
| 495 | |
| 496 bool ParallelAuthenticator::VerifyOwner() { | |
| 497 if (owner_is_verified_) | |
| 498 return true; | |
| 499 // Check if policy data is fine and continue in safe mode if needed. | |
| 500 bool is_safe_mode = false; | |
| 501 CrosSettings::Get()->GetBoolean(kPolicyMissingMitigationMode, &is_safe_mode); | |
| 502 if (!is_safe_mode) { | |
| 503 // Now we can continue with the login and report mount success. | |
| 504 user_can_login_ = true; | |
| 505 owner_is_verified_ = true; | |
| 506 return true; | |
| 507 } | |
| 508 // Now we can continue reading the private key. | |
| 509 DeviceSettingsService::Get()->SetUsername( | |
| 510 current_state_->user_context.GetUserID()); | |
| 511 // This should trigger certificate loading, which is needed in order to | |
| 512 // correctly determine if the current user is the owner. | |
| 513 if (LoginState::IsInitialized()) { | |
| 514 LoginState::Get()->SetLoggedInState(LoginState::LOGGED_IN_SAFE_MODE, | |
| 515 LoginState::LOGGED_IN_USER_NONE); | |
| 516 } | |
| 517 DeviceSettingsService::Get()->IsCurrentUserOwnerAsync( | |
| 518 base::Bind(&ParallelAuthenticator::OnOwnershipChecked, this)); | |
| 519 return false; | |
| 520 } | |
| 521 | |
| 522 void ParallelAuthenticator::OnOwnershipChecked(bool is_owner) { | |
| 523 // Now we can check if this user is the owner. | |
| 524 user_can_login_ = is_owner; | |
| 525 owner_is_verified_ = true; | |
| 526 Resolve(); | |
| 527 } | |
| 528 | |
| 529 void ParallelAuthenticator::Resolve() { | |
| 530 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 531 int mount_flags = cryptohome::MOUNT_FLAGS_NONE; | |
| 532 ParallelAuthenticator::AuthState state = ResolveState(); | |
| 533 VLOG(1) << "Resolved state to: " << state; | |
| 534 switch (state) { | |
| 535 case CONTINUE: | |
| 536 case POSSIBLE_PW_CHANGE: | |
| 537 case NO_MOUNT: | |
| 538 // These are intermediate states; we need more info from a request that | |
| 539 // is still pending. | |
| 540 break; | |
| 541 case FAILED_MOUNT: | |
| 542 // In this case, whether login succeeded or not, we can't log | |
| 543 // the user in because their data is horked. So, override with | |
| 544 // the appropriate failure. | |
| 545 BrowserThread::PostTask( | |
| 546 BrowserThread::UI, FROM_HERE, | |
| 547 base::Bind(&ParallelAuthenticator::OnLoginFailure, this, | |
| 548 LoginFailure(LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME))); | |
| 549 break; | |
| 550 case FAILED_REMOVE: | |
| 551 // In this case, we tried to remove the user's old cryptohome at her | |
| 552 // request, and the remove failed. | |
| 553 remove_user_data_on_failure_ = false; | |
| 554 BrowserThread::PostTask( | |
| 555 BrowserThread::UI, FROM_HERE, | |
| 556 base::Bind(&ParallelAuthenticator::OnLoginFailure, this, | |
| 557 LoginFailure(LoginFailure::DATA_REMOVAL_FAILED))); | |
| 558 break; | |
| 559 case FAILED_TMPFS: | |
| 560 // In this case, we tried to mount a tmpfs for guest and failed. | |
| 561 BrowserThread::PostTask( | |
| 562 BrowserThread::UI, FROM_HERE, | |
| 563 base::Bind(&ParallelAuthenticator::OnLoginFailure, this, | |
| 564 LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS))); | |
| 565 break; | |
| 566 case FAILED_TPM: | |
| 567 // In this case, we tried to create/mount cryptohome and failed | |
| 568 // because of the critical TPM error. | |
| 569 // Chrome will notify user and request reboot. | |
| 570 BrowserThread::PostTask( | |
| 571 BrowserThread::UI, FROM_HERE, | |
| 572 base::Bind(&ParallelAuthenticator::OnLoginFailure, this, | |
| 573 LoginFailure(LoginFailure::TPM_ERROR))); | |
| 574 break; | |
| 575 case FAILED_USERNAME_HASH: | |
| 576 // In this case, we failed the GetSanitizedUsername request to | |
| 577 // cryptohomed. This can happen for any login attempt. | |
| 578 BrowserThread::PostTask( | |
| 579 BrowserThread::UI, FROM_HERE, | |
| 580 base::Bind(&ParallelAuthenticator::OnLoginFailure, this, | |
| 581 LoginFailure(LoginFailure::USERNAME_HASH_FAILED))); | |
| 582 break; | |
| 583 case REMOVED_DATA_AFTER_FAILURE: | |
| 584 remove_user_data_on_failure_ = false; | |
| 585 BrowserThread::PostTask( | |
| 586 BrowserThread::UI, FROM_HERE, | |
| 587 base::Bind(&ParallelAuthenticator::OnLoginFailure, this, | |
| 588 *delayed_login_failure_)); | |
| 589 break; | |
| 590 case CREATE_NEW: | |
| 591 mount_flags |= cryptohome::CREATE_IF_MISSING; | |
| 592 case RECOVER_MOUNT: | |
| 593 current_state_->ResetCryptohomeStatus(); | |
| 594 SystemSaltGetter::Get()->GetSystemSalt( | |
| 595 base::Bind(&Mount, | |
| 596 current_state_.get(), | |
| 597 scoped_refptr<ParallelAuthenticator>(this), | |
| 598 mount_flags)); | |
| 599 break; | |
| 600 case NEED_OLD_PW: | |
| 601 BrowserThread::PostTask( | |
| 602 BrowserThread::UI, FROM_HERE, | |
| 603 base::Bind(&ParallelAuthenticator::OnPasswordChangeDetected, this)); | |
| 604 break; | |
| 605 case ONLINE_FAILED: | |
| 606 case NEED_NEW_PW: | |
| 607 case HAVE_NEW_PW: | |
| 608 NOTREACHED() << "Using obsolete ClientLogin code path."; | |
| 609 break; | |
| 610 case OFFLINE_LOGIN: | |
| 611 VLOG(2) << "Offline login"; | |
| 612 // Fall through. | |
| 613 case UNLOCK: | |
| 614 VLOG(2) << "Unlock"; | |
| 615 // Fall through. | |
| 616 case ONLINE_LOGIN: | |
| 617 VLOG(2) << "Online login"; | |
| 618 BrowserThread::PostTask( | |
| 619 BrowserThread::UI, FROM_HERE, | |
| 620 base::Bind(&ParallelAuthenticator::OnLoginSuccess, this)); | |
| 621 break; | |
| 622 case DEMO_LOGIN: | |
| 623 VLOG(2) << "Retail mode login"; | |
| 624 current_state_->user_context.SetIsUsingOAuth(false); | |
| 625 BrowserThread::PostTask( | |
| 626 BrowserThread::UI, FROM_HERE, | |
| 627 base::Bind(&ParallelAuthenticator::OnRetailModeLoginSuccess, this)); | |
| 628 break; | |
| 629 case GUEST_LOGIN: | |
| 630 BrowserThread::PostTask( | |
| 631 BrowserThread::UI, FROM_HERE, | |
| 632 base::Bind(&ParallelAuthenticator::OnOffTheRecordLoginSuccess, this)); | |
| 633 break; | |
| 634 case KIOSK_ACCOUNT_LOGIN: | |
| 635 case PUBLIC_ACCOUNT_LOGIN: | |
| 636 current_state_->user_context.SetIsUsingOAuth(false); | |
| 637 BrowserThread::PostTask( | |
| 638 BrowserThread::UI, FROM_HERE, | |
| 639 base::Bind(&ParallelAuthenticator::OnLoginSuccess, this)); | |
| 640 break; | |
| 641 case LOCALLY_MANAGED_USER_LOGIN: | |
| 642 current_state_->user_context.SetIsUsingOAuth(false); | |
| 643 BrowserThread::PostTask( | |
| 644 BrowserThread::UI, FROM_HERE, | |
| 645 base::Bind(&ParallelAuthenticator::OnLoginSuccess, this)); | |
| 646 break; | |
| 647 case LOGIN_FAILED: | |
| 648 current_state_->ResetCryptohomeStatus(); | |
| 649 BrowserThread::PostTask(BrowserThread::UI, | |
| 650 FROM_HERE, | |
| 651 base::Bind( | |
| 652 &ParallelAuthenticator::OnLoginFailure, | |
| 653 this, | |
| 654 current_state_->online_outcome())); | |
| 655 break; | |
| 656 case OWNER_REQUIRED: { | |
| 657 current_state_->ResetCryptohomeStatus(); | |
| 658 bool success = false; | |
| 659 DBusThreadManager::Get()->GetCryptohomeClient()->Unmount(&success); | |
| 660 if (!success) { | |
| 661 // Maybe we should reboot immediately here? | |
| 662 LOG(ERROR) << "Couldn't unmount users home!"; | |
| 663 } | |
| 664 BrowserThread::PostTask(BrowserThread::UI, | |
| 665 FROM_HERE, | |
| 666 base::Bind( | |
| 667 &ParallelAuthenticator::OnLoginFailure, | |
| 668 this, | |
| 669 LoginFailure(LoginFailure::OWNER_REQUIRED))); | |
| 670 break; | |
| 671 } | |
| 672 default: | |
| 673 NOTREACHED(); | |
| 674 break; | |
| 675 } | |
| 676 } | |
| 677 | |
| 678 // static. | |
| 679 std::string ParallelAuthenticator::HashPassword(const std::string& password, | |
| 680 const std::string& ascii_salt) { | |
| 681 // Update sha with ascii encoded salt, then update with ascii of password, | |
| 682 // then end. | |
| 683 // TODO(stevenjb/nkostylev): Handle empty system salt gracefully. | |
| 684 CHECK(!ascii_salt.empty()); | |
| 685 char passhash_buf[kPasswordHashLength]; | |
| 686 | |
| 687 // Hash salt and password | |
| 688 crypto::SHA256HashString(ascii_salt + password, | |
| 689 &passhash_buf, sizeof(passhash_buf)); | |
| 690 | |
| 691 // Only want the top half for 'weak' hashing so that the passphrase is not | |
| 692 // immediately exposed even if the output is reversed. | |
| 693 const int encoded_length = sizeof(passhash_buf) / 2; | |
| 694 | |
| 695 return StringToLowerASCII(base::HexEncode( | |
| 696 reinterpret_cast<const void*>(passhash_buf), encoded_length)); | |
| 697 } | |
| 698 | |
| 699 ParallelAuthenticator::~ParallelAuthenticator() {} | |
| 700 | |
| 701 ParallelAuthenticator::AuthState ParallelAuthenticator::ResolveState() { | |
| 702 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 703 // If we haven't mounted the user's home dir yet or | |
| 704 // haven't got sanitized username value, we can't be done. | |
| 705 // We never get past here if any of these two cryptohome ops is still pending. | |
| 706 // This is an important invariant. | |
| 707 if (!current_state_->cryptohome_complete() || | |
| 708 !current_state_->username_hash_obtained()) { | |
| 709 return CONTINUE; | |
| 710 } | |
| 711 | |
| 712 AuthState state = CONTINUE; | |
| 713 | |
| 714 if (current_state_->cryptohome_outcome() && | |
| 715 current_state_->username_hash_valid()) { | |
| 716 state = ResolveCryptohomeSuccessState(); | |
| 717 } else { | |
| 718 state = ResolveCryptohomeFailureState(); | |
| 719 } | |
| 720 | |
| 721 DCHECK(current_state_->cryptohome_complete()); // Ensure invariant holds. | |
| 722 migrate_attempted_ = false; | |
| 723 remove_attempted_ = false; | |
| 724 resync_attempted_ = false; | |
| 725 ephemeral_mount_attempted_ = false; | |
| 726 check_key_attempted_ = false; | |
| 727 | |
| 728 if (state != POSSIBLE_PW_CHANGE && | |
| 729 state != NO_MOUNT && | |
| 730 state != OFFLINE_LOGIN) | |
| 731 return state; | |
| 732 | |
| 733 if (current_state_->online_complete()) { | |
| 734 if (current_state_->online_outcome().reason() == LoginFailure::NONE) { | |
| 735 // Online attempt succeeded as well, so combine the results. | |
| 736 return ResolveOnlineSuccessState(state); | |
| 737 } | |
| 738 NOTREACHED() << "Using obsolete ClientLogin code path."; | |
| 739 } | |
| 740 // if online isn't complete yet, just return the offline result. | |
| 741 return state; | |
| 742 } | |
| 743 | |
| 744 ParallelAuthenticator::AuthState | |
| 745 ParallelAuthenticator::ResolveCryptohomeFailureState() { | |
| 746 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 747 if (remove_attempted_ || resync_attempted_) | |
| 748 return FAILED_REMOVE; | |
| 749 if (ephemeral_mount_attempted_) | |
| 750 return FAILED_TMPFS; | |
| 751 if (migrate_attempted_) | |
| 752 return NEED_OLD_PW; | |
| 753 if (check_key_attempted_) | |
| 754 return LOGIN_FAILED; | |
| 755 | |
| 756 if (current_state_->cryptohome_code() == | |
| 757 cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) { | |
| 758 // Critical TPM error detected, reboot needed. | |
| 759 return FAILED_TPM; | |
| 760 } | |
| 761 | |
| 762 // Return intermediate states in the following case: | |
| 763 // when there is an online result to use; | |
| 764 // This is the case after user finishes Gaia login; | |
| 765 if (current_state_->online_complete()) { | |
| 766 if (current_state_->cryptohome_code() == | |
| 767 cryptohome::MOUNT_ERROR_KEY_FAILURE) { | |
| 768 // If we tried a mount but they used the wrong key, we may need to | |
| 769 // ask the user for her old password. We'll only know once we've | |
| 770 // done the online check. | |
| 771 return POSSIBLE_PW_CHANGE; | |
| 772 } | |
| 773 if (current_state_->cryptohome_code() == | |
| 774 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) { | |
| 775 // If we tried a mount but the user did not exist, then we should wait | |
| 776 // for online login to succeed and try again with the "create" flag set. | |
| 777 return NO_MOUNT; | |
| 778 } | |
| 779 } | |
| 780 | |
| 781 if (!current_state_->username_hash_valid()) | |
| 782 return FAILED_USERNAME_HASH; | |
| 783 | |
| 784 return FAILED_MOUNT; | |
| 785 } | |
| 786 | |
| 787 ParallelAuthenticator::AuthState | |
| 788 ParallelAuthenticator::ResolveCryptohomeSuccessState() { | |
| 789 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 790 if (resync_attempted_) | |
| 791 return CREATE_NEW; | |
| 792 if (remove_attempted_) | |
| 793 return REMOVED_DATA_AFTER_FAILURE; | |
| 794 if (migrate_attempted_) | |
| 795 return RECOVER_MOUNT; | |
| 796 if (check_key_attempted_) | |
| 797 return UNLOCK; | |
| 798 | |
| 799 if (current_state_->user_type == User::USER_TYPE_GUEST) | |
| 800 return GUEST_LOGIN; | |
| 801 if (current_state_->user_type == User::USER_TYPE_RETAIL_MODE) | |
| 802 return DEMO_LOGIN; | |
| 803 if (current_state_->user_type == User::USER_TYPE_PUBLIC_ACCOUNT) | |
| 804 return PUBLIC_ACCOUNT_LOGIN; | |
| 805 if (current_state_->user_type == User::USER_TYPE_KIOSK_APP) | |
| 806 return KIOSK_ACCOUNT_LOGIN; | |
| 807 if (current_state_->user_type == User::USER_TYPE_LOCALLY_MANAGED) | |
| 808 return LOCALLY_MANAGED_USER_LOGIN; | |
| 809 | |
| 810 if (!VerifyOwner()) | |
| 811 return CONTINUE; | |
| 812 return user_can_login_ ? OFFLINE_LOGIN : OWNER_REQUIRED; | |
| 813 } | |
| 814 | |
| 815 ParallelAuthenticator::AuthState | |
| 816 ParallelAuthenticator::ResolveOnlineSuccessState( | |
| 817 ParallelAuthenticator::AuthState offline_state) { | |
| 818 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 819 switch (offline_state) { | |
| 820 case POSSIBLE_PW_CHANGE: | |
| 821 return NEED_OLD_PW; | |
| 822 case NO_MOUNT: | |
| 823 return CREATE_NEW; | |
| 824 case OFFLINE_LOGIN: | |
| 825 return ONLINE_LOGIN; | |
| 826 default: | |
| 827 NOTREACHED(); | |
| 828 return offline_state; | |
| 829 } | |
| 830 } | |
| 831 | |
| 832 void ParallelAuthenticator::ResolveLoginCompletionStatus() { | |
| 833 // Shortcut online state resolution process. | |
| 834 current_state_->RecordOnlineLoginStatus(LoginFailure::LoginFailureNone()); | |
| 835 Resolve(); | |
| 836 } | |
| 837 | |
| 838 void ParallelAuthenticator::SetOwnerState(bool owner_check_finished, | |
| 839 bool check_result) { | |
| 840 owner_is_verified_ = owner_check_finished; | |
| 841 user_can_login_ = check_result; | |
| 842 } | |
| 843 | |
| 844 } // namespace chromeos | |
| OLD | NEW |