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/stub_cros_settings_provider.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_util_internal.h"
49 #include "crypto/scoped_test_nss_chromeos_user.h"
50 #include "google_apis/gaia/mock_url_fetcher_factory.h"
51 #include "net/base/net_errors.h"
52 #include "net/url_request/url_request_status.h"
53 #include "testing/gmock/include/gmock/gmock.h"
54 #include "testing/gtest/include/gtest/gtest.h"
55 #include "third_party/cros_system_api/dbus/service_constants.h"
58 using ::testing::Invoke
;
59 using ::testing::Return
;
60 using ::testing::WithArg
;
67 // Label under which the user's key is stored.
68 const char kCryptohomeGAIAKeyLabel
[] = "gaia";
70 // Salt used by pre-hashed key.
71 const char kSalt
[] = "SALT $$";
73 // An owner key in PKCS#8 PrivateKeyInfo for testing owner checks.
74 const uint8 kOwnerPrivateKey
[] = {
75 0x30, 0x82, 0x01, 0x53, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
76 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
77 0x01, 0x3d, 0x30, 0x82, 0x01, 0x39, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00,
78 0xb4, 0xf5, 0xab, 0xfe, 0xd8, 0xf1, 0xcb, 0x5f, 0x8f, 0x48, 0x3e, 0xdf,
79 0x40, 0x8e, 0x2b, 0x15, 0x43, 0x6c, 0x67, 0x74, 0xa2, 0xcb, 0xe4, 0xf3,
80 0xec, 0xab, 0x41, 0x57, 0x1d, 0x5f, 0xed, 0xcf, 0x09, 0xf4, 0xcc, 0xbb,
81 0x52, 0x52, 0xe8, 0x46, 0xf5, 0xc5, 0x01, 0xa3, 0xd8, 0x24, 0xc0, 0x15,
82 0xc5, 0x65, 0x50, 0x7d, 0xbd, 0x4e, 0x81, 0xb2, 0x28, 0x38, 0xf9, 0x3d,
83 0x3e, 0x2a, 0x68, 0xf7, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x40, 0x40,
84 0xc7, 0xb5, 0xb3, 0xbc, 0xac, 0x0a, 0x77, 0x02, 0x0f, 0x05, 0xda, 0xdb,
85 0xfc, 0x48, 0xf6, 0x0a, 0xb5, 0xf2, 0xef, 0x31, 0x1c, 0x36, 0xb1, 0x0f,
86 0xa7, 0x5a, 0xf3, 0xb9, 0xa3, 0x4e, 0xb8, 0xf6, 0x10, 0xfe, 0x25, 0x7b,
87 0x36, 0xb4, 0x1b, 0x80, 0xe3, 0x92, 0x37, 0x83, 0xf0, 0x43, 0xb3, 0x00,
88 0xa6, 0x53, 0xc6, 0x1b, 0x7e, 0x4b, 0xb0, 0x33, 0xd4, 0xe1, 0x03, 0xc4,
89 0xaa, 0xbc, 0x89, 0x02, 0x21, 0x00, 0xde, 0xc8, 0x8d, 0x10, 0xbc, 0xf3,
90 0x43, 0x49, 0x1f, 0x07, 0xf7, 0x12, 0xeb, 0x0a, 0x90, 0xab, 0xb9, 0xaa,
91 0x81, 0xb5, 0x54, 0x71, 0xf4, 0x2e, 0xc4, 0x44, 0xec, 0xff, 0x7d, 0xff,
92 0xe8, 0xa5, 0x02, 0x21, 0x00, 0xcf, 0xf0, 0xbe, 0xa6, 0xde, 0x9c, 0x70,
93 0xed, 0xf0, 0xc3, 0x18, 0x9b, 0xca, 0xe5, 0x7c, 0x4b, 0x9b, 0xf5, 0x12,
94 0x5d, 0x86, 0xbe, 0x8d, 0xf1, 0xbc, 0x2c, 0x79, 0x59, 0xf5, 0xff, 0xbc,
95 0x6b, 0x02, 0x20, 0x7c, 0x09, 0x1c, 0xc1, 0x1c, 0xf2, 0x33, 0x9c, 0x1a,
96 0x72, 0xcc, 0xd4, 0xf3, 0x97, 0xc6, 0x44, 0x55, 0xf2, 0xe0, 0x94, 0x9c,
97 0x97, 0x75, 0x64, 0x34, 0x52, 0x4b, 0xc1, 0x53, 0xdd, 0x8f, 0x21, 0x02,
98 0x20, 0x0e, 0xef, 0x48, 0x92, 0x2d, 0x9c, 0xe8, 0xd3, 0x7e, 0x1e, 0x55,
99 0x0f, 0x23, 0x74, 0x76, 0x07, 0xec, 0x2c, 0x9e, 0xe4, 0x0e, 0xc0, 0x72,
100 0xeb, 0x70, 0xcb, 0x74, 0xef, 0xcc, 0x26, 0x50, 0xff, 0x02, 0x20, 0x29,
101 0x32, 0xd0, 0xbf, 0x11, 0xf2, 0xbf, 0x54, 0xfd, 0x6d, 0xf2, 0x1c, 0xbe,
102 0x50, 0x18, 0x62, 0x6d, 0x23, 0xe4, 0x26, 0x03, 0x8b, 0xb3, 0x42, 0x24,
103 0x7e, 0x68, 0x37, 0x26, 0xda, 0xb9, 0x87};
105 // The public key alone matcing kOwnerPrivateKey.
106 const uint8 kOwnerPublicKey
[] = {
107 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
108 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
109 0x00, 0xb4, 0xf5, 0xab, 0xfe, 0xd8, 0xf1, 0xcb, 0x5f, 0x8f, 0x48, 0x3e,
110 0xdf, 0x40, 0x8e, 0x2b, 0x15, 0x43, 0x6c, 0x67, 0x74, 0xa2, 0xcb, 0xe4,
111 0xf3, 0xec, 0xab, 0x41, 0x57, 0x1d, 0x5f, 0xed, 0xcf, 0x09, 0xf4, 0xcc,
112 0xbb, 0x52, 0x52, 0xe8, 0x46, 0xf5, 0xc5, 0x01, 0xa3, 0xd8, 0x24, 0xc0,
113 0x15, 0xc5, 0x65, 0x50, 0x7d, 0xbd, 0x4e, 0x81, 0xb2, 0x28, 0x38, 0xf9,
114 0x3d, 0x3e, 0x2a, 0x68, 0xf7, 0x02, 0x03, 0x01, 0x00, 0x01};
116 std::vector
<uint8
> GetOwnerPublicKey() {
117 return std::vector
<uint8
>(kOwnerPublicKey
,
118 kOwnerPublicKey
+ arraysize(kOwnerPublicKey
));
121 scoped_ptr
<crypto::RSAPrivateKey
> CreateOwnerKeyInSlot(PK11SlotInfo
* slot
) {
122 const std::vector
<uint8
> key(kOwnerPrivateKey
,
123 kOwnerPrivateKey
+ arraysize(kOwnerPrivateKey
));
124 return make_scoped_ptr(
125 crypto::RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(slot
, key
));
130 class CryptohomeAuthenticatorTest
: public testing::Test
{
132 CryptohomeAuthenticatorTest()
133 : user_context_("me@nowhere.org"),
134 user_manager_(new user_manager::FakeUserManager()),
135 user_manager_enabler_(user_manager_
),
137 mock_homedir_methods_(NULL
),
138 owner_key_util_(new ownership::MockOwnerKeyUtil()) {
139 OwnerSettingsServiceChromeOSFactory::GetInstance()
140 ->SetOwnerKeyUtilForTesting(owner_key_util_
);
141 user_context_
.SetKey(Key("fakepass"));
142 user_context_
.SetUserIDHash("me_nowhere_com_hash");
143 const user_manager::User
* user
=
144 user_manager_
->AddUser(user_context_
.GetUserID());
145 profile_
.set_profile_name(user_context_
.GetUserID());
147 ProfileHelper::Get()->SetUserToProfileMappingForTesting(user
, &profile_
);
149 CreateTransformedKey(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF
,
150 SystemSaltGetter::ConvertRawSaltToHexString(
151 FakeCryptohomeClient::GetStubSystemSalt()));
154 ~CryptohomeAuthenticatorTest() override
{}
156 void SetUp() override
{
157 base::CommandLine::ForCurrentProcess()->AppendSwitch(
158 switches::kLoginManager
);
160 mock_caller_
= new cryptohome::MockAsyncMethodCaller
;
161 cryptohome::AsyncMethodCaller::InitializeForTesting(mock_caller_
);
162 mock_homedir_methods_
= new cryptohome::MockHomedirMethods
;
163 mock_homedir_methods_
->SetUp(true, cryptohome::MOUNT_ERROR_NONE
);
164 cryptohome::HomedirMethods::InitializeForTesting(mock_homedir_methods_
);
166 fake_cryptohome_client_
= new FakeCryptohomeClient
;
167 chromeos::DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient(
168 scoped_ptr
<CryptohomeClient
>(fake_cryptohome_client_
));
170 SystemSaltGetter::Initialize();
172 auth_
= new ChromeCryptohomeAuthenticator(&consumer_
);
173 state_
.reset(new TestAttemptState(user_context_
, false));
176 // Tears down the test fixture.
177 void TearDown() override
{
178 SystemSaltGetter::Shutdown();
179 DBusThreadManager::Shutdown();
181 cryptohome::AsyncMethodCaller::Shutdown();
183 cryptohome::HomedirMethods::Shutdown();
184 mock_homedir_methods_
= NULL
;
187 void CreateTransformedKey(Key::KeyType type
, const std::string
& salt
) {
188 user_context_with_transformed_key_
= user_context_
;
189 user_context_with_transformed_key_
.GetKey()->Transform(type
, salt
);
190 transformed_key_
= *user_context_with_transformed_key_
.GetKey();
193 base::FilePath
PopulateTempFile(const char* data
, int data_len
) {
195 FILE* tmp_file
= base::CreateAndOpenTemporaryFile(&out
);
196 EXPECT_NE(tmp_file
, static_cast<FILE*>(NULL
));
197 EXPECT_EQ(base::WriteFile(out
, data
, data_len
), data_len
);
198 EXPECT_TRUE(base::CloseFile(tmp_file
));
202 // Allow test to fail and exit gracefully, even if OnAuthFailure()
203 // wasn't supposed to happen.
204 void FailOnLoginFailure() {
205 ON_CALL(consumer_
, OnAuthFailure(_
))
206 .WillByDefault(Invoke(MockAuthStatusConsumer::OnFailQuitAndFail
));
209 // Allow test to fail and exit gracefully, even if OnAuthSuccess()
210 // wasn't supposed to happen.
211 void FailOnLoginSuccess() {
212 ON_CALL(consumer_
, OnAuthSuccess(_
))
213 .WillByDefault(Invoke(MockAuthStatusConsumer::OnSuccessQuitAndFail
));
216 // Allow test to fail and exit gracefully, even if
217 // OnOffTheRecordAuthSuccess() wasn't supposed to happen.
218 void FailOnGuestLoginSuccess() {
219 ON_CALL(consumer_
, OnOffTheRecordAuthSuccess()).WillByDefault(
220 Invoke(MockAuthStatusConsumer::OnGuestSuccessQuitAndFail
));
223 void ExpectLoginFailure(const AuthFailure
& failure
) {
224 EXPECT_CALL(consumer_
, OnAuthFailure(failure
))
225 .WillOnce(Invoke(MockAuthStatusConsumer::OnFailQuit
))
226 .RetiresOnSaturation();
229 void ExpectLoginSuccess(const UserContext
& user_context
) {
230 EXPECT_CALL(consumer_
, OnAuthSuccess(user_context
))
231 .WillOnce(Invoke(MockAuthStatusConsumer::OnSuccessQuit
))
232 .RetiresOnSaturation();
235 void ExpectGuestLoginSuccess() {
236 EXPECT_CALL(consumer_
, OnOffTheRecordAuthSuccess())
237 .WillOnce(Invoke(MockAuthStatusConsumer::OnGuestSuccessQuit
))
238 .RetiresOnSaturation();
241 void ExpectPasswordChange() {
242 EXPECT_CALL(consumer_
, OnPasswordChangeDetected())
243 .WillOnce(Invoke(MockAuthStatusConsumer::OnMigrateQuit
))
244 .RetiresOnSaturation();
247 void ExpectGetKeyDataExCall(scoped_ptr
<int64
> key_type
,
248 scoped_ptr
<std::string
> salt
) {
249 key_definitions_
.clear();
250 key_definitions_
.push_back(cryptohome::KeyDefinition(
251 std::string() /* secret */,
252 kCryptohomeGAIAKeyLabel
,
253 cryptohome::PRIV_DEFAULT
));
254 cryptohome::KeyDefinition
& key_definition
= key_definitions_
.back();
255 key_definition
.revision
= 1;
257 key_definition
.provider_data
.push_back(
258 cryptohome::KeyDefinition::ProviderData("type"));
259 key_definition
.provider_data
.back().number
= key_type
.Pass();
262 key_definition
.provider_data
.push_back(
263 cryptohome::KeyDefinition::ProviderData("salt"));
264 key_definition
.provider_data
.back().bytes
= salt
.Pass();
266 EXPECT_CALL(*mock_homedir_methods_
, GetKeyDataEx(
267 cryptohome::Identification(user_context_
.GetUserID()),
268 kCryptohomeGAIAKeyLabel
,
270 .WillOnce(WithArg
<2>(Invoke(
272 &CryptohomeAuthenticatorTest::InvokeGetDataExCallback
)));
275 void ExpectMountExCall(bool expect_create_attempt
) {
276 const cryptohome::KeyDefinition
auth_key(transformed_key_
.GetSecret(),
278 cryptohome::PRIV_DEFAULT
);
279 cryptohome::MountParameters
mount(false /* ephemeral */);
280 if (expect_create_attempt
) {
281 mount
.create_keys
.push_back(cryptohome::KeyDefinition(
282 transformed_key_
.GetSecret(),
283 kCryptohomeGAIAKeyLabel
,
284 cryptohome::PRIV_DEFAULT
));
286 EXPECT_CALL(*mock_homedir_methods_
,
287 MountEx(cryptohome::Identification(user_context_
.GetUserID()),
288 cryptohome::Authorization(auth_key
),
292 .RetiresOnSaturation();
295 void RunResolve(CryptohomeAuthenticator
* auth
) {
297 base::MessageLoop::current()->RunUntilIdle();
300 void SetAttemptState(CryptohomeAuthenticator
* auth
, TestAttemptState
* state
) {
301 auth
->set_attempt_state(state
);
304 CryptohomeAuthenticator::AuthState
SetAndResolveState(
305 CryptohomeAuthenticator
* auth
,
306 TestAttemptState
* state
) {
307 auth
->set_attempt_state(state
);
308 return auth
->ResolveState();
311 void SetOwnerState(bool owner_check_finished
, bool check_result
) {
312 auth_
->SetOwnerState(owner_check_finished
, check_result
);
315 content::TestBrowserThreadBundle thread_bundle_
;
317 UserContext user_context_
;
318 UserContext user_context_with_transformed_key_
;
319 Key transformed_key_
;
321 std::vector
<cryptohome::KeyDefinition
> key_definitions_
;
323 ScopedDeviceSettingsTestHelper device_settings_test_helper_
;
324 ScopedTestCrosSettings test_cros_settings_
;
326 TestingProfile profile_
;
327 scoped_ptr
<TestingProfileManager
> profile_manager_
;
328 user_manager::FakeUserManager
* user_manager_
;
329 ScopedUserManagerEnabler user_manager_enabler_
;
331 cryptohome::MockAsyncMethodCaller
* mock_caller_
;
332 cryptohome::MockHomedirMethods
* mock_homedir_methods_
;
334 MockAuthStatusConsumer consumer_
;
336 scoped_refptr
<CryptohomeAuthenticator
> auth_
;
337 scoped_ptr
<TestAttemptState
> state_
;
338 FakeCryptohomeClient
* fake_cryptohome_client_
;
340 scoped_refptr
<ownership::MockOwnerKeyUtil
> owner_key_util_
;
343 void InvokeGetDataExCallback(
344 const cryptohome::HomedirMethods::GetKeyDataCallback
& callback
) {
345 callback
.Run(true /* success */,
346 cryptohome::MOUNT_ERROR_NONE
,
351 TEST_F(CryptohomeAuthenticatorTest
, OnAuthSuccess
) {
352 EXPECT_CALL(consumer_
, OnAuthSuccess(user_context_
))
354 .RetiresOnSaturation();
356 SetAttemptState(auth_
.get(), state_
.release());
357 auth_
->OnAuthSuccess();
360 TEST_F(CryptohomeAuthenticatorTest
, OnPasswordChangeDetected
) {
361 EXPECT_CALL(consumer_
, OnPasswordChangeDetected())
363 .RetiresOnSaturation();
364 SetAttemptState(auth_
.get(), state_
.release());
365 auth_
->OnPasswordChangeDetected();
368 TEST_F(CryptohomeAuthenticatorTest
, ResolveNothingDone
) {
369 EXPECT_EQ(CryptohomeAuthenticator::CONTINUE
,
370 SetAndResolveState(auth_
.get(), state_
.release()));
373 TEST_F(CryptohomeAuthenticatorTest
, ResolvePossiblePwChangeToFailedMount
) {
374 // Set up state as though a cryptohome mount attempt has occurred
375 // and been rejected.
376 state_
->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE
);
378 // When there is no online attempt and online results, POSSIBLE_PW_CHANGE
379 EXPECT_EQ(CryptohomeAuthenticator::FAILED_MOUNT
,
380 SetAndResolveState(auth_
.get(), state_
.release()));
383 TEST_F(CryptohomeAuthenticatorTest
, ResolveNeedOldPw
) {
384 // Set up state as though a cryptohome mount attempt has occurred
385 // and been rejected because of unmatched key; additionally,
386 // an online auth attempt has completed successfully.
387 state_
->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE
);
388 state_
->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
390 EXPECT_EQ(CryptohomeAuthenticator::NEED_OLD_PW
,
391 SetAndResolveState(auth_
.get(), state_
.release()));
394 TEST_F(CryptohomeAuthenticatorTest
, ResolveOwnerNeededDirectFailedMount
) {
395 // Set up state as though a cryptohome mount attempt has occurred
396 // and succeeded but we are in safe mode and the current user is not owner.
397 // This is a high level test to verify the proper transitioning in this mode
398 // only. It is not testing that we properly verify that the user is an owner
399 // or that we really are in "safe-mode".
400 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
401 SetOwnerState(true, false);
403 EXPECT_EQ(CryptohomeAuthenticator::OWNER_REQUIRED
,
404 SetAndResolveState(auth_
.get(), state_
.release()));
407 TEST_F(CryptohomeAuthenticatorTest
, ResolveOwnerNeededMount
) {
408 // Set up state as though a cryptohome mount attempt has occurred
409 // and succeeded but we are in safe mode and the current user is not owner.
410 // This test will check that the "safe-mode" policy is not set and will let
411 // the mount finish successfully.
412 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
413 SetOwnerState(false, false);
414 EXPECT_EQ(CryptohomeAuthenticator::OFFLINE_LOGIN
,
415 SetAndResolveState(auth_
.get(), state_
.release()));
418 // Test the case that login switches to SafeMode and a User that is not the
419 // owner tries to log in. The login should fail because of the missing owner
421 TEST_F(CryptohomeAuthenticatorTest
, ResolveOwnerNeededFailedMount
) {
422 crypto::ScopedTestNSSChromeOSUser
user_slot(user_context_
.GetUserIDHash());
423 owner_key_util_
->SetPublicKey(GetOwnerPublicKey());
425 profile_manager_
.reset(
426 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
427 ASSERT_TRUE(profile_manager_
->SetUp());
429 FailOnLoginSuccess(); // Set failing on success as the default...
430 AuthFailure failure
= AuthFailure(AuthFailure::OWNER_REQUIRED
);
431 ExpectLoginFailure(failure
);
433 // Set up state as though a cryptohome mount attempt has occurred
434 // and succeeded but we are in safe mode and the current user is not owner.
435 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
436 SetOwnerState(false, false);
437 // Remove the real DeviceSettingsProvider and replace it with a stub.
438 CrosSettingsProvider
* device_settings_provider
=
439 CrosSettings::Get()->GetProvider(chromeos::kReportDeviceVersionInfo
);
440 EXPECT_TRUE(device_settings_provider
!= NULL
);
442 CrosSettings::Get()->RemoveSettingsProvider(device_settings_provider
));
443 StubCrosSettingsProvider stub_settings_provider
;
444 CrosSettings::Get()->AddSettingsProvider(&stub_settings_provider
);
445 CrosSettings::Get()->SetBoolean(kPolicyMissingMitigationMode
, true);
447 // Initialize login state for this test to verify the login state is changed
449 LoginState::Initialize();
451 EXPECT_EQ(CryptohomeAuthenticator::CONTINUE
,
452 SetAndResolveState(auth_
.get(), state_
.release()));
453 EXPECT_TRUE(LoginState::Get()->IsInSafeMode());
455 // Flush all the pending operations. The operations should induce an owner
457 device_settings_test_helper_
.Flush();
459 state_
.reset(new TestAttemptState(user_context_
, false));
460 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
462 // The owner key util should not have found the owner key, so login should
464 EXPECT_EQ(CryptohomeAuthenticator::OWNER_REQUIRED
,
465 SetAndResolveState(auth_
.get(), state_
.release()));
466 EXPECT_TRUE(LoginState::Get()->IsInSafeMode());
468 // Unset global objects used by this test.
469 fake_cryptohome_client_
->set_unmount_result(true);
470 LoginState::Shutdown();
472 CrosSettings::Get()->RemoveSettingsProvider(&stub_settings_provider
));
473 CrosSettings::Get()->AddSettingsProvider(device_settings_provider
);
476 // Test the case that login switches to SafeMode and the Owner logs in, which
477 // should lead to a successful login.
478 TEST_F(CryptohomeAuthenticatorTest
, ResolveOwnerNeededSuccess
) {
479 crypto::ScopedTestNSSChromeOSUser
test_user_db(user_context_
.GetUserIDHash());
480 owner_key_util_
->SetPublicKey(GetOwnerPublicKey());
482 crypto::ScopedPK11Slot
user_slot(
483 crypto::GetPublicSlotForChromeOSUser(user_context_
.GetUserIDHash()));
484 CreateOwnerKeyInSlot(user_slot
.get());
486 profile_manager_
.reset(
487 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
488 ASSERT_TRUE(profile_manager_
->SetUp());
490 ExpectLoginSuccess(user_context_
);
492 // Set up state as though a cryptohome mount attempt has occurred
493 // and succeeded but we are in safe mode and the current user is not owner.
494 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
495 SetOwnerState(false, false);
496 // Remove the real DeviceSettingsProvider and replace it with a stub.
497 CrosSettingsProvider
* device_settings_provider
=
498 CrosSettings::Get()->GetProvider(chromeos::kReportDeviceVersionInfo
);
499 EXPECT_TRUE(device_settings_provider
!= NULL
);
501 CrosSettings::Get()->RemoveSettingsProvider(device_settings_provider
));
502 StubCrosSettingsProvider stub_settings_provider
;
503 CrosSettings::Get()->AddSettingsProvider(&stub_settings_provider
);
504 CrosSettings::Get()->SetBoolean(kPolicyMissingMitigationMode
, true);
506 // Initialize login state for this test to verify the login state is changed
508 LoginState::Initialize();
510 EXPECT_EQ(CryptohomeAuthenticator::CONTINUE
,
511 SetAndResolveState(auth_
.get(), state_
.release()));
512 EXPECT_TRUE(LoginState::Get()->IsInSafeMode());
514 // Flush all the pending operations. The operations should induce an owner
516 device_settings_test_helper_
.Flush();
518 state_
.reset(new TestAttemptState(user_context_
, false));
519 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
521 // The owner key util should find the owner key, so login should succeed.
522 EXPECT_EQ(CryptohomeAuthenticator::OFFLINE_LOGIN
,
523 SetAndResolveState(auth_
.get(), state_
.release()));
524 EXPECT_TRUE(LoginState::Get()->IsInSafeMode());
526 // Unset global objects used by this test.
527 fake_cryptohome_client_
->set_unmount_result(true);
528 LoginState::Shutdown();
530 CrosSettings::Get()->RemoveSettingsProvider(&stub_settings_provider
));
531 CrosSettings::Get()->AddSettingsProvider(device_settings_provider
);
534 TEST_F(CryptohomeAuthenticatorTest
, DriveFailedMount
) {
535 FailOnLoginSuccess();
536 ExpectLoginFailure(AuthFailure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME
));
538 // Set up state as though a cryptohome mount attempt has occurred
540 state_
->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_NONE
);
541 SetAttemptState(auth_
.get(), state_
.release());
543 RunResolve(auth_
.get());
546 TEST_F(CryptohomeAuthenticatorTest
, DriveGuestLogin
) {
547 ExpectGuestLoginSuccess();
548 FailOnLoginFailure();
550 // Set up mock async method caller to respond as though a tmpfs mount
551 // attempt has occurred and succeeded.
552 mock_caller_
->SetUp(true, cryptohome::MOUNT_ERROR_NONE
);
553 EXPECT_CALL(*mock_caller_
, AsyncMountGuest(_
)).Times(1).RetiresOnSaturation();
555 auth_
->LoginOffTheRecord();
556 base::MessageLoop::current()->Run();
559 TEST_F(CryptohomeAuthenticatorTest
, DriveGuestLoginButFail
) {
560 FailOnGuestLoginSuccess();
561 ExpectLoginFailure(AuthFailure(AuthFailure::COULD_NOT_MOUNT_TMPFS
));
563 // Set up mock async method caller to respond as though a tmpfs mount
564 // attempt has occurred and failed.
565 mock_caller_
->SetUp(false, cryptohome::MOUNT_ERROR_NONE
);
566 EXPECT_CALL(*mock_caller_
, AsyncMountGuest(_
)).Times(1).RetiresOnSaturation();
568 auth_
->LoginOffTheRecord();
569 base::MessageLoop::current()->Run();
572 TEST_F(CryptohomeAuthenticatorTest
, DriveDataResync
) {
573 UserContext
expected_user_context(user_context_with_transformed_key_
);
574 expected_user_context
.SetUserIDHash(
575 cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername
);
576 ExpectLoginSuccess(expected_user_context
);
577 FailOnLoginFailure();
579 // Set up mock async method caller to respond successfully to a cryptohome
581 mock_caller_
->SetUp(true, cryptohome::MOUNT_ERROR_NONE
);
582 EXPECT_CALL(*mock_caller_
, AsyncRemove(user_context_
.GetUserID(), _
))
584 .RetiresOnSaturation();
586 // Set up mock homedir methods to respond successfully to a cryptohome create
588 ExpectGetKeyDataExCall(scoped_ptr
<int64
>(), scoped_ptr
<std::string
>());
589 ExpectMountExCall(true /* expect_create_attempt */);
591 state_
->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
592 SetAttemptState(auth_
.get(), state_
.release());
594 auth_
->ResyncEncryptedData();
595 base::MessageLoop::current()->Run();
598 TEST_F(CryptohomeAuthenticatorTest
, DriveResyncFail
) {
599 FailOnLoginSuccess();
600 ExpectLoginFailure(AuthFailure(AuthFailure::DATA_REMOVAL_FAILED
));
602 // Set up mock async method caller to fail a cryptohome remove attempt.
603 mock_caller_
->SetUp(false, cryptohome::MOUNT_ERROR_NONE
);
604 EXPECT_CALL(*mock_caller_
, AsyncRemove(user_context_
.GetUserID(), _
))
606 .RetiresOnSaturation();
608 SetAttemptState(auth_
.get(), state_
.release());
610 auth_
->ResyncEncryptedData();
611 base::MessageLoop::current()->Run();
614 TEST_F(CryptohomeAuthenticatorTest
, DriveRequestOldPassword
) {
615 FailOnLoginSuccess();
616 ExpectPasswordChange();
618 state_
->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE
);
619 state_
->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
620 SetAttemptState(auth_
.get(), state_
.release());
622 RunResolve(auth_
.get());
625 TEST_F(CryptohomeAuthenticatorTest
, DriveDataRecover
) {
626 UserContext
expected_user_context(user_context_with_transformed_key_
);
627 expected_user_context
.SetUserIDHash(
628 cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername
);
629 ExpectLoginSuccess(expected_user_context
);
630 FailOnLoginFailure();
632 // Set up mock async method caller to respond successfully to a key migration.
633 mock_caller_
->SetUp(true, cryptohome::MOUNT_ERROR_NONE
);
637 user_context_
.GetUserID(), _
, transformed_key_
.GetSecret(), _
))
639 .RetiresOnSaturation();
641 // Set up mock homedir methods to respond successfully to a cryptohome mount
643 ExpectGetKeyDataExCall(scoped_ptr
<int64
>(), scoped_ptr
<std::string
>());
644 ExpectMountExCall(false /* expect_create_attempt */);
646 state_
->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
647 SetAttemptState(auth_
.get(), state_
.release());
649 auth_
->RecoverEncryptedData(std::string());
650 base::MessageLoop::current()->Run();
653 TEST_F(CryptohomeAuthenticatorTest
, DriveDataRecoverButFail
) {
654 FailOnLoginSuccess();
655 ExpectPasswordChange();
657 // Set up mock async method caller to fail a key migration attempt,
658 // asserting that the wrong password was used.
659 mock_caller_
->SetUp(false, cryptohome::MOUNT_ERROR_KEY_FAILURE
);
663 user_context_
.GetUserID(), _
, transformed_key_
.GetSecret(), _
))
665 .RetiresOnSaturation();
667 SetAttemptState(auth_
.get(), state_
.release());
669 auth_
->RecoverEncryptedData(std::string());
670 base::MessageLoop::current()->Run();
673 TEST_F(CryptohomeAuthenticatorTest
, ResolveNoMountToFailedMount
) {
674 // Set up state as though a cryptohome mount attempt has occurred
675 // and been rejected because the user doesn't exist.
676 state_
->PresetCryptohomeStatus(false,
677 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST
);
679 // When there is no online attempt and online results, NO_MOUNT will be
680 // resolved to FAILED_MOUNT.
681 EXPECT_EQ(CryptohomeAuthenticator::FAILED_MOUNT
,
682 SetAndResolveState(auth_
.get(), state_
.release()));
685 TEST_F(CryptohomeAuthenticatorTest
, ResolveCreateNew
) {
686 // Set up state as though a cryptohome mount attempt has occurred
687 // and been rejected because the user doesn't exist; additionally,
688 // an online auth attempt has completed successfully.
689 state_
->PresetCryptohomeStatus(false,
690 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST
);
691 state_
->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
693 EXPECT_EQ(CryptohomeAuthenticator::CREATE_NEW
,
694 SetAndResolveState(auth_
.get(), state_
.release()));
697 TEST_F(CryptohomeAuthenticatorTest
, DriveCreateForNewUser
) {
698 UserContext
expected_user_context(user_context_with_transformed_key_
);
699 expected_user_context
.SetUserIDHash(
700 cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername
);
701 ExpectLoginSuccess(expected_user_context
);
702 FailOnLoginFailure();
704 // Set up mock homedir methods to respond successfully to a cryptohome create
706 ExpectGetKeyDataExCall(scoped_ptr
<int64
>(), scoped_ptr
<std::string
>());
707 ExpectMountExCall(true /* expect_create_attempt */);
709 // Set up state as though a cryptohome mount attempt has occurred
710 // and been rejected because the user doesn't exist; additionally,
711 // an online auth attempt has completed successfully.
712 state_
->PresetCryptohomeStatus(false,
713 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST
);
714 state_
->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
715 SetAttemptState(auth_
.get(), state_
.release());
717 RunResolve(auth_
.get());
720 TEST_F(CryptohomeAuthenticatorTest
, DriveOfflineLogin
) {
721 ExpectLoginSuccess(user_context_
);
722 FailOnLoginFailure();
724 // Set up state as though a cryptohome mount attempt has occurred and
726 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
727 SetAttemptState(auth_
.get(), state_
.release());
729 RunResolve(auth_
.get());
732 TEST_F(CryptohomeAuthenticatorTest
, DriveOnlineLogin
) {
733 ExpectLoginSuccess(user_context_
);
734 FailOnLoginFailure();
736 // Set up state as though a cryptohome mount attempt has occurred and
738 state_
->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE
);
739 state_
->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone());
740 SetAttemptState(auth_
.get(), state_
.release());
742 RunResolve(auth_
.get());
745 TEST_F(CryptohomeAuthenticatorTest
, DriveUnlock
) {
746 ExpectLoginSuccess(user_context_
);
747 FailOnLoginFailure();
749 // Set up mock async method caller to respond successfully to a cryptohome
750 // key-check attempt.
751 mock_caller_
->SetUp(true, cryptohome::MOUNT_ERROR_NONE
);
752 EXPECT_CALL(*mock_caller_
, AsyncCheckKey(user_context_
.GetUserID(), _
, _
))
754 .RetiresOnSaturation();
756 auth_
->AuthenticateToUnlock(user_context_
);
757 base::MessageLoop::current()->Run();
760 TEST_F(CryptohomeAuthenticatorTest
, DriveLoginWithPreHashedPassword
) {
761 CreateTransformedKey(Key::KEY_TYPE_SALTED_SHA256
, kSalt
);
763 UserContext
expected_user_context(user_context_with_transformed_key_
);
764 expected_user_context
.SetUserIDHash(
765 cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername
);
766 ExpectLoginSuccess(expected_user_context
);
767 FailOnLoginFailure();
769 // Set up mock homedir methods to respond with key metadata indicating that a
770 // pre-hashed key was used to create the cryptohome and allow a successful
771 // mount when this pre-hashed key is used.
773 ExpectGetKeyDataExCall(
774 make_scoped_ptr(new int64(Key::KEY_TYPE_SALTED_SHA256
)),
775 make_scoped_ptr(new std::string(kSalt
)));
776 ExpectMountExCall(false /* expect_create_attempt */);
778 auth_
->AuthenticateToLogin(NULL
, user_context_
);
779 base::RunLoop().Run();
782 TEST_F(CryptohomeAuthenticatorTest
, FailLoginWithMissingSalt
) {
783 CreateTransformedKey(Key::KEY_TYPE_SALTED_SHA256
, kSalt
);
785 FailOnLoginSuccess();
786 ExpectLoginFailure(AuthFailure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME
));
788 // Set up mock homedir methods to respond with key metadata indicating that a
789 // pre-hashed key was used to create the cryptohome but without the required
791 ExpectGetKeyDataExCall(
792 make_scoped_ptr(new int64(Key::KEY_TYPE_SALTED_SHA256
)),
793 scoped_ptr
<std::string
>());
795 auth_
->AuthenticateToLogin(NULL
, user_context_
);
796 base::RunLoop().Run();
799 } // namespace chromeos