parallel_authenticator_unittest.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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.h"
13#include "base/string_util.h"
14#include "base/stringprintf.h"
15#include "chrome/browser/chromeos/cros/cros_library.h"
16#include "chrome/browser/chromeos/cros/mock_cert_library.h"
17#include "chrome/browser/chromeos/cros/mock_cryptohome_library.h"
18#include "chrome/browser/chromeos/login/mock_login_status_consumer.h"
19#include "chrome/browser/chromeos/login/mock_url_fetchers.h"
20#include "chrome/browser/chromeos/login/mock_user_manager.h"
21#include "chrome/browser/chromeos/login/test_attempt_state.h"
22#include "chrome/browser/chromeos/login/user.h"
23#include "chrome/browser/chromeos/settings/cros_settings.h"
24#include "chrome/browser/chromeos/settings/device_settings_test_helper.h"
25#include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
26#include "chrome/test/base/testing_profile.h"
27#include "chromeos/cryptohome/mock_async_method_caller.h"
28#include "chromeos/dbus/mock_cryptohome_client.h"
29#include "chromeos/dbus/mock_dbus_thread_manager.h"
30#include "content/public/test/test_browser_thread.h"
31#include "google_apis/gaia/mock_url_fetcher_factory.h"
32#include "googleurl/src/gurl.h"
33#include "net/base/net_errors.h"
34#include "net/url_request/url_request_status.h"
35#include "testing/gmock/include/gmock/gmock.h"
36#include "testing/gtest/include/gtest/gtest.h"
37#include "third_party/cros_system_api/dbus/service_constants.h"
38
39using ::testing::AnyNumber;
40using ::testing::DoAll;
41using ::testing::Invoke;
42using ::testing::Return;
43using ::testing::SetArgPointee;
44using ::testing::_;
45using content::BrowserThread;
46
47namespace chromeos {
48
49class TestOnlineAttempt : public OnlineAttempt {
50 public:
51  TestOnlineAttempt(AuthAttemptState* state,
52                    AuthAttemptStateResolver* resolver)
53      : OnlineAttempt(state, resolver) {
54  }
55};
56
57class ParallelAuthenticatorTest : public testing::Test {
58 public:
59  ParallelAuthenticatorTest()
60      : message_loop_(MessageLoop::TYPE_UI),
61        ui_thread_(BrowserThread::UI, &message_loop_),
62        file_thread_(BrowserThread::FILE, &message_loop_),
63        io_thread_(BrowserThread::IO),
64        username_("me@nowhere.org"),
65        password_("fakepass") {
66    hash_ascii_.assign("0a010000000000a0");
67    hash_ascii_.append(std::string(16, '0'));
68  }
69
70  virtual ~ParallelAuthenticatorTest() {
71    DCHECK(!mock_caller_);
72  }
73
74  virtual void SetUp() {
75    mock_caller_ = new cryptohome::MockAsyncMethodCaller;
76    cryptohome::AsyncMethodCaller::InitializeForTesting(mock_caller_);
77
78    chromeos::CrosLibrary::TestApi* test_api =
79        chromeos::CrosLibrary::Get()->GetTestApi();
80
81    mock_cryptohome_library_ = new MockCryptohomeLibrary();
82    test_api->SetCryptohomeLibrary(mock_cryptohome_library_, true);
83
84    mock_cert_library_ = new MockCertLibrary();
85    EXPECT_CALL(*mock_cert_library_, LoadKeyStore()).Times(AnyNumber());
86    test_api->SetCertLibrary(mock_cert_library_, true);
87
88    io_thread_.Start();
89
90    auth_ = new ParallelAuthenticator(&consumer_);
91    auth_->set_using_oauth(false);
92    state_.reset(new TestAttemptState(UserCredentials(username_,
93                                                      password_,
94                                                      std::string()),
95                                      hash_ascii_,
96                                      "",
97                                      "",
98                                      User::USER_TYPE_REGULAR,
99                                      false));
100  }
101
102  // Tears down the test fixture.
103  virtual void TearDown() {
104    // Prevent bogus gMock leak check from firing.
105    chromeos::CrosLibrary::TestApi* test_api =
106        chromeos::CrosLibrary::Get()->GetTestApi();
107    test_api->SetCryptohomeLibrary(NULL, false);
108
109    cryptohome::AsyncMethodCaller::Shutdown();
110    mock_caller_ = NULL;
111  }
112
113  base::FilePath PopulateTempFile(const char* data, int data_len) {
114    base::FilePath out;
115    FILE* tmp_file = file_util::CreateAndOpenTemporaryFile(&out);
116    EXPECT_NE(tmp_file, static_cast<FILE*>(NULL));
117    EXPECT_EQ(file_util::WriteFile(out, data, data_len), data_len);
118    EXPECT_TRUE(file_util::CloseFile(tmp_file));
119    return out;
120  }
121
122  // Allow test to fail and exit gracefully, even if OnLoginFailure()
123  // wasn't supposed to happen.
124  void FailOnLoginFailure() {
125    ON_CALL(consumer_, OnLoginFailure(_))
126        .WillByDefault(Invoke(MockConsumer::OnFailQuitAndFail));
127  }
128
129  // Allow test to fail and exit gracefully, even if
130  // OnRetailModeLoginSuccess() wasn't supposed to happen.
131  void FailOnRetailModeLoginSuccess() {
132    ON_CALL(consumer_, OnRetailModeLoginSuccess())
133        .WillByDefault(Invoke(MockConsumer::OnRetailModeSuccessQuitAndFail));
134  }
135
136  // Allow test to fail and exit gracefully, even if OnLoginSuccess()
137  // wasn't supposed to happen.
138  void FailOnLoginSuccess() {
139    ON_CALL(consumer_, OnLoginSuccess(_, _, _))
140        .WillByDefault(Invoke(MockConsumer::OnSuccessQuitAndFail));
141  }
142
143  // Allow test to fail and exit gracefully, even if
144  // OnOffTheRecordLoginSuccess() wasn't supposed to happen.
145  void FailOnGuestLoginSuccess() {
146    ON_CALL(consumer_, OnOffTheRecordLoginSuccess())
147        .WillByDefault(Invoke(MockConsumer::OnGuestSuccessQuitAndFail));
148  }
149
150  void ExpectLoginFailure(const LoginFailure& failure) {
151    EXPECT_CALL(consumer_, OnLoginFailure(failure))
152        .WillOnce(Invoke(MockConsumer::OnFailQuit))
153        .RetiresOnSaturation();
154  }
155
156  void ExpectRetailModeLoginSuccess() {
157    EXPECT_CALL(consumer_, OnRetailModeLoginSuccess())
158        .WillOnce(Invoke(MockConsumer::OnRetailModeSuccessQuit))
159        .RetiresOnSaturation();
160  }
161
162  void ExpectLoginSuccess(const std::string& username,
163                          const std::string& password,
164                          bool pending) {
165    EXPECT_CALL(consumer_, OnLoginSuccess(UserCredentials(username,
166                                                          password,
167                                                          std::string()),
168                                          pending,
169                                          false))
170        .WillOnce(Invoke(MockConsumer::OnSuccessQuit))
171        .RetiresOnSaturation();
172  }
173
174  void ExpectGuestLoginSuccess() {
175    EXPECT_CALL(consumer_, OnOffTheRecordLoginSuccess())
176        .WillOnce(Invoke(MockConsumer::OnGuestSuccessQuit))
177        .RetiresOnSaturation();
178  }
179
180  void ExpectPasswordChange() {
181    EXPECT_CALL(consumer_, OnPasswordChangeDetected())
182        .WillOnce(Invoke(MockConsumer::OnMigrateQuit))
183        .RetiresOnSaturation();
184  }
185
186  void RunResolve(ParallelAuthenticator* auth) {
187    auth->Resolve();
188    message_loop_.RunUntilIdle();
189  }
190
191  void SetAttemptState(ParallelAuthenticator* auth, TestAttemptState* state) {
192    auth->set_attempt_state(state);
193  }
194
195  ParallelAuthenticator::AuthState SetAndResolveState(
196      ParallelAuthenticator* auth, TestAttemptState* state) {
197    auth->set_attempt_state(state);
198    return auth->ResolveState();
199  }
200
201  void SetOwnerState(bool owner_check_finished, bool check_result) {
202    auth_->SetOwnerState(owner_check_finished, check_result);
203  }
204
205  void FakeOnlineAttempt() {
206    auth_->set_online_attempt(new TestOnlineAttempt(state_.get(), auth_.get()));
207  }
208
209  MessageLoop message_loop_;
210  content::TestBrowserThread ui_thread_;
211  content::TestBrowserThread file_thread_;
212  content::TestBrowserThread io_thread_;
213
214  std::string username_;
215  std::string password_;
216  std::string hash_ascii_;
217
218  ScopedDeviceSettingsTestHelper device_settings_test_helper_;
219
220  // Initializes / shuts down a stub CrosLibrary.
221  ScopedStubCrosEnabler stub_cros_enabler_;
222
223  // Mocks, destroyed by CrosLibrary class.
224  MockCertLibrary* mock_cert_library_;
225  MockCryptohomeLibrary* mock_cryptohome_library_;
226  ScopedMockUserManagerEnabler mock_user_manager_;
227
228  cryptohome::MockAsyncMethodCaller* mock_caller_;
229
230  MockConsumer consumer_;
231  scoped_refptr<ParallelAuthenticator> auth_;
232  scoped_ptr<TestAttemptState> state_;
233};
234
235TEST_F(ParallelAuthenticatorTest, OnLoginSuccess) {
236  EXPECT_CALL(consumer_, OnLoginSuccess(UserCredentials(username_,
237                                                        password_,
238                                                        std::string()),
239                                        false, false))
240      .Times(1)
241      .RetiresOnSaturation();
242
243  SetAttemptState(auth_, state_.release());
244  auth_->OnLoginSuccess(false);
245}
246
247TEST_F(ParallelAuthenticatorTest, OnPasswordChangeDetected) {
248  EXPECT_CALL(consumer_, OnPasswordChangeDetected())
249      .Times(1)
250      .RetiresOnSaturation();
251  SetAttemptState(auth_, state_.release());
252  auth_->OnPasswordChangeDetected();
253}
254
255TEST_F(ParallelAuthenticatorTest, ResolveNothingDone) {
256  EXPECT_EQ(ParallelAuthenticator::CONTINUE,
257            SetAndResolveState(auth_, state_.release()));
258}
259
260TEST_F(ParallelAuthenticatorTest, ResolvePossiblePwChange) {
261  // Set a fake online attempt so that we return intermediate cryptohome state.
262  FakeOnlineAttempt();
263
264  // Set up state as though a cryptohome mount attempt has occurred
265  // and been rejected.
266  state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE);
267
268  EXPECT_EQ(ParallelAuthenticator::POSSIBLE_PW_CHANGE,
269            SetAndResolveState(auth_, state_.release()));
270}
271
272TEST_F(ParallelAuthenticatorTest, ResolvePossiblePwChangeToFailedMount) {
273  // Set up state as though a cryptohome mount attempt has occurred
274  // and been rejected.
275  state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE);
276
277  // When there is no online attempt and online results, POSSIBLE_PW_CHANGE
278  EXPECT_EQ(ParallelAuthenticator::FAILED_MOUNT,
279            SetAndResolveState(auth_, state_.release()));
280}
281
282TEST_F(ParallelAuthenticatorTest, ResolveNeedOldPw) {
283  // Set up state as though a cryptohome mount attempt has occurred
284  // and been rejected because of unmatched key; additionally,
285  // an online auth attempt has completed successfully.
286  state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE);
287  state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
288
289  EXPECT_EQ(ParallelAuthenticator::NEED_OLD_PW,
290            SetAndResolveState(auth_, state_.release()));
291}
292
293TEST_F(ParallelAuthenticatorTest, ResolveOwnerNeededDirectFailedMount) {
294  // Set up state as though a cryptohome mount attempt has occurred
295  // and succeeded but we are in safe mode and the current user is not owner.
296  // This is a high level test to verify the proper transitioning in this mode
297  // only. It is not testing that we properly verify that the user is an owner
298  // or that we really are in "safe-mode".
299  state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
300  SetOwnerState(true, false);
301
302  EXPECT_EQ(ParallelAuthenticator::OWNER_REQUIRED,
303            SetAndResolveState(auth_, state_.release()));
304}
305
306TEST_F(ParallelAuthenticatorTest, ResolveOwnerNeededMount) {
307  // Set up state as though a cryptohome mount attempt has occurred
308  // and succeeded but we are in safe mode and the current user is not owner.
309  // This test will check that the "safe-mode" policy is not set and will let
310  // the mount finish successfully.
311  state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
312  SetOwnerState(false, false);
313  // and test that the mount has succeeded.
314  state_.reset(new TestAttemptState(UserCredentials(username_,
315                                                    password_,
316                                                    std::string()),
317                                    hash_ascii_,
318                                    "",
319                                    "",
320                                    User::USER_TYPE_REGULAR,
321                                    false));
322  state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
323  EXPECT_EQ(ParallelAuthenticator::OFFLINE_LOGIN,
324            SetAndResolveState(auth_, state_.release()));
325}
326
327TEST_F(ParallelAuthenticatorTest, ResolveOwnerNeededFailedMount) {
328  FailOnLoginSuccess();  // Set failing on success as the default...
329  LoginFailure failure = LoginFailure(LoginFailure::OWNER_REQUIRED);
330  ExpectLoginFailure(failure);
331
332  MockDBusThreadManager* mock_dbus_thread_manager =
333      new MockDBusThreadManager;
334  EXPECT_CALL(*mock_dbus_thread_manager, GetSystemBus())
335      .WillRepeatedly(Return(reinterpret_cast<dbus::Bus*>(NULL)));
336  DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager);
337  EXPECT_CALL(*mock_dbus_thread_manager->mock_cryptohome_client(), Unmount(_))
338      .WillOnce(DoAll(SetArgPointee<0>(true), Return(true)));
339
340  CrosSettingsProvider* device_settings_provider;
341  StubCrosSettingsProvider stub_settings_provider;
342  // Set up state as though a cryptohome mount attempt has occurred
343  // and succeeded but we are in safe mode and the current user is not owner.
344  state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
345  SetOwnerState(false, false);
346  // Remove the real DeviceSettingsProvider and replace it with a stub.
347  device_settings_provider =
348      CrosSettings::Get()->GetProvider(chromeos::kReportDeviceVersionInfo);
349  EXPECT_TRUE(device_settings_provider != NULL);
350  EXPECT_TRUE(
351      CrosSettings::Get()->RemoveSettingsProvider(device_settings_provider));
352  CrosSettings::Get()->AddSettingsProvider(&stub_settings_provider);
353  CrosSettings::Get()->SetBoolean(kPolicyMissingMitigationMode, true);
354
355  EXPECT_EQ(ParallelAuthenticator::CONTINUE,
356            SetAndResolveState(auth_, state_.release()));
357  // Let the owner verification run.
358  device_settings_test_helper_.Flush();
359  // and test that the mount has succeeded.
360  state_.reset(new TestAttemptState(UserCredentials(username_,
361                                                    password_,
362                                                    std::string()),
363                                    hash_ascii_,
364                                    "",
365                                    "",
366                                    User::USER_TYPE_REGULAR,
367                                    false));
368  state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
369  EXPECT_EQ(ParallelAuthenticator::OWNER_REQUIRED,
370            SetAndResolveState(auth_, state_.release()));
371
372  EXPECT_TRUE(
373      CrosSettings::Get()->RemoveSettingsProvider(&stub_settings_provider));
374  CrosSettings::Get()->AddSettingsProvider(device_settings_provider);
375  DBusThreadManager::Get()->Shutdown();
376}
377
378TEST_F(ParallelAuthenticatorTest, DriveFailedMount) {
379  FailOnLoginSuccess();
380  ExpectLoginFailure(LoginFailure(LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME));
381
382  // Set up state as though a cryptohome mount attempt has occurred
383  // and failed.
384  state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_NONE);
385  SetAttemptState(auth_, state_.release());
386
387  RunResolve(auth_.get());
388}
389
390TEST_F(ParallelAuthenticatorTest, DriveGuestLogin) {
391  ExpectGuestLoginSuccess();
392  FailOnLoginFailure();
393
394  // Set up mock cryptohome library to respond as though a tmpfs mount
395  // attempt has occurred and succeeded.
396  mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
397  EXPECT_CALL(*mock_caller_, AsyncMountGuest(_))
398      .Times(1)
399      .RetiresOnSaturation();
400
401  auth_->LoginOffTheRecord();
402  message_loop_.Run();
403}
404
405TEST_F(ParallelAuthenticatorTest, DriveGuestLoginButFail) {
406  FailOnGuestLoginSuccess();
407  ExpectLoginFailure(LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS));
408
409  // Set up mock cryptohome library to respond as though a tmpfs mount
410  // attempt has occurred and failed.
411  mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_NONE);
412  EXPECT_CALL(*mock_caller_, AsyncMountGuest(_))
413      .Times(1)
414      .RetiresOnSaturation();
415
416  auth_->LoginOffTheRecord();
417  message_loop_.Run();
418}
419
420TEST_F(ParallelAuthenticatorTest, DriveRetailModeUserLogin) {
421  ExpectRetailModeLoginSuccess();
422  FailOnLoginFailure();
423
424  // Set up mock cryptohome library to respond as though a tmpfs mount
425  // attempt has occurred and succeeded.
426  mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
427  EXPECT_CALL(*mock_caller_, AsyncMountGuest(_))
428      .Times(1)
429      .RetiresOnSaturation();
430
431  auth_->LoginRetailMode();
432  message_loop_.Run();
433}
434
435TEST_F(ParallelAuthenticatorTest, DriveRetailModeLoginButFail) {
436  FailOnRetailModeLoginSuccess();
437  ExpectLoginFailure(LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS));
438
439  // Set up mock cryptohome library to respond as though a tmpfs mount
440  // attempt has occurred and failed.
441  mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_NONE);
442  EXPECT_CALL(*mock_caller_, AsyncMountGuest(_))
443      .Times(1)
444      .RetiresOnSaturation();
445
446  auth_->LoginRetailMode();
447  message_loop_.Run();
448}
449
450TEST_F(ParallelAuthenticatorTest, DriveDataResync) {
451  ExpectLoginSuccess(username_, password_, false);
452  FailOnLoginFailure();
453
454  // Set up mock cryptohome library to respond successfully to a cryptohome
455  // remove attempt and a cryptohome create attempt (indicated by the
456  // |CREATE_IF_MISSING| flag to AsyncMount).
457  mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
458  EXPECT_CALL(*mock_caller_, AsyncRemove(username_, _))
459      .Times(1)
460      .RetiresOnSaturation();
461  EXPECT_CALL(*mock_caller_, AsyncMount(username_, hash_ascii_,
462                                        cryptohome::CREATE_IF_MISSING, _))
463      .Times(1)
464      .RetiresOnSaturation();
465
466  state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
467  SetAttemptState(auth_, state_.release());
468
469  auth_->ResyncEncryptedData();
470  message_loop_.Run();
471}
472
473TEST_F(ParallelAuthenticatorTest, DriveResyncFail) {
474  FailOnLoginSuccess();
475  ExpectLoginFailure(LoginFailure(LoginFailure::DATA_REMOVAL_FAILED));
476
477  // Set up mock cryptohome library to fail a cryptohome remove attempt.
478  mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_NONE);
479  EXPECT_CALL(*mock_caller_, AsyncRemove(username_, _))
480      .Times(1)
481      .RetiresOnSaturation();
482
483  SetAttemptState(auth_, state_.release());
484
485  auth_->ResyncEncryptedData();
486  message_loop_.Run();
487}
488
489TEST_F(ParallelAuthenticatorTest, DriveRequestOldPassword) {
490  FailOnLoginSuccess();
491  ExpectPasswordChange();
492
493  state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE);
494  state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
495  SetAttemptState(auth_, state_.release());
496
497  RunResolve(auth_.get());
498}
499
500TEST_F(ParallelAuthenticatorTest, DriveDataRecover) {
501  ExpectLoginSuccess(username_, password_, false);
502  FailOnLoginFailure();
503
504  // Set up mock cryptohome library to respond successfully to a key migration.
505  mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
506  EXPECT_CALL(*mock_caller_, AsyncMigrateKey(username_, _, hash_ascii_, _))
507      .Times(1)
508      .RetiresOnSaturation();
509  EXPECT_CALL(*mock_caller_, AsyncMount(username_, hash_ascii_,
510                                        cryptohome::MOUNT_FLAGS_NONE, _))
511      .Times(1)
512      .RetiresOnSaturation();
513  EXPECT_CALL(*mock_cryptohome_library_, GetSystemSalt())
514      .WillOnce(Return(std::string()))
515      .RetiresOnSaturation();
516
517  state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
518  SetAttemptState(auth_, state_.release());
519
520  auth_->RecoverEncryptedData(std::string());
521  message_loop_.Run();
522}
523
524TEST_F(ParallelAuthenticatorTest, DriveDataRecoverButFail) {
525  FailOnLoginSuccess();
526  ExpectPasswordChange();
527
528  // Set up mock cryptohome library to fail a key migration attempt,
529  // asserting that the wrong password was used.
530  mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_KEY_FAILURE);
531  EXPECT_CALL(*mock_caller_, AsyncMigrateKey(username_, _, hash_ascii_, _))
532      .Times(1)
533      .RetiresOnSaturation();
534  EXPECT_CALL(*mock_cryptohome_library_, GetSystemSalt())
535      .WillOnce(Return(std::string()))
536      .RetiresOnSaturation();
537
538  SetAttemptState(auth_, state_.release());
539
540  auth_->RecoverEncryptedData(std::string());
541  message_loop_.Run();
542}
543
544TEST_F(ParallelAuthenticatorTest, ResolveNoMount) {
545  // Set a fake online attempt so that we return intermediate cryptohome state.
546  FakeOnlineAttempt();
547
548  // Set up state as though a cryptohome mount attempt has occurred
549  // and been rejected because the user doesn't exist.
550  state_->PresetCryptohomeStatus(false,
551                                 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST);
552
553  EXPECT_EQ(ParallelAuthenticator::NO_MOUNT,
554            SetAndResolveState(auth_, state_.release()));
555}
556
557TEST_F(ParallelAuthenticatorTest, ResolveNoMountToFailedMount) {
558  // Set up state as though a cryptohome mount attempt has occurred
559  // and been rejected because the user doesn't exist.
560  state_->PresetCryptohomeStatus(false,
561                                 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST);
562
563  // When there is no online attempt and online results, NO_MOUNT will be
564  // resolved to FAILED_MOUNT.
565  EXPECT_EQ(ParallelAuthenticator::FAILED_MOUNT,
566            SetAndResolveState(auth_, state_.release()));
567}
568
569TEST_F(ParallelAuthenticatorTest, ResolveCreateNew) {
570  // Set up state as though a cryptohome mount attempt has occurred
571  // and been rejected because the user doesn't exist; additionally,
572  // an online auth attempt has completed successfully.
573  state_->PresetCryptohomeStatus(false,
574                                 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST);
575  state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
576
577  EXPECT_EQ(ParallelAuthenticator::CREATE_NEW,
578            SetAndResolveState(auth_, state_.release()));
579}
580
581TEST_F(ParallelAuthenticatorTest, DriveCreateForNewUser) {
582  ExpectLoginSuccess(username_, password_, false);
583  FailOnLoginFailure();
584
585  // Set up mock cryptohome library to respond successfully to a cryptohome
586  // create attempt (indicated by the |CREATE_IF_MISSING| flag to AsyncMount).
587  mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
588  EXPECT_CALL(*mock_caller_, AsyncMount(username_, hash_ascii_,
589                                        cryptohome::CREATE_IF_MISSING, _))
590      .Times(1)
591      .RetiresOnSaturation();
592
593  // Set up state as though a cryptohome mount attempt has occurred
594  // and been rejected because the user doesn't exist; additionally,
595  // an online auth attempt has completed successfully.
596  state_->PresetCryptohomeStatus(false,
597                                 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST);
598  state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
599  SetAttemptState(auth_, state_.release());
600
601  RunResolve(auth_.get());
602}
603
604TEST_F(ParallelAuthenticatorTest, DriveOfflineLogin) {
605  ExpectLoginSuccess(username_, password_, false);
606  FailOnLoginFailure();
607
608  // Set up state as though a cryptohome mount attempt has occurred and
609  // succeeded.
610  state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
611  GoogleServiceAuthError error =
612      GoogleServiceAuthError::FromConnectionError(net::ERR_CONNECTION_RESET);
613  state_->PresetOnlineLoginStatus(LoginFailure::FromNetworkAuthFailure(error));
614  SetAttemptState(auth_, state_.release());
615
616  RunResolve(auth_.get());
617}
618
619TEST_F(ParallelAuthenticatorTest, DriveOfflineLoginDelayedOnline) {
620  ExpectLoginSuccess(username_, password_, true);
621  FailOnLoginFailure();
622
623  // Set up state as though a cryptohome mount attempt has occurred and
624  // succeeded.
625  state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
626  // state_ is released further down.
627  SetAttemptState(auth_, state_.get());
628  RunResolve(auth_.get());
629
630  // Offline login has completed, so now we "complete" the online request.
631  GoogleServiceAuthError error(
632      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
633  LoginFailure failure = LoginFailure::FromNetworkAuthFailure(error);
634  state_.release()->PresetOnlineLoginStatus(failure);
635  ExpectLoginFailure(failure);
636
637  RunResolve(auth_.get());
638}
639
640TEST_F(ParallelAuthenticatorTest, DriveOfflineLoginGetNewPassword) {
641  ExpectLoginSuccess(username_, password_, true);
642  FailOnLoginFailure();
643
644  // Set up mock cryptohome library to respond successfully to a key migration.
645  mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
646  EXPECT_CALL(*mock_caller_, AsyncMigrateKey(username_,
647                                              state_->ascii_hash,
648                                              _,
649                                              _))
650      .Times(1)
651      .RetiresOnSaturation();
652  EXPECT_CALL(*mock_cryptohome_library_, GetSystemSalt())
653      .WillOnce(Return(std::string()))
654      .RetiresOnSaturation();
655
656  // Set up state as though a cryptohome mount attempt has occurred and
657  // succeeded; also, an online request that never made it.
658  state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
659  // state_ is released further down.
660  SetAttemptState(auth_, state_.get());
661  RunResolve(auth_.get());
662
663  // Offline login has completed, so now we "complete" the online request.
664  GoogleServiceAuthError error(
665      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
666  LoginFailure failure = LoginFailure::FromNetworkAuthFailure(error);
667  state_.release()->PresetOnlineLoginStatus(failure);
668  ExpectLoginFailure(failure);
669
670  RunResolve(auth_.get());
671
672  // After the request below completes, OnLoginSuccess gets called again.
673  ExpectLoginSuccess(username_, password_, false);
674
675  MockURLFetcherFactory<SuccessFetcher> factory;
676  TestingProfile profile;
677
678  auth_->RetryAuth(&profile,
679                   UserCredentials(username_,
680                                   std::string(),
681                                   std::string()),
682                   std::string(),
683                   std::string());
684  message_loop_.Run();
685  message_loop_.RunUntilIdle();
686}
687
688TEST_F(ParallelAuthenticatorTest, DriveOfflineLoginGetCaptchad) {
689  ExpectLoginSuccess(username_, password_, true);
690  FailOnLoginFailure();
691  EXPECT_CALL(*mock_cryptohome_library_, GetSystemSalt())
692      .WillOnce(Return(std::string()))
693      .RetiresOnSaturation();
694
695  // Set up state as though a cryptohome mount attempt has occurred and
696  // succeeded; also, an online request that never made it.
697  state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
698  // state_ is released further down.
699  SetAttemptState(auth_, state_.get());
700  RunResolve(auth_.get());
701
702  // Offline login has completed, so now we "complete" the online request.
703  GoogleServiceAuthError error(
704      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
705  LoginFailure failure = LoginFailure::FromNetworkAuthFailure(error);
706  state_.release()->PresetOnlineLoginStatus(failure);
707  ExpectLoginFailure(failure);
708
709  RunResolve(auth_.get());
710
711  // After the request below completes, OnLoginSuccess gets called again.
712  failure = LoginFailure::FromNetworkAuthFailure(
713      GoogleServiceAuthError::FromClientLoginCaptchaChallenge(
714          CaptchaFetcher::GetCaptchaToken(),
715          GURL(CaptchaFetcher::GetCaptchaUrl()),
716          GURL(CaptchaFetcher::GetUnlockUrl())));
717  ExpectLoginFailure(failure);
718
719  MockURLFetcherFactory<CaptchaFetcher> factory;
720  TestingProfile profile;
721
722  auth_->RetryAuth(&profile,
723                   UserCredentials(username_,
724                                   std::string(),
725                                   std::string()),
726                   std::string(),
727                   std::string());
728  message_loop_.Run();
729  message_loop_.RunUntilIdle();
730}
731
732TEST_F(ParallelAuthenticatorTest, DriveOnlineLogin) {
733  ExpectLoginSuccess(username_, password_, false);
734  FailOnLoginFailure();
735
736  // Set up state as though a cryptohome mount attempt has occurred and
737  // succeeded.
738  state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
739  state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
740  SetAttemptState(auth_, state_.release());
741
742  RunResolve(auth_.get());
743}
744
745// http://crbug.com/106538
746TEST_F(ParallelAuthenticatorTest, DISABLED_DriveNeedNewPassword) {
747  FailOnLoginSuccess();  // Set failing on success as the default...
748  // ...but expect ONE successful login first.
749  ExpectLoginSuccess(username_, password_, true);
750  GoogleServiceAuthError error(
751      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
752  LoginFailure failure = LoginFailure::FromNetworkAuthFailure(error);
753  ExpectLoginFailure(failure);
754
755  // Set up state as though a cryptohome mount attempt has occurred and
756  // succeeded.
757  state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
758  state_->PresetOnlineLoginStatus(failure);
759  SetAttemptState(auth_, state_.release());
760
761  RunResolve(auth_.get());
762}
763
764TEST_F(ParallelAuthenticatorTest, DriveUnlock) {
765  ExpectLoginSuccess(username_, std::string(), false);
766  FailOnLoginFailure();
767
768  // Set up mock cryptohome library to respond successfully to a cryptohome
769  // key-check attempt.
770  mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
771  EXPECT_CALL(*mock_caller_, AsyncCheckKey(username_, _, _))
772      .Times(1)
773      .RetiresOnSaturation();
774  EXPECT_CALL(*mock_cryptohome_library_, GetSystemSalt())
775      .WillOnce(Return(std::string()))
776      .RetiresOnSaturation();
777
778  auth_->AuthenticateToUnlock(UserCredentials(username_,
779                                              std::string(),
780                                              std::string()));
781  message_loop_.Run();
782}
783
784}  // namespace chromeos
785