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

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

Issue 1213043003: Start the migration of passwords from the Keychain. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 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 "chrome/browser/password_manager/password_store_mac_internal.h"
11 #include "chrome/browser/prefs/browser_prefs.h"
12 #include "chrome/test/base/testing_pref_service_syncable.h"
10 #include "components/os_crypt/os_crypt.h" 13 #include "components/os_crypt/os_crypt.h"
11 #include "components/password_manager/core/browser/login_database.h" 14 #include "components/password_manager/core/browser/login_database.h"
12 #include "components/password_manager/core/browser/password_manager_test_utils.h " 15 #include "components/password_manager/core/browser/password_manager_test_utils.h "
13 #include "components/password_manager/core/browser/password_store_consumer.h" 16 #include "components/password_manager/core/browser/password_store_consumer.h"
17 #include "components/password_manager/core/common/password_manager_pref_names.h"
14 #include "content/public/browser/browser_thread.h" 18 #include "content/public/browser/browser_thread.h"
15 #include "content/public/test/test_browser_thread_bundle.h" 19 #include "content/public/test/test_browser_thread_bundle.h"
16 #include "crypto/mock_apple_keychain.h" 20 #include "crypto/mock_apple_keychain.h"
17 #include "testing/gmock/include/gmock/gmock.h" 21 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h" 22 #include "testing/gtest/include/gtest/gtest.h"
19 23
20 namespace { 24 namespace {
21 25
22 using autofill::PasswordForm; 26 using autofill::PasswordForm;
23 using content::BrowserThread; 27 using content::BrowserThread;
28 using password_manager::PasswordStoreChange;
29 using password_manager::PasswordStoreChangeList;
24 using testing::_; 30 using testing::_;
25 using testing::ElementsAre; 31 using testing::ElementsAre;
26 using testing::IsEmpty; 32 using testing::IsEmpty;
27 using testing::Pointee; 33 using testing::Pointee;
28 34
29 ACTION(QuitUIMessageLoop) { 35 ACTION(QuitUIMessageLoop) {
30 DCHECK_CURRENTLY_ON(BrowserThread::UI); 36 DCHECK_CURRENTLY_ON(BrowserThread::UI);
31 base::MessageLoop::current()->Quit(); 37 base::MessageLoop::current()->Quit();
32 } 38 }
33 39
40 PasswordStoreChangeList AddChangeForForm(const PasswordForm& form) {
41 return PasswordStoreChangeList(
42 1, PasswordStoreChange(PasswordStoreChange::ADD, form));
43 }
44
34 class MockPasswordStoreConsumer 45 class MockPasswordStoreConsumer
35 : public password_manager::PasswordStoreConsumer { 46 : public password_manager::PasswordStoreConsumer {
36 public: 47 public:
37 MOCK_METHOD1(OnGetPasswordStoreResultsConstRef, 48 MOCK_METHOD1(OnGetPasswordStoreResultsConstRef,
38 void(const std::vector<PasswordForm*>&)); 49 void(const std::vector<PasswordForm*>&));
39 50
40 // GMock cannot mock methods with move-only args. 51 // GMock cannot mock methods with move-only args.
41 void OnGetPasswordStoreResults(ScopedVector<PasswordForm> results) override { 52 void OnGetPasswordStoreResults(ScopedVector<PasswordForm> results) override {
42 OnGetPasswordStoreResultsConstRef(results.get()); 53 OnGetPasswordStoreResultsConstRef(results.get());
43 } 54 }
(...skipping 19 matching lines...) Expand all
63 BadLoginDatabase() : password_manager::LoginDatabase(base::FilePath()) {} 74 BadLoginDatabase() : password_manager::LoginDatabase(base::FilePath()) {}
64 ~BadLoginDatabase() override {} 75 ~BadLoginDatabase() override {}
65 76
66 // LoginDatabase: 77 // LoginDatabase:
67 bool Init() override { return false; } 78 bool Init() override { return false; }
68 79
69 private: 80 private:
70 DISALLOW_COPY_AND_ASSIGN(BadLoginDatabase); 81 DISALLOW_COPY_AND_ASSIGN(BadLoginDatabase);
71 }; 82 };
72 83
73 class PasswordStoreProxyMacTest : public testing::Test { 84 class PasswordStoreProxyMacTest
85 : public testing::TestWithParam<PasswordStoreProxyMac::MigrationStatus> {
74 public: 86 public:
87 PasswordStoreProxyMacTest();
88 ~PasswordStoreProxyMacTest() override;
89
75 void SetUp() override; 90 void SetUp() override;
76 void TearDown() override; 91 void TearDown() override;
77 92
78 void CreateAndInitPasswordStore( 93 void CreateAndInitPasswordStore(
79 scoped_ptr<password_manager::LoginDatabase> login_db); 94 scoped_ptr<password_manager::LoginDatabase> login_db);
80 95
81 void ClosePasswordStore(); 96 void ClosePasswordStore();
82 97
83 // Do a store-level query to wait for all the previously enqueued operations 98 // Do a store-level query to wait for all the previously enqueued operations
84 // to finish. 99 // to finish.
(...skipping 14 matching lines...) Expand all
99 return store_->login_metadata_db(); 114 return store_->login_metadata_db();
100 } 115 }
101 116
102 PasswordStoreProxyMac* store() { return store_.get(); } 117 PasswordStoreProxyMac* store() { return store_.get(); }
103 118
104 protected: 119 protected:
105 content::TestBrowserThreadBundle ui_thread_; 120 content::TestBrowserThreadBundle ui_thread_;
106 121
107 base::ScopedTempDir db_dir_; 122 base::ScopedTempDir db_dir_;
108 scoped_refptr<PasswordStoreProxyMac> store_; 123 scoped_refptr<PasswordStoreProxyMac> store_;
124 TestingPrefServiceSyncable testing_prefs_;
109 }; 125 };
110 126
111 void PasswordStoreProxyMacTest::SetUp() { 127 PasswordStoreProxyMacTest::PasswordStoreProxyMacTest() {
112 ASSERT_TRUE(db_dir_.CreateUniqueTempDir()); 128 EXPECT_TRUE(db_dir_.CreateUniqueTempDir());
113 129 chrome::RegisterUserProfilePrefs(testing_prefs_.registry());
130 testing_prefs_.SetInteger(password_manager::prefs::kKeychainMigrationStatus,
131 GetParam());
114 // Ensure that LoginDatabase will use the mock keychain if it needs to 132 // Ensure that LoginDatabase will use the mock keychain if it needs to
115 // encrypt/decrypt a password. 133 // encrypt/decrypt a password.
116 OSCrypt::UseMockKeychain(true); 134 OSCrypt::UseMockKeychain(true);
135 }
136
137 PasswordStoreProxyMacTest::~PasswordStoreProxyMacTest() {
138 }
139
140 void PasswordStoreProxyMacTest::SetUp() {
117 scoped_ptr<password_manager::LoginDatabase> login_db( 141 scoped_ptr<password_manager::LoginDatabase> login_db(
118 new password_manager::LoginDatabase(test_login_db_file_path())); 142 new password_manager::LoginDatabase(test_login_db_file_path()));
119 CreateAndInitPasswordStore(login_db.Pass()); 143 CreateAndInitPasswordStore(login_db.Pass());
120 // Make sure deferred initialization is performed before some tests start 144 // Make sure deferred initialization is performed before some tests start
121 // accessing the |login_db| directly. 145 // accessing the |login_db| directly.
122 FinishAsyncProcessing(); 146 FinishAsyncProcessing();
123 } 147 }
124 148
125 void PasswordStoreProxyMacTest::TearDown() { 149 void PasswordStoreProxyMacTest::TearDown() {
126 ClosePasswordStore(); 150 ClosePasswordStore();
127 } 151 }
128 152
129 void PasswordStoreProxyMacTest::CreateAndInitPasswordStore( 153 void PasswordStoreProxyMacTest::CreateAndInitPasswordStore(
130 scoped_ptr<password_manager::LoginDatabase> login_db) { 154 scoped_ptr<password_manager::LoginDatabase> login_db) {
131 store_ = new PasswordStoreProxyMac( 155 store_ = new PasswordStoreProxyMac(
132 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), 156 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
133 make_scoped_ptr(new crypto::MockAppleKeychain), login_db.Pass()); 157 make_scoped_ptr(new crypto::MockAppleKeychain), login_db.Pass(),
158 &testing_prefs_);
134 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare())); 159 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
135 } 160 }
136 161
137 void PasswordStoreProxyMacTest::ClosePasswordStore() { 162 void PasswordStoreProxyMacTest::ClosePasswordStore() {
138 if (!store_) 163 if (!store_)
139 return; 164 return;
140 store_->Shutdown(); 165 store_->Shutdown();
141 EXPECT_FALSE(store_->GetBackgroundTaskRunner()); 166 EXPECT_FALSE(store_->GetBackgroundTaskRunner());
142 base::MessageLoop::current()->RunUntilIdle(); 167 base::MessageLoop::current()->RunUntilIdle();
143 store_ = nullptr; 168 store_ = nullptr;
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 list.push_back(password_manager::PasswordStoreChange( 245 list.push_back(password_manager::PasswordStoreChange(
221 password_manager::PasswordStoreChange::REMOVE, old_form)); 246 password_manager::PasswordStoreChange::REMOVE, old_form));
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 else 250 else
226 store()->RemoveLoginsSyncedBetween(base::Time(), next_day); 251 store()->RemoveLoginsSyncedBetween(base::Time(), next_day);
227 FinishAsyncProcessing(); 252 FinishAsyncProcessing();
228 } 253 }
229 254
230 TEST_F(PasswordStoreProxyMacTest, FormLifeCycle) { 255 // ----------- Tests -------------
256
257 TEST_P(PasswordStoreProxyMacTest, FormLifeCycle) {
231 PasswordForm password_form; 258 PasswordForm password_form;
232 password_form.origin = GURL("http://example.com"); 259 password_form.origin = GURL("http://example.com");
233 password_form.username_value = base::ASCIIToUTF16("test1@gmail.com"); 260 password_form.username_value = base::ASCIIToUTF16("test1@gmail.com");
234 password_form.password_value = base::ASCIIToUTF16("12345"); 261 password_form.password_value = base::ASCIIToUTF16("12345");
235 password_form.signon_realm = "http://example.com/"; 262 password_form.signon_realm = "http://example.com/";
236 263
237 AddForm(password_form); 264 AddForm(password_form);
238 password_form.password_value = base::ASCIIToUTF16("password"); 265 password_form.password_value = base::ASCIIToUTF16("password");
239 UpdateForm(password_form); 266 UpdateForm(password_form);
240 RemoveForm(password_form); 267 RemoveForm(password_form);
268
269 int status = testing_prefs_.GetInteger(
270 password_manager::prefs::kKeychainMigrationStatus);
271 if (GetParam() == PasswordStoreProxyMac::NOT_STARTED ||
272 GetParam() == PasswordStoreProxyMac::FAILED_ONCE) {
273 EXPECT_EQ(PasswordStoreProxyMac::MIGRATED, status);
274 } else {
275 EXPECT_EQ(GetParam(), status);
276 }
241 } 277 }
242 278
243 TEST_F(PasswordStoreProxyMacTest, TestRemoveLoginsCreatedBetween) { 279 TEST_P(PasswordStoreProxyMacTest, TestRemoveLoginsCreatedBetween) {
244 CheckRemoveLoginsBetween(true); 280 CheckRemoveLoginsBetween(true);
245 } 281 }
246 282
247 TEST_F(PasswordStoreProxyMacTest, TestRemoveLoginsSyncedBetween) { 283 TEST_P(PasswordStoreProxyMacTest, TestRemoveLoginsSyncedBetween) {
248 CheckRemoveLoginsBetween(false); 284 CheckRemoveLoginsBetween(false);
249 } 285 }
250 286
251 TEST_F(PasswordStoreProxyMacTest, FillLogins) { 287 TEST_P(PasswordStoreProxyMacTest, FillLogins) {
252 PasswordForm password_form; 288 PasswordForm password_form;
253 password_form.origin = GURL("http://example.com"); 289 password_form.origin = GURL("http://example.com");
254 password_form.signon_realm = "http://example.com/"; 290 password_form.signon_realm = "http://example.com/";
255 password_form.username_value = base::ASCIIToUTF16("test1@gmail.com"); 291 password_form.username_value = base::ASCIIToUTF16("test1@gmail.com");
256 password_form.password_value = base::ASCIIToUTF16("12345"); 292 password_form.password_value = base::ASCIIToUTF16("12345");
257 AddForm(password_form); 293 AddForm(password_form);
258 294
259 PasswordForm blacklisted_form; 295 PasswordForm blacklisted_form;
260 blacklisted_form.origin = GURL("http://example2.com"); 296 blacklisted_form.origin = GURL("http://example2.com");
261 blacklisted_form.signon_realm = "http://example2.com/"; 297 blacklisted_form.signon_realm = "http://example2.com/";
(...skipping 14 matching lines...) Expand all
276 .WillOnce(QuitUIMessageLoop()); 312 .WillOnce(QuitUIMessageLoop());
277 base::MessageLoop::current()->Run(); 313 base::MessageLoop::current()->Run();
278 314
279 store()->GetAutofillableLogins(&mock_consumer); 315 store()->GetAutofillableLogins(&mock_consumer);
280 EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef( 316 EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef(
281 ElementsAre(Pointee(password_form)))) 317 ElementsAre(Pointee(password_form))))
282 .WillOnce(QuitUIMessageLoop()); 318 .WillOnce(QuitUIMessageLoop());
283 base::MessageLoop::current()->Run(); 319 base::MessageLoop::current()->Run();
284 } 320 }
285 321
286 TEST_F(PasswordStoreProxyMacTest, OperationsOnABadDatabaseSilentlyFail) { 322 TEST_P(PasswordStoreProxyMacTest, OperationsOnABadDatabaseSilentlyFail) {
287 // Verify that operations on a PasswordStore with a bad database cause no 323 // Verify that operations on a PasswordStore with a bad database cause no
288 // explosions, but fail without side effect, return no data and trigger no 324 // explosions, but fail without side effect, return no data and trigger no
289 // notifications. 325 // notifications.
290 ClosePasswordStore(); 326 ClosePasswordStore();
291 CreateAndInitPasswordStore(make_scoped_ptr(new BadLoginDatabase)); 327 CreateAndInitPasswordStore(make_scoped_ptr(new BadLoginDatabase));
292 FinishAsyncProcessing(); 328 FinishAsyncProcessing();
293 EXPECT_FALSE(login_db()); 329 EXPECT_FALSE(login_db());
294 330
295 // The store should outlive the observer. 331 // The store should outlive the observer.
296 scoped_refptr<PasswordStoreProxyMac> store_refptr = store(); 332 scoped_refptr<PasswordStoreProxyMac> store_refptr = store();
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 377
342 // Delete one login; a range of logins. 378 // Delete one login; a range of logins.
343 store()->RemoveLogin(*form); 379 store()->RemoveLogin(*form);
344 store()->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max()); 380 store()->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max());
345 store()->RemoveLoginsSyncedBetween(base::Time(), base::Time::Max()); 381 store()->RemoveLoginsSyncedBetween(base::Time(), base::Time::Max());
346 FinishAsyncProcessing(); 382 FinishAsyncProcessing();
347 383
348 // Verify no notifications are fired during shutdown either. 384 // Verify no notifications are fired during shutdown either.
349 ClosePasswordStore(); 385 ClosePasswordStore();
350 } 386 }
387
388 INSTANTIATE_TEST_CASE_P(,
389 PasswordStoreProxyMacTest,
390 testing::Values(PasswordStoreProxyMac::NOT_STARTED,
391 PasswordStoreProxyMac::MIGRATED,
392 PasswordStoreProxyMac::FAILED_ONCE,
393 PasswordStoreProxyMac::FAILED_TWICE));
394
395 // Test the migration process.
396 class PasswordStoreProxyMacMigrationTest : public PasswordStoreProxyMacTest {
397 public:
398 void SetUp() override;
399
400 void TestMigration(bool lock_keychain);
401
402 protected:
403 scoped_ptr<password_manager::LoginDatabase> login_db_;
404 scoped_ptr<crypto::MockAppleKeychain> keychain_;
405 };
406
407 void PasswordStoreProxyMacMigrationTest::SetUp() {
408 login_db_.reset(
409 new password_manager::LoginDatabase(test_login_db_file_path()));
410 keychain_.reset(new crypto::MockAppleKeychain);
411 }
412
413 void PasswordStoreProxyMacMigrationTest::TestMigration(bool lock_keychain) {
414 PasswordForm form;
415 form.origin = GURL("http://accounts.google.com/LoginAuth");
416 form.signon_realm = "http://accounts.google.com/";
417 form.username_value = base::ASCIIToUTF16("my_username");
418 form.password_value = base::ASCIIToUTF16("12345");
419
420 login_db_->set_clear_password_values(true);
421 EXPECT_TRUE(login_db_->Init());
422 EXPECT_EQ(AddChangeForForm(form), login_db_->AddLogin(form));
423 login_db_.reset(
vabr (Chromium) 2015/07/03 08:40:48 Is this just to undo lines 420 and 421? Perhaps a
vasilii 2015/07/03 12:59:11 I needed another instance because LoginDatabase do
vabr (Chromium) 2015/07/06 09:50:19 Acknowledged.
424 new password_manager::LoginDatabase(test_login_db_file_path()));
425 MacKeychainPasswordFormAdapter adapter(keychain_.get());
426 EXPECT_TRUE(adapter.AddPassword(form));
427
428 // Force migration.
429 if (lock_keychain)
430 keychain_->set_locked(true);
431 crypto::MockAppleKeychain* weak_keychain = keychain_.get();
432 store_ = new PasswordStoreProxyMac(
433 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
434 keychain_.Pass(), login_db_.Pass(), &testing_prefs_);
435 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
436 FinishAsyncProcessing();
437
438 // Check the password is still there.
439 if (lock_keychain)
440 weak_keychain->set_locked(false);
441 MockPasswordStoreConsumer mock_consumer;
442 store()->GetLogins(form, PasswordStoreProxyMac::ALLOW_PROMPT, &mock_consumer);
443 EXPECT_CALL(mock_consumer,
444 OnGetPasswordStoreResultsConstRef(ElementsAre(Pointee(form))))
445 .WillOnce(QuitUIMessageLoop());
446 base::MessageLoop::current()->Run();
447
448 int status = testing_prefs_.GetInteger(
449 password_manager::prefs::kKeychainMigrationStatus);
450 if (lock_keychain) {
451 EXPECT_EQ(GetParam() == PasswordStoreProxyMac::NOT_STARTED
452 ? PasswordStoreProxyMac::FAILED_ONCE
453 : PasswordStoreProxyMac::FAILED_TWICE,
454 status);
455 } else {
456 EXPECT_EQ(PasswordStoreProxyMac::MIGRATED, status);
457 }
458 }
459
460 TEST_P(PasswordStoreProxyMacMigrationTest, TestSuccessfullMigration) {
461 TestMigration(false);
462 }
463
464 TEST_P(PasswordStoreProxyMacMigrationTest, TestFailedMigration) {
465 TestMigration(true);
466 }
467
468 INSTANTIATE_TEST_CASE_P(,
469 PasswordStoreProxyMacMigrationTest,
470 testing::Values(PasswordStoreProxyMac::NOT_STARTED,
vabr (Chromium) 2015/07/03 08:40:48 Would it make sense to run this test also for the
vasilii 2015/07/03 12:59:11 Done.
471 PasswordStoreProxyMac::FAILED_ONCE));
472
351 } // namespace 473 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698