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. 4 5 #include "chrome/browser/chromeos/login/auth/chrome_cryptohome_authenticator.h" 6 7 #include <string> 8 #include <vector> 9 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/fake_user_manager.h" 20 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" 21 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h" 22 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h" 23 #include "chrome/browser/chromeos/profiles/profile_helper.h" 24 #include "chrome/browser/chromeos/settings/cros_settings.h" 25 #include "chrome/browser/chromeos/settings/device_settings_test_helper.h" 26 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h" 27 #include "chrome/test/base/testing_browser_process.h" 28 #include "chrome/test/base/testing_profile.h" 29 #include "chrome/test/base/testing_profile_manager.h" 30 #include "chromeos/chromeos_switches.h" 31 #include "chromeos/cryptohome/cryptohome_parameters.h" 32 #include "chromeos/cryptohome/homedir_methods.h" 33 #include "chromeos/cryptohome/mock_async_method_caller.h" 34 #include "chromeos/cryptohome/mock_homedir_methods.h" 35 #include "chromeos/cryptohome/system_salt_getter.h" 36 #include "chromeos/dbus/cros_disks_client.h" 37 #include "chromeos/dbus/cryptohome/rpc.pb.h" 38 #include "chromeos/dbus/dbus_thread_manager.h" 39 #include "chromeos/dbus/fake_cryptohome_client.h" 40 #include "chromeos/login/auth/key.h" 41 #include "chromeos/login/auth/mock_auth_status_consumer.h" 42 #include "chromeos/login/auth/mock_url_fetchers.h" 43 #include "chromeos/login/auth/test_attempt_state.h" 44 #include "chromeos/login/auth/user_context.h" 45 #include "chromeos/login/login_state.h" 46 #include "components/ownership/mock_owner_key_util.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" 56 #include "url/gurl.h" 57 58 using ::testing::Invoke; 59 using ::testing::Return; 60 using ::testing::WithArg; 61 using ::testing::_; 62 63 namespace chromeos { 64 65 namespace { 66 67 // Label under which the user's key is stored. 68 const char kCryptohomeGAIAKeyLabel[] = "gaia"; 69 70 // Salt used by pre-hashed key. 71 const char kSalt[] = "SALT $$"; 72 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}; 104 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}; 115 116 std::vector<uint8> GetOwnerPublicKey() { 117 return std::vector<uint8>(kOwnerPublicKey, 118 kOwnerPublicKey + arraysize(kOwnerPublicKey)); 119 } 120 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)); 126 } 127 128 } // namespace 129 130 class CryptohomeAuthenticatorTest : public testing::Test { 131 public: 132 CryptohomeAuthenticatorTest() 133 : user_context_("me (at) nowhere.org"), 134 user_manager_(new FakeUserManager()), 135 user_manager_enabler_(user_manager_), 136 mock_caller_(NULL), 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()); 146 147 ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, &profile_); 148 149 CreateTransformedKey(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, 150 SystemSaltGetter::ConvertRawSaltToHexString( 151 FakeCryptohomeClient::GetStubSystemSalt())); 152 } 153 154 virtual ~CryptohomeAuthenticatorTest() {} 155 156 virtual void SetUp() { 157 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kLoginManager); 158 159 mock_caller_ = new cryptohome::MockAsyncMethodCaller; 160 cryptohome::AsyncMethodCaller::InitializeForTesting(mock_caller_); 161 mock_homedir_methods_ = new cryptohome::MockHomedirMethods; 162 mock_homedir_methods_->SetUp(true, cryptohome::MOUNT_ERROR_NONE); 163 cryptohome::HomedirMethods::InitializeForTesting(mock_homedir_methods_); 164 165 fake_cryptohome_client_ = new FakeCryptohomeClient; 166 chromeos::DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient( 167 scoped_ptr<CryptohomeClient>(fake_cryptohome_client_)); 168 169 SystemSaltGetter::Initialize(); 170 171 auth_ = new ChromeCryptohomeAuthenticator(&consumer_); 172 state_.reset(new TestAttemptState(user_context_, false)); 173 } 174 175 // Tears down the test fixture. 176 virtual void TearDown() { 177 SystemSaltGetter::Shutdown(); 178 DBusThreadManager::Shutdown(); 179 180 cryptohome::AsyncMethodCaller::Shutdown(); 181 mock_caller_ = NULL; 182 cryptohome::HomedirMethods::Shutdown(); 183 mock_homedir_methods_ = NULL; 184 } 185 186 void CreateTransformedKey(Key::KeyType type, const std::string& salt) { 187 user_context_with_transformed_key_ = user_context_; 188 user_context_with_transformed_key_.GetKey()->Transform(type, salt); 189 transformed_key_ = *user_context_with_transformed_key_.GetKey(); 190 } 191 192 base::FilePath PopulateTempFile(const char* data, int data_len) { 193 base::FilePath out; 194 FILE* tmp_file = base::CreateAndOpenTemporaryFile(&out); 195 EXPECT_NE(tmp_file, static_cast<FILE*>(NULL)); 196 EXPECT_EQ(base::WriteFile(out, data, data_len), data_len); 197 EXPECT_TRUE(base::CloseFile(tmp_file)); 198 return out; 199 } 200 201 // Allow test to fail and exit gracefully, even if OnAuthFailure() 202 // wasn't supposed to happen. 203 void FailOnLoginFailure() { 204 ON_CALL(consumer_, OnAuthFailure(_)) 205 .WillByDefault(Invoke(MockAuthStatusConsumer::OnFailQuitAndFail)); 206 } 207 208 // Allow test to fail and exit gracefully, even if 209 // OnRetailModeAuthSuccess() wasn't supposed to happen. 210 void FailOnRetailModeLoginSuccess() { 211 ON_CALL(consumer_, OnRetailModeAuthSuccess(_)).WillByDefault( 212 Invoke(MockAuthStatusConsumer::OnRetailModeSuccessQuitAndFail)); 213 } 214 215 // Allow test to fail and exit gracefully, even if OnAuthSuccess() 216 // wasn't supposed to happen. 217 void FailOnLoginSuccess() { 218 ON_CALL(consumer_, OnAuthSuccess(_)) 219 .WillByDefault(Invoke(MockAuthStatusConsumer::OnSuccessQuitAndFail)); 220 } 221 222 // Allow test to fail and exit gracefully, even if 223 // OnOffTheRecordAuthSuccess() wasn't supposed to happen. 224 void FailOnGuestLoginSuccess() { 225 ON_CALL(consumer_, OnOffTheRecordAuthSuccess()).WillByDefault( 226 Invoke(MockAuthStatusConsumer::OnGuestSuccessQuitAndFail)); 227 } 228 229 void ExpectLoginFailure(const AuthFailure& failure) { 230 EXPECT_CALL(consumer_, OnAuthFailure(failure)) 231 .WillOnce(Invoke(MockAuthStatusConsumer::OnFailQuit)) 232 .RetiresOnSaturation(); 233 } 234 235 void ExpectRetailModeLoginSuccess() { 236 EXPECT_CALL(consumer_, OnRetailModeAuthSuccess(_)) 237 .WillOnce(Invoke(MockAuthStatusConsumer::OnRetailModeSuccessQuit)) 238 .RetiresOnSaturation(); 239 } 240 241 void ExpectLoginSuccess(const UserContext& user_context) { 242 EXPECT_CALL(consumer_, OnAuthSuccess(user_context)) 243 .WillOnce(Invoke(MockAuthStatusConsumer::OnSuccessQuit)) 244 .RetiresOnSaturation(); 245 } 246 247 void ExpectGuestLoginSuccess() { 248 EXPECT_CALL(consumer_, OnOffTheRecordAuthSuccess()) 249 .WillOnce(Invoke(MockAuthStatusConsumer::OnGuestSuccessQuit)) 250 .RetiresOnSaturation(); 251 } 252 253 void ExpectPasswordChange() { 254 EXPECT_CALL(consumer_, OnPasswordChangeDetected()) 255 .WillOnce(Invoke(MockAuthStatusConsumer::OnMigrateQuit)) 256 .RetiresOnSaturation(); 257 } 258 259 void ExpectGetKeyDataExCall(scoped_ptr<int64> key_type, 260 scoped_ptr<std::string> salt) { 261 key_definitions_.clear(); 262 key_definitions_.push_back(cryptohome::KeyDefinition( 263 std::string() /* secret */, 264 kCryptohomeGAIAKeyLabel, 265 cryptohome::PRIV_DEFAULT)); 266 cryptohome::KeyDefinition& key_definition = key_definitions_.back(); 267 key_definition.revision = 1; 268 if (key_type) { 269 key_definition.provider_data.push_back( 270 cryptohome::KeyDefinition::ProviderData("type")); 271 key_definition.provider_data.back().number = key_type.Pass(); 272 } 273 if (salt) { 274 key_definition.provider_data.push_back( 275 cryptohome::KeyDefinition::ProviderData("salt")); 276 key_definition.provider_data.back().bytes = salt.Pass(); 277 } 278 EXPECT_CALL(*mock_homedir_methods_, GetKeyDataEx( 279 cryptohome::Identification(user_context_.GetUserID()), 280 kCryptohomeGAIAKeyLabel, 281 _)) 282 .WillOnce(WithArg<2>(Invoke( 283 this, 284 &CryptohomeAuthenticatorTest::InvokeGetDataExCallback))); 285 } 286 287 void ExpectMountExCall(bool expect_create_attempt) { 288 const cryptohome::KeyDefinition auth_key(transformed_key_.GetSecret(), 289 std::string(), 290 cryptohome::PRIV_DEFAULT); 291 cryptohome::MountParameters mount(false /* ephemeral */); 292 if (expect_create_attempt) { 293 mount.create_keys.push_back(cryptohome::KeyDefinition( 294 transformed_key_.GetSecret(), 295 kCryptohomeGAIAKeyLabel, 296 cryptohome::PRIV_DEFAULT)); 297 } 298 EXPECT_CALL(*mock_homedir_methods_, 299 MountEx(cryptohome::Identification(user_context_.GetUserID()), 300 cryptohome::Authorization(auth_key), 301 mount, 302 _)) 303 .Times(1) 304 .RetiresOnSaturation(); 305 } 306 307 void RunResolve(CryptohomeAuthenticator* auth) { 308 auth->Resolve(); 309 base::MessageLoop::current()->RunUntilIdle(); 310 } 311 312 void SetAttemptState(CryptohomeAuthenticator* auth, TestAttemptState* state) { 313 auth->set_attempt_state(state); 314 } 315 316 CryptohomeAuthenticator::AuthState SetAndResolveState( 317 CryptohomeAuthenticator* auth, 318 TestAttemptState* state) { 319 auth->set_attempt_state(state); 320 return auth->ResolveState(); 321 } 322 323 void SetOwnerState(bool owner_check_finished, bool check_result) { 324 auth_->SetOwnerState(owner_check_finished, check_result); 325 } 326 327 content::TestBrowserThreadBundle thread_bundle_; 328 329 UserContext user_context_; 330 UserContext user_context_with_transformed_key_; 331 Key transformed_key_; 332 333 std::vector<cryptohome::KeyDefinition> key_definitions_; 334 335 ScopedDeviceSettingsTestHelper device_settings_test_helper_; 336 ScopedTestCrosSettings test_cros_settings_; 337 338 TestingProfile profile_; 339 scoped_ptr<TestingProfileManager> profile_manager_; 340 FakeUserManager* user_manager_; 341 ScopedUserManagerEnabler user_manager_enabler_; 342 343 cryptohome::MockAsyncMethodCaller* mock_caller_; 344 cryptohome::MockHomedirMethods* mock_homedir_methods_; 345 346 MockAuthStatusConsumer consumer_; 347 348 scoped_refptr<CryptohomeAuthenticator> auth_; 349 scoped_ptr<TestAttemptState> state_; 350 FakeCryptohomeClient* fake_cryptohome_client_; 351 352 scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util_; 353 354 private: 355 void InvokeGetDataExCallback( 356 const cryptohome::HomedirMethods::GetKeyDataCallback& callback) { 357 callback.Run(true /* success */, 358 cryptohome::MOUNT_ERROR_NONE, 359 key_definitions_); 360 } 361 }; 362 363 TEST_F(CryptohomeAuthenticatorTest, OnAuthSuccess) { 364 EXPECT_CALL(consumer_, OnAuthSuccess(user_context_)) 365 .Times(1) 366 .RetiresOnSaturation(); 367 368 SetAttemptState(auth_.get(), state_.release()); 369 auth_->OnAuthSuccess(); 370 } 371 372 TEST_F(CryptohomeAuthenticatorTest, OnPasswordChangeDetected) { 373 EXPECT_CALL(consumer_, OnPasswordChangeDetected()) 374 .Times(1) 375 .RetiresOnSaturation(); 376 SetAttemptState(auth_.get(), state_.release()); 377 auth_->OnPasswordChangeDetected(); 378 } 379 380 TEST_F(CryptohomeAuthenticatorTest, ResolveNothingDone) { 381 EXPECT_EQ(CryptohomeAuthenticator::CONTINUE, 382 SetAndResolveState(auth_.get(), state_.release())); 383 } 384 385 TEST_F(CryptohomeAuthenticatorTest, ResolvePossiblePwChangeToFailedMount) { 386 // Set up state as though a cryptohome mount attempt has occurred 387 // and been rejected. 388 state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE); 389 390 // When there is no online attempt and online results, POSSIBLE_PW_CHANGE 391 EXPECT_EQ(CryptohomeAuthenticator::FAILED_MOUNT, 392 SetAndResolveState(auth_.get(), state_.release())); 393 } 394 395 TEST_F(CryptohomeAuthenticatorTest, ResolveNeedOldPw) { 396 // Set up state as though a cryptohome mount attempt has occurred 397 // and been rejected because of unmatched key; additionally, 398 // an online auth attempt has completed successfully. 399 state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE); 400 state_->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone()); 401 402 EXPECT_EQ(CryptohomeAuthenticator::NEED_OLD_PW, 403 SetAndResolveState(auth_.get(), state_.release())); 404 } 405 406 TEST_F(CryptohomeAuthenticatorTest, ResolveOwnerNeededDirectFailedMount) { 407 // Set up state as though a cryptohome mount attempt has occurred 408 // and succeeded but we are in safe mode and the current user is not owner. 409 // This is a high level test to verify the proper transitioning in this mode 410 // only. It is not testing that we properly verify that the user is an owner 411 // or that we really are in "safe-mode". 412 state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE); 413 SetOwnerState(true, false); 414 415 EXPECT_EQ(CryptohomeAuthenticator::OWNER_REQUIRED, 416 SetAndResolveState(auth_.get(), state_.release())); 417 } 418 419 TEST_F(CryptohomeAuthenticatorTest, ResolveOwnerNeededMount) { 420 // Set up state as though a cryptohome mount attempt has occurred 421 // and succeeded but we are in safe mode and the current user is not owner. 422 // This test will check that the "safe-mode" policy is not set and will let 423 // the mount finish successfully. 424 state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE); 425 SetOwnerState(false, false); 426 EXPECT_EQ(CryptohomeAuthenticator::OFFLINE_LOGIN, 427 SetAndResolveState(auth_.get(), state_.release())); 428 } 429 430 // Test the case that login switches to SafeMode and a User that is not the 431 // owner tries to log in. The login should fail because of the missing owner 432 // private key. 433 TEST_F(CryptohomeAuthenticatorTest, ResolveOwnerNeededFailedMount) { 434 crypto::ScopedTestNSSChromeOSUser user_slot(user_context_.GetUserIDHash()); 435 owner_key_util_->SetPublicKey(GetOwnerPublicKey()); 436 437 profile_manager_.reset( 438 new TestingProfileManager(TestingBrowserProcess::GetGlobal())); 439 ASSERT_TRUE(profile_manager_->SetUp()); 440 441 FailOnLoginSuccess(); // Set failing on success as the default... 442 AuthFailure failure = AuthFailure(AuthFailure::OWNER_REQUIRED); 443 ExpectLoginFailure(failure); 444 445 // Set up state as though a cryptohome mount attempt has occurred 446 // and succeeded but we are in safe mode and the current user is not owner. 447 state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE); 448 SetOwnerState(false, false); 449 // Remove the real DeviceSettingsProvider and replace it with a stub. 450 CrosSettingsProvider* device_settings_provider = 451 CrosSettings::Get()->GetProvider(chromeos::kReportDeviceVersionInfo); 452 EXPECT_TRUE(device_settings_provider != NULL); 453 EXPECT_TRUE( 454 CrosSettings::Get()->RemoveSettingsProvider(device_settings_provider)); 455 StubCrosSettingsProvider stub_settings_provider; 456 CrosSettings::Get()->AddSettingsProvider(&stub_settings_provider); 457 CrosSettings::Get()->SetBoolean(kPolicyMissingMitigationMode, true); 458 459 // Initialize login state for this test to verify the login state is changed 460 // to SAFE_MODE. 461 LoginState::Initialize(); 462 463 EXPECT_EQ(CryptohomeAuthenticator::CONTINUE, 464 SetAndResolveState(auth_.get(), state_.release())); 465 EXPECT_TRUE(LoginState::Get()->IsInSafeMode()); 466 467 // Flush all the pending operations. The operations should induce an owner 468 // verification. 469 device_settings_test_helper_.Flush(); 470 471 state_.reset(new TestAttemptState(user_context_, false)); 472 state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE); 473 474 // The owner key util should not have found the owner key, so login should 475 // not be allowed. 476 EXPECT_EQ(CryptohomeAuthenticator::OWNER_REQUIRED, 477 SetAndResolveState(auth_.get(), state_.release())); 478 EXPECT_TRUE(LoginState::Get()->IsInSafeMode()); 479 480 // Unset global objects used by this test. 481 fake_cryptohome_client_->set_unmount_result(true); 482 LoginState::Shutdown(); 483 EXPECT_TRUE( 484 CrosSettings::Get()->RemoveSettingsProvider(&stub_settings_provider)); 485 CrosSettings::Get()->AddSettingsProvider(device_settings_provider); 486 } 487 488 // Test the case that login switches to SafeMode and the Owner logs in, which 489 // should lead to a successful login. 490 TEST_F(CryptohomeAuthenticatorTest, ResolveOwnerNeededSuccess) { 491 crypto::ScopedTestNSSChromeOSUser test_user_db(user_context_.GetUserIDHash()); 492 owner_key_util_->SetPublicKey(GetOwnerPublicKey()); 493 494 crypto::ScopedPK11Slot user_slot( 495 crypto::GetPublicSlotForChromeOSUser(user_context_.GetUserIDHash())); 496 CreateOwnerKeyInSlot(user_slot.get()); 497 498 profile_manager_.reset( 499 new TestingProfileManager(TestingBrowserProcess::GetGlobal())); 500 ASSERT_TRUE(profile_manager_->SetUp()); 501 502 ExpectLoginSuccess(user_context_); 503 504 // Set up state as though a cryptohome mount attempt has occurred 505 // and succeeded but we are in safe mode and the current user is not owner. 506 state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE); 507 SetOwnerState(false, false); 508 // Remove the real DeviceSettingsProvider and replace it with a stub. 509 CrosSettingsProvider* device_settings_provider = 510 CrosSettings::Get()->GetProvider(chromeos::kReportDeviceVersionInfo); 511 EXPECT_TRUE(device_settings_provider != NULL); 512 EXPECT_TRUE( 513 CrosSettings::Get()->RemoveSettingsProvider(device_settings_provider)); 514 StubCrosSettingsProvider stub_settings_provider; 515 CrosSettings::Get()->AddSettingsProvider(&stub_settings_provider); 516 CrosSettings::Get()->SetBoolean(kPolicyMissingMitigationMode, true); 517 518 // Initialize login state for this test to verify the login state is changed 519 // to SAFE_MODE. 520 LoginState::Initialize(); 521 522 EXPECT_EQ(CryptohomeAuthenticator::CONTINUE, 523 SetAndResolveState(auth_.get(), state_.release())); 524 EXPECT_TRUE(LoginState::Get()->IsInSafeMode()); 525 526 // Flush all the pending operations. The operations should induce an owner 527 // verification. 528 device_settings_test_helper_.Flush(); 529 530 state_.reset(new TestAttemptState(user_context_, false)); 531 state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE); 532 533 // The owner key util should find the owner key, so login should succeed. 534 EXPECT_EQ(CryptohomeAuthenticator::OFFLINE_LOGIN, 535 SetAndResolveState(auth_.get(), state_.release())); 536 EXPECT_TRUE(LoginState::Get()->IsInSafeMode()); 537 538 // Unset global objects used by this test. 539 fake_cryptohome_client_->set_unmount_result(true); 540 LoginState::Shutdown(); 541 EXPECT_TRUE( 542 CrosSettings::Get()->RemoveSettingsProvider(&stub_settings_provider)); 543 CrosSettings::Get()->AddSettingsProvider(device_settings_provider); 544 } 545 546 TEST_F(CryptohomeAuthenticatorTest, DriveFailedMount) { 547 FailOnLoginSuccess(); 548 ExpectLoginFailure(AuthFailure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME)); 549 550 // Set up state as though a cryptohome mount attempt has occurred 551 // and failed. 552 state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_NONE); 553 SetAttemptState(auth_.get(), state_.release()); 554 555 RunResolve(auth_.get()); 556 } 557 558 TEST_F(CryptohomeAuthenticatorTest, DriveGuestLogin) { 559 ExpectGuestLoginSuccess(); 560 FailOnLoginFailure(); 561 562 // Set up mock async method caller to respond as though a tmpfs mount 563 // attempt has occurred and succeeded. 564 mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE); 565 EXPECT_CALL(*mock_caller_, AsyncMountGuest(_)).Times(1).RetiresOnSaturation(); 566 567 auth_->LoginOffTheRecord(); 568 base::MessageLoop::current()->Run(); 569 } 570 571 TEST_F(CryptohomeAuthenticatorTest, DriveGuestLoginButFail) { 572 FailOnGuestLoginSuccess(); 573 ExpectLoginFailure(AuthFailure(AuthFailure::COULD_NOT_MOUNT_TMPFS)); 574 575 // Set up mock async method caller to respond as though a tmpfs mount 576 // attempt has occurred and failed. 577 mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_NONE); 578 EXPECT_CALL(*mock_caller_, AsyncMountGuest(_)).Times(1).RetiresOnSaturation(); 579 580 auth_->LoginOffTheRecord(); 581 base::MessageLoop::current()->Run(); 582 } 583 584 TEST_F(CryptohomeAuthenticatorTest, DriveRetailModeUserLogin) { 585 ExpectRetailModeLoginSuccess(); 586 FailOnLoginFailure(); 587 588 // Set up mock async method caller to respond as though a tmpfs mount 589 // attempt has occurred and succeeded. 590 mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE); 591 EXPECT_CALL(*mock_caller_, AsyncMountGuest(_)).Times(1).RetiresOnSaturation(); 592 593 auth_->LoginRetailMode(); 594 base::MessageLoop::current()->Run(); 595 } 596 597 TEST_F(CryptohomeAuthenticatorTest, DriveRetailModeLoginButFail) { 598 FailOnRetailModeLoginSuccess(); 599 ExpectLoginFailure(AuthFailure(AuthFailure::COULD_NOT_MOUNT_TMPFS)); 600 601 // Set up mock async method caller to respond as though a tmpfs mount 602 // attempt has occurred and failed. 603 mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_NONE); 604 EXPECT_CALL(*mock_caller_, AsyncMountGuest(_)).Times(1).RetiresOnSaturation(); 605 606 auth_->LoginRetailMode(); 607 base::MessageLoop::current()->Run(); 608 } 609 610 TEST_F(CryptohomeAuthenticatorTest, DriveDataResync) { 611 UserContext expected_user_context(user_context_with_transformed_key_); 612 expected_user_context.SetUserIDHash( 613 cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername); 614 ExpectLoginSuccess(expected_user_context); 615 FailOnLoginFailure(); 616 617 // Set up mock async method caller to respond successfully to a cryptohome 618 // remove attempt. 619 mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE); 620 EXPECT_CALL(*mock_caller_, AsyncRemove(user_context_.GetUserID(), _)) 621 .Times(1) 622 .RetiresOnSaturation(); 623 624 // Set up mock homedir methods to respond successfully to a cryptohome create 625 // attempt. 626 ExpectGetKeyDataExCall(scoped_ptr<int64>(), scoped_ptr<std::string>()); 627 ExpectMountExCall(true /* expect_create_attempt */); 628 629 state_->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone()); 630 SetAttemptState(auth_.get(), state_.release()); 631 632 auth_->ResyncEncryptedData(); 633 base::MessageLoop::current()->Run(); 634 } 635 636 TEST_F(CryptohomeAuthenticatorTest, DriveResyncFail) { 637 FailOnLoginSuccess(); 638 ExpectLoginFailure(AuthFailure(AuthFailure::DATA_REMOVAL_FAILED)); 639 640 // Set up mock async method caller to fail a cryptohome remove attempt. 641 mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_NONE); 642 EXPECT_CALL(*mock_caller_, AsyncRemove(user_context_.GetUserID(), _)) 643 .Times(1) 644 .RetiresOnSaturation(); 645 646 SetAttemptState(auth_.get(), state_.release()); 647 648 auth_->ResyncEncryptedData(); 649 base::MessageLoop::current()->Run(); 650 } 651 652 TEST_F(CryptohomeAuthenticatorTest, DriveRequestOldPassword) { 653 FailOnLoginSuccess(); 654 ExpectPasswordChange(); 655 656 state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE); 657 state_->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone()); 658 SetAttemptState(auth_.get(), state_.release()); 659 660 RunResolve(auth_.get()); 661 } 662 663 TEST_F(CryptohomeAuthenticatorTest, DriveDataRecover) { 664 UserContext expected_user_context(user_context_with_transformed_key_); 665 expected_user_context.SetUserIDHash( 666 cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername); 667 ExpectLoginSuccess(expected_user_context); 668 FailOnLoginFailure(); 669 670 // Set up mock async method caller to respond successfully to a key migration. 671 mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE); 672 EXPECT_CALL( 673 *mock_caller_, 674 AsyncMigrateKey( 675 user_context_.GetUserID(), _, transformed_key_.GetSecret(), _)) 676 .Times(1) 677 .RetiresOnSaturation(); 678 679 // Set up mock homedir methods to respond successfully to a cryptohome mount 680 // attempt. 681 ExpectGetKeyDataExCall(scoped_ptr<int64>(), scoped_ptr<std::string>()); 682 ExpectMountExCall(false /* expect_create_attempt */); 683 684 state_->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone()); 685 SetAttemptState(auth_.get(), state_.release()); 686 687 auth_->RecoverEncryptedData(std::string()); 688 base::MessageLoop::current()->Run(); 689 } 690 691 TEST_F(CryptohomeAuthenticatorTest, DriveDataRecoverButFail) { 692 FailOnLoginSuccess(); 693 ExpectPasswordChange(); 694 695 // Set up mock async method caller to fail a key migration attempt, 696 // asserting that the wrong password was used. 697 mock_caller_->SetUp(false, cryptohome::MOUNT_ERROR_KEY_FAILURE); 698 EXPECT_CALL( 699 *mock_caller_, 700 AsyncMigrateKey( 701 user_context_.GetUserID(), _, transformed_key_.GetSecret(), _)) 702 .Times(1) 703 .RetiresOnSaturation(); 704 705 SetAttemptState(auth_.get(), state_.release()); 706 707 auth_->RecoverEncryptedData(std::string()); 708 base::MessageLoop::current()->Run(); 709 } 710 711 TEST_F(CryptohomeAuthenticatorTest, ResolveNoMountToFailedMount) { 712 // Set up state as though a cryptohome mount attempt has occurred 713 // and been rejected because the user doesn't exist. 714 state_->PresetCryptohomeStatus(false, 715 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST); 716 717 // When there is no online attempt and online results, NO_MOUNT will be 718 // resolved to FAILED_MOUNT. 719 EXPECT_EQ(CryptohomeAuthenticator::FAILED_MOUNT, 720 SetAndResolveState(auth_.get(), state_.release())); 721 } 722 723 TEST_F(CryptohomeAuthenticatorTest, ResolveCreateNew) { 724 // Set up state as though a cryptohome mount attempt has occurred 725 // and been rejected because the user doesn't exist; additionally, 726 // an online auth attempt has completed successfully. 727 state_->PresetCryptohomeStatus(false, 728 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST); 729 state_->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone()); 730 731 EXPECT_EQ(CryptohomeAuthenticator::CREATE_NEW, 732 SetAndResolveState(auth_.get(), state_.release())); 733 } 734 735 TEST_F(CryptohomeAuthenticatorTest, DriveCreateForNewUser) { 736 UserContext expected_user_context(user_context_with_transformed_key_); 737 expected_user_context.SetUserIDHash( 738 cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername); 739 ExpectLoginSuccess(expected_user_context); 740 FailOnLoginFailure(); 741 742 // Set up mock homedir methods to respond successfully to a cryptohome create 743 // attempt. 744 ExpectGetKeyDataExCall(scoped_ptr<int64>(), scoped_ptr<std::string>()); 745 ExpectMountExCall(true /* expect_create_attempt */); 746 747 // Set up state as though a cryptohome mount attempt has occurred 748 // and been rejected because the user doesn't exist; additionally, 749 // an online auth attempt has completed successfully. 750 state_->PresetCryptohomeStatus(false, 751 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST); 752 state_->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone()); 753 SetAttemptState(auth_.get(), state_.release()); 754 755 RunResolve(auth_.get()); 756 } 757 758 TEST_F(CryptohomeAuthenticatorTest, DriveOfflineLogin) { 759 ExpectLoginSuccess(user_context_); 760 FailOnLoginFailure(); 761 762 // Set up state as though a cryptohome mount attempt has occurred and 763 // succeeded. 764 state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE); 765 SetAttemptState(auth_.get(), state_.release()); 766 767 RunResolve(auth_.get()); 768 } 769 770 TEST_F(CryptohomeAuthenticatorTest, DriveOnlineLogin) { 771 ExpectLoginSuccess(user_context_); 772 FailOnLoginFailure(); 773 774 // Set up state as though a cryptohome mount attempt has occurred and 775 // succeeded. 776 state_->PresetCryptohomeStatus(true, cryptohome::MOUNT_ERROR_NONE); 777 state_->PresetOnlineLoginStatus(AuthFailure::AuthFailureNone()); 778 SetAttemptState(auth_.get(), state_.release()); 779 780 RunResolve(auth_.get()); 781 } 782 783 TEST_F(CryptohomeAuthenticatorTest, DriveUnlock) { 784 ExpectLoginSuccess(user_context_); 785 FailOnLoginFailure(); 786 787 // Set up mock async method caller to respond successfully to a cryptohome 788 // key-check attempt. 789 mock_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE); 790 EXPECT_CALL(*mock_caller_, AsyncCheckKey(user_context_.GetUserID(), _, _)) 791 .Times(1) 792 .RetiresOnSaturation(); 793 794 auth_->AuthenticateToUnlock(user_context_); 795 base::MessageLoop::current()->Run(); 796 } 797 798 TEST_F(CryptohomeAuthenticatorTest, DriveLoginWithPreHashedPassword) { 799 CreateTransformedKey(Key::KEY_TYPE_SALTED_SHA256, kSalt); 800 801 UserContext expected_user_context(user_context_with_transformed_key_); 802 expected_user_context.SetUserIDHash( 803 cryptohome::MockAsyncMethodCaller::kFakeSanitizedUsername); 804 ExpectLoginSuccess(expected_user_context); 805 FailOnLoginFailure(); 806 807 // Set up mock homedir methods to respond with key metadata indicating that a 808 // pre-hashed key was used to create the cryptohome and allow a successful 809 // mount when this pre-hashed key is used. 810 811 ExpectGetKeyDataExCall( 812 make_scoped_ptr(new int64(Key::KEY_TYPE_SALTED_SHA256)), 813 make_scoped_ptr(new std::string(kSalt))); 814 ExpectMountExCall(false /* expect_create_attempt */); 815 816 auth_->AuthenticateToLogin(NULL, user_context_); 817 base::RunLoop().Run(); 818 } 819 820 TEST_F(CryptohomeAuthenticatorTest, FailLoginWithMissingSalt) { 821 CreateTransformedKey(Key::KEY_TYPE_SALTED_SHA256, kSalt); 822 823 FailOnLoginSuccess(); 824 ExpectLoginFailure(AuthFailure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME)); 825 826 // Set up mock homedir methods to respond with key metadata indicating that a 827 // pre-hashed key was used to create the cryptohome but without the required 828 // salt. 829 ExpectGetKeyDataExCall( 830 make_scoped_ptr(new int64(Key::KEY_TYPE_SALTED_SHA256)), 831 scoped_ptr<std::string>()); 832 833 auth_->AuthenticateToLogin(NULL, user_context_); 834 base::RunLoop().Run(); 835 } 836 837 } // namespace chromeos 838