Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Side by Side Diff: chrome/browser/password_manager/password_store_proxy_mac_unittest.cc

Issue 1226303003: Start the migration of passwords from the Keychain. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix the test Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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_proxy_mac.h"
6 6
7 #include "base/files/scoped_temp_dir.h" 7 #include "base/files/scoped_temp_dir.h"
8 #include "base/scoped_observer.h" 8 #include "base/scoped_observer.h"
9 #include "base/strings/utf_string_conversions.h" 9 #include "base/strings/utf_string_conversions.h"
10 #include "base/test/histogram_tester.h"
11 #include "chrome/browser/password_manager/password_store_mac.h"
12 #include "chrome/browser/password_manager/password_store_mac_internal.h"
13 #include "chrome/browser/prefs/browser_prefs.h"
14 #include "chrome/test/base/testing_pref_service_syncable.h"
10 #include "components/os_crypt/os_crypt.h" 15 #include "components/os_crypt/os_crypt.h"
11 #include "components/password_manager/core/browser/login_database.h" 16 #include "components/password_manager/core/browser/login_database.h"
12 #include "components/password_manager/core/browser/password_manager_test_utils.h " 17 #include "components/password_manager/core/browser/password_manager_test_utils.h "
13 #include "components/password_manager/core/browser/password_store_consumer.h" 18 #include "components/password_manager/core/browser/password_store_consumer.h"
19 #include "components/password_manager/core/common/password_manager_pref_names.h"
14 #include "content/public/browser/browser_thread.h" 20 #include "content/public/browser/browser_thread.h"
15 #include "content/public/test/test_browser_thread_bundle.h" 21 #include "content/public/test/test_browser_thread_bundle.h"
16 #include "crypto/mock_apple_keychain.h" 22 #include "crypto/mock_apple_keychain.h"
17 #include "testing/gmock/include/gmock/gmock.h" 23 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h" 24 #include "testing/gtest/include/gtest/gtest.h"
19 25
20 namespace { 26 namespace {
21 27
22 using autofill::PasswordForm; 28 using autofill::PasswordForm;
23 using content::BrowserThread; 29 using content::BrowserThread;
30 using password_manager::MigrationStatus;
31 using password_manager::PasswordStoreChange;
32 using password_manager::PasswordStoreChangeList;
24 using testing::_; 33 using testing::_;
25 using testing::ElementsAre; 34 using testing::ElementsAre;
26 using testing::IsEmpty; 35 using testing::IsEmpty;
27 using testing::Pointee; 36 using testing::Pointee;
28 37
29 ACTION(QuitUIMessageLoop) { 38 ACTION(QuitUIMessageLoop) {
30 DCHECK_CURRENTLY_ON(BrowserThread::UI); 39 DCHECK_CURRENTLY_ON(BrowserThread::UI);
31 base::MessageLoop::current()->Quit(); 40 base::MessageLoop::current()->Quit();
32 } 41 }
33 42
43 // Returns a change list corresponding to |form| being added.
44 PasswordStoreChangeList AddChangeForForm(const PasswordForm& form) {
45 return PasswordStoreChangeList(
46 1, PasswordStoreChange(PasswordStoreChange::ADD, form));
47 }
48
34 class MockPasswordStoreConsumer 49 class MockPasswordStoreConsumer
35 : public password_manager::PasswordStoreConsumer { 50 : public password_manager::PasswordStoreConsumer {
36 public: 51 public:
37 MOCK_METHOD1(OnGetPasswordStoreResultsConstRef, 52 MOCK_METHOD1(OnGetPasswordStoreResultsConstRef,
38 void(const std::vector<PasswordForm*>&)); 53 void(const std::vector<PasswordForm*>&));
39 54
40 // GMock cannot mock methods with move-only args. 55 // GMock cannot mock methods with move-only args.
41 void OnGetPasswordStoreResults(ScopedVector<PasswordForm> results) override { 56 void OnGetPasswordStoreResults(ScopedVector<PasswordForm> results) override {
42 OnGetPasswordStoreResultsConstRef(results.get()); 57 OnGetPasswordStoreResultsConstRef(results.get());
43 } 58 }
(...skipping 19 matching lines...) Expand all
63 BadLoginDatabase() : password_manager::LoginDatabase(base::FilePath()) {} 78 BadLoginDatabase() : password_manager::LoginDatabase(base::FilePath()) {}
64 ~BadLoginDatabase() override {} 79 ~BadLoginDatabase() override {}
65 80
66 // LoginDatabase: 81 // LoginDatabase:
67 bool Init() override { return false; } 82 bool Init() override { return false; }
68 83
69 private: 84 private:
70 DISALLOW_COPY_AND_ASSIGN(BadLoginDatabase); 85 DISALLOW_COPY_AND_ASSIGN(BadLoginDatabase);
71 }; 86 };
72 87
73 class PasswordStoreProxyMacTest : public testing::Test { 88 class PasswordStoreProxyMacTest
89 : public testing::TestWithParam<MigrationStatus> {
74 public: 90 public:
91 PasswordStoreProxyMacTest();
92 ~PasswordStoreProxyMacTest() override;
93
75 void SetUp() override; 94 void SetUp() override;
76 void TearDown() override; 95 void TearDown() override;
77 96
78 void CreateAndInitPasswordStore( 97 void CreateAndInitPasswordStore(
79 scoped_ptr<password_manager::LoginDatabase> login_db); 98 scoped_ptr<password_manager::LoginDatabase> login_db);
80 99
81 void ClosePasswordStore(); 100 void ClosePasswordStore();
82 101
83 // Do a store-level query to wait for all the previously enqueued operations 102 // Do a store-level query to wait for all the previously enqueued operations
84 // to finish. 103 // to finish.
(...skipping 14 matching lines...) Expand all
99 return store_->login_metadata_db(); 118 return store_->login_metadata_db();
100 } 119 }
101 120
102 PasswordStoreProxyMac* store() { return store_.get(); } 121 PasswordStoreProxyMac* store() { return store_.get(); }
103 122
104 protected: 123 protected:
105 content::TestBrowserThreadBundle ui_thread_; 124 content::TestBrowserThreadBundle ui_thread_;
106 125
107 base::ScopedTempDir db_dir_; 126 base::ScopedTempDir db_dir_;
108 scoped_refptr<PasswordStoreProxyMac> store_; 127 scoped_refptr<PasswordStoreProxyMac> store_;
128 TestingPrefServiceSyncable testing_prefs_;
109 }; 129 };
110 130
111 void PasswordStoreProxyMacTest::SetUp() { 131 PasswordStoreProxyMacTest::PasswordStoreProxyMacTest() {
112 ASSERT_TRUE(db_dir_.CreateUniqueTempDir()); 132 EXPECT_TRUE(db_dir_.CreateUniqueTempDir());
113 133 chrome::RegisterUserProfilePrefs(testing_prefs_.registry());
134 testing_prefs_.SetInteger(password_manager::prefs::kKeychainMigrationStatus,
135 static_cast<int>(GetParam()));
114 // Ensure that LoginDatabase will use the mock keychain if it needs to 136 // Ensure that LoginDatabase will use the mock keychain if it needs to
115 // encrypt/decrypt a password. 137 // encrypt/decrypt a password.
116 OSCrypt::UseMockKeychain(true); 138 OSCrypt::UseMockKeychain(true);
139 }
140
141 PasswordStoreProxyMacTest::~PasswordStoreProxyMacTest() {
142 }
143
144 void PasswordStoreProxyMacTest::SetUp() {
117 scoped_ptr<password_manager::LoginDatabase> login_db( 145 scoped_ptr<password_manager::LoginDatabase> login_db(
118 new password_manager::LoginDatabase(test_login_db_file_path())); 146 new password_manager::LoginDatabase(test_login_db_file_path()));
119 CreateAndInitPasswordStore(login_db.Pass()); 147 CreateAndInitPasswordStore(login_db.Pass());
120 // Make sure deferred initialization is performed before some tests start
121 // accessing the |login_db| directly.
122 FinishAsyncProcessing();
123 } 148 }
124 149
125 void PasswordStoreProxyMacTest::TearDown() { 150 void PasswordStoreProxyMacTest::TearDown() {
126 ClosePasswordStore(); 151 ClosePasswordStore();
127 } 152 }
128 153
129 void PasswordStoreProxyMacTest::CreateAndInitPasswordStore( 154 void PasswordStoreProxyMacTest::CreateAndInitPasswordStore(
130 scoped_ptr<password_manager::LoginDatabase> login_db) { 155 scoped_ptr<password_manager::LoginDatabase> login_db) {
131 store_ = new PasswordStoreProxyMac( 156 store_ = new PasswordStoreProxyMac(
132 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), 157 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
133 make_scoped_ptr(new crypto::MockAppleKeychain), login_db.Pass()); 158 make_scoped_ptr(new crypto::MockAppleKeychain), login_db.Pass(),
159 &testing_prefs_);
134 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare())); 160 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
135 } 161 }
136 162
137 void PasswordStoreProxyMacTest::ClosePasswordStore() { 163 void PasswordStoreProxyMacTest::ClosePasswordStore() {
138 if (!store_) 164 if (!store_)
139 return; 165 return;
140 store_->Shutdown(); 166 store_->Shutdown();
141 EXPECT_FALSE(store_->GetBackgroundTaskRunner()); 167 EXPECT_FALSE(store_->GetBackgroundTaskRunner());
142 base::MessageLoop::current()->RunUntilIdle();
143 store_ = nullptr; 168 store_ = nullptr;
144 } 169 }
145 170
146 void PasswordStoreProxyMacTest::FinishAsyncProcessing() { 171 void PasswordStoreProxyMacTest::FinishAsyncProcessing() {
147 // Do a store-level query to wait for all the previously enqueued operations 172 // Do a store-level query to wait for all the previously enqueued operations
148 // to finish. 173 // to finish.
149 MockPasswordStoreConsumer consumer; 174 MockPasswordStoreConsumer consumer;
150 store_->GetLogins(PasswordForm(), 175 store_->GetLogins(PasswordForm(),
151 password_manager::PasswordStore::ALLOW_PROMPT, &consumer); 176 password_manager::PasswordStore::ALLOW_PROMPT, &consumer);
152 EXPECT_CALL(consumer, OnGetPasswordStoreResultsConstRef(_)) 177 EXPECT_CALL(consumer, OnGetPasswordStoreResultsConstRef(_))
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 EXPECT_CALL(mock_observer, OnLoginsChanged(list)); 247 EXPECT_CALL(mock_observer, OnLoginsChanged(list));
223 if (check_created) { 248 if (check_created) {
224 store()->RemoveLoginsCreatedBetween(base::Time(), next_day, 249 store()->RemoveLoginsCreatedBetween(base::Time(), next_day,
225 base::Closure()); 250 base::Closure());
226 } else { 251 } else {
227 store()->RemoveLoginsSyncedBetween(base::Time(), next_day); 252 store()->RemoveLoginsSyncedBetween(base::Time(), next_day);
228 } 253 }
229 FinishAsyncProcessing(); 254 FinishAsyncProcessing();
230 } 255 }
231 256
232 TEST_F(PasswordStoreProxyMacTest, FormLifeCycle) { 257 // ----------- Tests -------------
258
259 TEST_P(PasswordStoreProxyMacTest, StartAndStop) {
260 // PasswordStore::Shutdown() immediately follows PasswordStore::Init(). The
261 // message loop isn't running in between. Anyway, PasswordStore should end up
262 // in the right state.
263 ClosePasswordStore();
264
265 int status = testing_prefs_.GetInteger(
266 password_manager::prefs::kKeychainMigrationStatus);
267 if (GetParam() == MigrationStatus::NOT_STARTED ||
268 GetParam() == MigrationStatus::FAILED_ONCE) {
269 EXPECT_EQ(static_cast<int>(MigrationStatus::MIGRATED), status);
270 } else {
271 EXPECT_EQ(static_cast<int>(GetParam()), status);
272 }
273 }
274
275 TEST_P(PasswordStoreProxyMacTest, FormLifeCycle) {
233 PasswordForm password_form; 276 PasswordForm password_form;
234 password_form.origin = GURL("http://example.com"); 277 password_form.origin = GURL("http://example.com");
235 password_form.username_value = base::ASCIIToUTF16("test1@gmail.com"); 278 password_form.username_value = base::ASCIIToUTF16("test1@gmail.com");
236 password_form.password_value = base::ASCIIToUTF16("12345"); 279 password_form.password_value = base::ASCIIToUTF16("12345");
237 password_form.signon_realm = "http://example.com/"; 280 password_form.signon_realm = "http://example.com/";
238 281
239 AddForm(password_form); 282 AddForm(password_form);
240 password_form.password_value = base::ASCIIToUTF16("password"); 283 password_form.password_value = base::ASCIIToUTF16("password");
241 UpdateForm(password_form); 284 UpdateForm(password_form);
242 RemoveForm(password_form); 285 RemoveForm(password_form);
243 } 286 }
244 287
245 TEST_F(PasswordStoreProxyMacTest, TestRemoveLoginsCreatedBetween) { 288 TEST_P(PasswordStoreProxyMacTest, TestRemoveLoginsCreatedBetween) {
246 CheckRemoveLoginsBetween(true); 289 CheckRemoveLoginsBetween(true);
247 } 290 }
248 291
249 TEST_F(PasswordStoreProxyMacTest, TestRemoveLoginsSyncedBetween) { 292 TEST_P(PasswordStoreProxyMacTest, TestRemoveLoginsSyncedBetween) {
250 CheckRemoveLoginsBetween(false); 293 CheckRemoveLoginsBetween(false);
251 } 294 }
252 295
253 TEST_F(PasswordStoreProxyMacTest, FillLogins) { 296 TEST_P(PasswordStoreProxyMacTest, FillLogins) {
254 PasswordForm password_form; 297 PasswordForm password_form;
255 password_form.origin = GURL("http://example.com"); 298 password_form.origin = GURL("http://example.com");
256 password_form.signon_realm = "http://example.com/"; 299 password_form.signon_realm = "http://example.com/";
257 password_form.username_value = base::ASCIIToUTF16("test1@gmail.com"); 300 password_form.username_value = base::ASCIIToUTF16("test1@gmail.com");
258 password_form.password_value = base::ASCIIToUTF16("12345"); 301 password_form.password_value = base::ASCIIToUTF16("12345");
259 AddForm(password_form); 302 AddForm(password_form);
260 303
261 PasswordForm blacklisted_form; 304 PasswordForm blacklisted_form;
262 blacklisted_form.origin = GURL("http://example2.com"); 305 blacklisted_form.origin = GURL("http://example2.com");
263 blacklisted_form.signon_realm = "http://example2.com/"; 306 blacklisted_form.signon_realm = "http://example2.com/";
(...skipping 14 matching lines...) Expand all
278 .WillOnce(QuitUIMessageLoop()); 321 .WillOnce(QuitUIMessageLoop());
279 base::MessageLoop::current()->Run(); 322 base::MessageLoop::current()->Run();
280 323
281 store()->GetAutofillableLogins(&mock_consumer); 324 store()->GetAutofillableLogins(&mock_consumer);
282 EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef( 325 EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef(
283 ElementsAre(Pointee(password_form)))) 326 ElementsAre(Pointee(password_form))))
284 .WillOnce(QuitUIMessageLoop()); 327 .WillOnce(QuitUIMessageLoop());
285 base::MessageLoop::current()->Run(); 328 base::MessageLoop::current()->Run();
286 } 329 }
287 330
288 TEST_F(PasswordStoreProxyMacTest, OperationsOnABadDatabaseSilentlyFail) { 331 TEST_P(PasswordStoreProxyMacTest, OperationsOnABadDatabaseSilentlyFail) {
289 // Verify that operations on a PasswordStore with a bad database cause no 332 // Verify that operations on a PasswordStore with a bad database cause no
290 // explosions, but fail without side effect, return no data and trigger no 333 // explosions, but fail without side effect, return no data and trigger no
291 // notifications. 334 // notifications.
292 ClosePasswordStore(); 335 ClosePasswordStore();
293 CreateAndInitPasswordStore(make_scoped_ptr(new BadLoginDatabase)); 336 CreateAndInitPasswordStore(make_scoped_ptr(new BadLoginDatabase));
294 FinishAsyncProcessing(); 337 FinishAsyncProcessing();
295 EXPECT_FALSE(login_db()); 338 EXPECT_FALSE(login_db());
296 339
297 // The store should outlive the observer. 340 // The store should outlive the observer.
298 scoped_refptr<PasswordStoreProxyMac> store_refptr = store(); 341 scoped_refptr<PasswordStoreProxyMac> store_refptr = store();
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 // Delete one login; a range of logins. 387 // Delete one login; a range of logins.
345 store()->RemoveLogin(*form); 388 store()->RemoveLogin(*form);
346 store()->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max(), 389 store()->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max(),
347 base::Closure()); 390 base::Closure());
348 store()->RemoveLoginsSyncedBetween(base::Time(), base::Time::Max()); 391 store()->RemoveLoginsSyncedBetween(base::Time(), base::Time::Max());
349 FinishAsyncProcessing(); 392 FinishAsyncProcessing();
350 393
351 // Verify no notifications are fired during shutdown either. 394 // Verify no notifications are fired during shutdown either.
352 ClosePasswordStore(); 395 ClosePasswordStore();
353 } 396 }
397
398 INSTANTIATE_TEST_CASE_P(,
399 PasswordStoreProxyMacTest,
400 testing::Values(MigrationStatus::NOT_STARTED,
401 MigrationStatus::MIGRATED,
402 MigrationStatus::FAILED_ONCE,
403 MigrationStatus::FAILED_TWICE));
404
405 // Test the migration process.
406 class PasswordStoreProxyMacMigrationTest : public PasswordStoreProxyMacTest {
407 public:
408 void SetUp() override;
409
410 void TestMigration(bool lock_keychain);
411
412 protected:
413 scoped_ptr<password_manager::LoginDatabase> login_db_;
414 scoped_ptr<crypto::MockAppleKeychain> keychain_;
415 base::HistogramTester histogram_tester_;
416 };
417
418 void PasswordStoreProxyMacMigrationTest::SetUp() {
419 login_db_.reset(
420 new password_manager::LoginDatabase(test_login_db_file_path()));
421 keychain_.reset(new crypto::MockAppleKeychain);
422 }
423
424 void PasswordStoreProxyMacMigrationTest::TestMigration(bool lock_keychain) {
425 PasswordForm form;
426 form.origin = GURL("http://accounts.google.com/LoginAuth");
427 form.signon_realm = "http://accounts.google.com/";
428 form.username_value = base::ASCIIToUTF16("my_username");
429 form.password_value = base::ASCIIToUTF16("12345");
430
431 if (GetParam() != MigrationStatus::MIGRATED)
432 login_db_->set_clear_password_values(true);
433 EXPECT_TRUE(login_db_->Init());
434 EXPECT_EQ(AddChangeForForm(form), login_db_->AddLogin(form));
435 // Prepare another database instance with the same content which is to be
436 // initialized by PasswordStoreProxyMac.
437 login_db_.reset(
438 new password_manager::LoginDatabase(test_login_db_file_path()));
439 MacKeychainPasswordFormAdapter adapter(keychain_.get());
440 EXPECT_TRUE(adapter.AddPassword(form));
441
442 // Init the store. It may trigger the migration.
443 if (lock_keychain)
444 keychain_->set_locked(true);
445 store_ = new PasswordStoreProxyMac(
446 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
447 keychain_.Pass(), login_db_.Pass(), &testing_prefs_);
448 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
449 FinishAsyncProcessing();
450
451 // Check the password is still there.
452 if (lock_keychain && store_->password_store_mac()) {
453 static_cast<crypto::MockAppleKeychain*>(
454 store_->password_store_mac()->keychain())->set_locked(false);
455 }
456 MockPasswordStoreConsumer mock_consumer;
457 store()->GetLogins(form, PasswordStoreProxyMac::ALLOW_PROMPT, &mock_consumer);
458 EXPECT_CALL(mock_consumer,
459 OnGetPasswordStoreResultsConstRef(ElementsAre(Pointee(form))))
460 .WillOnce(QuitUIMessageLoop());
461 base::MessageLoop::current()->Run();
462
463 int status = testing_prefs_.GetInteger(
464 password_manager::prefs::kKeychainMigrationStatus);
465 if (GetParam() == MigrationStatus::MIGRATED ||
466 GetParam() == MigrationStatus::FAILED_TWICE) {
467 EXPECT_EQ(static_cast<int>(GetParam()), status);
468 } else if (lock_keychain) {
469 EXPECT_EQ(static_cast<int>(GetParam() == MigrationStatus::NOT_STARTED
470 ? MigrationStatus::FAILED_ONCE
471 : MigrationStatus::FAILED_TWICE),
472 status);
473 } else {
474 EXPECT_EQ(static_cast<int>(MigrationStatus::MIGRATED), status);
475 }
476 histogram_tester_.ExpectUniqueSample(
477 "PasswordManager.KeychainMigration.Status",
478 status, 1);
479 }
480
481 TEST_P(PasswordStoreProxyMacMigrationTest, TestSuccessfullMigration) {
482 TestMigration(false);
483 }
484
485 TEST_P(PasswordStoreProxyMacMigrationTest, TestFailedMigration) {
486 TestMigration(true);
487 }
488
489 INSTANTIATE_TEST_CASE_P(,
490 PasswordStoreProxyMacMigrationTest,
491 testing::Values(MigrationStatus::NOT_STARTED,
492 MigrationStatus::MIGRATED,
493 MigrationStatus::FAILED_ONCE,
494 MigrationStatus::FAILED_TWICE));
495
354 } // namespace 496 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698