Home | History | Annotate | Download | only in login
      1 // Copyright (c) 2011 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 #include <vector>
      9 
     10 #include "base/file_path.h"
     11 #include "base/file_util.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/message_loop.h"
     14 #include "base/path_service.h"
     15 #include "base/string_util.h"
     16 #include "base/stringprintf.h"
     17 #include "chrome/browser/chromeos/cros/mock_cryptohome_library.h"
     18 #include "chrome/browser/chromeos/cros/mock_library_loader.h"
     19 #include "chrome/browser/chromeos/login/mock_auth_response_handler.h"
     20 #include "chrome/browser/chromeos/login/mock_login_status_consumer.h"
     21 #include "chrome/browser/chromeos/login/mock_url_fetchers.h"
     22 #include "chrome/browser/chromeos/login/test_attempt_state.h"
     23 #include "chrome/common/chrome_paths.h"
     24 #include "chrome/common/net/gaia/gaia_auth_fetcher_unittest.h"
     25 #include "chrome/common/net/url_fetcher.h"
     26 #include "chrome/test/testing_profile.h"
     27 #include "chrome/test/thread_test_helper.h"
     28 #include "content/browser/browser_thread.h"
     29 #include "googleurl/src/gurl.h"
     30 #include "net/base/net_errors.h"
     31 #include "net/url_request/url_request_status.h"
     32 #include "testing/gmock/include/gmock/gmock.h"
     33 #include "testing/gtest/include/gtest/gtest.h"
     34 
     35 using namespace file_util;
     36 using ::testing::AnyNumber;
     37 using ::testing::DoAll;
     38 using ::testing::Invoke;
     39 using ::testing::Return;
     40 using ::testing::SetArgumentPointee;
     41 using ::testing::_;
     42 
     43 namespace chromeos {
     44 class ResolveChecker : public ThreadTestHelper {
     45  public:
     46   ResolveChecker(TestAttemptState* state,
     47                  ParallelAuthenticator* auth,
     48                  ParallelAuthenticator::AuthState expected)
     49       : ThreadTestHelper(BrowserThread::IO),
     50         state_(state),
     51         auth_(auth),
     52         expected_(expected) {
     53   }
     54   ~ResolveChecker() {}
     55 
     56   virtual void RunTest() {
     57     auth_->set_attempt_state(state_);
     58     set_test_result(expected_ == auth_->ResolveState());
     59   }
     60 
     61  private:
     62   TestAttemptState* state_;
     63   ParallelAuthenticator* auth_;
     64   ParallelAuthenticator::AuthState expected_;
     65 };
     66 
     67 class ParallelAuthenticatorTest : public ::testing::Test {
     68  public:
     69   ParallelAuthenticatorTest()
     70       : message_loop_(MessageLoop::TYPE_UI),
     71         ui_thread_(BrowserThread::UI, &message_loop_),
     72         file_thread_(BrowserThread::FILE),
     73         io_thread_(BrowserThread::IO),
     74         username_("me (at) nowhere.org"),
     75         password_("fakepass") {
     76     hash_ascii_.assign("0a010000000000a0");
     77     hash_ascii_.append(std::string(16, '0'));
     78   }
     79 
     80   ~ParallelAuthenticatorTest() {}
     81 
     82   virtual void SetUp() {
     83     chromeos::CrosLibrary::TestApi* test_api =
     84         chromeos::CrosLibrary::Get()->GetTestApi();
     85 
     86     loader_ = new MockLibraryLoader();
     87     ON_CALL(*loader_, Load(_))
     88         .WillByDefault(Return(true));
     89     EXPECT_CALL(*loader_, Load(_))
     90         .Times(AnyNumber());
     91 
     92     test_api->SetLibraryLoader(loader_, true);
     93 
     94     mock_library_ = new MockCryptohomeLibrary();
     95     test_api->SetCryptohomeLibrary(mock_library_, true);
     96     file_thread_.Start();
     97     io_thread_.Start();
     98 
     99     auth_ = new ParallelAuthenticator(&consumer_);
    100     state_.reset(new TestAttemptState(username_,
    101                                       password_,
    102                                       hash_ascii_,
    103                                       "",
    104                                       "",
    105                                       false));
    106   }
    107 
    108   // Tears down the test fixture.
    109   virtual void TearDown() {
    110     // Prevent bogus gMock leak check from firing.
    111     chromeos::CrosLibrary::TestApi* test_api =
    112         chromeos::CrosLibrary::Get()->GetTestApi();
    113     test_api->SetLibraryLoader(NULL, false);
    114     test_api->SetCryptohomeLibrary(NULL, false);
    115   }
    116 
    117   FilePath PopulateTempFile(const char* data, int data_len) {
    118     FilePath out;
    119     FILE* tmp_file = CreateAndOpenTemporaryFile(&out);
    120     EXPECT_NE(tmp_file, static_cast<FILE*>(NULL));
    121     EXPECT_EQ(WriteFile(out, data, data_len), data_len);
    122     EXPECT_TRUE(CloseFile(tmp_file));
    123     return out;
    124   }
    125 
    126   FilePath FakeLocalaccountFile(const std::string& ascii) {
    127     FilePath exe_dir;
    128     FilePath local_account_file;
    129     PathService::Get(base::DIR_EXE, &exe_dir);
    130     FILE* tmp_file = CreateAndOpenTemporaryFileInDir(exe_dir,
    131                                                      &local_account_file);
    132     int ascii_len = ascii.length();
    133     EXPECT_NE(tmp_file, static_cast<FILE*>(NULL));
    134     EXPECT_EQ(WriteFile(local_account_file, ascii.c_str(), ascii_len),
    135               ascii_len);
    136     EXPECT_TRUE(CloseFile(tmp_file));
    137     return local_account_file;
    138   }
    139 
    140   void ReadLocalaccountFile(ParallelAuthenticator* auth,
    141                             const std::string& filename) {
    142     BrowserThread::PostTask(
    143         BrowserThread::FILE, FROM_HERE,
    144         NewRunnableMethod(auth,
    145                           &ParallelAuthenticator::LoadLocalaccount,
    146                           filename));
    147     file_thread_.Stop();
    148     file_thread_.Start();
    149   }
    150 
    151   // Allow test to fail and exit gracefully, even if OnLoginFailure()
    152   // wasn't supposed to happen.
    153   void FailOnLoginFailure() {
    154     ON_CALL(consumer_, OnLoginFailure(_))
    155         .WillByDefault(Invoke(MockConsumer::OnFailQuitAndFail));
    156   }
    157 
    158   // Allow test to fail and exit gracefully, even if OnLoginSuccess()
    159   // wasn't supposed to happen.
    160   void FailOnLoginSuccess() {
    161     ON_CALL(consumer_, OnLoginSuccess(_, _, _, _))
    162         .WillByDefault(Invoke(MockConsumer::OnSuccessQuitAndFail));
    163   }
    164 
    165   // Allow test to fail and exit gracefully, even if
    166   // OnOffTheRecordLoginSuccess() wasn't supposed to happen.
    167   void FailOnGuestLoginSuccess() {
    168     ON_CALL(consumer_, OnOffTheRecordLoginSuccess())
    169         .WillByDefault(Invoke(MockConsumer::OnGuestSuccessQuitAndFail));
    170   }
    171 
    172   void ExpectLoginFailure(const LoginFailure& failure) {
    173     EXPECT_CALL(consumer_, OnLoginFailure(failure))
    174         .WillOnce(Invoke(MockConsumer::OnFailQuit))
    175         .RetiresOnSaturation();
    176   }
    177 
    178   void ExpectLoginSuccess(const std::string& username,
    179                           const std::string& password,
    180                           const GaiaAuthConsumer::ClientLoginResult& result,
    181                           bool pending) {
    182     EXPECT_CALL(consumer_, OnLoginSuccess(username, password, result, pending))
    183         .WillOnce(Invoke(MockConsumer::OnSuccessQuit))
    184         .RetiresOnSaturation();
    185   }
    186 
    187   void ExpectGuestLoginSuccess() {
    188     EXPECT_CALL(consumer_, OnOffTheRecordLoginSuccess())
    189         .WillOnce(Invoke(MockConsumer::OnGuestSuccessQuit))
    190         .RetiresOnSaturation();
    191   }
    192 
    193   void ExpectPasswordChange() {
    194     EXPECT_CALL(consumer_, OnPasswordChangeDetected(result_))
    195         .WillOnce(Invoke(MockConsumer::OnMigrateQuit))
    196         .RetiresOnSaturation();
    197   }
    198 
    199   void RunResolve(ParallelAuthenticator* auth, MessageLoop* loop) {
    200     BrowserThread::PostTask(
    201         BrowserThread::IO, FROM_HERE,
    202         NewRunnableMethod(auth, &ParallelAuthenticator::Resolve));
    203     loop->Run();
    204   }
    205 
    206   void SetAttemptState(ParallelAuthenticator* auth, TestAttemptState* state) {
    207     auth->set_attempt_state(state);
    208   }
    209 
    210   MessageLoop message_loop_;
    211   BrowserThread ui_thread_;
    212   BrowserThread file_thread_;
    213   BrowserThread io_thread_;
    214 
    215   std::string username_;
    216   std::string password_;
    217   std::string hash_ascii_;
    218   GaiaAuthConsumer::ClientLoginResult result_;
    219 
    220   // Mocks, destroyed by CrosLibrary class.
    221   MockCryptohomeLibrary* mock_library_;
    222   MockLibraryLoader* loader_;
    223 
    224   MockConsumer consumer_;
    225   scoped_refptr<ParallelAuthenticator> auth_;
    226   scoped_ptr<TestAttemptState> state_;
    227 };
    228 
    229 TEST_F(ParallelAuthenticatorTest, SaltToAscii) {
    230   unsigned char fake_salt[8] = { 0 };
    231   fake_salt[0] = 10;
    232   fake_salt[1] = 1;
    233   fake_salt[7] = 10 << 4;
    234   std::vector<unsigned char> salt_v(fake_salt, fake_salt + sizeof(fake_salt));
    235 
    236   ON_CALL(*mock_library_, GetSystemSalt())
    237       .WillByDefault(Return(salt_v));
    238   EXPECT_CALL(*mock_library_, GetSystemSalt())
    239       .Times(1)
    240       .RetiresOnSaturation();
    241 
    242   EXPECT_EQ("0a010000000000a0", auth_->SaltAsAscii());
    243 }
    244 
    245 TEST_F(ParallelAuthenticatorTest, ReadLocalaccount) {
    246   FilePath tmp_file_path = FakeLocalaccountFile(username_);
    247 
    248   ReadLocalaccountFile(auth_.get(), tmp_file_path.BaseName().value());
    249   EXPECT_EQ(auth_->localaccount_, username_);
    250   Delete(tmp_file_path, false);
    251 }
    252 
    253 TEST_F(ParallelAuthenticatorTest, ReadLocalaccountTrailingWS) {
    254   FilePath tmp_file_path =
    255       FakeLocalaccountFile(base::StringPrintf("%s\n", username_.c_str()));
    256 
    257   ReadLocalaccountFile(auth_.get(), tmp_file_path.BaseName().value());
    258   EXPECT_EQ(auth_->localaccount_, username_);
    259   Delete(tmp_file_path, false);
    260 }
    261 
    262 TEST_F(ParallelAuthenticatorTest, ReadNoLocalaccount) {
    263   FilePath tmp_file_path = FakeLocalaccountFile(username_);
    264   EXPECT_TRUE(Delete(tmp_file_path, false));  // Ensure non-existent file.
    265 
    266   ReadLocalaccountFile(auth_.get(), tmp_file_path.BaseName().value());
    267   EXPECT_EQ(auth_->localaccount_, std::string());
    268 }
    269 
    270 TEST_F(ParallelAuthenticatorTest, OnLoginSuccess) {
    271   EXPECT_CALL(consumer_, OnLoginSuccess(username_, password_, result_, false))
    272       .Times(1)
    273       .RetiresOnSaturation();
    274 
    275   SetAttemptState(auth_, state_.release());
    276   auth_->OnLoginSuccess(result_, false);
    277 }
    278 
    279 TEST_F(ParallelAuthenticatorTest, OnPasswordChangeDetected) {
    280   EXPECT_CALL(consumer_, OnPasswordChangeDetected(result_))
    281       .Times(1)
    282       .RetiresOnSaturation();
    283   SetAttemptState(auth_, state_.release());
    284   auth_->OnPasswordChangeDetected(result_);
    285 }
    286 
    287 TEST_F(ParallelAuthenticatorTest, ResolveNothingDone) {
    288   scoped_refptr<ResolveChecker> checker(
    289       new ResolveChecker(state_.release(),
    290                          auth_.get(),
    291                          ParallelAuthenticator::CONTINUE));
    292   EXPECT_TRUE(checker->Run());
    293 }
    294 
    295 TEST_F(ParallelAuthenticatorTest, ResolvePossiblePwChange) {
    296   // Set up state as though a cryptohome mount attempt has occurred
    297   // and been rejected.
    298   state_->PresetCryptohomeStatus(false,
    299                                  chromeos::kCryptohomeMountErrorKeyFailure);
    300   scoped_refptr<ResolveChecker> checker(
    301       new ResolveChecker(state_.release(),
    302                          auth_.get(),
    303                          ParallelAuthenticator::POSSIBLE_PW_CHANGE));
    304   EXPECT_TRUE(checker->Run());
    305 }
    306 
    307 TEST_F(ParallelAuthenticatorTest, DriveFailedMount) {
    308   FailOnLoginSuccess();
    309   ExpectLoginFailure(LoginFailure(LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME));
    310 
    311   // Set up state as though a cryptohome mount attempt has occurred
    312   // and failed.
    313   state_->PresetCryptohomeStatus(false, 0);
    314   SetAttemptState(auth_, state_.release());
    315 
    316   RunResolve(auth_.get(), &message_loop_);
    317 }
    318 
    319 TEST_F(ParallelAuthenticatorTest, DriveGuestLogin) {
    320   ExpectGuestLoginSuccess();
    321   FailOnLoginFailure();
    322 
    323   // Set up mock cryptohome library to respond as though a tmpfs mount
    324   // attempt has occurred and succeeded.
    325   mock_library_->SetUp(true, 0);
    326   EXPECT_CALL(*mock_library_, AsyncMountForBwsi(_))
    327       .Times(1)
    328       .RetiresOnSaturation();
    329 
    330   auth_->LoginOffTheRecord();
    331   message_loop_.Run();
    332 }
    333 
    334 TEST_F(ParallelAuthenticatorTest, DriveGuestLoginButFail) {
    335   FailOnGuestLoginSuccess();
    336   ExpectLoginFailure(LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS));
    337 
    338   // Set up mock cryptohome library to respond as though a tmpfs mount
    339   // attempt has occurred and failed.
    340   mock_library_->SetUp(false, 0);
    341   EXPECT_CALL(*mock_library_, AsyncMountForBwsi(_))
    342       .Times(1)
    343       .RetiresOnSaturation();
    344 
    345   auth_->LoginOffTheRecord();
    346   message_loop_.Run();
    347 }
    348 
    349 TEST_F(ParallelAuthenticatorTest, DriveDataResync) {
    350   ExpectLoginSuccess(username_, password_, result_, false);
    351   FailOnLoginFailure();
    352 
    353   // Set up mock cryptohome library to respond successfully to a cryptohome
    354   // remove attempt and a cryptohome create attempt (specified by the |true|
    355   // argument to AsyncMount).
    356   mock_library_->SetUp(true, 0);
    357   EXPECT_CALL(*mock_library_, AsyncRemove(username_, _))
    358       .Times(1)
    359       .RetiresOnSaturation();
    360   EXPECT_CALL(*mock_library_, AsyncMount(username_, hash_ascii_, true, _))
    361       .Times(1)
    362       .RetiresOnSaturation();
    363 
    364   state_->PresetOnlineLoginStatus(result_, LoginFailure::None());
    365   SetAttemptState(auth_, state_.release());
    366 
    367   auth_->ResyncEncryptedData(result_);
    368   message_loop_.Run();
    369 }
    370 
    371 TEST_F(ParallelAuthenticatorTest, DriveResyncFail) {
    372   FailOnLoginSuccess();
    373   ExpectLoginFailure(LoginFailure(LoginFailure::DATA_REMOVAL_FAILED));
    374 
    375   // Set up mock cryptohome library to fail a cryptohome remove attempt.
    376   mock_library_->SetUp(false, 0);
    377   EXPECT_CALL(*mock_library_, AsyncRemove(username_, _))
    378       .Times(1)
    379       .RetiresOnSaturation();
    380 
    381   SetAttemptState(auth_, state_.release());
    382 
    383   auth_->ResyncEncryptedData(result_);
    384   message_loop_.Run();
    385 }
    386 
    387 TEST_F(ParallelAuthenticatorTest, DriveRequestOldPassword) {
    388   FailOnLoginSuccess();
    389   ExpectPasswordChange();
    390 
    391   state_->PresetCryptohomeStatus(false,
    392                                 chromeos::kCryptohomeMountErrorKeyFailure);
    393   state_->PresetOnlineLoginStatus(result_, LoginFailure::None());
    394   SetAttemptState(auth_, state_.release());
    395 
    396   RunResolve(auth_.get(), &message_loop_);
    397 }
    398 
    399 TEST_F(ParallelAuthenticatorTest, DriveDataRecover) {
    400   ExpectLoginSuccess(username_, password_, result_, false);
    401   FailOnLoginFailure();
    402 
    403   // Set up mock cryptohome library to respond successfully to a key migration.
    404   mock_library_->SetUp(true, 0);
    405   EXPECT_CALL(*mock_library_, AsyncMigrateKey(username_, _, hash_ascii_, _))
    406       .Times(1)
    407       .RetiresOnSaturation();
    408   EXPECT_CALL(*mock_library_, AsyncMount(username_, hash_ascii_, false, _))
    409       .Times(1)
    410       .RetiresOnSaturation();
    411   EXPECT_CALL(*mock_library_, GetSystemSalt())
    412       .WillOnce(Return(CryptohomeBlob(2, 0)))
    413       .RetiresOnSaturation();
    414 
    415   state_->PresetOnlineLoginStatus(result_, LoginFailure::None());
    416   SetAttemptState(auth_, state_.release());
    417 
    418   auth_->RecoverEncryptedData(std::string(), result_);
    419   message_loop_.Run();
    420 }
    421 
    422 TEST_F(ParallelAuthenticatorTest, DriveDataRecoverButFail) {
    423   FailOnLoginSuccess();
    424   ExpectPasswordChange();
    425 
    426   // Set up mock cryptohome library to fail a key migration attempt,
    427   // asserting that the wrong password was used.
    428   mock_library_->SetUp(false, chromeos::kCryptohomeMountErrorKeyFailure);
    429   EXPECT_CALL(*mock_library_, AsyncMigrateKey(username_, _, hash_ascii_, _))
    430       .Times(1)
    431       .RetiresOnSaturation();
    432   EXPECT_CALL(*mock_library_, GetSystemSalt())
    433       .WillOnce(Return(CryptohomeBlob(2, 0)))
    434       .RetiresOnSaturation();
    435 
    436   SetAttemptState(auth_, state_.release());
    437 
    438   auth_->RecoverEncryptedData(std::string(), result_);
    439   message_loop_.Run();
    440 }
    441 
    442 TEST_F(ParallelAuthenticatorTest, ResolveNoMount) {
    443   // Set up state as though a cryptohome mount attempt has occurred
    444   // and been rejected because the user doesn't exist.
    445   state_->PresetCryptohomeStatus(
    446       false,
    447       chromeos::kCryptohomeMountErrorUserDoesNotExist);
    448   scoped_refptr<ResolveChecker> checker(
    449       new ResolveChecker(state_.release(),
    450                          auth_.get(),
    451                          ParallelAuthenticator::NO_MOUNT));
    452   EXPECT_TRUE(checker->Run());
    453 }
    454 
    455 TEST_F(ParallelAuthenticatorTest, ResolveCreateNew) {
    456   // Set up state as though a cryptohome mount attempt has occurred
    457   // and been rejected because the user doesn't exist; additionally,
    458   // an online auth attempt has completed successfully.
    459   state_->PresetCryptohomeStatus(
    460       false,
    461       chromeos::kCryptohomeMountErrorUserDoesNotExist);
    462   state_->PresetOnlineLoginStatus(GaiaAuthConsumer::ClientLoginResult(),
    463                                  LoginFailure::None());
    464   scoped_refptr<ResolveChecker> checker(
    465       new ResolveChecker(state_.release(),
    466                          auth_.get(),
    467                          ParallelAuthenticator::CREATE_NEW));
    468   EXPECT_TRUE(checker->Run());
    469 }
    470 
    471 TEST_F(ParallelAuthenticatorTest, DriveCreateForNewUser) {
    472   ExpectLoginSuccess(username_, password_, result_, false);
    473   FailOnLoginFailure();
    474 
    475   // Set up mock cryptohome library to respond successfully to a cryptohome
    476   // create attempt (specified by the |true| argument to AsyncMount).
    477   mock_library_->SetUp(true, 0);
    478   EXPECT_CALL(*mock_library_, AsyncMount(username_, hash_ascii_, true, _))
    479       .Times(1)
    480       .RetiresOnSaturation();
    481 
    482   // Set up state as though a cryptohome mount attempt has occurred
    483   // and been rejected because the user doesn't exist; additionally,
    484   // an online auth attempt has completed successfully.
    485   state_->PresetCryptohomeStatus(
    486       false,
    487       chromeos::kCryptohomeMountErrorUserDoesNotExist);
    488   state_->PresetOnlineLoginStatus(GaiaAuthConsumer::ClientLoginResult(),
    489                                  LoginFailure::None());
    490   SetAttemptState(auth_, state_.release());
    491 
    492   RunResolve(auth_.get(), &message_loop_);
    493 }
    494 
    495 TEST_F(ParallelAuthenticatorTest, DriveOfflineLogin) {
    496   ExpectLoginSuccess(username_, password_, result_, false);
    497   FailOnLoginFailure();
    498 
    499   // Set up state as though a cryptohome mount attempt has occurred and
    500   // succeeded.
    501   state_->PresetCryptohomeStatus(true, 0);
    502   GoogleServiceAuthError error =
    503       GoogleServiceAuthError::FromConnectionError(net::ERR_CONNECTION_RESET);
    504   state_->PresetOnlineLoginStatus(result_,
    505                                  LoginFailure::FromNetworkAuthFailure(error));
    506   SetAttemptState(auth_, state_.release());
    507 
    508   RunResolve(auth_.get(), &message_loop_);
    509 }
    510 
    511 TEST_F(ParallelAuthenticatorTest, DriveOfflineLoginDelayedOnline) {
    512   ExpectLoginSuccess(username_, password_, result_, true);
    513   FailOnLoginFailure();
    514 
    515   // Set up state as though a cryptohome mount attempt has occurred and
    516   // succeeded.
    517   state_->PresetCryptohomeStatus(true, 0);
    518   // state_ is released further down.
    519   SetAttemptState(auth_, state_.get());
    520   RunResolve(auth_.get(), &message_loop_);
    521 
    522   // Offline login has completed, so now we "complete" the online request.
    523   GoogleServiceAuthError error(
    524       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
    525   LoginFailure failure = LoginFailure::FromNetworkAuthFailure(error);
    526   state_.release()->PresetOnlineLoginStatus(result_, failure);
    527   ExpectLoginFailure(failure);
    528 
    529   RunResolve(auth_.get(), &message_loop_);
    530 }
    531 
    532 TEST_F(ParallelAuthenticatorTest, DriveOfflineLoginGetNewPassword) {
    533   ExpectLoginSuccess(username_, password_, result_, true);
    534   FailOnLoginFailure();
    535 
    536   // Set up mock cryptohome library to respond successfully to a key migration.
    537   mock_library_->SetUp(true, 0);
    538   EXPECT_CALL(*mock_library_, AsyncMigrateKey(username_,
    539                                               state_->ascii_hash,
    540                                               _,
    541                                               _))
    542       .Times(1)
    543       .RetiresOnSaturation();
    544   EXPECT_CALL(*mock_library_, GetSystemSalt())
    545       .WillOnce(Return(CryptohomeBlob(2, 0)))
    546       .RetiresOnSaturation();
    547 
    548   // Set up state as though a cryptohome mount attempt has occurred and
    549   // succeeded; also, an online request that never made it.
    550   state_->PresetCryptohomeStatus(true, 0);
    551   // state_ is released further down.
    552   SetAttemptState(auth_, state_.get());
    553   RunResolve(auth_.get(), &message_loop_);
    554 
    555   // Offline login has completed, so now we "complete" the online request.
    556   GoogleServiceAuthError error(
    557       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
    558   LoginFailure failure = LoginFailure::FromNetworkAuthFailure(error);
    559   state_.release()->PresetOnlineLoginStatus(result_, failure);
    560   ExpectLoginFailure(failure);
    561 
    562   RunResolve(auth_.get(), &message_loop_);
    563 
    564   // After the request below completes, OnLoginSuccess gets called again.
    565   ExpectLoginSuccess(username_, password_, result_, false);
    566 
    567   MockFactory<SuccessFetcher> factory;
    568   URLFetcher::set_factory(&factory);
    569   TestingProfile profile;
    570 
    571   auth_->RetryAuth(&profile,
    572                    username_,
    573                    std::string(),
    574                    std::string(),
    575                    std::string());
    576   message_loop_.Run();
    577 }
    578 
    579 TEST_F(ParallelAuthenticatorTest, DriveOfflineLoginGetCaptchad) {
    580   ExpectLoginSuccess(username_, password_, result_, true);
    581   FailOnLoginFailure();
    582   EXPECT_CALL(*mock_library_, GetSystemSalt())
    583       .WillOnce(Return(CryptohomeBlob(2, 0)))
    584       .RetiresOnSaturation();
    585 
    586   // Set up state as though a cryptohome mount attempt has occurred and
    587   // succeeded; also, an online request that never made it.
    588   state_->PresetCryptohomeStatus(true, 0);
    589   // state_ is released further down.
    590   SetAttemptState(auth_, state_.get());
    591   RunResolve(auth_.get(), &message_loop_);
    592 
    593   // Offline login has completed, so now we "complete" the online request.
    594   GoogleServiceAuthError error(
    595       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
    596   LoginFailure failure = LoginFailure::FromNetworkAuthFailure(error);
    597   state_.release()->PresetOnlineLoginStatus(result_, failure);
    598   ExpectLoginFailure(failure);
    599 
    600   RunResolve(auth_.get(), &message_loop_);
    601 
    602   // After the request below completes, OnLoginSuccess gets called again.
    603   failure = LoginFailure::FromNetworkAuthFailure(
    604       GoogleServiceAuthError::FromCaptchaChallenge(
    605           CaptchaFetcher::GetCaptchaToken(),
    606           GURL(CaptchaFetcher::GetCaptchaUrl()),
    607           GURL(CaptchaFetcher::GetUnlockUrl())));
    608   ExpectLoginFailure(failure);
    609 
    610   MockFactory<CaptchaFetcher> factory;
    611   URLFetcher::set_factory(&factory);
    612   TestingProfile profile;
    613 
    614   auth_->RetryAuth(&profile,
    615                    username_,
    616                    std::string(),
    617                    std::string(),
    618                    std::string());
    619   message_loop_.Run();
    620 }
    621 
    622 TEST_F(ParallelAuthenticatorTest, DriveOnlineLogin) {
    623   GaiaAuthConsumer::ClientLoginResult success("sid", "lsid", "", "");
    624   ExpectLoginSuccess(username_, password_, success, false);
    625   FailOnLoginFailure();
    626 
    627   // Set up state as though a cryptohome mount attempt has occurred and
    628   // succeeded.
    629   state_->PresetCryptohomeStatus(true, 0);
    630   state_->PresetOnlineLoginStatus(success, LoginFailure::None());
    631   SetAttemptState(auth_, state_.release());
    632 
    633   RunResolve(auth_.get(), &message_loop_);
    634 }
    635 
    636 TEST_F(ParallelAuthenticatorTest, DriveNeedNewPassword) {
    637   FailOnLoginSuccess();  // Set failing on success as the default...
    638   // ...but expect ONE successful login first.
    639   ExpectLoginSuccess(username_, password_, result_, true);
    640   GoogleServiceAuthError error(
    641       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
    642   LoginFailure failure = LoginFailure::FromNetworkAuthFailure(error);
    643   ExpectLoginFailure(failure);
    644 
    645   // Set up state as though a cryptohome mount attempt has occurred and
    646   // succeeded.
    647   state_->PresetCryptohomeStatus(true, 0);
    648   state_->PresetOnlineLoginStatus(result_, failure);
    649   SetAttemptState(auth_, state_.release());
    650 
    651   RunResolve(auth_.get(), &message_loop_);
    652 }
    653 
    654 TEST_F(ParallelAuthenticatorTest, DriveLocalLogin) {
    655   ExpectGuestLoginSuccess();
    656   FailOnLoginFailure();
    657 
    658   // Set up mock cryptohome library to respond as though a tmpfs mount
    659   // attempt has occurred and succeeded.
    660   mock_library_->SetUp(true, 0);
    661   EXPECT_CALL(*mock_library_, AsyncMountForBwsi(_))
    662       .Times(1)
    663       .RetiresOnSaturation();
    664 
    665   // Pre-set test state as though an online login attempt failed to complete,
    666   // and that a cryptohome mount attempt failed because the user doesn't exist.
    667   GoogleServiceAuthError error =
    668       GoogleServiceAuthError::FromConnectionError(net::ERR_CONNECTION_RESET);
    669   LoginFailure failure =
    670       LoginFailure::FromNetworkAuthFailure(error);
    671   state_->PresetOnlineLoginStatus(result_, failure);
    672   state_->PresetCryptohomeStatus(
    673       false,
    674       chromeos::kCryptohomeMountErrorUserDoesNotExist);
    675   SetAttemptState(auth_, state_.release());
    676 
    677   // Deal with getting the localaccount file
    678   FilePath tmp_file_path = FakeLocalaccountFile(username_);
    679   ReadLocalaccountFile(auth_.get(), tmp_file_path.BaseName().value());
    680 
    681   RunResolve(auth_.get(), &message_loop_);
    682 
    683   Delete(tmp_file_path, false);
    684 }
    685 
    686 TEST_F(ParallelAuthenticatorTest, DriveUnlock) {
    687   ExpectLoginSuccess(username_, std::string(), result_, false);
    688   FailOnLoginFailure();
    689 
    690   // Set up mock cryptohome library to respond successfully to a cryptohome
    691   // key-check attempt.
    692   mock_library_->SetUp(true, 0);
    693   EXPECT_CALL(*mock_library_, AsyncCheckKey(username_, _, _))
    694       .Times(1)
    695       .RetiresOnSaturation();
    696   EXPECT_CALL(*mock_library_, GetSystemSalt())
    697       .WillOnce(Return(CryptohomeBlob(2, 0)))
    698       .RetiresOnSaturation();
    699 
    700   auth_->AuthenticateToUnlock(username_, "");
    701   message_loop_.Run();
    702 }
    703 
    704 TEST_F(ParallelAuthenticatorTest, DriveLocalUnlock) {
    705   ExpectLoginSuccess(username_, std::string(), result_, false);
    706   FailOnLoginFailure();
    707 
    708   // Set up mock cryptohome library to fail a cryptohome key-check
    709   // attempt.
    710   mock_library_->SetUp(false, 0);
    711   EXPECT_CALL(*mock_library_, AsyncCheckKey(username_, _, _))
    712       .Times(1)
    713       .RetiresOnSaturation();
    714   EXPECT_CALL(*mock_library_, GetSystemSalt())
    715       .WillOnce(Return(CryptohomeBlob(2, 0)))
    716       .RetiresOnSaturation();
    717 
    718   // Deal with getting the localaccount file
    719   FilePath tmp_file_path = FakeLocalaccountFile(username_);
    720   ReadLocalaccountFile(auth_.get(), tmp_file_path.BaseName().value());
    721 
    722   auth_->AuthenticateToUnlock(username_, "");
    723   message_loop_.Run();
    724 
    725   Delete(tmp_file_path, false);
    726 }
    727 
    728 }  // namespace chromeos
    729