| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/password_manager/password_store_proxy_mac.h" | 5 #include "chrome/browser/password_manager/password_store_mac.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/files/scoped_temp_dir.h" | 9 #include "base/files/scoped_temp_dir.h" |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| 11 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
| 12 #include "base/run_loop.h" | 12 #include "base/run_loop.h" |
| 13 #include "base/scoped_observer.h" | 13 #include "base/scoped_observer.h" |
| 14 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
| 15 #include "base/test/histogram_tester.h" | 15 #include "base/test/histogram_tester.h" |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 64 | 64 |
| 65 std::vector<std::unique_ptr<PasswordForm>> forms_; | 65 std::vector<std::unique_ptr<PasswordForm>> forms_; |
| 66 base::RunLoop* nested_loop_ = nullptr; | 66 base::RunLoop* nested_loop_ = nullptr; |
| 67 | 67 |
| 68 DISALLOW_COPY_AND_ASSIGN(MockPasswordStoreConsumer); | 68 DISALLOW_COPY_AND_ASSIGN(MockPasswordStoreConsumer); |
| 69 }; | 69 }; |
| 70 | 70 |
| 71 class MockPasswordStoreObserver | 71 class MockPasswordStoreObserver |
| 72 : public password_manager::PasswordStore::Observer { | 72 : public password_manager::PasswordStore::Observer { |
| 73 public: | 73 public: |
| 74 explicit MockPasswordStoreObserver(PasswordStoreProxyMac* password_store) | 74 explicit MockPasswordStoreObserver(PasswordStoreMac* password_store) |
| 75 : guard_(this) { | 75 : guard_(this) { |
| 76 guard_.Add(password_store); | 76 guard_.Add(password_store); |
| 77 } | 77 } |
| 78 MOCK_METHOD1(OnLoginsChanged, | 78 MOCK_METHOD1(OnLoginsChanged, |
| 79 void(const password_manager::PasswordStoreChangeList& changes)); | 79 void(const password_manager::PasswordStoreChangeList& changes)); |
| 80 | 80 |
| 81 private: | 81 private: |
| 82 ScopedObserver<PasswordStoreProxyMac, MockPasswordStoreObserver> guard_; | 82 ScopedObserver<PasswordStoreMac, MockPasswordStoreObserver> guard_; |
| 83 | 83 |
| 84 DISALLOW_COPY_AND_ASSIGN(MockPasswordStoreObserver); | 84 DISALLOW_COPY_AND_ASSIGN(MockPasswordStoreObserver); |
| 85 }; | 85 }; |
| 86 | 86 |
| 87 // A mock LoginDatabase that simulates a failing Init() method. | 87 // A mock LoginDatabase that simulates a failing Init() method. |
| 88 class BadLoginDatabase : public password_manager::LoginDatabase { | 88 class BadLoginDatabase : public password_manager::LoginDatabase { |
| 89 public: | 89 public: |
| 90 BadLoginDatabase() : password_manager::LoginDatabase(base::FilePath()) {} | 90 BadLoginDatabase() : password_manager::LoginDatabase(base::FilePath()) {} |
| 91 ~BadLoginDatabase() override {} | 91 ~BadLoginDatabase() override {} |
| 92 | 92 |
| 93 // LoginDatabase: | 93 // LoginDatabase: |
| 94 bool Init() override { return false; } | 94 bool Init() override { return false; } |
| 95 | 95 |
| 96 private: | 96 private: |
| 97 DISALLOW_COPY_AND_ASSIGN(BadLoginDatabase); | 97 DISALLOW_COPY_AND_ASSIGN(BadLoginDatabase); |
| 98 }; | 98 }; |
| 99 | 99 |
| 100 class PasswordStoreProxyMacTest | 100 class PasswordStoreMacTest : public testing::TestWithParam<MigrationStatus> { |
| 101 : public testing::TestWithParam<MigrationStatus> { | |
| 102 public: | 101 public: |
| 103 PasswordStoreProxyMacTest(); | 102 PasswordStoreMacTest(); |
| 104 ~PasswordStoreProxyMacTest() override; | 103 ~PasswordStoreMacTest() override; |
| 105 | 104 |
| 106 void CreateAndInitPasswordStore( | 105 void CreateAndInitPasswordStore( |
| 107 std::unique_ptr<password_manager::LoginDatabase> login_db); | 106 std::unique_ptr<password_manager::LoginDatabase> login_db); |
| 108 | 107 |
| 109 void ClosePasswordStore(); | 108 void ClosePasswordStore(); |
| 110 | 109 |
| 111 // Do a store-level query to wait for all the previously enqueued operations | 110 // Do a store-level query to wait for all the previously enqueued operations |
| 112 // to finish. | 111 // to finish. |
| 113 void FinishAsyncProcessing(); | 112 void FinishAsyncProcessing(); |
| 114 | 113 |
| 115 // Add/Update/Remove |form| and verify the operation succeeded. | 114 // Add/Update/Remove |form| and verify the operation succeeded. |
| 116 void AddForm(const PasswordForm& form); | 115 void AddForm(const PasswordForm& form); |
| 117 void UpdateForm(const PasswordForm& form); | 116 void UpdateForm(const PasswordForm& form); |
| 118 void RemoveForm(const PasswordForm& form); | 117 void RemoveForm(const PasswordForm& form); |
| 119 | 118 |
| 120 base::FilePath test_login_db_file_path() const; | 119 base::FilePath test_login_db_file_path() const; |
| 121 | 120 |
| 122 // Returns the expected migration status after the password store was inited. | 121 // Returns the expected migration status after the password store was inited. |
| 123 MigrationStatus GetTargetStatus() const; | 122 MigrationStatus GetTargetStatus() const; |
| 124 | 123 |
| 125 password_manager::LoginDatabase* login_db() const { | 124 password_manager::LoginDatabase* login_db() const { |
| 126 return store_->login_metadata_db(); | 125 return store_->login_metadata_db(); |
| 127 } | 126 } |
| 128 | 127 |
| 129 PasswordStoreProxyMac* store() { return store_.get(); } | 128 PasswordStoreMac* store() { return store_.get(); } |
| 130 | 129 |
| 131 protected: | 130 protected: |
| 132 content::TestBrowserThreadBundle ui_thread_; | 131 content::TestBrowserThreadBundle ui_thread_; |
| 133 | 132 |
| 134 base::ScopedTempDir db_dir_; | 133 base::ScopedTempDir db_dir_; |
| 135 scoped_refptr<PasswordStoreProxyMac> store_; | 134 scoped_refptr<PasswordStoreMac> store_; |
| 136 sync_preferences::TestingPrefServiceSyncable testing_prefs_; | 135 sync_preferences::TestingPrefServiceSyncable testing_prefs_; |
| 137 }; | 136 }; |
| 138 | 137 |
| 139 PasswordStoreProxyMacTest::PasswordStoreProxyMacTest() { | 138 PasswordStoreMacTest::PasswordStoreMacTest() { |
| 140 EXPECT_TRUE(db_dir_.CreateUniqueTempDir()); | 139 EXPECT_TRUE(db_dir_.CreateUniqueTempDir()); |
| 141 chrome::RegisterUserProfilePrefs(testing_prefs_.registry()); | 140 chrome::RegisterUserProfilePrefs(testing_prefs_.registry()); |
| 142 testing_prefs_.SetInteger(password_manager::prefs::kKeychainMigrationStatus, | 141 testing_prefs_.SetInteger(password_manager::prefs::kKeychainMigrationStatus, |
| 143 static_cast<int>(GetParam())); | 142 static_cast<int>(GetParam())); |
| 144 // Ensure that LoginDatabase will use the mock keychain if it needs to | 143 // Ensure that LoginDatabase will use the mock keychain if it needs to |
| 145 // encrypt/decrypt a password. | 144 // encrypt/decrypt a password. |
| 146 OSCryptMocker::SetUpWithSingleton(); | 145 OSCryptMocker::SetUpWithSingleton(); |
| 147 } | 146 } |
| 148 | 147 |
| 149 PasswordStoreProxyMacTest::~PasswordStoreProxyMacTest() { | 148 PasswordStoreMacTest::~PasswordStoreMacTest() { |
| 150 ClosePasswordStore(); | 149 ClosePasswordStore(); |
| 151 OSCryptMocker::TearDown(); | 150 OSCryptMocker::TearDown(); |
| 152 } | 151 } |
| 153 | 152 |
| 154 void PasswordStoreProxyMacTest::CreateAndInitPasswordStore( | 153 void PasswordStoreMacTest::CreateAndInitPasswordStore( |
| 155 std::unique_ptr<password_manager::LoginDatabase> login_db) { | 154 std::unique_ptr<password_manager::LoginDatabase> login_db) { |
| 156 store_ = new PasswordStoreProxyMac( | 155 store_ = new PasswordStoreMac( |
| 157 BrowserThread::GetTaskRunnerForThread(BrowserThread::UI), | 156 BrowserThread::GetTaskRunnerForThread(BrowserThread::UI), |
| 158 std::move(login_db), &testing_prefs_); | 157 std::move(login_db), &testing_prefs_); |
| 159 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare(), nullptr)); | 158 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare(), nullptr)); |
| 160 } | 159 } |
| 161 | 160 |
| 162 void PasswordStoreProxyMacTest::ClosePasswordStore() { | 161 void PasswordStoreMacTest::ClosePasswordStore() { |
| 163 if (!store_) | 162 if (!store_) |
| 164 return; | 163 return; |
| 165 store_->ShutdownOnUIThread(); | 164 store_->ShutdownOnUIThread(); |
| 166 EXPECT_FALSE(store_->GetBackgroundTaskRunner()); | 165 EXPECT_FALSE(store_->GetBackgroundTaskRunner()); |
| 167 store_ = nullptr; | 166 store_ = nullptr; |
| 168 } | 167 } |
| 169 | 168 |
| 170 void PasswordStoreProxyMacTest::FinishAsyncProcessing() { | 169 void PasswordStoreMacTest::FinishAsyncProcessing() { |
| 171 // Do a store-level query to wait for all the previously enqueued operations | 170 // Do a store-level query to wait for all the previously enqueued operations |
| 172 // to finish. | 171 // to finish. |
| 173 MockPasswordStoreConsumer consumer; | 172 MockPasswordStoreConsumer consumer; |
| 174 store_->GetLogins({PasswordForm::SCHEME_HTML, std::string(), GURL()}, | 173 store_->GetLogins({PasswordForm::SCHEME_HTML, std::string(), GURL()}, |
| 175 &consumer); | 174 &consumer); |
| 176 consumer.WaitForResult(); | 175 consumer.WaitForResult(); |
| 177 } | 176 } |
| 178 | 177 |
| 179 base::FilePath PasswordStoreProxyMacTest::test_login_db_file_path() const { | 178 base::FilePath PasswordStoreMacTest::test_login_db_file_path() const { |
| 180 return db_dir_.GetPath().Append(FILE_PATH_LITERAL("login.db")); | 179 return db_dir_.GetPath().Append(FILE_PATH_LITERAL("login.db")); |
| 181 } | 180 } |
| 182 | 181 |
| 183 MigrationStatus PasswordStoreProxyMacTest::GetTargetStatus() const { | 182 MigrationStatus PasswordStoreMacTest::GetTargetStatus() const { |
| 184 if (GetParam() == MigrationStatus::NOT_STARTED || | 183 if (GetParam() == MigrationStatus::NOT_STARTED || |
| 185 GetParam() == MigrationStatus::FAILED_ONCE || | 184 GetParam() == MigrationStatus::FAILED_ONCE || |
| 186 GetParam() == MigrationStatus::FAILED_TWICE) { | 185 GetParam() == MigrationStatus::FAILED_TWICE) { |
| 187 return MigrationStatus::MIGRATION_STOPPED; | 186 return MigrationStatus::MIGRATION_STOPPED; |
| 188 } | 187 } |
| 189 return GetParam(); | 188 return GetParam(); |
| 190 } | 189 } |
| 191 | 190 |
| 192 void PasswordStoreProxyMacTest::AddForm(const PasswordForm& form) { | 191 void PasswordStoreMacTest::AddForm(const PasswordForm& form) { |
| 193 MockPasswordStoreObserver mock_observer(store()); | 192 MockPasswordStoreObserver mock_observer(store()); |
| 194 | 193 |
| 195 password_manager::PasswordStoreChangeList list; | 194 password_manager::PasswordStoreChangeList list; |
| 196 list.push_back(password_manager::PasswordStoreChange( | 195 list.push_back(password_manager::PasswordStoreChange( |
| 197 password_manager::PasswordStoreChange::ADD, form)); | 196 password_manager::PasswordStoreChange::ADD, form)); |
| 198 EXPECT_CALL(mock_observer, OnLoginsChanged(list)); | 197 EXPECT_CALL(mock_observer, OnLoginsChanged(list)); |
| 199 store()->AddLogin(form); | 198 store()->AddLogin(form); |
| 200 FinishAsyncProcessing(); | 199 FinishAsyncProcessing(); |
| 201 } | 200 } |
| 202 | 201 |
| 203 void PasswordStoreProxyMacTest::UpdateForm(const PasswordForm& form) { | 202 void PasswordStoreMacTest::UpdateForm(const PasswordForm& form) { |
| 204 MockPasswordStoreObserver mock_observer(store()); | 203 MockPasswordStoreObserver mock_observer(store()); |
| 205 | 204 |
| 206 password_manager::PasswordStoreChangeList list; | 205 password_manager::PasswordStoreChangeList list; |
| 207 list.push_back(password_manager::PasswordStoreChange( | 206 list.push_back(password_manager::PasswordStoreChange( |
| 208 password_manager::PasswordStoreChange::UPDATE, form)); | 207 password_manager::PasswordStoreChange::UPDATE, form)); |
| 209 EXPECT_CALL(mock_observer, OnLoginsChanged(list)); | 208 EXPECT_CALL(mock_observer, OnLoginsChanged(list)); |
| 210 store()->UpdateLogin(form); | 209 store()->UpdateLogin(form); |
| 211 FinishAsyncProcessing(); | 210 FinishAsyncProcessing(); |
| 212 } | 211 } |
| 213 | 212 |
| 214 void PasswordStoreProxyMacTest::RemoveForm(const PasswordForm& form) { | 213 void PasswordStoreMacTest::RemoveForm(const PasswordForm& form) { |
| 215 MockPasswordStoreObserver mock_observer(store()); | 214 MockPasswordStoreObserver mock_observer(store()); |
| 216 | 215 |
| 217 password_manager::PasswordStoreChangeList list; | 216 password_manager::PasswordStoreChangeList list; |
| 218 list.push_back(password_manager::PasswordStoreChange( | 217 list.push_back(password_manager::PasswordStoreChange( |
| 219 password_manager::PasswordStoreChange::REMOVE, form)); | 218 password_manager::PasswordStoreChange::REMOVE, form)); |
| 220 EXPECT_CALL(mock_observer, OnLoginsChanged(list)); | 219 EXPECT_CALL(mock_observer, OnLoginsChanged(list)); |
| 221 store()->RemoveLogin(form); | 220 store()->RemoveLogin(form); |
| 222 FinishAsyncProcessing(); | 221 FinishAsyncProcessing(); |
| 223 } | 222 } |
| 224 | 223 |
| 225 // ----------- Tests ------------- | 224 // ----------- Tests ------------- |
| 226 | 225 |
| 227 TEST_P(PasswordStoreProxyMacTest, Sanity) { | 226 TEST_P(PasswordStoreMacTest, Sanity) { |
| 228 base::HistogramTester histogram_tester; | 227 base::HistogramTester histogram_tester; |
| 229 | 228 |
| 230 CreateAndInitPasswordStore(base::MakeUnique<password_manager::LoginDatabase>( | 229 CreateAndInitPasswordStore(base::MakeUnique<password_manager::LoginDatabase>( |
| 231 test_login_db_file_path())); | 230 test_login_db_file_path())); |
| 232 FinishAsyncProcessing(); | 231 FinishAsyncProcessing(); |
| 233 ClosePasswordStore(); | 232 ClosePasswordStore(); |
| 234 | 233 |
| 235 int status = testing_prefs_.GetInteger( | 234 int status = testing_prefs_.GetInteger( |
| 236 password_manager::prefs::kKeychainMigrationStatus); | 235 password_manager::prefs::kKeychainMigrationStatus); |
| 237 EXPECT_EQ(static_cast<int>(GetTargetStatus()), status); | 236 EXPECT_EQ(static_cast<int>(GetTargetStatus()), status); |
| 238 histogram_tester.ExpectUniqueSample( | 237 histogram_tester.ExpectUniqueSample( |
| 239 "PasswordManager.KeychainMigration.Status", status, 1); | 238 "PasswordManager.KeychainMigration.Status", status, 1); |
| 240 } | 239 } |
| 241 | 240 |
| 242 TEST_P(PasswordStoreProxyMacTest, StartAndStop) { | 241 TEST_P(PasswordStoreMacTest, StartAndStop) { |
| 243 base::HistogramTester histogram_tester; | 242 base::HistogramTester histogram_tester; |
| 244 // PasswordStore::ShutdownOnUIThread() immediately follows | 243 // PasswordStore::ShutdownOnUIThread() immediately follows |
| 245 // PasswordStore::Init(). The message loop isn't running in between. Anyway, | 244 // PasswordStore::Init(). The message loop isn't running in between. Anyway, |
| 246 // PasswordStore should not collapse. | 245 // PasswordStore should not collapse. |
| 247 CreateAndInitPasswordStore(base::MakeUnique<password_manager::LoginDatabase>( | 246 CreateAndInitPasswordStore(base::MakeUnique<password_manager::LoginDatabase>( |
| 248 test_login_db_file_path())); | 247 test_login_db_file_path())); |
| 249 ClosePasswordStore(); | 248 ClosePasswordStore(); |
| 250 | 249 |
| 251 histogram_tester.ExpectUniqueSample( | 250 histogram_tester.ExpectUniqueSample( |
| 252 "PasswordManager.KeychainMigration.Status", | 251 "PasswordManager.KeychainMigration.Status", |
| 253 static_cast<int>(GetTargetStatus()), 1); | 252 static_cast<int>(GetTargetStatus()), 1); |
| 254 } | 253 } |
| 255 | 254 |
| 256 TEST_P(PasswordStoreProxyMacTest, OperationsOnABadDatabaseSilentlyFail) { | 255 TEST_P(PasswordStoreMacTest, OperationsOnABadDatabaseSilentlyFail) { |
| 257 // Verify that operations on a PasswordStore with a bad database cause no | 256 // Verify that operations on a PasswordStore with a bad database cause no |
| 258 // explosions, but fail without side effect, return no data and trigger no | 257 // explosions, but fail without side effect, return no data and trigger no |
| 259 // notifications. | 258 // notifications. |
| 260 CreateAndInitPasswordStore(base::MakeUnique<BadLoginDatabase>()); | 259 CreateAndInitPasswordStore(base::MakeUnique<BadLoginDatabase>()); |
| 261 FinishAsyncProcessing(); | 260 FinishAsyncProcessing(); |
| 262 EXPECT_FALSE(login_db()); | 261 EXPECT_FALSE(login_db()); |
| 263 | 262 |
| 264 // The store should outlive the observer. | 263 // The store should outlive the observer. |
| 265 scoped_refptr<PasswordStoreProxyMac> store_refptr = store(); | 264 scoped_refptr<PasswordStoreMac> store_refptr = store(); |
| 266 MockPasswordStoreObserver mock_observer(store()); | 265 MockPasswordStoreObserver mock_observer(store()); |
| 267 EXPECT_CALL(mock_observer, OnLoginsChanged(_)).Times(0); | 266 EXPECT_CALL(mock_observer, OnLoginsChanged(_)).Times(0); |
| 268 | 267 |
| 269 // Add a new autofillable login + a blacklisted login. | 268 // Add a new autofillable login + a blacklisted login. |
| 270 password_manager::PasswordFormData www_form_data = { | 269 password_manager::PasswordFormData www_form_data = { |
| 271 PasswordForm::SCHEME_HTML, | 270 PasswordForm::SCHEME_HTML, |
| 272 "http://www.facebook.com/", | 271 "http://www.facebook.com/", |
| 273 "http://www.facebook.com/index.html", | 272 "http://www.facebook.com/index.html", |
| 274 "login", | 273 "login", |
| 275 L"username", | 274 L"username", |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 store()->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max(), | 317 store()->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max(), |
| 319 base::Closure()); | 318 base::Closure()); |
| 320 store()->RemoveLoginsSyncedBetween(base::Time(), base::Time::Max()); | 319 store()->RemoveLoginsSyncedBetween(base::Time(), base::Time::Max()); |
| 321 FinishAsyncProcessing(); | 320 FinishAsyncProcessing(); |
| 322 | 321 |
| 323 // Verify no notifications are fired during shutdown either. | 322 // Verify no notifications are fired during shutdown either. |
| 324 ClosePasswordStore(); | 323 ClosePasswordStore(); |
| 325 } | 324 } |
| 326 | 325 |
| 327 INSTANTIATE_TEST_CASE_P(, | 326 INSTANTIATE_TEST_CASE_P(, |
| 328 PasswordStoreProxyMacTest, | 327 PasswordStoreMacTest, |
| 329 testing::Values(MigrationStatus::NOT_STARTED, | 328 testing::Values(MigrationStatus::NOT_STARTED, |
| 330 MigrationStatus::MIGRATED, | 329 MigrationStatus::MIGRATED, |
| 331 MigrationStatus::FAILED_ONCE, | 330 MigrationStatus::FAILED_ONCE, |
| 332 MigrationStatus::FAILED_TWICE, | 331 MigrationStatus::FAILED_TWICE, |
| 333 MigrationStatus::MIGRATED_DELETED, | 332 MigrationStatus::MIGRATED_DELETED, |
| 334 MigrationStatus::MIGRATED_PARTIALLY, | 333 MigrationStatus::MIGRATED_PARTIALLY, |
| 335 MigrationStatus::MIGRATION_STOPPED)); | 334 MigrationStatus::MIGRATION_STOPPED)); |
| 336 | 335 |
| 337 } // namespace | 336 } // namespace |
| OLD | NEW |