Home | History | Annotate | Download | only in login
      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.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));
    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 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));
    130 }
    131 
    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));
    163   }
    164 }
    165 
    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));
    178 }
    179 
    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));
    190 }
    191 
    192 }  // namespace
    193 
    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) {
    206 }
    207 
    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;
    224 
    225   SystemSaltGetter::Get()->GetSystemSalt(
    226       base::Bind(&Mount,
    227                  current_state_.get(),
    228                  scoped_refptr<ParallelAuthenticator>(this),
    229                  cryptohome::MOUNT_FLAGS_NONE));
    230 }
    231 
    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)));
    242 
    243   // Reset the verified flag.
    244   owner_is_verified_ = false;
    245 
    246   SystemSaltGetter::Get()->GetSystemSalt(
    247       base::Bind(&Mount,
    248                  current_state_.get(),
    249                  scoped_refptr<ParallelAuthenticator>(this),
    250                  cryptohome::MOUNT_FLAGS_NONE));
    251 
    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));
    258 }
    259 
    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)));
    272 }
    273 
    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));
    290 }
    291 
    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));
    308 }
    309 
    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));
    324 }
    325 
    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));
    343 }
    344 
    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);
    360 }
    361 
    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);
    373 }
    374 
    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));
    384   {
    385     base::AutoLock for_this_block(success_lock_);
    386     already_reported_success_ = true;
    387   }
    388   if (consumer_)
    389     consumer_->OnLoginSuccess(current_state_->user_context);
    390 }
    391 
    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();
    402 }
    403 
    404 void ParallelAuthenticator::OnPasswordChangeDetected() {
    405   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    406   if (consumer_)
    407     consumer_->OnPasswordChangeDetected();
    408 }
    409 
    410 void ParallelAuthenticator::OnLoginFailure(const LoginFailure& error) {
    411   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    412 
    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;
    419   }
    420 
    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);
    430 }
    431 
    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));
    442 }
    443 
    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)));
    452 }
    453 
    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)));
    462 }
    463 
    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;
    475   }
    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);
    484   }
    485   DeviceSettingsService::Get()->IsCurrentUserOwnerAsync(
    486       base::Bind(&ParallelAuthenticator::OnOwnershipChecked, this));
    487   return false;
    488 }
    489 
    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();
    495 }
    496 
    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!";
    631       }
    632       BrowserThread::PostTask(BrowserThread::UI,
    633                               FROM_HERE,
    634                               base::Bind(
    635                                   &ParallelAuthenticator::OnLoginFailure,
    636                                   this,
    637                                   LoginFailure(LoginFailure::OWNER_REQUIRED)));
    638       break;
    639     }
    640     default:
    641       NOTREACHED();
    642       break;
    643   }
    644 }
    645 
    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];
    654 
    655   // Hash salt and password
    656   crypto::SHA256HashString(ascii_salt + password,
    657                            &passhash_buf, sizeof(passhash_buf));
    658 
    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;
    662 
    663   return StringToLowerASCII(base::HexEncode(
    664       reinterpret_cast<const void*>(passhash_buf), encoded_length));
    665 }
    666 
    667 ParallelAuthenticator::~ParallelAuthenticator() {}
    668 
    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;
    678   }
    679 
    680   AuthState state = CONTINUE;
    681 
    682   if (current_state_->cryptohome_outcome() &&
    683       current_state_->username_hash_valid()) {
    684     state = ResolveCryptohomeSuccessState();
    685   } else {
    686     state = ResolveCryptohomeFailureState();
    687   }
    688 
    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;
    695 
    696   if (state != POSSIBLE_PW_CHANGE &&
    697       state != NO_MOUNT &&
    698       state != OFFLINE_LOGIN)
    699     return state;
    700 
    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);
    705     }
    706     NOTREACHED() << "Using obsolete ClientLogin code path.";
    707   }
    708   // if online isn't complete yet, just return the offline result.
    709   return state;
    710 }
    711 
    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;
    723 
    724   if (current_state_->cryptohome_code() ==
    725       cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
    726     // Critical TPM error detected, reboot needed.
    727     return FAILED_TPM;
    728   }
    729 
    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;
    740     }
    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;
    746     }
    747   }
    748 
    749   if (!current_state_->username_hash_valid())
    750     return FAILED_USERNAME_HASH;
    751 
    752   return FAILED_MOUNT;
    753 }
    754 
    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;
    766 
    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;
    777 
    778   if (!VerifyOwner())
    779     return CONTINUE;
    780   return user_can_login_ ? OFFLINE_LOGIN : OWNER_REQUIRED;
    781 }
    782 
    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;
    797   }
    798 }
    799 
    800 void ParallelAuthenticator::ResolveLoginCompletionStatus() {
    801   // Shortcut online state resolution process.
    802   current_state_->RecordOnlineLoginStatus(LoginFailure::LoginFailureNone());
    803   Resolve();
    804 }
    805 
    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;
    810 }
    811 
    812 }  // namespace chromeos
    813