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_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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |