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 <string>
      8 
      9 #include "base/file_util.h"
     10 #include "base/files/file_path.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/strings/string_util.h"
     14 #include "base/strings/stringprintf.h"
     15 #include "chrome/browser/chromeos/cros/network_library.h"
     16 #include "chrome/browser/chromeos/login/mock_login_status_consumer.h"
     17 #include "chrome/browser/chromeos/login/mock_url_fetchers.h"
     18 #include "chrome/browser/chromeos/login/mock_user_manager.h"
     19 #include "chrome/browser/chromeos/login/test_attempt_state.h"
     20 #include "chrome/browser/chromeos/login/user.h"
     21 #include "chrome/browser/chromeos/login/user_manager.h"
     22 #include "chrome/browser/chromeos/settings/cros_settings.h"
     23 #include "chrome/browser/chromeos/settings/device_settings_test_helper.h"
     24 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
     25 #include "chrome/test/base/testing_profile.h"
     26 #include "chromeos/cryptohome/mock_async_method_caller.h"
     27 #include "chromeos/cryptohome/mock_cryptohome_library.h"
     28 #include "chromeos/dbus/fake_cryptohome_client.h"
     29 #include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
     30 #include "content/public/test/test_browser_thread_bundle.h"
     31 #include "google_apis/gaia/mock_url_fetcher_factory.h"
     32 #include "net/base/net_errors.h"
     33 #include "net/url_request/url_request_status.h"
     34 #include "testing/gmock/include/gmock/gmock.h"
     35 #include "testing/gtest/include/gtest/gtest.h"
     36 #include "third_party/cros_system_api/dbus/service_constants.h"
     37 #include "url/gurl.h"
     38 
     39 using ::testing::Invoke;
     40 using ::testing::Return;
     41 using ::testing::_;
     42 
     43 namespace chromeos {
     44 
     45 class TestOnlineAttempt : public OnlineAttempt {
     46  public:
     47   TestOnlineAttempt(AuthAttemptState* state,
     48                     AuthAttemptStateResolver* resolver)
     49       : OnlineAttempt(state, resolver) {
     50   }
     51 };
     52 
     53 class ParallelAuthenticatorTest : public testing::Test {
     54  public:
     55   ParallelAuthenticatorTest()
     56       : username_("me (at) nowhere.org"),
     57         password_("fakepass"),
     58         hash_ascii_("0a010000000000a0" + std::string(16, '0')),
     59         user_manager_enabler_(new MockUserManager) {
     60   }
     61 
     62   virtual ~ParallelAuthenticatorTest() {
     63     DCHECK(!mock_caller_);
     64   }
     65 
     66   virtual void SetUp() {
     67     mock_caller_ = new cryptohome::MockAsyncMethodCaller;
     68     cryptohome::AsyncMethodCaller::InitializeForTesting(mock_caller_);
     69 
     70     mock_cryptohome_library_ .reset(new MockCryptohomeLibrary());
     71     CryptohomeLibrary::SetForTest(mock_cryptohome_library_.get());
     72 
     73     auth_ = new ParallelAuthenticator(&consumer_);
     74     state_.reset(new TestAttemptState(UserContext(username_,
     75                                                   password_,
     76                                                   std::string()),
     77                                       hash_ascii_,
     78                                       "",
     79                                       "",
     80                                       User::USER_TYPE_REGULAR,
     81                                       false));
     82   }
     83 
     84   // Tears down the test fixture.
     85   virtual void TearDown() {
     86     CryptohomeLibrary::SetForTest(NULL);
     87 
     88     cryptohome::AsyncMethodCaller::Shutdown();
     89     mock_caller_ = NULL;
     90   }
     91 
     92   base::FilePath PopulateTempFile(const char* data, int data_len) {
     93     base::FilePath out;
     94     FILE* tmp_file = file_util::CreateAndOpenTemporaryFile(&out);
     95     EXPECT_NE(tmp_file, static_cast<FILE*>(NULL));
     96     EXPECT_EQ(file_util::WriteFile(out, data, data_len), data_len);
     97     EXPECT_TRUE(file_util::CloseFile(tmp_file));
     98     return out;
     99   }
    100 
    101   // Allow test to fail and exit gracefully, even if OnLoginFailure()
    102   // wasn't supposed to happen.
    103   void FailOnLoginFailure() {
    104     ON_CALL(consumer_, OnLoginFailure(_))
    105         .WillByDefault(Invoke(MockConsumer::OnFailQuitAndFail));
    106   }
    107 
    108   // Allow test to fail and exit gracefully, even if
    109   // OnRetailModeLoginSuccess() wasn't supposed to happen.
    110   void FailOnRetailModeLoginSuccess() {
    111     ON_CALL(consumer_, OnRetailModeLoginSuccess(_))
    112         .WillByDefault(Invoke(MockConsumer::OnRetailModeSuccessQuitAndFail));
    113   }
    114 
    115   // Allow test to fail and exit gracefully, even if OnLoginSuccess()
    116   // wasn't supposed to happen.
    117   void FailOnLoginSuccess() {
    118     ON_CALL(consumer_, OnLoginSuccess(_, _, _))
    119         .WillByDefault(Invoke(MockConsumer::OnSuccessQuitAndFail));
    120   }
    121 
    122   // Allow test to fail and exit gracefully, even if
    123   // OnOffTheRecordLoginSuccess() wasn't supposed to happen.
    124   void FailOnGuestLoginSuccess() {
    125     ON_CALL(consumer_, OnOffTheRecordLoginSuccess())
    126         .WillByDefault(Invoke(MockConsumer::OnGuestSuccessQuitAndFail));
    127   }
    128 
    129   void ExpectLoginFailure(const LoginFailure& failure) {
    130     EXPECT_CALL(consumer_, OnLoginFailure(failure))
    131         .WillOnce(Invoke(MockConsumer::OnFailQuit))
    132         .RetiresOnSaturation();
    133   }
    134 
    135   void ExpectRetailModeLoginSuccess() {
    136     EXPECT_CALL(consumer_, OnRetailModeLoginSuccess(_))
    137         .WillOnce(Invoke(MockConsumer::OnRetailModeSuccessQuit))
    138         .RetiresOnSaturation();
    139   }
    140 
    141   void ExpectLoginSuccess(const std::string& username,
    142                           const std::string& password,
    143                           const std::string& username_hash_,
    144                           bool pending) {
    145     EXPECT_CALL(consumer_, OnLoginSuccess(UserContext(username,
    146                                                       password,
    147                                                       std::string(),
    148                                                       username_hash_),
    149                                           pending,
    150                                           true /* using_oauth */))
    151         .WillOnce(Invoke(MockConsumer::OnSuccessQuit))
    152         .RetiresOnSaturation();
    153   }
    154 
    155   void ExpectGuestLoginSuccess() {
    156     EXPECT_CALL(consumer_, OnOffTheRecordLoginSuccess())
    157         .WillOnce(Invoke(MockConsumer::OnGuestSuccessQuit))
    158         .RetiresOnSaturation();
    159   }
    160 
    161   void ExpectPasswordChange() {
    162     EXPECT_CALL(consumer_, OnPasswordChangeDetected())
    163         .WillOnce(Invoke(MockConsumer::OnMigrateQuit))
    164         .RetiresOnSaturation();
    165   }
    166 
    167   void RunResolve(ParallelAuthenticator* auth) {
    168     auth->Resolve();
    169     base::MessageLoop::current()->RunUntilIdle();
    170   }
    171 
    172   void SetAttemptState(ParallelAuthenticator* auth, TestAttemptState* state) {
    173     auth->set_attempt_state(state);
    174   }
    175 
    176   ParallelAuthenticator::AuthState SetAndResolveState(
    177       ParallelAuthenticator* auth, TestAttemptState* state) {
    178     auth->set_attempt_state(state);
    179     return auth->ResolveState();
    180   }
    181 
    182   void SetOwnerState(bool owner_check_finished, bool check_result) {
    183     auth_->SetOwnerState(owner_check_finished, check_result);
    184   }
    185 
    186   void FakeOnlineAttempt() {
    187     auth_->set_online_attempt(new TestOnlineAttempt(state_.get(), auth_.get()));
    188   }
    189 
    190   content::TestBrowserThreadBundle thread_bundle_;
    191 
    192   std::string username_;
    193   std::string password_;
    194   std::string username_hash_;
    195   std::string hash_ascii_;
    196 
    197   ScopedStubNetworkLibraryEnabler stub_network_library_enabler_;
    198   ScopedDeviceSettingsTestHelper device_settings_test_helper_;
    199   ScopedTestCrosSettings test_cros_settings_;
    200 
    201   ScopedUserManagerEnabler user_manager_enabler_;
    202 
    203   scoped_ptr<MockCryptohomeLibrary> mock_cryptohome_library_;
    204 
    205   cryptohome::MockAsyncMethodCaller* mock_caller_;
    206 
    207   MockConsumer consumer_;
    208   scoped_refptr<ParallelAuthenticator> auth_;
    209   scoped_ptr<TestAttemptState> state_;
    210 };
    211 
    212 TEST_F(ParallelAuthenticatorTest, OnLoginSuccess) {
    213   EXPECT_CALL(consumer_, OnLoginSuccess(UserContext(username_,
    214                                                     password_,
    215                                                     std::string(),
    216                                                     username_hash_),
    217                                         false, true /* using oauth */))
    218       .Times(1)
    219       .RetiresOnSaturation();
    220 
    221   SetAttemptState(auth_.get(), state_.release());
    222   auth_->OnLoginSuccess(false);
    223 }
    224 
    225 TEST_F(ParallelAuthenticatorTest, OnPasswordChangeDetected) {
    226   EXPECT_CALL(consumer_, OnPasswordChangeDetected())
    227       .Times(1)
    228       .RetiresOnSaturation();
    229   SetAttemptState(auth_.get(), state_.release());
    230   auth_->OnPasswordChangeDetected();
    231 }
    232 
    233 TEST_F(ParallelAuthenticatorTest, ResolveNothingDone) {
    234   EXPECT_EQ(ParallelAuthenticator::CONTINUE,
    235             SetAndResolveState(auth_.get(), state_.release()));
    236 }
    237 
    238 TEST_F(ParallelAuthenticatorTest, ResolvePossiblePwChange) {
    239   // Set a fake online attempt so that we return intermediate cryptohome state.
    240   FakeOnlineAttempt();
    241 
    242   // Set up state as though a cryptohome mount attempt has occurred
    243   // and been rejected.
    244   state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE);
    245 
    246   EXPECT_EQ(ParallelAuthenticator::POSSIBLE_PW_CHANGE,
    247             SetAndResolveState(auth_.get(), state_.release()));
    248 }
    249 
    250 TEST_F(ParallelAuthenticatorTest, ResolvePossiblePwChangeToFailedMount) {
    251   // Set up state as though a cryptohome mount attempt has occurred
    252   // and been rejected.
    253   state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE);
    254 
    255   // When there is no online attempt and online results, POSSIBLE_PW_CHANGE
    256   EXPECT_EQ(ParallelAuthenticator::FAILED_MOUNT,
    257             SetAndResolveState(auth_.get(), state_.release()));
    258 }
    259 
    260 TEST_F(ParallelAuthenticatorTest, ResolveNeedOldPw) {
    261   // Set up state as though a cryptohome mount attempt has occurred
    262   // and been rejected because of unmatched key; additionally,
    263   // an online auth attempt has completed successfully.
    264   state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE);
    265   state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
    266 
    267   EXPECT_EQ(ParallelAuthenticator::NEED_OLD_PW,
    268             SetAndResolveState(auth_.get(), state_.release()));
    269 }
    270 
    271 TEST_F(ParallelAuthenticatorTest, ResolveOwnerNeededDirectFailedMount) {
    272   // Set up state as though a cryptohome mount attempt has occurred
    273   // and succeeded but we are in safe mode and the current user is not owner.
    274   // This is a high level test to verify the proper transitioning in this mode
    275   // only. It is not testing that we properly verify that the user is an owner
    276   // or that we really are in "safe-mode".
    277   state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
    278   SetOwnerState(true, false);
    279 
    280   EXPECT_EQ(ParallelAuthenticator::OWNER_REQUIRED,
    281             SetAndResolveState(auth_.get(), state_.release()));
    282 }
    283 
    284 TEST_F(ParallelAuthenticatorTest, ResolveOwnerNeededMount) {
    285   // Set up state as though a cryptohome mount attempt has occurred
    286   // and succeeded but we are in safe mode and the current user is not owner.
    287   // This test will check that the "safe-mode" policy is not set and will let
    288   // the mount finish successfully.
    289   state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
    290   SetOwnerState(false, false);
    291   // and test that the mount has succeeded.
    292   state_.reset(new TestAttemptState(UserContext(username_,
    293                                                 password_,
    294                                                 std::string()),
    295                                     hash_ascii_,
    296                                     "",
    297                                     "",
    298                                     User::USER_TYPE_REGULAR,
    299                                     false));
    300   state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
    301   EXPECT_EQ(ParallelAuthenticator::OFFLINE_LOGIN,
    302             SetAndResolveState(auth_.get(), state_.release()));
    303 }
    304 
    305 TEST_F(ParallelAuthenticatorTest, ResolveOwnerNeededFailedMount) {
    306   FailOnLoginSuccess();  // Set failing on success as the default...
    307   LoginFailure failure = LoginFailure(LoginFailure::OWNER_REQUIRED);
    308   ExpectLoginFailure(failure);
    309 
    310   MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager =
    311       new MockDBusThreadManagerWithoutGMock;
    312   DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager);
    313   FakeCryptohomeClient* fake_cryptohome_client  =
    314       mock_dbus_thread_manager->fake_cryptohome_client();
    315   fake_cryptohome_client->set_unmount_result(true);
    316 
    317   CrosSettingsProvider* device_settings_provider;
    318   StubCrosSettingsProvider stub_settings_provider;
    319   // Set up state as though a cryptohome mount attempt has occurred
    320   // and succeeded but we are in safe mode and the current user is not owner.
    321   state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
    322   SetOwnerState(false, false);
    323   // Remove the real DeviceSettingsProvider and replace it with a stub.
    324   device_settings_provider =
    325       CrosSettings::Get()->GetProvider(chromeos::kReportDeviceVersionInfo);
    326   EXPECT_TRUE(device_settings_provider != NULL);
    327   EXPECT_TRUE(
    328       CrosSettings::Get()->RemoveSettingsProvider(device_settings_provider));
    329   CrosSettings::Get()->AddSettingsProvider(&stub_settings_provider);
    330   CrosSettings::Get()->SetBoolean(kPolicyMissingMitigationMode, true);
    331 
    332   EXPECT_EQ(ParallelAuthenticator::CONTINUE,
    333             SetAndResolveState(auth_.get(), state_.release()));
    334   // Let the owner verification run.
    335   device_settings_test_helper_.Flush();
    336   // and test that the mount has succeeded.
    337   state_.reset(new TestAttemptState(UserContext(username_,
    338                                                 password_,
    339                                                 std::string()),
    340                                     hash_ascii_,
    341                                     "",
    342                                     "",
    343                                     User::USER_TYPE_REGULAR,
    344                                     false));
    345   state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
    346   EXPECT_EQ(ParallelAuthenticator::OWNER_REQUIRED,
    347             SetAndResolveState(auth_.get(), state_.release()));
    348 
    349   EXPECT_TRUE(
    350       CrosSettings::Get()->RemoveSettingsProvider(&stub_settings_provider));
    351   CrosSettings::Get()->AddSettingsProvider(device_settings_provider);
    352   DBusThreadManager::Get()->Shutdown();
    353 }
    354 
    355 TEST_F(ParallelAuthenticatorTest, DriveFailedMount) {
    356   FailOnLoginSuccess();
    357   ExpectLoginFailure(LoginFailure(LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME));
    358 
    359   // Set up state as though a cryptohome mount attempt has occurred
    360   // and failed.
    361   state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_NONE);
    362   SetAttemptState(auth_.get(), state_.release());
    363 
    364   RunResolve(auth_.get());
    365 }
    366 
    367 TEST_F(ParallelAuthenticatorTest, DriveGuestLogin) {
    368   ExpectGuestLoginSuccess();
    369   FailOnLoginFailure();
    370 
    371   // Set up mock cryptohome library to respond as though a tmpfs mount
    372   // attempt has occurred and succeeded.
    373   mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
    374   EXPECT_CALL(*mock_caller_, AsyncMountGuest(_))
    375       .Times(1)
    376       .RetiresOnSaturation();
    377 
    378   auth_->LoginOffTheRecord();
    379   base::MessageLoop::current()->Run();
    380 }
    381 
    382 TEST_F(ParallelAuthenticatorTest, DriveGuestLoginButFail) {
    383   FailOnGuestLoginSuccess();
    384   ExpectLoginFailure(LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS));
    385 
    386   // Set up mock cryptohome library to respond as though a tmpfs mount
    387   // attempt has occurred and failed.
    388   mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_NONE);
    389   EXPECT_CALL(*mock_caller_, AsyncMountGuest(_))
    390       .Times(1)
    391       .RetiresOnSaturation();
    392 
    393   auth_->LoginOffTheRecord();
    394   base::MessageLoop::current()->Run();
    395 }
    396 
    397 TEST_F(ParallelAuthenticatorTest, DriveRetailModeUserLogin) {
    398   ExpectRetailModeLoginSuccess();
    399   FailOnLoginFailure();
    400 
    401   // Set up mock cryptohome library to respond as though a tmpfs mount
    402   // attempt has occurred and succeeded.
    403   mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
    404   EXPECT_CALL(*mock_caller_, AsyncMountGuest(_))
    405       .Times(1)
    406       .RetiresOnSaturation();
    407 
    408   auth_->LoginRetailMode();
    409   base::MessageLoop::current()->Run();
    410 }
    411 
    412 TEST_F(ParallelAuthenticatorTest, DriveRetailModeLoginButFail) {
    413   FailOnRetailModeLoginSuccess();
    414   ExpectLoginFailure(LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS));
    415 
    416   // Set up mock cryptohome library to respond as though a tmpfs mount
    417   // attempt has occurred and failed.
    418   mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_NONE);
    419   EXPECT_CALL(*mock_caller_, AsyncMountGuest(_))
    420       .Times(1)
    421       .RetiresOnSaturation();
    422 
    423   auth_->LoginRetailMode();
    424   base::MessageLoop::current()->Run();
    425 }
    426 
    427 TEST_F(ParallelAuthenticatorTest, DriveDataResync) {
    428   ExpectLoginSuccess(username_,
    429                      password_,
    430                      cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername,
    431                      false);
    432   FailOnLoginFailure();
    433 
    434   // Set up mock cryptohome library to respond successfully to a cryptohome
    435   // remove attempt and a cryptohome create attempt (indicated by the
    436   // |CREATE_IF_MISSING| flag to AsyncMount).
    437   mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
    438   EXPECT_CALL(*mock_caller_, AsyncRemove(username_, _))
    439       .Times(1)
    440       .RetiresOnSaturation();
    441   EXPECT_CALL(*mock_caller_, AsyncMount(username_, hash_ascii_,
    442                                         cryptohome::CREATE_IF_MISSING, _))
    443       .Times(1)
    444       .RetiresOnSaturation();
    445   EXPECT_CALL(*mock_caller_, AsyncGetSanitizedUsername(username_, _))
    446       .Times(1)
    447       .RetiresOnSaturation();
    448 
    449   state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
    450   SetAttemptState(auth_.get(), state_.release());
    451 
    452   auth_->ResyncEncryptedData();
    453   base::MessageLoop::current()->Run();
    454 }
    455 
    456 TEST_F(ParallelAuthenticatorTest, DriveResyncFail) {
    457   FailOnLoginSuccess();
    458   ExpectLoginFailure(LoginFailure(LoginFailure::DATA_REMOVAL_FAILED));
    459 
    460   // Set up mock cryptohome library to fail a cryptohome remove attempt.
    461   mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_NONE);
    462   EXPECT_CALL(*mock_caller_, AsyncRemove(username_, _))
    463       .Times(1)
    464       .RetiresOnSaturation();
    465 
    466   SetAttemptState(auth_.get(), state_.release());
    467 
    468   auth_->ResyncEncryptedData();
    469   base::MessageLoop::current()->Run();
    470 }
    471 
    472 TEST_F(ParallelAuthenticatorTest, DriveRequestOldPassword) {
    473   FailOnLoginSuccess();
    474   ExpectPasswordChange();
    475 
    476   state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE);
    477   state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
    478   SetAttemptState(auth_.get(), state_.release());
    479 
    480   RunResolve(auth_.get());
    481 }
    482 
    483 TEST_F(ParallelAuthenticatorTest, DriveDataRecover) {
    484   ExpectLoginSuccess(username_,
    485                      password_,
    486                      cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername,
    487                      false);
    488   FailOnLoginFailure();
    489 
    490   // Set up mock cryptohome library to respond successfully to a key migration.
    491   mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
    492   EXPECT_CALL(*mock_caller_, AsyncMigrateKey(username_, _, hash_ascii_, _))
    493       .Times(1)
    494       .RetiresOnSaturation();
    495   EXPECT_CALL(*mock_caller_, AsyncMount(username_, hash_ascii_,
    496                                         cryptohome::MOUNT_FLAGS_NONE, _))
    497       .Times(1)
    498       .RetiresOnSaturation();
    499   EXPECT_CALL(*mock_caller_, AsyncGetSanitizedUsername(username_, _))
    500         .Times(1)
    501         .RetiresOnSaturation();
    502   EXPECT_CALL(*mock_cryptohome_library_, GetSystemSalt())
    503       .WillOnce(Return(std::string()))
    504       .RetiresOnSaturation();
    505 
    506   state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
    507   SetAttemptState(auth_.get(), state_.release());
    508 
    509   auth_->RecoverEncryptedData(std::string());
    510   base::MessageLoop::current()->Run();
    511 }
    512 
    513 TEST_F(ParallelAuthenticatorTest, DriveDataRecoverButFail) {
    514   FailOnLoginSuccess();
    515   ExpectPasswordChange();
    516 
    517   // Set up mock cryptohome library to fail a key migration attempt,
    518   // asserting that the wrong password was used.
    519   mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_KEY_FAILURE);
    520   EXPECT_CALL(*mock_caller_, AsyncMigrateKey(username_, _, hash_ascii_, _))
    521       .Times(1)
    522       .RetiresOnSaturation();
    523   EXPECT_CALL(*mock_cryptohome_library_, GetSystemSalt())
    524       .WillOnce(Return(std::string()))
    525       .RetiresOnSaturation();
    526 
    527   SetAttemptState(auth_.get(), state_.release());
    528 
    529   auth_->RecoverEncryptedData(std::string());
    530   base::MessageLoop::current()->Run();
    531 }
    532 
    533 TEST_F(ParallelAuthenticatorTest, ResolveNoMount) {
    534   // Set a fake online attempt so that we return intermediate cryptohome state.
    535   FakeOnlineAttempt();
    536 
    537   // Set up state as though a cryptohome mount attempt has occurred
    538   // and been rejected because the user doesn't exist.
    539   state_->PresetCryptohomeStatus(false,
    540                                  cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST);
    541 
    542   EXPECT_EQ(ParallelAuthenticator::NO_MOUNT,
    543             SetAndResolveState(auth_.get(), state_.release()));
    544 }
    545 
    546 TEST_F(ParallelAuthenticatorTest, ResolveNoMountToFailedMount) {
    547   // Set up state as though a cryptohome mount attempt has occurred
    548   // and been rejected because the user doesn't exist.
    549   state_->PresetCryptohomeStatus(false,
    550                                  cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST);
    551 
    552   // When there is no online attempt and online results, NO_MOUNT will be
    553   // resolved to FAILED_MOUNT.
    554   EXPECT_EQ(ParallelAuthenticator::FAILED_MOUNT,
    555             SetAndResolveState(auth_.get(), state_.release()));
    556 }
    557 
    558 TEST_F(ParallelAuthenticatorTest, ResolveCreateNew) {
    559   // Set up state as though a cryptohome mount attempt has occurred
    560   // and been rejected because the user doesn't exist; additionally,
    561   // an online auth attempt has completed successfully.
    562   state_->PresetCryptohomeStatus(false,
    563                                  cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST);
    564   state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
    565 
    566   EXPECT_EQ(ParallelAuthenticator::CREATE_NEW,
    567             SetAndResolveState(auth_.get(), state_.release()));
    568 }
    569 
    570 TEST_F(ParallelAuthenticatorTest, DriveCreateForNewUser) {
    571   ExpectLoginSuccess(username_,
    572                      password_,
    573                      cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername,
    574                      false);
    575   FailOnLoginFailure();
    576 
    577   // Set up mock cryptohome library to respond successfully to a cryptohome
    578   // create attempt (indicated by the |CREATE_IF_MISSING| flag to AsyncMount).
    579   mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
    580   EXPECT_CALL(*mock_caller_, AsyncMount(username_, hash_ascii_,
    581                                         cryptohome::CREATE_IF_MISSING, _))
    582       .Times(1)
    583       .RetiresOnSaturation();
    584   EXPECT_CALL(*mock_caller_, AsyncGetSanitizedUsername(username_, _))
    585       .Times(1)
    586       .RetiresOnSaturation();
    587 
    588   // Set up state as though a cryptohome mount attempt has occurred
    589   // and been rejected because the user doesn't exist; additionally,
    590   // an online auth attempt has completed successfully.
    591   state_->PresetCryptohomeStatus(false,
    592                                  cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST);
    593   state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
    594   SetAttemptState(auth_.get(), state_.release());
    595 
    596   RunResolve(auth_.get());
    597 }
    598 
    599 TEST_F(ParallelAuthenticatorTest, DriveOfflineLogin) {
    600   ExpectLoginSuccess(username_, password_, username_hash_, false);
    601   FailOnLoginFailure();
    602 
    603   // Set up state as though a cryptohome mount attempt has occurred and
    604   // succeeded.
    605   state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
    606   SetAttemptState(auth_.get(), state_.release());
    607 
    608   RunResolve(auth_.get());
    609 }
    610 
    611 TEST_F(ParallelAuthenticatorTest, DriveOnlineLogin) {
    612   ExpectLoginSuccess(username_, password_, username_hash_, false);
    613   FailOnLoginFailure();
    614 
    615   // Set up state as though a cryptohome mount attempt has occurred and
    616   // succeeded.
    617   state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
    618   state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
    619   SetAttemptState(auth_.get(), state_.release());
    620 
    621   RunResolve(auth_.get());
    622 }
    623 
    624 TEST_F(ParallelAuthenticatorTest, DriveUnlock) {
    625   ExpectLoginSuccess(username_, std::string(), std::string(), false);
    626   FailOnLoginFailure();
    627 
    628   // Set up mock cryptohome library to respond successfully to a cryptohome
    629   // key-check attempt.
    630   mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
    631   EXPECT_CALL(*mock_caller_, AsyncCheckKey(username_, _, _))
    632       .Times(1)
    633       .RetiresOnSaturation();
    634   EXPECT_CALL(*mock_cryptohome_library_, GetSystemSalt())
    635       .WillOnce(Return(std::string()))
    636       .RetiresOnSaturation();
    637 
    638   auth_->AuthenticateToUnlock(UserContext(username_,
    639                                           std::string(),
    640                                           std::string()));
    641   base::MessageLoop::current()->Run();
    642 }
    643 
    644 }  // namespace chromeos
    645