Home | History | Annotate | Download | only in auth
      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