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