Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / chromeos / login / parallel_authenticator.cc
blobf866c5b640f8870e467b11a37339cf80d81d7b75
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.
5 #include "chrome/browser/chromeos/login/parallel_authenticator.h"
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"
32 using content::BrowserThread;
34 namespace chromeos {
36 namespace {
38 // Length of password hashed with SHA-256.
39 const int kPasswordHashLength = 32;
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();
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();
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);
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.username,
88 ParallelAuthenticator::HashPassword(attempt->user_context.password,
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.username,
97 base::Bind(&TriggerResolveHash,
98 attempt,
99 resolver));
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));
113 // Calls cryptohome's MountPublic method
114 void MountPublic(AuthAttemptState* attempt,
115 scoped_refptr<ParallelAuthenticator> resolver,
116 int flags) {
117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
118 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountPublic(
119 attempt->user_context.username,
120 flags,
121 base::Bind(&TriggerResolveWithLoginTimeMarker,
122 "CryptohomeMountPublic-End",
123 attempt,
124 resolver));
125 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
126 attempt->user_context.username,
127 base::Bind(&TriggerResolveHash,
128 attempt,
129 resolver));
132 // Calls cryptohome's key migration method.
133 void Migrate(AuthAttemptState* attempt,
134 scoped_refptr<ParallelAuthenticator> resolver,
135 bool passing_old_hash,
136 const std::string& old_password,
137 const std::string& system_salt) {
138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
139 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
140 "CryptohomeMigrate-Start", false);
141 cryptohome::AsyncMethodCaller* caller =
142 cryptohome::AsyncMethodCaller::GetInstance();
143 if (passing_old_hash) {
144 caller->AsyncMigrateKey(
145 attempt->user_context.username,
146 ParallelAuthenticator::HashPassword(old_password, system_salt),
147 ParallelAuthenticator::HashPassword(attempt->user_context.password,
148 system_salt),
149 base::Bind(&TriggerResolveWithLoginTimeMarker,
150 "CryptohomeMount-End",
151 attempt,
152 resolver));
153 } else {
154 caller->AsyncMigrateKey(
155 attempt->user_context.username,
156 ParallelAuthenticator::HashPassword(attempt->user_context.password,
157 system_salt),
158 ParallelAuthenticator::HashPassword(old_password, system_salt),
159 base::Bind(&TriggerResolveWithLoginTimeMarker,
160 "CryptohomeMount-End",
161 attempt,
162 resolver));
166 // Calls cryptohome's remove method.
167 void Remove(AuthAttemptState* attempt,
168 scoped_refptr<ParallelAuthenticator> resolver) {
169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
170 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
171 "CryptohomeRemove-Start", false);
172 cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
173 attempt->user_context.username,
174 base::Bind(&TriggerResolveWithLoginTimeMarker,
175 "CryptohomeRemove-End",
176 attempt,
177 resolver));
180 // Calls cryptohome's key check method.
181 void CheckKey(AuthAttemptState* attempt,
182 scoped_refptr<ParallelAuthenticator> resolver,
183 const std::string& system_salt) {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
185 cryptohome::AsyncMethodCaller::GetInstance()->AsyncCheckKey(
186 attempt->user_context.username,
187 ParallelAuthenticator::HashPassword(attempt->user_context.password,
188 system_salt),
189 base::Bind(&TriggerResolve, attempt, resolver));
192 } // namespace
194 ParallelAuthenticator::ParallelAuthenticator(LoginStatusConsumer* consumer)
195 : Authenticator(consumer),
196 migrate_attempted_(false),
197 remove_attempted_(false),
198 resync_attempted_(false),
199 ephemeral_mount_attempted_(false),
200 check_key_attempted_(false),
201 already_reported_success_(false),
202 owner_is_verified_(false),
203 user_can_login_(false),
204 remove_user_data_on_failure_(false),
205 delayed_login_failure_(NULL) {
208 void ParallelAuthenticator::AuthenticateToLogin(
209 Profile* profile,
210 const UserContext& user_context) {
211 std::string canonicalized = gaia::CanonicalizeEmail(user_context.username);
212 authentication_profile_ = profile;
213 current_state_.reset(
214 new AuthAttemptState(
215 UserContext(canonicalized,
216 user_context.password,
217 user_context.auth_code),
218 std::string(), // login_token, not used.
219 std::string(), // login_captcha, not used.
220 User::USER_TYPE_REGULAR,
221 !UserManager::Get()->IsKnownUser(canonicalized)));
222 // Reset the verified flag.
223 owner_is_verified_ = false;
225 SystemSaltGetter::Get()->GetSystemSalt(
226 base::Bind(&Mount,
227 current_state_.get(),
228 scoped_refptr<ParallelAuthenticator>(this),
229 cryptohome::MOUNT_FLAGS_NONE));
232 void ParallelAuthenticator::CompleteLogin(Profile* profile,
233 const UserContext& user_context) {
234 std::string canonicalized = gaia::CanonicalizeEmail(user_context.username);
235 authentication_profile_ = profile;
236 current_state_.reset(
237 new AuthAttemptState(
238 UserContext(canonicalized,
239 user_context.password,
240 user_context.auth_code),
241 !UserManager::Get()->IsKnownUser(canonicalized)));
243 // Reset the verified flag.
244 owner_is_verified_ = false;
246 SystemSaltGetter::Get()->GetSystemSalt(
247 base::Bind(&Mount,
248 current_state_.get(),
249 scoped_refptr<ParallelAuthenticator>(this),
250 cryptohome::MOUNT_FLAGS_NONE));
252 // For login completion from extension, we just need to resolve the current
253 // auth attempt state, the rest of OAuth related tasks will be done in
254 // parallel.
255 BrowserThread::PostTask(
256 BrowserThread::UI, FROM_HERE,
257 base::Bind(&ParallelAuthenticator::ResolveLoginCompletionStatus, this));
260 void ParallelAuthenticator::AuthenticateToUnlock(
261 const UserContext& user_context) {
262 current_state_.reset(
263 new AuthAttemptState(
264 gaia::CanonicalizeEmail(user_context.username),
265 user_context.password));
266 remove_user_data_on_failure_ = false;
267 check_key_attempted_ = true;
268 SystemSaltGetter::Get()->GetSystemSalt(
269 base::Bind(&CheckKey,
270 current_state_.get(),
271 scoped_refptr<ParallelAuthenticator>(this)));
274 void ParallelAuthenticator::LoginAsLocallyManagedUser(
275 const UserContext& user_context) {
276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
277 // TODO(nkostylev): Pass proper value for |user_is_new| or remove (not used).
278 current_state_.reset(
279 new AuthAttemptState(user_context,
280 "", // login_token
281 "", // login_captcha
282 User::USER_TYPE_LOCALLY_MANAGED,
283 false));
284 remove_user_data_on_failure_ = false;
285 SystemSaltGetter::Get()->GetSystemSalt(
286 base::Bind(&Mount,
287 current_state_.get(),
288 scoped_refptr<ParallelAuthenticator>(this),
289 cryptohome::MOUNT_FLAGS_NONE));
292 void ParallelAuthenticator::LoginRetailMode() {
293 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
294 // Note: |kRetailModeUserEMail| is used in other places to identify a retail
295 // mode session.
296 current_state_.reset(new AuthAttemptState(
297 UserContext(UserManager::kRetailModeUserName,
298 std::string(), // password
299 std::string()), // auth_code
300 std::string(), // login_token
301 std::string(), // login_captcha
302 User::USER_TYPE_RETAIL_MODE,
303 false));
304 remove_user_data_on_failure_ = false;
305 ephemeral_mount_attempted_ = true;
306 MountGuest(current_state_.get(),
307 scoped_refptr<ParallelAuthenticator>(this));
310 void ParallelAuthenticator::LoginOffTheRecord() {
311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
312 current_state_.reset(new AuthAttemptState(
313 UserContext(UserManager::kGuestUserName, // username
314 std::string(), // password
315 std::string()), // auth_code
316 std::string(), // login_token
317 std::string(), // login_captcha
318 User::USER_TYPE_GUEST,
319 false));
320 remove_user_data_on_failure_ = false;
321 ephemeral_mount_attempted_ = true;
322 MountGuest(current_state_.get(),
323 scoped_refptr<ParallelAuthenticator>(this));
326 void ParallelAuthenticator::LoginAsPublicAccount(const std::string& username) {
327 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
328 current_state_.reset(new AuthAttemptState(
329 UserContext(username,
330 std::string(), // password
331 std::string()), // auth_code
332 std::string(), // login_token
333 std::string(), // login_captcha
334 User::USER_TYPE_PUBLIC_ACCOUNT,
335 false));
336 remove_user_data_on_failure_ = false;
337 ephemeral_mount_attempted_ = true;
338 SystemSaltGetter::Get()->GetSystemSalt(
339 base::Bind(&Mount,
340 current_state_.get(),
341 scoped_refptr<ParallelAuthenticator>(this),
342 cryptohome::CREATE_IF_MISSING | cryptohome::ENSURE_EPHEMERAL));
345 void ParallelAuthenticator::LoginAsKioskAccount(
346 const std::string& app_user_id) {
347 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
348 current_state_.reset(new AuthAttemptState(
349 UserContext(app_user_id,
350 std::string(), // password
351 std::string()), // auth_code
352 std::string(), // login_token
353 std::string(), // login_captcha
354 User::USER_TYPE_KIOSK_APP,
355 false));
356 remove_user_data_on_failure_ = true;
357 MountPublic(current_state_.get(),
358 scoped_refptr<ParallelAuthenticator>(this),
359 cryptohome::CREATE_IF_MISSING);
362 void ParallelAuthenticator::OnRetailModeLoginSuccess() {
363 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
364 VLOG(1) << "Retail mode login success";
365 // Send notification of success
366 AuthenticationNotificationDetails details(true);
367 content::NotificationService::current()->Notify(
368 chrome::NOTIFICATION_LOGIN_AUTHENTICATION,
369 content::NotificationService::AllSources(),
370 content::Details<AuthenticationNotificationDetails>(&details));
371 if (consumer_)
372 consumer_->OnRetailModeLoginSuccess(current_state_->user_context);
375 void ParallelAuthenticator::OnLoginSuccess() {
376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
377 VLOG(1) << "Login success";
378 // Send notification of success
379 AuthenticationNotificationDetails details(true);
380 content::NotificationService::current()->Notify(
381 chrome::NOTIFICATION_LOGIN_AUTHENTICATION,
382 content::NotificationService::AllSources(),
383 content::Details<AuthenticationNotificationDetails>(&details));
385 base::AutoLock for_this_block(success_lock_);
386 already_reported_success_ = true;
388 if (consumer_)
389 consumer_->OnLoginSuccess(current_state_->user_context);
392 void ParallelAuthenticator::OnOffTheRecordLoginSuccess() {
393 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
394 // Send notification of success
395 AuthenticationNotificationDetails details(true);
396 content::NotificationService::current()->Notify(
397 chrome::NOTIFICATION_LOGIN_AUTHENTICATION,
398 content::NotificationService::AllSources(),
399 content::Details<AuthenticationNotificationDetails>(&details));
400 if (consumer_)
401 consumer_->OnOffTheRecordLoginSuccess();
404 void ParallelAuthenticator::OnPasswordChangeDetected() {
405 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
406 if (consumer_)
407 consumer_->OnPasswordChangeDetected();
410 void ParallelAuthenticator::OnLoginFailure(const LoginFailure& error) {
411 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
413 // OnLoginFailure will be called again with the same |error|
414 // after the cryptohome has been removed.
415 if (remove_user_data_on_failure_) {
416 delayed_login_failure_ = &error;
417 RemoveEncryptedData();
418 return;
421 // Send notification of failure
422 AuthenticationNotificationDetails details(false);
423 content::NotificationService::current()->Notify(
424 chrome::NOTIFICATION_LOGIN_AUTHENTICATION,
425 content::NotificationService::AllSources(),
426 content::Details<AuthenticationNotificationDetails>(&details));
427 LOG(WARNING) << "Login failed: " << error.GetErrorString();
428 if (consumer_)
429 consumer_->OnLoginFailure(error);
432 void ParallelAuthenticator::RecoverEncryptedData(
433 const std::string& old_password) {
434 migrate_attempted_ = true;
435 current_state_->ResetCryptohomeStatus();
436 SystemSaltGetter::Get()->GetSystemSalt(
437 base::Bind(&Migrate,
438 current_state_.get(),
439 scoped_refptr<ParallelAuthenticator>(this),
440 true,
441 old_password));
444 void ParallelAuthenticator::RemoveEncryptedData() {
445 remove_attempted_ = true;
446 current_state_->ResetCryptohomeStatus();
447 BrowserThread::PostTask(
448 BrowserThread::UI, FROM_HERE,
449 base::Bind(&Remove,
450 current_state_.get(),
451 scoped_refptr<ParallelAuthenticator>(this)));
454 void ParallelAuthenticator::ResyncEncryptedData() {
455 resync_attempted_ = true;
456 current_state_->ResetCryptohomeStatus();
457 BrowserThread::PostTask(
458 BrowserThread::UI, FROM_HERE,
459 base::Bind(&Remove,
460 current_state_.get(),
461 scoped_refptr<ParallelAuthenticator>(this)));
464 bool ParallelAuthenticator::VerifyOwner() {
465 if (owner_is_verified_)
466 return true;
467 // Check if policy data is fine and continue in safe mode if needed.
468 bool is_safe_mode = false;
469 CrosSettings::Get()->GetBoolean(kPolicyMissingMitigationMode, &is_safe_mode);
470 if (!is_safe_mode) {
471 // Now we can continue with the login and report mount success.
472 user_can_login_ = true;
473 owner_is_verified_ = true;
474 return true;
476 // Now we can continue reading the private key.
477 DeviceSettingsService::Get()->SetUsername(
478 current_state_->user_context.username);
479 // This should trigger certificate loading, which is needed in order to
480 // correctly determine if the current user is the owner.
481 if (LoginState::IsInitialized()) {
482 LoginState::Get()->SetLoggedInState(LoginState::LOGGED_IN_SAFE_MODE,
483 LoginState::LOGGED_IN_USER_NONE);
485 DeviceSettingsService::Get()->IsCurrentUserOwnerAsync(
486 base::Bind(&ParallelAuthenticator::OnOwnershipChecked, this));
487 return false;
490 void ParallelAuthenticator::OnOwnershipChecked(bool is_owner) {
491 // Now we can check if this user is the owner.
492 user_can_login_ = is_owner;
493 owner_is_verified_ = true;
494 Resolve();
497 void ParallelAuthenticator::Resolve() {
498 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
499 int mount_flags = cryptohome::MOUNT_FLAGS_NONE;
500 ParallelAuthenticator::AuthState state = ResolveState();
501 VLOG(1) << "Resolved state to: " << state;
502 switch (state) {
503 case CONTINUE:
504 case POSSIBLE_PW_CHANGE:
505 case NO_MOUNT:
506 // These are intermediate states; we need more info from a request that
507 // is still pending.
508 break;
509 case FAILED_MOUNT:
510 // In this case, whether login succeeded or not, we can't log
511 // the user in because their data is horked. So, override with
512 // the appropriate failure.
513 BrowserThread::PostTask(
514 BrowserThread::UI, FROM_HERE,
515 base::Bind(&ParallelAuthenticator::OnLoginFailure, this,
516 LoginFailure(LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME)));
517 break;
518 case FAILED_REMOVE:
519 // In this case, we tried to remove the user's old cryptohome at her
520 // request, and the remove failed.
521 remove_user_data_on_failure_ = false;
522 BrowserThread::PostTask(
523 BrowserThread::UI, FROM_HERE,
524 base::Bind(&ParallelAuthenticator::OnLoginFailure, this,
525 LoginFailure(LoginFailure::DATA_REMOVAL_FAILED)));
526 break;
527 case FAILED_TMPFS:
528 // In this case, we tried to mount a tmpfs for guest and failed.
529 BrowserThread::PostTask(
530 BrowserThread::UI, FROM_HERE,
531 base::Bind(&ParallelAuthenticator::OnLoginFailure, this,
532 LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS)));
533 break;
534 case FAILED_TPM:
535 // In this case, we tried to create/mount cryptohome and failed
536 // because of the critical TPM error.
537 // Chrome will notify user and request reboot.
538 BrowserThread::PostTask(
539 BrowserThread::UI, FROM_HERE,
540 base::Bind(&ParallelAuthenticator::OnLoginFailure, this,
541 LoginFailure(LoginFailure::TPM_ERROR)));
542 break;
543 case FAILED_USERNAME_HASH:
544 // In this case, we failed the GetSanitizedUsername request to
545 // cryptohomed. This can happen for any login attempt.
546 BrowserThread::PostTask(
547 BrowserThread::UI, FROM_HERE,
548 base::Bind(&ParallelAuthenticator::OnLoginFailure, this,
549 LoginFailure(LoginFailure::USERNAME_HASH_FAILED)));
550 break;
551 case REMOVED_DATA_AFTER_FAILURE:
552 remove_user_data_on_failure_ = false;
553 BrowserThread::PostTask(
554 BrowserThread::UI, FROM_HERE,
555 base::Bind(&ParallelAuthenticator::OnLoginFailure, this,
556 *delayed_login_failure_));
557 break;
558 case CREATE_NEW:
559 mount_flags |= cryptohome::CREATE_IF_MISSING;
560 case RECOVER_MOUNT:
561 current_state_->ResetCryptohomeStatus();
562 SystemSaltGetter::Get()->GetSystemSalt(
563 base::Bind(&Mount,
564 current_state_.get(),
565 scoped_refptr<ParallelAuthenticator>(this),
566 mount_flags));
567 break;
568 case NEED_OLD_PW:
569 BrowserThread::PostTask(
570 BrowserThread::UI, FROM_HERE,
571 base::Bind(&ParallelAuthenticator::OnPasswordChangeDetected, this));
572 break;
573 case ONLINE_FAILED:
574 case NEED_NEW_PW:
575 case HAVE_NEW_PW:
576 NOTREACHED() << "Using obsolete ClientLogin code path.";
577 break;
578 case OFFLINE_LOGIN:
579 VLOG(2) << "Offline login";
580 // Fall through.
581 case UNLOCK:
582 VLOG(2) << "Unlock";
583 // Fall through.
584 case ONLINE_LOGIN:
585 VLOG(2) << "Online login";
586 BrowserThread::PostTask(
587 BrowserThread::UI, FROM_HERE,
588 base::Bind(&ParallelAuthenticator::OnLoginSuccess, this));
589 break;
590 case DEMO_LOGIN:
591 VLOG(2) << "Retail mode login";
592 current_state_->user_context.using_oauth = false;
593 BrowserThread::PostTask(
594 BrowserThread::UI, FROM_HERE,
595 base::Bind(&ParallelAuthenticator::OnRetailModeLoginSuccess, this));
596 break;
597 case GUEST_LOGIN:
598 BrowserThread::PostTask(
599 BrowserThread::UI, FROM_HERE,
600 base::Bind(&ParallelAuthenticator::OnOffTheRecordLoginSuccess, this));
601 break;
602 case KIOSK_ACCOUNT_LOGIN:
603 case PUBLIC_ACCOUNT_LOGIN:
604 current_state_->user_context.using_oauth = false;
605 BrowserThread::PostTask(
606 BrowserThread::UI, FROM_HERE,
607 base::Bind(&ParallelAuthenticator::OnLoginSuccess, this));
608 break;
609 case LOCALLY_MANAGED_USER_LOGIN:
610 current_state_->user_context.using_oauth = false;
611 BrowserThread::PostTask(
612 BrowserThread::UI, FROM_HERE,
613 base::Bind(&ParallelAuthenticator::OnLoginSuccess, this));
614 break;
615 case LOGIN_FAILED:
616 current_state_->ResetCryptohomeStatus();
617 BrowserThread::PostTask(BrowserThread::UI,
618 FROM_HERE,
619 base::Bind(
620 &ParallelAuthenticator::OnLoginFailure,
621 this,
622 current_state_->online_outcome()));
623 break;
624 case OWNER_REQUIRED: {
625 current_state_->ResetCryptohomeStatus();
626 bool success = false;
627 DBusThreadManager::Get()->GetCryptohomeClient()->Unmount(&success);
628 if (!success) {
629 // Maybe we should reboot immediately here?
630 LOG(ERROR) << "Couldn't unmount users home!";
632 BrowserThread::PostTask(BrowserThread::UI,
633 FROM_HERE,
634 base::Bind(
635 &ParallelAuthenticator::OnLoginFailure,
636 this,
637 LoginFailure(LoginFailure::OWNER_REQUIRED)));
638 break;
640 default:
641 NOTREACHED();
642 break;
646 // static.
647 std::string ParallelAuthenticator::HashPassword(const std::string& password,
648 const std::string& ascii_salt) {
649 // Update sha with ascii encoded salt, then update with ascii of password,
650 // then end.
651 // TODO(stevenjb/nkostylev): Handle empty system salt gracefully.
652 CHECK(!ascii_salt.empty());
653 char passhash_buf[kPasswordHashLength];
655 // Hash salt and password
656 crypto::SHA256HashString(ascii_salt + password,
657 &passhash_buf, sizeof(passhash_buf));
659 // Only want the top half for 'weak' hashing so that the passphrase is not
660 // immediately exposed even if the output is reversed.
661 const int encoded_length = sizeof(passhash_buf) / 2;
663 return StringToLowerASCII(base::HexEncode(
664 reinterpret_cast<const void*>(passhash_buf), encoded_length));
667 ParallelAuthenticator::~ParallelAuthenticator() {}
669 ParallelAuthenticator::AuthState ParallelAuthenticator::ResolveState() {
670 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
671 // If we haven't mounted the user's home dir yet or
672 // haven't got sanitized username value, we can't be done.
673 // We never get past here if any of these two cryptohome ops is still pending.
674 // This is an important invariant.
675 if (!current_state_->cryptohome_complete() ||
676 !current_state_->username_hash_obtained()) {
677 return CONTINUE;
680 AuthState state = CONTINUE;
682 if (current_state_->cryptohome_outcome() &&
683 current_state_->username_hash_valid()) {
684 state = ResolveCryptohomeSuccessState();
685 } else {
686 state = ResolveCryptohomeFailureState();
689 DCHECK(current_state_->cryptohome_complete()); // Ensure invariant holds.
690 migrate_attempted_ = false;
691 remove_attempted_ = false;
692 resync_attempted_ = false;
693 ephemeral_mount_attempted_ = false;
694 check_key_attempted_ = false;
696 if (state != POSSIBLE_PW_CHANGE &&
697 state != NO_MOUNT &&
698 state != OFFLINE_LOGIN)
699 return state;
701 if (current_state_->online_complete()) {
702 if (current_state_->online_outcome().reason() == LoginFailure::NONE) {
703 // Online attempt succeeded as well, so combine the results.
704 return ResolveOnlineSuccessState(state);
706 NOTREACHED() << "Using obsolete ClientLogin code path.";
708 // if online isn't complete yet, just return the offline result.
709 return state;
712 ParallelAuthenticator::AuthState
713 ParallelAuthenticator::ResolveCryptohomeFailureState() {
714 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
715 if (remove_attempted_ || resync_attempted_)
716 return FAILED_REMOVE;
717 if (ephemeral_mount_attempted_)
718 return FAILED_TMPFS;
719 if (migrate_attempted_)
720 return NEED_OLD_PW;
721 if (check_key_attempted_)
722 return LOGIN_FAILED;
724 if (current_state_->cryptohome_code() ==
725 cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
726 // Critical TPM error detected, reboot needed.
727 return FAILED_TPM;
730 // Return intermediate states in the following case:
731 // when there is an online result to use;
732 // This is the case after user finishes Gaia login;
733 if (current_state_->online_complete()) {
734 if (current_state_->cryptohome_code() ==
735 cryptohome::MOUNT_ERROR_KEY_FAILURE) {
736 // If we tried a mount but they used the wrong key, we may need to
737 // ask the user for her old password. We'll only know once we've
738 // done the online check.
739 return POSSIBLE_PW_CHANGE;
741 if (current_state_->cryptohome_code() ==
742 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) {
743 // If we tried a mount but the user did not exist, then we should wait
744 // for online login to succeed and try again with the "create" flag set.
745 return NO_MOUNT;
749 if (!current_state_->username_hash_valid())
750 return FAILED_USERNAME_HASH;
752 return FAILED_MOUNT;
755 ParallelAuthenticator::AuthState
756 ParallelAuthenticator::ResolveCryptohomeSuccessState() {
757 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
758 if (resync_attempted_)
759 return CREATE_NEW;
760 if (remove_attempted_)
761 return REMOVED_DATA_AFTER_FAILURE;
762 if (migrate_attempted_)
763 return RECOVER_MOUNT;
764 if (check_key_attempted_)
765 return UNLOCK;
767 if (current_state_->user_type == User::USER_TYPE_GUEST)
768 return GUEST_LOGIN;
769 if (current_state_->user_type == User::USER_TYPE_RETAIL_MODE)
770 return DEMO_LOGIN;
771 if (current_state_->user_type == User::USER_TYPE_PUBLIC_ACCOUNT)
772 return PUBLIC_ACCOUNT_LOGIN;
773 if (current_state_->user_type == User::USER_TYPE_KIOSK_APP)
774 return KIOSK_ACCOUNT_LOGIN;
775 if (current_state_->user_type == User::USER_TYPE_LOCALLY_MANAGED)
776 return LOCALLY_MANAGED_USER_LOGIN;
778 if (!VerifyOwner())
779 return CONTINUE;
780 return user_can_login_ ? OFFLINE_LOGIN : OWNER_REQUIRED;
783 ParallelAuthenticator::AuthState
784 ParallelAuthenticator::ResolveOnlineSuccessState(
785 ParallelAuthenticator::AuthState offline_state) {
786 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
787 switch (offline_state) {
788 case POSSIBLE_PW_CHANGE:
789 return NEED_OLD_PW;
790 case NO_MOUNT:
791 return CREATE_NEW;
792 case OFFLINE_LOGIN:
793 return ONLINE_LOGIN;
794 default:
795 NOTREACHED();
796 return offline_state;
800 void ParallelAuthenticator::ResolveLoginCompletionStatus() {
801 // Shortcut online state resolution process.
802 current_state_->RecordOnlineLoginStatus(LoginFailure::LoginFailureNone());
803 Resolve();
806 void ParallelAuthenticator::SetOwnerState(bool owner_check_finished,
807 bool check_result) {
808 owner_is_verified_ = owner_check_finished;
809 user_can_login_ = check_result;
812 } // namespace chromeos