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

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

Issue 1207373002: Implement Mac Keychain migration algorithm. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: more comments 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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_mac.h" 5 #include "chrome/browser/password_manager/password_store_mac.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/files/scoped_temp_dir.h" 8 #include "base/files/scoped_temp_dir.h"
9 #include "base/scoped_observer.h" 9 #include "base/scoped_observer.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
(...skipping 1155 matching lines...) Expand 10 before | Expand all | Expand 10 after
1166 } 1166 }
1167 1167
1168 #pragma mark - 1168 #pragma mark -
1169 1169
1170 class PasswordStoreMacTest : public testing::Test { 1170 class PasswordStoreMacTest : public testing::Test {
1171 public: 1171 public:
1172 PasswordStoreMacTest() : ui_thread_(BrowserThread::UI, &message_loop_) {} 1172 PasswordStoreMacTest() : ui_thread_(BrowserThread::UI, &message_loop_) {}
1173 1173
1174 void SetUp() override { 1174 void SetUp() override {
1175 ASSERT_TRUE(db_dir_.CreateUniqueTempDir()); 1175 ASSERT_TRUE(db_dir_.CreateUniqueTempDir());
1176 histogram_tester_.reset(new base::HistogramTester);
1176 1177
1177 // Ensure that LoginDatabase will use the mock keychain if it needs to 1178 // Ensure that LoginDatabase will use the mock keychain if it needs to
1178 // encrypt/decrypt a password. 1179 // encrypt/decrypt a password.
1179 OSCrypt::UseMockKeychain(true); 1180 OSCrypt::UseMockKeychain(true);
1180 login_db_.reset( 1181 login_db_.reset(
1181 new password_manager::LoginDatabase(test_login_db_file_path())); 1182 new password_manager::LoginDatabase(test_login_db_file_path()));
1182 thread_.reset(new base::Thread("Chrome_PasswordStore_Thread")); 1183 thread_.reset(new base::Thread("Chrome_PasswordStore_Thread"));
1183 ASSERT_TRUE(thread_->Start()); 1184 ASSERT_TRUE(thread_->Start());
1184 ASSERT_TRUE(thread_->task_runner()->PostTask( 1185 ASSERT_TRUE(thread_->task_runner()->PostTask(
1185 FROM_HERE, base::Bind(&PasswordStoreMacTest::InitLoginDatabase, 1186 FROM_HERE, base::Bind(&PasswordStoreMacTest::InitLoginDatabase,
1186 base::Unretained(login_db_.get())))); 1187 base::Unretained(login_db_.get()))));
1187 CreateAndInitPasswordStore(login_db_.get()); 1188 CreateAndInitPasswordStore(login_db_.get());
1188 // Make sure deferred initialization is performed before some tests start 1189 // Make sure deferred initialization is performed before some tests start
1189 // accessing the |login_db| directly. 1190 // accessing the |login_db| directly.
1190 FinishAsyncProcessing(); 1191 FinishAsyncProcessing();
1191 } 1192 }
1192 1193
1193 void TearDown() override { 1194 void TearDown() override {
1194 ClosePasswordStore(); 1195 ClosePasswordStore();
1195 thread_.reset(); 1196 thread_.reset();
1196 login_db_.reset(); 1197 login_db_.reset();
1197 // Whatever a test did, PasswordStoreMac stores only empty password values 1198 // Whatever a test did, PasswordStoreMac stores only empty password values
1198 // in LoginDatabase. The empty valus do not require encryption and therefore 1199 // in LoginDatabase. The empty valus do not require encryption and therefore
1199 // OSCrypt shouldn't call the Keychain. The histogram doesn't cover the 1200 // OSCrypt shouldn't call the Keychain. The histogram doesn't cover the
1200 // internet passwords. 1201 // internet passwords.
1201 EXPECT_FALSE(histogram_tester_.GetHistogramSamplesSinceCreation( 1202 if (histogram_tester_) {
1202 "OSX.Keychain.Access")); 1203 scoped_ptr<base::HistogramSamples> samples =
1204 histogram_tester_->GetHistogramSamplesSinceCreation(
1205 "OSX.Keychain.Access");
1206 EXPECT_TRUE(!samples || samples->TotalCount() == 0);
1207 }
1203 } 1208 }
1204 1209
1205 static void InitLoginDatabase(password_manager::LoginDatabase* login_db) { 1210 static void InitLoginDatabase(password_manager::LoginDatabase* login_db) {
1206 ASSERT_TRUE(login_db->Init()); 1211 ASSERT_TRUE(login_db->Init());
1207 } 1212 }
1208 1213
1209 void CreateAndInitPasswordStore(password_manager::LoginDatabase* login_db) { 1214 void CreateAndInitPasswordStore(password_manager::LoginDatabase* login_db) {
1210 store_ = new PasswordStoreMac( 1215 store_ = new PasswordStoreMac(
1211 base::ThreadTaskRunnerHandle::Get(), nullptr, 1216 base::ThreadTaskRunnerHandle::Get(), nullptr,
1212 make_scoped_ptr<AppleKeychain>(new MockAppleKeychain), login_db); 1217 make_scoped_ptr<AppleKeychain>(new MockAppleKeychain), login_db);
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
1297 1302
1298 protected: 1303 protected:
1299 base::MessageLoopForUI message_loop_; 1304 base::MessageLoopForUI message_loop_;
1300 content::TestBrowserThread ui_thread_; 1305 content::TestBrowserThread ui_thread_;
1301 // Thread that the synchronous methods are run on. 1306 // Thread that the synchronous methods are run on.
1302 scoped_ptr<base::Thread> thread_; 1307 scoped_ptr<base::Thread> thread_;
1303 1308
1304 base::ScopedTempDir db_dir_; 1309 base::ScopedTempDir db_dir_;
1305 scoped_ptr<password_manager::LoginDatabase> login_db_; 1310 scoped_ptr<password_manager::LoginDatabase> login_db_;
1306 scoped_refptr<PasswordStoreMac> store_; 1311 scoped_refptr<PasswordStoreMac> store_;
1307 base::HistogramTester histogram_tester_; 1312 scoped_ptr<base::HistogramTester> histogram_tester_;
1308 }; 1313 };
1309 1314
1310 TEST_F(PasswordStoreMacTest, TestStoreUpdate) { 1315 TEST_F(PasswordStoreMacTest, TestStoreUpdate) {
1311 // Insert a password into both the database and the keychain. 1316 // Insert a password into both the database and the keychain.
1312 // This is done manually, rather than through store_->AddLogin, because the 1317 // This is done manually, rather than through store_->AddLogin, because the
1313 // Mock Keychain isn't smart enough to be able to support update generically, 1318 // Mock Keychain isn't smart enough to be able to support update generically,
1314 // so some.domain.com triggers special handling to test it that make inserting 1319 // so some.domain.com triggers special handling to test it that make inserting
1315 // fail. 1320 // fail.
1316 PasswordFormData joint_data = { 1321 PasswordFormData joint_data = {
1317 PasswordForm::SCHEME_HTML, "http://some.domain.com/", 1322 PasswordForm::SCHEME_HTML, "http://some.domain.com/",
(...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after
1751 // Verify that federated credentials can be stored, retrieved and deleted. 1756 // Verify that federated credentials can be stored, retrieved and deleted.
1752 TEST_F(PasswordStoreMacTest, StoringAndRetrievingFederatedCredentials) { 1757 TEST_F(PasswordStoreMacTest, StoringAndRetrievingFederatedCredentials) {
1753 PasswordForm form; 1758 PasswordForm form;
1754 form.signon_realm = "android://7x7IDboo8u9YKraUsbmVkuf1@net.rateflix.app/"; 1759 form.signon_realm = "android://7x7IDboo8u9YKraUsbmVkuf1@net.rateflix.app/";
1755 form.federation_url = GURL(password_manager::kTestingFederationUrlSpec); 1760 form.federation_url = GURL(password_manager::kTestingFederationUrlSpec);
1756 form.username_value = base::UTF8ToUTF16("randomusername"); 1761 form.username_value = base::UTF8ToUTF16("randomusername");
1757 form.password_value = base::UTF8ToUTF16(""); // No password. 1762 form.password_value = base::UTF8ToUTF16(""); // No password.
1758 1763
1759 VerifyCredentialLifecycle(form); 1764 VerifyCredentialLifecycle(form);
1760 } 1765 }
1766
1767 void CheckMigrationResult(PasswordStoreMac::MigrationResult expected_result,
1768 PasswordStoreMac::MigrationResult result) {
1769 EXPECT_EQ(expected_result, result);
1770 QuitUIMessageLoop();
1771 }
1772
1773 // Import the passwords from the Keychain to LoginDatabase.
1774 TEST_F(PasswordStoreMacTest, ImportFromKeychain) {
1775 PasswordForm form1;
1776 form1.origin = GURL("http://accounts.google.com/LoginAuth");
1777 form1.signon_realm = "http://accounts.google.com/";
1778 form1.username_value = ASCIIToUTF16("my_username");
1779 form1.password_value = ASCIIToUTF16("my_password");
1780
1781 PasswordForm form2;
1782 form2.origin = GURL("http://facebook.com/Login");
1783 form2.signon_realm = "http://facebook.com/";
1784 form2.username_value = ASCIIToUTF16("my_username");
1785 form2.password_value = ASCIIToUTF16("my_password");
1786
1787 PasswordForm blacklisted_form;
1788 blacklisted_form.origin = GURL("http://badsite.com/Login");
1789 blacklisted_form.signon_realm = "http://badsite.com/";
1790 blacklisted_form.blacklisted_by_user = true;
1791
1792 store()->AddLogin(form1);
1793 store()->AddLogin(form2);
1794 store()->AddLogin(blacklisted_form);
1795 FinishAsyncProcessing();
1796
1797 ASSERT_TRUE(base::PostTaskAndReplyWithResult(
1798 thread_->task_runner().get(), FROM_HERE,
1799 base::Bind(&PasswordStoreMac::ImportFromKeychain, store()),
1800 base::Bind(&CheckMigrationResult, PasswordStoreMac::MIGRATION_OK)));
1801 FinishAsyncProcessing();
1802
1803 // The password should be stored in the database by now.
1804 ScopedVector<PasswordForm> matching_items;
1805 EXPECT_TRUE(login_db()->GetLogins(form1, &matching_items));
1806 ASSERT_EQ(1u, matching_items.size());
1807 EXPECT_EQ(form1, *matching_items[0]);
1808
1809 EXPECT_TRUE(login_db()->GetLogins(form2, &matching_items));
1810 ASSERT_EQ(1u, matching_items.size());
1811 EXPECT_EQ(form2, *matching_items[0]);
1812
1813 EXPECT_TRUE(login_db()->GetLogins(blacklisted_form, &matching_items));
1814 ASSERT_EQ(1u, matching_items.size());
1815 EXPECT_EQ(blacklisted_form, *matching_items[0]);
1816
1817 // The passwords are encrypted using a key from the Keychain.
1818 EXPECT_TRUE(histogram_tester_->GetHistogramSamplesSinceCreation(
1819 "OSX.Keychain.Access")->TotalCount());
1820 histogram_tester_.reset();
1821 }
1822
1823 // Import a federated credential while the Keychain is locked.
1824 TEST_F(PasswordStoreMacTest, ImportFederatedFromLockedKeychain) {
1825 keychain()->set_locked(true);
1826 PasswordForm form1;
1827 form1.origin = GURL("http://example.com/Login");
1828 form1.signon_realm = "http://example.com/";
1829 form1.username_value = ASCIIToUTF16("my_username");
1830 form1.federation_url = GURL("https://accounts.google.com/");
1831
1832 store()->AddLogin(form1);
1833 FinishAsyncProcessing();
1834 ASSERT_TRUE(base::PostTaskAndReplyWithResult(
1835 thread_->task_runner().get(), FROM_HERE,
1836 base::Bind(&PasswordStoreMac::ImportFromKeychain, store()),
1837 base::Bind(&CheckMigrationResult, PasswordStoreMac::MIGRATION_OK)));
1838 FinishAsyncProcessing();
1839
1840 ScopedVector<PasswordForm> matching_items;
1841 EXPECT_TRUE(login_db()->GetLogins(form1, &matching_items));
1842 ASSERT_EQ(1u, matching_items.size());
1843 EXPECT_EQ(form1, *matching_items[0]);
1844 }
1845
1846 // Try to import while the Keychain is locked but the encryption key had been
1847 // read earlier.
1848 TEST_F(PasswordStoreMacTest, ImportFromLockedKeychainError) {
1849 PasswordForm form1;
1850 form1.origin = GURL("http://accounts.google.com/LoginAuth");
1851 form1.signon_realm = "http://accounts.google.com/";
1852 form1.username_value = ASCIIToUTF16("my_username");
1853 form1.password_value = ASCIIToUTF16("my_password");
1854 store()->AddLogin(form1);
1855 FinishAsyncProcessing();
1856
1857 // Add a second keychain item matching the Database entry.
1858 PasswordForm form2 = form1;
1859 form2.origin = GURL("http://accounts.google.com/Login");
1860 form2.password_value = ASCIIToUTF16("1234");
1861 MacKeychainPasswordFormAdapter adapter(keychain());
1862 EXPECT_TRUE(adapter.AddPassword(form2));
1863
1864 keychain()->set_locked(true);
1865 ASSERT_TRUE(base::PostTaskAndReplyWithResult(
1866 thread_->task_runner().get(), FROM_HERE,
1867 base::Bind(&PasswordStoreMac::ImportFromKeychain, store()),
1868 base::Bind(&CheckMigrationResult, PasswordStoreMac::KEYCHAIN_BLOCKED)));
1869 FinishAsyncProcessing();
1870
1871 ScopedVector<PasswordForm> matching_items;
1872 EXPECT_TRUE(login_db()->GetLogins(form1, &matching_items));
1873 ASSERT_EQ(1u, matching_items.size());
1874 EXPECT_EQ(base::string16(), matching_items[0]->password_value);
1875
1876 histogram_tester_->ExpectUniqueSample(
1877 "PasswordManager.KeychainMigration.NumPasswordsOnFailure", 1, 1);
1878 histogram_tester_->ExpectUniqueSample(
1879 "PasswordManager.KeychainMigration.NumFailedPasswords", 1, 1);
1880 histogram_tester_->ExpectUniqueSample(
1881 "PasswordManager.KeychainMigration.NumChromeOwnedFailedPasswords", 2, 1);
1882 // Don't test the encryption key access.
1883 histogram_tester_.reset();
1884 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698