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.
5 #include "chrome/browser/chromeos/login/parallel_authenticator.h"
9 #include "base/command_line.h"
10 #include "base/file_util.h"
11 #include "base/files/file_path.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.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/chromeos_switches.h"
27 #include "chromeos/cryptohome/mock_async_method_caller.h"
28 #include "chromeos/cryptohome/system_salt_getter.h"
29 #include "chromeos/dbus/fake_cryptohome_client.h"
30 #include "chromeos/dbus/fake_dbus_thread_manager.h"
31 #include "content/public/test/test_browser_thread_bundle.h"
32 #include "google_apis/gaia/mock_url_fetcher_factory.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"
40 using ::testing::Invoke;
41 using ::testing::Return;
46 class ParallelAuthenticatorTest : public testing::Test {
48 ParallelAuthenticatorTest()
49 : username_("me@nowhere.org"),
50 password_("fakepass"),
51 hash_ascii_(ParallelAuthenticator::HashPassword(
53 SystemSaltGetter::ConvertRawSaltToHexString(
54 FakeCryptohomeClient::GetStubSystemSalt()))),
55 user_manager_enabler_(new MockUserManager),
59 virtual ~ParallelAuthenticatorTest() {
60 DCHECK(!mock_caller_);
63 virtual void SetUp() {
64 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kLoginManager);
66 mock_caller_ = new cryptohome::MockAsyncMethodCaller;
67 cryptohome::AsyncMethodCaller::InitializeForTesting(mock_caller_);
69 FakeDBusThreadManager* fake_dbus_thread_manager = new FakeDBusThreadManager;
70 fake_cryptohome_client_ = new FakeCryptohomeClient;
71 fake_dbus_thread_manager->SetCryptohomeClient(
72 scoped_ptr<CryptohomeClient>(fake_cryptohome_client_));
73 DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager);
75 SystemSaltGetter::Initialize();
77 auth_ = new ParallelAuthenticator(&consumer_);
78 state_.reset(new TestAttemptState(UserContext(username_,
83 User::USER_TYPE_REGULAR,
87 // Tears down the test fixture.
88 virtual void TearDown() {
89 SystemSaltGetter::Shutdown();
90 DBusThreadManager::Shutdown();
92 cryptohome::AsyncMethodCaller::Shutdown();
96 base::FilePath PopulateTempFile(const char* data, int data_len) {
98 FILE* tmp_file = base::CreateAndOpenTemporaryFile(&out);
99 EXPECT_NE(tmp_file, static_cast<FILE*>(NULL));
100 EXPECT_EQ(file_util::WriteFile(out, data, data_len), data_len);
101 EXPECT_TRUE(base::CloseFile(tmp_file));
105 // Allow test to fail and exit gracefully, even if OnLoginFailure()
106 // wasn't supposed to happen.
107 void FailOnLoginFailure() {
108 ON_CALL(consumer_, OnLoginFailure(_))
109 .WillByDefault(Invoke(MockConsumer::OnFailQuitAndFail));
112 // Allow test to fail and exit gracefully, even if
113 // OnRetailModeLoginSuccess() wasn't supposed to happen.
114 void FailOnRetailModeLoginSuccess() {
115 ON_CALL(consumer_, OnRetailModeLoginSuccess(_))
116 .WillByDefault(Invoke(MockConsumer::OnRetailModeSuccessQuitAndFail));
119 // Allow test to fail and exit gracefully, even if OnLoginSuccess()
120 // wasn't supposed to happen.
121 void FailOnLoginSuccess() {
122 ON_CALL(consumer_, OnLoginSuccess(_))
123 .WillByDefault(Invoke(MockConsumer::OnSuccessQuitAndFail));
126 // Allow test to fail and exit gracefully, even if
127 // OnOffTheRecordLoginSuccess() wasn't supposed to happen.
128 void FailOnGuestLoginSuccess() {
129 ON_CALL(consumer_, OnOffTheRecordLoginSuccess())
130 .WillByDefault(Invoke(MockConsumer::OnGuestSuccessQuitAndFail));
133 void ExpectLoginFailure(const LoginFailure& failure) {
134 EXPECT_CALL(consumer_, OnLoginFailure(failure))
135 .WillOnce(Invoke(MockConsumer::OnFailQuit))
136 .RetiresOnSaturation();
139 void ExpectRetailModeLoginSuccess() {
140 EXPECT_CALL(consumer_, OnRetailModeLoginSuccess(_))
141 .WillOnce(Invoke(MockConsumer::OnRetailModeSuccessQuit))
142 .RetiresOnSaturation();
145 void ExpectLoginSuccess(const std::string& username,
146 const std::string& password,
147 const std::string& username_hash_,
149 EXPECT_CALL(consumer_, OnLoginSuccess(UserContext(
155 UserContext::AUTH_FLOW_OFFLINE)))
156 .WillOnce(Invoke(MockConsumer::OnSuccessQuit))
157 .RetiresOnSaturation();
160 void ExpectGuestLoginSuccess() {
161 EXPECT_CALL(consumer_, OnOffTheRecordLoginSuccess())
162 .WillOnce(Invoke(MockConsumer::OnGuestSuccessQuit))
163 .RetiresOnSaturation();
166 void ExpectPasswordChange() {
167 EXPECT_CALL(consumer_, OnPasswordChangeDetected())
168 .WillOnce(Invoke(MockConsumer::OnMigrateQuit))
169 .RetiresOnSaturation();
172 void RunResolve(ParallelAuthenticator* auth) {
174 base::MessageLoop::current()->RunUntilIdle();
177 void SetAttemptState(ParallelAuthenticator* auth, TestAttemptState* state) {
178 auth->set_attempt_state(state);
181 ParallelAuthenticator::AuthState SetAndResolveState(
182 ParallelAuthenticator* auth, TestAttemptState* state) {
183 auth->set_attempt_state(state);
184 return auth->ResolveState();
187 void SetOwnerState(bool owner_check_finished, bool check_result) {
188 auth_->SetOwnerState(owner_check_finished, check_result);
191 content::TestBrowserThreadBundle thread_bundle_;
193 std::string username_;
194 std::string password_;
195 std::string username_hash_;
196 std::string hash_ascii_;
198 ScopedDeviceSettingsTestHelper device_settings_test_helper_;
199 ScopedTestCrosSettings test_cros_settings_;
201 ScopedUserManagerEnabler user_manager_enabler_;
203 cryptohome::MockAsyncMethodCaller* mock_caller_;
205 MockConsumer consumer_;
206 scoped_refptr<ParallelAuthenticator> auth_;
207 scoped_ptr<TestAttemptState> state_;
208 FakeCryptohomeClient* fake_cryptohome_client_;
211 TEST_F(ParallelAuthenticatorTest, OnLoginSuccess) {
212 EXPECT_CALL(consumer_, OnLoginSuccess(UserContext(
218 UserContext::AUTH_FLOW_OFFLINE)))
220 .RetiresOnSaturation();
222 SetAttemptState(auth_.get(), state_.release());
223 auth_->OnLoginSuccess();
226 TEST_F(ParallelAuthenticatorTest, OnPasswordChangeDetected) {
227 EXPECT_CALL(consumer_, OnPasswordChangeDetected())
229 .RetiresOnSaturation();
230 SetAttemptState(auth_.get(), state_.release());
231 auth_->OnPasswordChangeDetected();
234 TEST_F(ParallelAuthenticatorTest, ResolveNothingDone) {
235 EXPECT_EQ(ParallelAuthenticator::CONTINUE,
236 SetAndResolveState(auth_.get(), state_.release()));
240 TEST_F(ParallelAuthenticatorTest, ResolvePossiblePwChangeToFailedMount) {
241 // Set up state as though a cryptohome mount attempt has occurred
242 // and been rejected.
243 state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE);
245 // When there is no online attempt and online results, POSSIBLE_PW_CHANGE
246 EXPECT_EQ(ParallelAuthenticator::FAILED_MOUNT,
247 SetAndResolveState(auth_.get(), state_.release()));
250 TEST_F(ParallelAuthenticatorTest, ResolveNeedOldPw) {
251 // Set up state as though a cryptohome mount attempt has occurred
252 // and been rejected because of unmatched key; additionally,
253 // an online auth attempt has completed successfully.
254 state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE);
255 state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
257 EXPECT_EQ(ParallelAuthenticator::NEED_OLD_PW,
258 SetAndResolveState(auth_.get(), state_.release()));
261 TEST_F(ParallelAuthenticatorTest, ResolveOwnerNeededDirectFailedMount) {
262 // Set up state as though a cryptohome mount attempt has occurred
263 // and succeeded but we are in safe mode and the current user is not owner.
264 // This is a high level test to verify the proper transitioning in this mode
265 // only. It is not testing that we properly verify that the user is an owner
266 // or that we really are in "safe-mode".
267 state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
268 SetOwnerState(true, false);
270 EXPECT_EQ(ParallelAuthenticator::OWNER_REQUIRED,
271 SetAndResolveState(auth_.get(), state_.release()));
274 TEST_F(ParallelAuthenticatorTest, ResolveOwnerNeededMount) {
275 // Set up state as though a cryptohome mount attempt has occurred
276 // and succeeded but we are in safe mode and the current user is not owner.
277 // This test will check that the "safe-mode" policy is not set and will let
278 // the mount finish successfully.
279 state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
280 SetOwnerState(false, false);
281 // and test that the mount has succeeded.
282 state_.reset(new TestAttemptState(UserContext(username_,
287 User::USER_TYPE_REGULAR,
289 state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
290 EXPECT_EQ(ParallelAuthenticator::OFFLINE_LOGIN,
291 SetAndResolveState(auth_.get(), state_.release()));
294 TEST_F(ParallelAuthenticatorTest, ResolveOwnerNeededFailedMount) {
295 FailOnLoginSuccess(); // Set failing on success as the default...
296 LoginFailure failure = LoginFailure(LoginFailure::OWNER_REQUIRED);
297 ExpectLoginFailure(failure);
299 fake_cryptohome_client_->set_unmount_result(true);
301 CrosSettingsProvider* device_settings_provider;
302 StubCrosSettingsProvider stub_settings_provider;
303 // Set up state as though a cryptohome mount attempt has occurred
304 // and succeeded but we are in safe mode and the current user is not owner.
305 state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
306 SetOwnerState(false, false);
307 // Remove the real DeviceSettingsProvider and replace it with a stub.
308 device_settings_provider =
309 CrosSettings::Get()->GetProvider(chromeos::kReportDeviceVersionInfo);
310 EXPECT_TRUE(device_settings_provider != NULL);
312 CrosSettings::Get()->RemoveSettingsProvider(device_settings_provider));
313 CrosSettings::Get()->AddSettingsProvider(&stub_settings_provider);
314 CrosSettings::Get()->SetBoolean(kPolicyMissingMitigationMode, true);
316 // Initialize login state for this test to verify the login state is changed
318 LoginState::Initialize();
320 EXPECT_EQ(ParallelAuthenticator::CONTINUE,
321 SetAndResolveState(auth_.get(), state_.release()));
322 EXPECT_TRUE(LoginState::Get()->IsInSafeMode());
324 // Simulate TPM token ready event.
325 DeviceSettingsService::Get()->OnTPMTokenReady();
327 // Flush all the pending operations. The operations should induce an owner
329 device_settings_test_helper_.Flush();
330 // and test that the mount has succeeded.
331 state_.reset(new TestAttemptState(UserContext(username_,
336 User::USER_TYPE_REGULAR,
338 state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
339 EXPECT_EQ(ParallelAuthenticator::OWNER_REQUIRED,
340 SetAndResolveState(auth_.get(), state_.release()));
342 // Unset global objects used by this test.
343 LoginState::Shutdown();
345 CrosSettings::Get()->RemoveSettingsProvider(&stub_settings_provider));
346 CrosSettings::Get()->AddSettingsProvider(device_settings_provider);
349 TEST_F(ParallelAuthenticatorTest, DriveFailedMount) {
350 FailOnLoginSuccess();
351 ExpectLoginFailure(LoginFailure(LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME));
353 // Set up state as though a cryptohome mount attempt has occurred
355 state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_NONE);
356 SetAttemptState(auth_.get(), state_.release());
358 RunResolve(auth_.get());
361 TEST_F(ParallelAuthenticatorTest, DriveGuestLogin) {
362 ExpectGuestLoginSuccess();
363 FailOnLoginFailure();
365 // Set up mock async method caller to respond as though a tmpfs mount
366 // attempt has occurred and succeeded.
367 mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
368 EXPECT_CALL(*mock_caller_, AsyncMountGuest(_))
370 .RetiresOnSaturation();
372 auth_->LoginOffTheRecord();
373 base::MessageLoop::current()->Run();
376 TEST_F(ParallelAuthenticatorTest, DriveGuestLoginButFail) {
377 FailOnGuestLoginSuccess();
378 ExpectLoginFailure(LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS));
380 // Set up mock async method caller to respond as though a tmpfs mount
381 // attempt has occurred and failed.
382 mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_NONE);
383 EXPECT_CALL(*mock_caller_, AsyncMountGuest(_))
385 .RetiresOnSaturation();
387 auth_->LoginOffTheRecord();
388 base::MessageLoop::current()->Run();
391 TEST_F(ParallelAuthenticatorTest, DriveRetailModeUserLogin) {
392 ExpectRetailModeLoginSuccess();
393 FailOnLoginFailure();
395 // Set up mock async method caller to respond as though a tmpfs mount
396 // attempt has occurred and succeeded.
397 mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
398 EXPECT_CALL(*mock_caller_, AsyncMountGuest(_))
400 .RetiresOnSaturation();
402 auth_->LoginRetailMode();
403 base::MessageLoop::current()->Run();
406 TEST_F(ParallelAuthenticatorTest, DriveRetailModeLoginButFail) {
407 FailOnRetailModeLoginSuccess();
408 ExpectLoginFailure(LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS));
410 // Set up mock async method caller to respond as though a tmpfs mount
411 // attempt has occurred and failed.
412 mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_NONE);
413 EXPECT_CALL(*mock_caller_, AsyncMountGuest(_))
415 .RetiresOnSaturation();
417 auth_->LoginRetailMode();
418 base::MessageLoop::current()->Run();
421 TEST_F(ParallelAuthenticatorTest, DriveDataResync) {
422 ExpectLoginSuccess(username_,
424 cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername,
426 FailOnLoginFailure();
428 // Set up mock async method caller to respond successfully to a cryptohome
429 // remove attempt and a cryptohome create attempt (indicated by the
430 // |CREATE_IF_MISSING| flag to AsyncMount).
431 mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
432 EXPECT_CALL(*mock_caller_, AsyncRemove(username_, _))
434 .RetiresOnSaturation();
435 EXPECT_CALL(*mock_caller_, AsyncMount(username_, hash_ascii_,
436 cryptohome::CREATE_IF_MISSING, _))
438 .RetiresOnSaturation();
439 EXPECT_CALL(*mock_caller_, AsyncGetSanitizedUsername(username_, _))
441 .RetiresOnSaturation();
443 state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
444 SetAttemptState(auth_.get(), state_.release());
446 auth_->ResyncEncryptedData();
447 base::MessageLoop::current()->Run();
450 TEST_F(ParallelAuthenticatorTest, DriveResyncFail) {
451 FailOnLoginSuccess();
452 ExpectLoginFailure(LoginFailure(LoginFailure::DATA_REMOVAL_FAILED));
454 // Set up mock async method caller to fail a cryptohome remove attempt.
455 mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_NONE);
456 EXPECT_CALL(*mock_caller_, AsyncRemove(username_, _))
458 .RetiresOnSaturation();
460 SetAttemptState(auth_.get(), state_.release());
462 auth_->ResyncEncryptedData();
463 base::MessageLoop::current()->Run();
466 TEST_F(ParallelAuthenticatorTest, DriveRequestOldPassword) {
467 FailOnLoginSuccess();
468 ExpectPasswordChange();
470 state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE);
471 state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
472 SetAttemptState(auth_.get(), state_.release());
474 RunResolve(auth_.get());
477 TEST_F(ParallelAuthenticatorTest, DriveDataRecover) {
478 ExpectLoginSuccess(username_,
480 cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername,
482 FailOnLoginFailure();
484 // Set up mock async method caller to respond successfully to a key migration.
485 mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
486 EXPECT_CALL(*mock_caller_, AsyncMigrateKey(username_, _, hash_ascii_, _))
488 .RetiresOnSaturation();
489 EXPECT_CALL(*mock_caller_, AsyncMount(username_, hash_ascii_,
490 cryptohome::MOUNT_FLAGS_NONE, _))
492 .RetiresOnSaturation();
493 EXPECT_CALL(*mock_caller_, AsyncGetSanitizedUsername(username_, _))
495 .RetiresOnSaturation();
497 state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
498 SetAttemptState(auth_.get(), state_.release());
500 auth_->RecoverEncryptedData(std::string());
501 base::MessageLoop::current()->Run();
504 TEST_F(ParallelAuthenticatorTest, DriveDataRecoverButFail) {
505 FailOnLoginSuccess();
506 ExpectPasswordChange();
508 // Set up mock async method caller to fail a key migration attempt,
509 // asserting that the wrong password was used.
510 mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_KEY_FAILURE);
511 EXPECT_CALL(*mock_caller_, AsyncMigrateKey(username_, _, hash_ascii_, _))
513 .RetiresOnSaturation();
515 SetAttemptState(auth_.get(), state_.release());
517 auth_->RecoverEncryptedData(std::string());
518 base::MessageLoop::current()->Run();
521 TEST_F(ParallelAuthenticatorTest, ResolveNoMountToFailedMount) {
522 // Set up state as though a cryptohome mount attempt has occurred
523 // and been rejected because the user doesn't exist.
524 state_->PresetCryptohomeStatus(false,
525 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST);
527 // When there is no online attempt and online results, NO_MOUNT will be
528 // resolved to FAILED_MOUNT.
529 EXPECT_EQ(ParallelAuthenticator::FAILED_MOUNT,
530 SetAndResolveState(auth_.get(), state_.release()));
533 TEST_F(ParallelAuthenticatorTest, ResolveCreateNew) {
534 // Set up state as though a cryptohome mount attempt has occurred
535 // and been rejected because the user doesn't exist; additionally,
536 // an online auth attempt has completed successfully.
537 state_->PresetCryptohomeStatus(false,
538 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST);
539 state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
541 EXPECT_EQ(ParallelAuthenticator::CREATE_NEW,
542 SetAndResolveState(auth_.get(), state_.release()));
545 TEST_F(ParallelAuthenticatorTest, DriveCreateForNewUser) {
546 ExpectLoginSuccess(username_,
548 cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername,
550 FailOnLoginFailure();
552 // Set up mock async method caller to respond successfully to a cryptohome
553 // create attempt (indicated by the |CREATE_IF_MISSING| flag to AsyncMount).
554 mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
555 EXPECT_CALL(*mock_caller_, AsyncMount(username_, hash_ascii_,
556 cryptohome::CREATE_IF_MISSING, _))
558 .RetiresOnSaturation();
559 EXPECT_CALL(*mock_caller_, AsyncGetSanitizedUsername(username_, _))
561 .RetiresOnSaturation();
563 // Set up state as though a cryptohome mount attempt has occurred
564 // and been rejected because the user doesn't exist; additionally,
565 // an online auth attempt has completed successfully.
566 state_->PresetCryptohomeStatus(false,
567 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST);
568 state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
569 SetAttemptState(auth_.get(), state_.release());
571 RunResolve(auth_.get());
574 TEST_F(ParallelAuthenticatorTest, DriveOfflineLogin) {
575 ExpectLoginSuccess(username_, password_, username_hash_, false);
576 FailOnLoginFailure();
578 // Set up state as though a cryptohome mount attempt has occurred and
580 state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
581 SetAttemptState(auth_.get(), state_.release());
583 RunResolve(auth_.get());
586 TEST_F(ParallelAuthenticatorTest, DriveOnlineLogin) {
587 ExpectLoginSuccess(username_, password_, username_hash_, false);
588 FailOnLoginFailure();
590 // Set up state as though a cryptohome mount attempt has occurred and
592 state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE);
593 state_->PresetOnlineLoginStatus(LoginFailure::LoginFailureNone());
594 SetAttemptState(auth_.get(), state_.release());
596 RunResolve(auth_.get());
599 TEST_F(ParallelAuthenticatorTest, DriveUnlock) {
600 ExpectLoginSuccess(username_, std::string(), std::string(), false);
601 FailOnLoginFailure();
603 // Set up mock async method caller to respond successfully to a cryptohome
604 // key-check attempt.
605 mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
606 EXPECT_CALL(*mock_caller_, AsyncCheckKey(username_, _, _))
608 .RetiresOnSaturation();
610 auth_->AuthenticateToUnlock(UserContext(username_,
613 base::MessageLoop::current()->Run();
616 } // namespace chromeos