1 // Copyright 2014 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/auth/chrome_cryptohome_authenticator.h"
10 #include "base/basictypes.h"
11 #include "base/command_line.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/run_loop.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/stringprintf.h"
19 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
20 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h"
21 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
22 #include "chrome/browser/chromeos/profiles/profile_helper.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/scoped_cros_settings_test_helper.h"
26 #include "chrome/test/base/testing_browser_process.h"
27 #include "chrome/test/base/testing_profile.h"
28 #include "chrome/test/base/testing_profile_manager.h"
29 #include "chromeos/chromeos_switches.h"
30 #include "chromeos/cryptohome/cryptohome_parameters.h"
31 #include "chromeos/cryptohome/homedir_methods.h"
32 #include "chromeos/cryptohome/mock_async_method_caller.h"
33 #include "chromeos/cryptohome/mock_homedir_methods.h"
34 #include "chromeos/cryptohome/system_salt_getter.h"
35 #include "chromeos/dbus/cros_disks_client.h"
36 #include "chromeos/dbus/cryptohome/rpc.pb.h"
37 #include "chromeos/dbus/dbus_thread_manager.h"
38 #include "chromeos/dbus/fake_cryptohome_client.h"
39 #include "chromeos/login/auth/key.h"
40 #include "chromeos/login/auth/mock_auth_status_consumer.h"
41 #include "chromeos/login/auth/mock_url_fetchers.h"
42 #include "chromeos/login/auth/test_attempt_state.h"
43 #include "chromeos/login/auth/user_context.h"
44 #include "chromeos/login/login_state.h"
45 #include "components/ownership/mock_owner_key_util.h"
46 #include "components/user_manager/fake_user_manager.h"
47 #include "content/public/test/test_browser_thread_bundle.h"
48 #include "crypto/nss_key_util.h"
49 #include "crypto/nss_util_internal.h"
50 #include "crypto/scoped_test_nss_chromeos_user.h"
51 #include "google_apis/gaia/mock_url_fetcher_factory.h"
52 #include "net/base/net_errors.h"
53 #include "net/url_request/url_request_status.h"
54 #include "testing/gmock/include/gmock/gmock.h"
55 #include "testing/gtest/include/gtest/gtest.h"
56 #include "third_party/cros_system_api/dbus/service_constants.h"
59 using ::testing::Invoke
;
60 using ::testing::Return
;
61 using ::testing::WithArg
;
68 // Label under which the user's key is stored.
69 const char kCryptohomeGAIAKeyLabel
[] = "gaia";
71 // Salt used by pre-hashed key.
72 const char kSalt
[] = "SALT $$";
74 // An owner key in PKCS#8 PrivateKeyInfo for testing owner checks.
75 const uint8 kOwnerPrivateKey
[] = {
76 0x30, 0x82, 0x01, 0x53, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
77 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
78 0x01, 0x3d, 0x30, 0x82, 0x01, 0x39, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00,
79 0xb4, 0xf5, 0xab, 0xfe, 0xd8, 0xf1, 0xcb, 0x5f, 0x8f, 0x48, 0x3e, 0xdf,
80 0x40, 0x8e, 0x2b, 0x15, 0x43, 0x6c, 0x67, 0x74, 0xa2, 0xcb, 0xe4, 0xf3,
81 0xec, 0xab, 0x41, 0x57, 0x1d, 0x5f, 0xed, 0xcf, 0x09, 0xf4, 0xcc, 0xbb,
82 0x52, 0x52, 0xe8, 0x46, 0xf5, 0xc5, 0x01, 0xa3, 0xd8, 0x24, 0xc0, 0x15,
83 0xc5, 0x65, 0x50, 0x7d, 0xbd, 0x4e, 0x81, 0xb2, 0x28, 0x38, 0xf9, 0x3d,
84 0x3e, 0x2a, 0x68, 0xf7, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x40, 0x40,
85 0xc7, 0xb5, 0xb3, 0xbc, 0xac, 0x0a, 0x77, 0x02, 0x0f, 0x05, 0xda, 0xdb,
86 0xfc, 0x48, 0xf6, 0x0a, 0xb5, 0xf2, 0xef, 0x31, 0x1c, 0x36, 0xb1, 0x0f,
87 0xa7, 0x5a, 0xf3, 0xb9, 0xa3, 0x4e, 0xb8, 0xf6, 0x10, 0xfe, 0x25, 0x7b,
88 0x36, 0xb4, 0x1b, 0x80, 0xe3, 0x92, 0x37, 0x83, 0xf0, 0x43, 0xb3, 0x00,
89 0xa6, 0x53, 0xc6, 0x1b, 0x7e, 0x4b, 0xb0, 0x33, 0xd4, 0xe1, 0x03, 0xc4,
90 0xaa, 0xbc, 0x89, 0x02, 0x21, 0x00, 0xde, 0xc8, 0x8d, 0x10, 0xbc, 0xf3,
91 0x43, 0x49, 0x1f, 0x07, 0xf7, 0x12, 0xeb, 0x0a, 0x90, 0xab, 0xb9, 0xaa,
92 0x81, 0xb5, 0x54, 0x71, 0xf4, 0x2e, 0xc4, 0x44, 0xec, 0xff, 0x7d, 0xff,
93 0xe8, 0xa5, 0x02, 0x21, 0x00, 0xcf, 0xf0, 0xbe, 0xa6, 0xde, 0x9c, 0x70,
94 0xed, 0xf0, 0xc3, 0x18, 0x9b, 0xca, 0xe5, 0x7c, 0x4b, 0x9b, 0xf5, 0x12,
95 0x5d, 0x86, 0xbe, 0x8d, 0xf1, 0xbc, 0x2c, 0x79, 0x59, 0xf5, 0xff, 0xbc,
96 0x6b, 0x02, 0x20, 0x7c, 0x09, 0x1c, 0xc1, 0x1c, 0xf2, 0x33, 0x9c, 0x1a,
97 0x72, 0xcc, 0xd4, 0xf3, 0x97, 0xc6, 0x44, 0x55, 0xf2, 0xe0, 0x94, 0x9c,
98 0x97, 0x75, 0x64, 0x34, 0x52, 0x4b, 0xc1, 0x53, 0xdd, 0x8f, 0x21, 0x02,
99 0x20, 0x0e, 0xef, 0x48, 0x92, 0x2d, 0x9c, 0xe8, 0xd3, 0x7e, 0x1e, 0x55,
100 0x0f, 0x23, 0x74, 0x76, 0x07, 0xec, 0x2c, 0x9e, 0xe4, 0x0e, 0xc0, 0x72,
101 0xeb, 0x70, 0xcb, 0x74, 0xef, 0xcc, 0x26, 0x50, 0xff, 0x02, 0x20, 0x29,
102 0x32, 0xd0, 0xbf, 0x11, 0xf2, 0xbf, 0x54, 0xfd, 0x6d, 0xf2, 0x1c, 0xbe,
103 0x50, 0x18, 0x62, 0x6d, 0x23, 0xe4, 0x26, 0x03, 0x8b, 0xb3, 0x42, 0x24,
104 0x7e, 0x68, 0x37, 0x26, 0xda, 0xb9, 0x87};
106 // The public key alone matcing kOwnerPrivateKey.
107 const uint8 kOwnerPublicKey
[] = {
108 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
109 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
110 0x00, 0xb4, 0xf5, 0xab, 0xfe, 0xd8, 0xf1, 0xcb, 0x5f, 0x8f, 0x48, 0x3e,
111 0xdf, 0x40, 0x8e, 0x2b, 0x15, 0x43, 0x6c, 0x67, 0x74, 0xa2, 0xcb, 0xe4,
112 0xf3, 0xec, 0xab, 0x41, 0x57, 0x1d, 0x5f, 0xed, 0xcf, 0x09, 0xf4, 0xcc,
113 0xbb, 0x52, 0x52, 0xe8, 0x46, 0xf5, 0xc5, 0x01, 0xa3, 0xd8, 0x24, 0xc0,
114 0x15, 0xc5, 0x65, 0x50, 0x7d, 0xbd, 0x4e, 0x81, 0xb2, 0x28, 0x38, 0xf9,
115 0x3d, 0x3e, 0x2a, 0x68, 0xf7, 0x02, 0x03, 0x01, 0x00, 0x01};
117 std::vector
<uint8
> GetOwnerPublicKey() {
118 return std::vector
<uint8
>(kOwnerPublicKey
,
119 kOwnerPublicKey
+ arraysize(kOwnerPublicKey
));
122 bool CreateOwnerKeyInSlot(PK11SlotInfo
* slot
) {
123 const std::vector
<uint8
> key(kOwnerPrivateKey
,
124 kOwnerPrivateKey
+ arraysize(kOwnerPrivateKey
));
125 return crypto::ImportNSSKeyFromPrivateKeyInfo(slot
, key
,
126 true /* permanent */);
131 class CryptohomeAuthenticatorTest
: public testing::Test
{
133 CryptohomeAuthenticatorTest()
134 : user_context_("me@nowhere.org"),
135 user_manager_(new user_manager::FakeUserManager()),
136 user_manager_enabler_(user_manager_
),
138 mock_homedir_methods_(NULL
),
139 owner_key_util_(new ownership::MockOwnerKeyUtil()) {
140 OwnerSettingsServiceChromeOSFactory::GetInstance()
141 ->SetOwnerKeyUtilForTesting(owner_key_util_
);
142 user_context_
.SetKey(Key("fakepass"));
143 user_context_
.SetUserIDHash("me_nowhere_com_hash");
144 const user_manager::User
* user
=
145 user_manager_
->AddUser(user_context_
.GetUserID());
146 profile_
.set_profile_name(user_context_
.GetUserID());
148 ProfileHelper::Get()->SetUserToProfileMappingForTesting(user
, &profile_
);
150 CreateTransformedKey(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF
,
151 SystemSaltGetter::ConvertRawSaltToHexString(
152 FakeCryptohomeClient::GetStubSystemSalt()));
155 ~CryptohomeAuthenticatorTest() override
{}
157 void SetUp() override
{
158 base::CommandLine::ForCurrentProcess()->AppendSwitch(
159 switches::kLoginManager
);
161 mock_caller_
= new cryptohome::MockAsyncMethodCaller
;
162 cryptohome::AsyncMethodCaller::InitializeForTesting(mock_caller_
);
163 mock_homedir_methods_
= new cryptohome::MockHomedirMethods
;
164 mock_homedir_methods_
->SetUp(true, cryptohome::MOUNT_ERROR_NONE
);
165 cryptohome::HomedirMethods::InitializeForTesting(mock_homedir_methods_
);
167 fake_cryptohome_client_
= new FakeCryptohomeClient
;
168 chromeos::DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient(
169 scoped_ptr
<CryptohomeClient
>(fake_cryptohome_client_
));
171 SystemSaltGetter::Initialize();
173 auth_
= new ChromeCryptohomeAuthenticator(&consumer_
);
174 state_
.reset(new TestAttemptState(user_context_
, false));
177 // Tears down the test fixture.
178 void TearDown() override
{
179 SystemSaltGetter::Shutdown();
180 DBusThreadManager::Shutdown();
182 cryptohome::AsyncMethodCaller::Shutdown();
184 cryptohome::HomedirMethods::Shutdown();
185 mock_homedir_methods_
= NULL
;
188 void CreateTransformedKey(Key::KeyType type
, const std::string
& salt
) {
189 user_context_with_transformed_key_
= user_context_
;
190 user_context_with_transformed_key_
.GetKey()->Transform(type
, salt
);
191 transformed_key_
= *user_context_with_transformed_key_
.GetKey();
194 base::FilePath
PopulateTempFile(const char* data
, int data_len
) {
196 FILE* tmp_file
= base::CreateAndOpenTemporaryFile(&out
);
197 EXPECT_NE(tmp_file
, static_cast<FILE*>(NULL
));
198 EXPECT_EQ(base::WriteFile(out
, data
, data_len
), data_len
);
199 EXPECT_TRUE(base::CloseFile(tmp_file
));
203 // Allow test to fail and exit gracefully, even if OnAuthFailure()
204 // wasn't supposed to happen.
205 void FailOnLoginFailure() {
206 ON_CALL(consumer_
, OnAuthFailure(_
))
207 .WillByDefault(Invoke(MockAuthStatusConsumer::OnFailQuitAndFail
));
210 // Allow test to fail and exit gracefully, even if OnAuthSuccess()
211 // wasn't supposed to happen.
212 void FailOnLoginSuccess() {
213 ON_CALL(consumer_
, OnAuthSuccess(_
))
214 .WillByDefault(Invoke(MockAuthStatusConsumer::OnSuccessQuitAndFail
));
217 // Allow test to fail and exit gracefully, even if
218 // OnOffTheRecordAuthSuccess() wasn't supposed to happen.
219 void FailOnGuestLoginSuccess() {
220 ON_CALL(consumer_
, OnOffTheRecordAuthSuccess()).WillByDefault(
221 Invoke(MockAuthStatusConsumer::OnGuestSuccessQuitAndFail
));
224 void ExpectLoginFailure(const AuthFailure
& failure
) {
225 EXPECT_CALL(consumer_
, OnAuthFailure(failure
))
226 .WillOnce(Invoke(MockAuthStatusConsumer::OnFailQuit
))
227 .RetiresOnSaturation();
230 void ExpectLoginSuccess(const UserContext
& user_context
) {
231 EXPECT_CALL(consumer_
, OnAuthSuccess(user_context
))
232 .WillOnce(Invoke(MockAuthStatusConsumer::OnSuccessQuit
))
233 .RetiresOnSaturation();
236 void ExpectGuestLoginSuccess() {
237 EXPECT_CALL(consumer_
, OnOffTheRecordAuthSuccess())
238 .WillOnce(Invoke(MockAuthStatusConsumer::OnGuestSuccessQuit
))
239 .RetiresOnSaturation();
242 void ExpectPasswordChange() {
243 EXPECT_CALL(consumer_
, OnPasswordChangeDetected())
244 .WillOnce(Invoke(MockAuthStatusConsumer::OnMigrateQuit
))
245 .RetiresOnSaturation();
248 void ExpectGetKeyDataExCall(scoped_ptr
<int64
> key_type
,
249 scoped_ptr
<std::string
> salt
) {
250 key_definitions_
.clear();
251 key_definitions_
.push_back(cryptohome::KeyDefinition(
252 std::string() /* secret */,
253 kCryptohomeGAIAKeyLabel
,
254 cryptohome::PRIV_DEFAULT
));
255 cryptohome::KeyDefinition
& key_definition
= key_definitions_
.back();
256 key_definition
.revision
= 1;
258 key_definition
.provider_data
.push_back(
259 cryptohome::KeyDefinition::ProviderData("type"));
260 key_definition
.provider_data
.back().number
= key_type
.Pass();
263 key_definition
.provider_data
.push_back(
264 cryptohome::KeyDefinition::ProviderData("salt"));
265 key_definition
.provider_data
.back().bytes
= salt
.Pass();
267 EXPECT_CALL(*mock_homedir_methods_
, GetKeyDataEx(
268 cryptohome::Identification(user_context_
.GetUserID()),
269 kCryptohomeGAIAKeyLabel
,
271 .WillOnce(WithArg
<2>(Invoke(
273 &CryptohomeAuthenticatorTest::InvokeGetDataExCallback
)));
276 void ExpectMountExCall(bool expect_create_attempt
) {
277 const cryptohome::KeyDefinition
auth_key(transformed_key_
.GetSecret(),
279 cryptohome::PRIV_DEFAULT
);
280 cryptohome::MountParameters
mount(false /* ephemeral */);
281 if (expect_create_attempt
) {
282 mount
.create_keys
.push_back(cryptohome::KeyDefinition(
283 transformed_key_
.GetSecret(),
284 kCryptohomeGAIAKeyLabel
,
285 cryptohome::PRIV_DEFAULT
));
287 EXPECT_CALL(*mock_homedir_methods_
,
288 MountEx(cryptohome::Identification(user_context_
.GetUserID()),
289 cryptohome::Authorization(auth_key
),
293 .RetiresOnSaturation();
296 void RunResolve(CryptohomeAuthenticator
* auth
) {
298 base::MessageLoop::current()->RunUntilIdle();
301 void SetAttemptState(CryptohomeAuthenticator
* auth
, TestAttemptState
* state
) {
302 auth
->set_attempt_state(state
);
305 CryptohomeAuthenticator::AuthState
SetAndResolveState(
306 CryptohomeAuthenticator
* auth
,
307 TestAttemptState
* state
) {
308 auth
->set_attempt_state(state
);
309 return auth
->ResolveState();
312 void SetOwnerState(bool owner_check_finished
, bool check_result
) {
313 auth_
->SetOwnerState(owner_check_finished
, check_result
);
316 content::TestBrowserThreadBundle thread_bundle_
;
318 UserContext user_context_
;
319 UserContext user_context_with_transformed_key_
;
320 Key transformed_key_
;
322 std::vector
<cryptohome::KeyDefinition
> key_definitions_
;
324 ScopedDeviceSettingsTestHelper device_settings_test_helper_
;
325 ScopedTestCrosSettings test_cros_settings_
;
327 TestingProfile profile_
;
328 scoped_ptr
<TestingProfileManager
> profile_manager_
;
329 user_manager::FakeUserManager
* user_manager_
;
330 ScopedUserManagerEnabler user_manager_enabler_
;
332 cryptohome::MockAsyncMethodCaller
* mock_caller_
;
333 cryptohome::MockHomedirMethods
* mock_homedir_methods_
;
335 MockAuthStatusConsumer consumer_
;
337 scoped_refptr
<CryptohomeAuthenticator
> auth_
;
338 scoped_ptr
<TestAttemptState
> state_
;
339 FakeCryptohomeClient
* fake_cryptohome_client_
;
341 scoped_refptr
<ownership::MockOwnerKeyUtil
> owner_key_util_
;
344 void InvokeGetDataExCallback(
345 const cryptohome::HomedirMethods::GetKeyDataCallback
& callback
) {
346 callback
.Run(true /* success */,
347 cryptohome::MOUNT_ERROR_NONE
,
352 TEST_F(CryptohomeAuthenticatorTest
, OnAuthSuccess
) {
353 EXPECT_CALL(consumer_
, OnAuthSuccess(user_context_
))
355 .RetiresOnSaturation();
357 SetAttemptState(auth_
.get(), state_
.release());
358 auth_
->OnAuthSuccess();
361 TEST_F(CryptohomeAuthenticatorTest
, OnPasswordChangeDetected
) {
362 EXPECT_CALL(consumer_
, OnPasswordChangeDetected())
364 .RetiresOnSaturation();
365 SetAttemptState(auth_
.get(), state_
.release());
366 auth_
->OnPasswordChangeDetected();
369 TEST_F(CryptohomeAuthenticatorTest
, ResolveNothingDone
) {
370 EXPECT_EQ(CryptohomeAuthenticator::CONTINUE
,
371 SetAndResolveState(auth_
.get(), state_
.release()));
374 TEST_F(CryptohomeAuthenticatorTest
, ResolvePossiblePwChangeToFailedMount
) {
375 // Set up state as though a cryptohome mount attempt has occurred
376 // and been rejected.
377 state_
->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE
);
379 // When there is no online attempt and online results, POSSIBLE_PW_CHANGE
380 EXPECT_EQ(CryptohomeAuthenticator::FAILED_MOUNT
,
381 SetAndResolveState(auth_
.get(), state_
.release()));
384 TEST_F(CryptohomeAuthenticatorTest
, ResolveNeedOldPw
) {
385 // Set up state as though a cryptohome mount attempt has occurred
386 // and been rejected because of unmatched key; additionally,
387 // an online auth attempt has completed successfully.
388 state_
->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE
);
389 state_
->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
391 EXPECT_EQ(CryptohomeAuthenticator::NEED_OLD_PW
,
392 SetAndResolveState(auth_
.get(), state_
.release()));
395 TEST_F(CryptohomeAuthenticatorTest
, ResolveOwnerNeededDirectFailedMount
) {
396 // Set up state as though a cryptohome mount attempt has occurred
397 // and succeeded but we are in safe mode and the current user is not owner.
398 // This is a high level test to verify the proper transitioning in this mode
399 // only. It is not testing that we properly verify that the user is an owner
400 // or that we really are in "safe-mode".
401 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
402 SetOwnerState(true, false);
404 EXPECT_EQ(CryptohomeAuthenticator::OWNER_REQUIRED
,
405 SetAndResolveState(auth_
.get(), state_
.release()));
408 TEST_F(CryptohomeAuthenticatorTest
, ResolveOwnerNeededMount
) {
409 // Set up state as though a cryptohome mount attempt has occurred
410 // and succeeded but we are in safe mode and the current user is not owner.
411 // This test will check that the "safe-mode" policy is not set and will let
412 // the mount finish successfully.
413 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
414 SetOwnerState(false, false);
415 EXPECT_EQ(CryptohomeAuthenticator::OFFLINE_LOGIN
,
416 SetAndResolveState(auth_
.get(), state_
.release()));
419 // Test the case that login switches to SafeMode and a User that is not the
420 // owner tries to log in. The login should fail because of the missing owner
422 TEST_F(CryptohomeAuthenticatorTest
, ResolveOwnerNeededFailedMount
) {
423 crypto::ScopedTestNSSChromeOSUser
user_slot(user_context_
.GetUserIDHash());
424 owner_key_util_
->SetPublicKey(GetOwnerPublicKey());
426 profile_manager_
.reset(
427 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
428 ASSERT_TRUE(profile_manager_
->SetUp());
430 FailOnLoginSuccess(); // Set failing on success as the default...
431 AuthFailure failure
= AuthFailure(AuthFailure::OWNER_REQUIRED
);
432 ExpectLoginFailure(failure
);
434 // Set up state as though a cryptohome mount attempt has occurred
435 // and succeeded but we are in safe mode and the current user is not owner.
436 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
437 SetOwnerState(false, false);
438 ScopedCrosSettingsTestHelper
settings_helper(false);
439 settings_helper
.ReplaceProvider(kPolicyMissingMitigationMode
);
440 settings_helper
.SetBoolean(kPolicyMissingMitigationMode
, true);
442 // Initialize login state for this test to verify the login state is changed
444 LoginState::Initialize();
446 EXPECT_EQ(CryptohomeAuthenticator::CONTINUE
,
447 SetAndResolveState(auth_
.get(), state_
.release()));
448 EXPECT_TRUE(LoginState::Get()->IsInSafeMode());
450 // Flush all the pending operations. The operations should induce an owner
452 device_settings_test_helper_
.Flush();
454 state_
.reset(new TestAttemptState(user_context_
, false));
455 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
457 // The owner key util should not have found the owner key, so login should
459 EXPECT_EQ(CryptohomeAuthenticator::OWNER_REQUIRED
,
460 SetAndResolveState(auth_
.get(), state_
.release()));
461 EXPECT_TRUE(LoginState::Get()->IsInSafeMode());
463 // Unset global objects used by this test.
464 fake_cryptohome_client_
->set_unmount_result(true);
465 LoginState::Shutdown();
468 // Test the case that login switches to SafeMode and the Owner logs in, which
469 // should lead to a successful login.
470 TEST_F(CryptohomeAuthenticatorTest
, ResolveOwnerNeededSuccess
) {
471 crypto::ScopedTestNSSChromeOSUser
test_user_db(user_context_
.GetUserIDHash());
472 owner_key_util_
->SetPublicKey(GetOwnerPublicKey());
474 crypto::ScopedPK11Slot
user_slot(
475 crypto::GetPublicSlotForChromeOSUser(user_context_
.GetUserIDHash()));
476 ASSERT_TRUE(CreateOwnerKeyInSlot(user_slot
.get()));
478 profile_manager_
.reset(
479 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
480 ASSERT_TRUE(profile_manager_
->SetUp());
482 ExpectLoginSuccess(user_context_
);
484 // Set up state as though a cryptohome mount attempt has occurred
485 // and succeeded but we are in safe mode and the current user is not owner.
486 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
487 SetOwnerState(false, false);
488 ScopedCrosSettingsTestHelper
settings_helper(false);
489 settings_helper
.ReplaceProvider(kPolicyMissingMitigationMode
);
490 settings_helper
.SetBoolean(kPolicyMissingMitigationMode
, true);
492 // Initialize login state for this test to verify the login state is changed
494 LoginState::Initialize();
496 EXPECT_EQ(CryptohomeAuthenticator::CONTINUE
,
497 SetAndResolveState(auth_
.get(), state_
.release()));
498 EXPECT_TRUE(LoginState::Get()->IsInSafeMode());
500 // Flush all the pending operations. The operations should induce an owner
502 device_settings_test_helper_
.Flush();
504 state_
.reset(new TestAttemptState(user_context_
, false));
505 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
507 // The owner key util should find the owner key, so login should succeed.
508 EXPECT_EQ(CryptohomeAuthenticator::OFFLINE_LOGIN
,
509 SetAndResolveState(auth_
.get(), state_
.release()));
510 EXPECT_TRUE(LoginState::Get()->IsInSafeMode());
512 // Unset global objects used by this test.
513 fake_cryptohome_client_
->set_unmount_result(true);
514 LoginState::Shutdown();
517 TEST_F(CryptohomeAuthenticatorTest
, DriveFailedMount
) {
518 FailOnLoginSuccess();
519 ExpectLoginFailure(AuthFailure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME
));
521 // Set up state as though a cryptohome mount attempt has occurred
523 state_
->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_NONE
);
524 SetAttemptState(auth_
.get(), state_
.release());
526 RunResolve(auth_
.get());
529 TEST_F(CryptohomeAuthenticatorTest
, DriveGuestLogin
) {
530 ExpectGuestLoginSuccess();
531 FailOnLoginFailure();
533 // Set up mock async method caller to respond as though a tmpfs mount
534 // attempt has occurred and succeeded.
535 mock_caller_
->SetUp(true, cryptohome::MOUNT_ERROR_NONE
);
536 EXPECT_CALL(*mock_caller_
, AsyncMountGuest(_
)).Times(1).RetiresOnSaturation();
538 auth_
->LoginOffTheRecord();
539 base::MessageLoop::current()->Run();
542 TEST_F(CryptohomeAuthenticatorTest
, DriveGuestLoginButFail
) {
543 FailOnGuestLoginSuccess();
544 ExpectLoginFailure(AuthFailure(AuthFailure::COULD_NOT_MOUNT_TMPFS
));
546 // Set up mock async method caller to respond as though a tmpfs mount
547 // attempt has occurred and failed.
548 mock_caller_
->SetUp(false, cryptohome::MOUNT_ERROR_NONE
);
549 EXPECT_CALL(*mock_caller_
, AsyncMountGuest(_
)).Times(1).RetiresOnSaturation();
551 auth_
->LoginOffTheRecord();
552 base::MessageLoop::current()->Run();
555 TEST_F(CryptohomeAuthenticatorTest
, DriveDataResync
) {
556 UserContext
expected_user_context(user_context_with_transformed_key_
);
557 expected_user_context
.SetUserIDHash(
558 cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername
);
559 ExpectLoginSuccess(expected_user_context
);
560 FailOnLoginFailure();
562 // Set up mock async method caller to respond successfully to a cryptohome
564 mock_caller_
->SetUp(true, cryptohome::MOUNT_ERROR_NONE
);
565 EXPECT_CALL(*mock_caller_
, AsyncRemove(user_context_
.GetUserID(), _
))
567 .RetiresOnSaturation();
569 // Set up mock homedir methods to respond successfully to a cryptohome create
571 ExpectGetKeyDataExCall(scoped_ptr
<int64
>(), scoped_ptr
<std::string
>());
572 ExpectMountExCall(true /* expect_create_attempt */);
574 state_
->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
575 SetAttemptState(auth_
.get(), state_
.release());
577 auth_
->ResyncEncryptedData();
578 base::MessageLoop::current()->Run();
581 TEST_F(CryptohomeAuthenticatorTest
, DriveResyncFail
) {
582 FailOnLoginSuccess();
583 ExpectLoginFailure(AuthFailure(AuthFailure::DATA_REMOVAL_FAILED
));
585 // Set up mock async method caller to fail a cryptohome remove attempt.
586 mock_caller_
->SetUp(false, cryptohome::MOUNT_ERROR_NONE
);
587 EXPECT_CALL(*mock_caller_
, AsyncRemove(user_context_
.GetUserID(), _
))
589 .RetiresOnSaturation();
591 SetAttemptState(auth_
.get(), state_
.release());
593 auth_
->ResyncEncryptedData();
594 base::MessageLoop::current()->Run();
597 TEST_F(CryptohomeAuthenticatorTest
, DriveRequestOldPassword
) {
598 FailOnLoginSuccess();
599 ExpectPasswordChange();
601 state_
->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE
);
602 state_
->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
603 SetAttemptState(auth_
.get(), state_
.release());
605 RunResolve(auth_
.get());
608 TEST_F(CryptohomeAuthenticatorTest
, DriveDataRecover
) {
609 UserContext
expected_user_context(user_context_with_transformed_key_
);
610 expected_user_context
.SetUserIDHash(
611 cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername
);
612 ExpectLoginSuccess(expected_user_context
);
613 FailOnLoginFailure();
615 // Set up mock async method caller to respond successfully to a key migration.
616 mock_caller_
->SetUp(true, cryptohome::MOUNT_ERROR_NONE
);
620 user_context_
.GetUserID(), _
, transformed_key_
.GetSecret(), _
))
622 .RetiresOnSaturation();
624 // Set up mock homedir methods to respond successfully to a cryptohome mount
626 ExpectGetKeyDataExCall(scoped_ptr
<int64
>(), scoped_ptr
<std::string
>());
627 ExpectMountExCall(false /* expect_create_attempt */);
629 state_
->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
630 SetAttemptState(auth_
.get(), state_
.release());
632 auth_
->RecoverEncryptedData(std::string());
633 base::MessageLoop::current()->Run();
636 TEST_F(CryptohomeAuthenticatorTest
, DriveDataRecoverButFail
) {
637 FailOnLoginSuccess();
638 ExpectPasswordChange();
640 // Set up mock async method caller to fail a key migration attempt,
641 // asserting that the wrong password was used.
642 mock_caller_
->SetUp(false, cryptohome::MOUNT_ERROR_KEY_FAILURE
);
646 user_context_
.GetUserID(), _
, transformed_key_
.GetSecret(), _
))
648 .RetiresOnSaturation();
650 SetAttemptState(auth_
.get(), state_
.release());
652 auth_
->RecoverEncryptedData(std::string());
653 base::MessageLoop::current()->Run();
656 TEST_F(CryptohomeAuthenticatorTest
, ResolveNoMountToFailedMount
) {
657 // Set up state as though a cryptohome mount attempt has occurred
658 // and been rejected because the user doesn't exist.
659 state_
->PresetCryptohomeStatus(false,
660 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST
);
662 // When there is no online attempt and online results, NO_MOUNT will be
663 // resolved to FAILED_MOUNT.
664 EXPECT_EQ(CryptohomeAuthenticator::FAILED_MOUNT
,
665 SetAndResolveState(auth_
.get(), state_
.release()));
668 TEST_F(CryptohomeAuthenticatorTest
, ResolveCreateNew
) {
669 // Set up state as though a cryptohome mount attempt has occurred
670 // and been rejected because the user doesn't exist; additionally,
671 // an online auth attempt has completed successfully.
672 state_
->PresetCryptohomeStatus(false,
673 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST
);
674 state_
->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
676 EXPECT_EQ(CryptohomeAuthenticator::CREATE_NEW
,
677 SetAndResolveState(auth_
.get(), state_
.release()));
680 TEST_F(CryptohomeAuthenticatorTest
, DriveCreateForNewUser
) {
681 UserContext
expected_user_context(user_context_with_transformed_key_
);
682 expected_user_context
.SetUserIDHash(
683 cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername
);
684 ExpectLoginSuccess(expected_user_context
);
685 FailOnLoginFailure();
687 // Set up mock homedir methods to respond successfully to a cryptohome create
689 ExpectGetKeyDataExCall(scoped_ptr
<int64
>(), scoped_ptr
<std::string
>());
690 ExpectMountExCall(true /* expect_create_attempt */);
692 // Set up state as though a cryptohome mount attempt has occurred
693 // and been rejected because the user doesn't exist; additionally,
694 // an online auth attempt has completed successfully.
695 state_
->PresetCryptohomeStatus(false,
696 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST
);
697 state_
->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
698 SetAttemptState(auth_
.get(), state_
.release());
700 RunResolve(auth_
.get());
703 TEST_F(CryptohomeAuthenticatorTest
, DriveOfflineLogin
) {
704 ExpectLoginSuccess(user_context_
);
705 FailOnLoginFailure();
707 // Set up state as though a cryptohome mount attempt has occurred and
709 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
710 SetAttemptState(auth_
.get(), state_
.release());
712 RunResolve(auth_
.get());
715 TEST_F(CryptohomeAuthenticatorTest
, DriveOnlineLogin
) {
716 ExpectLoginSuccess(user_context_
);
717 FailOnLoginFailure();
719 // Set up state as though a cryptohome mount attempt has occurred and
721 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
722 state_
->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
723 SetAttemptState(auth_
.get(), state_
.release());
725 RunResolve(auth_
.get());
728 TEST_F(CryptohomeAuthenticatorTest
, DriveUnlock
) {
729 ExpectLoginSuccess(user_context_
);
730 FailOnLoginFailure();
732 // Set up mock async method caller to respond successfully to a cryptohome
733 // key-check attempt.
734 mock_caller_
->SetUp(true, cryptohome::MOUNT_ERROR_NONE
);
735 EXPECT_CALL(*mock_caller_
, AsyncCheckKey(user_context_
.GetUserID(), _
, _
))
737 .RetiresOnSaturation();
739 auth_
->AuthenticateToUnlock(user_context_
);
740 base::MessageLoop::current()->Run();
743 TEST_F(CryptohomeAuthenticatorTest
, DriveLoginWithPreHashedPassword
) {
744 CreateTransformedKey(Key::KEY_TYPE_SALTED_SHA256
, kSalt
);
746 UserContext
expected_user_context(user_context_with_transformed_key_
);
747 expected_user_context
.SetUserIDHash(
748 cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername
);
749 ExpectLoginSuccess(expected_user_context
);
750 FailOnLoginFailure();
752 // Set up mock homedir methods to respond with key metadata indicating that a
753 // pre-hashed key was used to create the cryptohome and allow a successful
754 // mount when this pre-hashed key is used.
756 ExpectGetKeyDataExCall(
757 make_scoped_ptr(new int64(Key::KEY_TYPE_SALTED_SHA256
)),
758 make_scoped_ptr(new std::string(kSalt
)));
759 ExpectMountExCall(false /* expect_create_attempt */);
761 auth_
->AuthenticateToLogin(NULL
, user_context_
);
762 base::RunLoop().Run();
765 TEST_F(CryptohomeAuthenticatorTest
, FailLoginWithMissingSalt
) {
766 CreateTransformedKey(Key::KEY_TYPE_SALTED_SHA256
, kSalt
);
768 FailOnLoginSuccess();
769 ExpectLoginFailure(AuthFailure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME
));
771 // Set up mock homedir methods to respond with key metadata indicating that a
772 // pre-hashed key was used to create the cryptohome but without the required
774 ExpectGetKeyDataExCall(
775 make_scoped_ptr(new int64(Key::KEY_TYPE_SALTED_SHA256
)),
776 scoped_ptr
<std::string
>());
778 auth_
->AuthenticateToLogin(NULL
, user_context_
);
779 base::RunLoop().Run();
782 } // namespace chromeos