| OLD | NEW |
| 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/memory/scoped_vector.h" | 9 #include "base/memory/scoped_vector.h" |
| 10 #include "base/scoped_observer.h" | 10 #include "base/scoped_observer.h" |
| 11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 12 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
| 13 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
| 14 #include "base/synchronization/waitable_event.h" |
| 14 #include "chrome/browser/password_manager/password_store_mac_internal.h" | 15 #include "chrome/browser/password_manager/password_store_mac_internal.h" |
| 15 #include "chrome/common/chrome_paths.h" | 16 #include "chrome/common/chrome_paths.h" |
| 17 #include "components/password_manager/core/browser/login_database.h" |
| 16 #include "components/password_manager/core/browser/password_store_consumer.h" | 18 #include "components/password_manager/core/browser/password_store_consumer.h" |
| 17 #include "content/public/test/test_browser_thread.h" | 19 #include "content/public/test/test_browser_thread.h" |
| 18 #include "crypto/mock_apple_keychain.h" | 20 #include "crypto/mock_apple_keychain.h" |
| 19 #include "testing/gmock/include/gmock/gmock.h" | 21 #include "testing/gmock/include/gmock/gmock.h" |
| 20 #include "testing/gtest/include/gtest/gtest.h" | 22 #include "testing/gtest/include/gtest/gtest.h" |
| 21 | 23 |
| 22 using autofill::PasswordForm; | 24 using autofill::PasswordForm; |
| 23 using base::ASCIIToUTF16; | 25 using base::ASCIIToUTF16; |
| 24 using base::WideToUTF16; | 26 using base::WideToUTF16; |
| 25 using content::BrowserThread; | 27 using content::BrowserThread; |
| 26 using crypto::MockAppleKeychain; | 28 using crypto::MockAppleKeychain; |
| 27 using internal_keychain_helpers::FormsMatchForMerge; | 29 using internal_keychain_helpers::FormsMatchForMerge; |
| 28 using internal_keychain_helpers::STRICT_FORM_MATCH; | 30 using internal_keychain_helpers::STRICT_FORM_MATCH; |
| 29 using password_manager::LoginDatabase; | 31 using password_manager::LoginDatabase; |
| 30 using password_manager::PasswordStore; | 32 using password_manager::PasswordStore; |
| 31 using password_manager::PasswordStoreConsumer; | 33 using password_manager::PasswordStoreConsumer; |
| 32 using testing::_; | 34 using testing::_; |
| 33 using testing::DoAll; | 35 using testing::DoAll; |
| 34 using testing::Invoke; | 36 using testing::Invoke; |
| 35 using testing::WithArg; | 37 using testing::WithArg; |
| 36 | 38 |
| 37 namespace { | 39 namespace { |
| 38 | 40 |
| 41 ACTION(STLDeleteElements0) { |
| 42 STLDeleteContainerPointers(arg0.begin(), arg0.end()); |
| 43 } |
| 44 |
| 45 ACTION(QuitUIMessageLoop) { |
| 46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 47 base::MessageLoop::current()->Quit(); |
| 48 } |
| 49 |
| 39 class MockPasswordStoreConsumer : public PasswordStoreConsumer { | 50 class MockPasswordStoreConsumer : public PasswordStoreConsumer { |
| 40 public: | 51 public: |
| 41 MOCK_METHOD1(OnGetPasswordStoreResults, | 52 MOCK_METHOD1(OnGetPasswordStoreResults, |
| 42 void(const std::vector<autofill::PasswordForm*>&)); | 53 void(const std::vector<autofill::PasswordForm*>&)); |
| 43 | 54 |
| 44 void CopyElements(const std::vector<autofill::PasswordForm*>& forms) { | 55 void CopyElements(const std::vector<autofill::PasswordForm*>& forms) { |
| 45 last_result.clear(); | 56 last_result.clear(); |
| 46 for (size_t i = 0; i < forms.size(); ++i) { | 57 for (size_t i = 0; i < forms.size(); ++i) { |
| 47 last_result.push_back(*forms[i]); | 58 last_result.push_back(*forms[i]); |
| 48 } | 59 } |
| 49 } | 60 } |
| 50 | 61 |
| 62 // Runs the current thread's message loop until OnGetPasswordStoreResults() |
| 63 // is posted to it. This method should be called immediately after GetLogins, |
| 64 // without pumping the message loop in-between. |
| 65 void WaitOnGetPasswordStoreResults() { |
| 66 EXPECT_CALL(*this, OnGetPasswordStoreResults(_)).WillOnce(DoAll( |
| 67 WithArg<0>(Invoke(this, &MockPasswordStoreConsumer::CopyElements)), |
| 68 WithArg<0>(STLDeleteElements0()), |
| 69 QuitUIMessageLoop())); |
| 70 base::MessageLoop::current()->Run(); |
| 71 } |
| 72 |
| 51 std::vector<PasswordForm> last_result; | 73 std::vector<PasswordForm> last_result; |
| 52 }; | 74 }; |
| 53 | 75 |
| 54 ACTION(STLDeleteElements0) { | 76 class MockPasswordStoreObserver : public PasswordStore::Observer { |
| 55 STLDeleteContainerPointers(arg0.begin(), arg0.end()); | 77 public: |
| 56 } | 78 MOCK_METHOD1(OnLoginsChanged, |
| 79 void(const password_manager::PasswordStoreChangeList& changes)); |
| 80 }; |
| 57 | 81 |
| 58 ACTION(QuitUIMessageLoop) { | 82 // A mock LoginDatabase that simulates a failing Init() method. |
| 59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 83 class BadLoginDatabase : public password_manager::LoginDatabase { |
| 60 base::MessageLoop::current()->Quit(); | 84 public: |
| 61 } | 85 BadLoginDatabase() : password_manager::LoginDatabase(base::FilePath()) {} |
| 86 ~BadLoginDatabase() override {} |
| 87 |
| 88 // LoginDatabase: |
| 89 bool Init() override { return false; } |
| 90 |
| 91 private: |
| 92 DISALLOW_COPY_AND_ASSIGN(BadLoginDatabase); |
| 93 }; |
| 94 |
| 95 // A LoginDatabase that simulates an Init() method that takes a long time. |
| 96 class SlowToInitLoginDatabase : public password_manager::LoginDatabase { |
| 97 public: |
| 98 // Creates an instance whose Init() method will block until |event| is |
| 99 // signaled. |event| must outlive |this|. |
| 100 SlowToInitLoginDatabase(const base::FilePath& db_path, |
| 101 base::WaitableEvent* event) |
| 102 : password_manager::LoginDatabase(db_path), event_(event) {} |
| 103 ~SlowToInitLoginDatabase() override {} |
| 104 |
| 105 // LoginDatabase: |
| 106 bool Init() override { |
| 107 event_->Wait(); |
| 108 return password_manager::LoginDatabase::Init(); |
| 109 } |
| 110 |
| 111 private: |
| 112 base::WaitableEvent* event_; |
| 113 |
| 114 DISALLOW_COPY_AND_ASSIGN(SlowToInitLoginDatabase); |
| 115 }; |
| 62 | 116 |
| 63 class TestPasswordStoreMac : public PasswordStoreMac { | 117 class TestPasswordStoreMac : public PasswordStoreMac { |
| 64 public: | 118 public: |
| 65 TestPasswordStoreMac( | 119 TestPasswordStoreMac( |
| 66 scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner, | 120 scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner, |
| 67 scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner, | 121 scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner, |
| 68 crypto::AppleKeychain* keychain, | 122 scoped_ptr<crypto::AppleKeychain> keychain, |
| 69 LoginDatabase* login_db) | 123 scoped_ptr<password_manager::LoginDatabase> login_db) |
| 70 : PasswordStoreMac(main_thread_runner, | 124 : PasswordStoreMac(main_thread_runner, |
| 71 db_thread_runner, | 125 db_thread_runner, |
| 72 keychain, | 126 keychain.Pass(), |
| 73 login_db) { | 127 login_db.Pass()) {} |
| 74 } | |
| 75 | 128 |
| 76 using PasswordStoreMac::GetBackgroundTaskRunner; | 129 using PasswordStoreMac::GetBackgroundTaskRunner; |
| 77 | 130 |
| 78 private: | 131 private: |
| 79 ~TestPasswordStoreMac() override {} | 132 ~TestPasswordStoreMac() override {} |
| 80 | 133 |
| 81 DISALLOW_COPY_AND_ASSIGN(TestPasswordStoreMac); | 134 DISALLOW_COPY_AND_ASSIGN(TestPasswordStoreMac); |
| 82 }; | 135 }; |
| 83 | 136 |
| 84 } // namespace | 137 } // namespace |
| (...skipping 960 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1045 STLDeleteElements(&owned_passwords); | 1098 STLDeleteElements(&owned_passwords); |
| 1046 } | 1099 } |
| 1047 | 1100 |
| 1048 #pragma mark - | 1101 #pragma mark - |
| 1049 | 1102 |
| 1050 class PasswordStoreMacTest : public testing::Test { | 1103 class PasswordStoreMacTest : public testing::Test { |
| 1051 public: | 1104 public: |
| 1052 PasswordStoreMacTest() : ui_thread_(BrowserThread::UI, &message_loop_) {} | 1105 PasswordStoreMacTest() : ui_thread_(BrowserThread::UI, &message_loop_) {} |
| 1053 | 1106 |
| 1054 void SetUp() override { | 1107 void SetUp() override { |
| 1055 login_db_ = new LoginDatabase(); | |
| 1056 ASSERT_TRUE(db_dir_.CreateUniqueTempDir()); | 1108 ASSERT_TRUE(db_dir_.CreateUniqueTempDir()); |
| 1057 base::FilePath db_file = db_dir_.path().AppendASCII("login.db"); | |
| 1058 ASSERT_TRUE(login_db_->Init(db_file)); | |
| 1059 | 1109 |
| 1060 keychain_ = new MockAppleKeychain(); | 1110 scoped_ptr<password_manager::LoginDatabase> login_db( |
| 1111 new password_manager::LoginDatabase(test_login_db_file_path())); |
| 1112 CreateAndInitPasswordStore(login_db.Pass()); |
| 1113 // Make sure deferred initialization is performed before some tests start |
| 1114 // accessing the |login_db| directly. |
| 1115 FinishAsyncProcessing(); |
| 1116 } |
| 1061 | 1117 |
| 1118 void TearDown() override { ClosePasswordStore(); } |
| 1119 |
| 1120 void CreateAndInitPasswordStore( |
| 1121 scoped_ptr<password_manager::LoginDatabase> login_db) { |
| 1062 store_ = new TestPasswordStoreMac( | 1122 store_ = new TestPasswordStoreMac( |
| 1063 base::MessageLoopProxy::current(), | 1123 base::MessageLoopProxy::current(), base::MessageLoopProxy::current(), |
| 1064 base::MessageLoopProxy::current(), | 1124 make_scoped_ptr<AppleKeychain>(new MockAppleKeychain), login_db.Pass()); |
| 1065 keychain_, | |
| 1066 login_db_); | |
| 1067 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare())); | 1125 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare())); |
| 1068 } | 1126 } |
| 1069 | 1127 |
| 1070 void TearDown() override { | 1128 void ClosePasswordStore() { |
| 1129 if (!store_) |
| 1130 return; |
| 1131 |
| 1071 store_->Shutdown(); | 1132 store_->Shutdown(); |
| 1072 EXPECT_FALSE(store_->GetBackgroundTaskRunner().get()); | 1133 EXPECT_FALSE(store_->GetBackgroundTaskRunner()); |
| 1134 base::MessageLoop::current()->RunUntilIdle(); |
| 1135 store_ = nullptr; |
| 1073 } | 1136 } |
| 1074 | 1137 |
| 1075 void WaitForStoreUpdate() { | 1138 base::FilePath test_login_db_file_path() const { |
| 1076 // Do a store-level query to wait for all the operations above to be done. | 1139 return db_dir_.path().Append(FILE_PATH_LITERAL("login.db")); |
| 1140 } |
| 1141 |
| 1142 password_manager::LoginDatabase* login_db() const { |
| 1143 return store_->login_metadata_db(); |
| 1144 } |
| 1145 |
| 1146 MockAppleKeychain* keychain() { |
| 1147 return static_cast<MockAppleKeychain*>(store_->keychain()); |
| 1148 } |
| 1149 |
| 1150 void FinishAsyncProcessing() { |
| 1151 // Do a store-level query to wait for all the previously enqueued operations |
| 1152 // to finish. |
| 1077 MockPasswordStoreConsumer consumer; | 1153 MockPasswordStoreConsumer consumer; |
| 1078 EXPECT_CALL(consumer, OnGetPasswordStoreResults(_)) | |
| 1079 .WillOnce(DoAll(WithArg<0>(STLDeleteElements0()), QuitUIMessageLoop())); | |
| 1080 store_->GetLogins(PasswordForm(), PasswordStore::ALLOW_PROMPT, &consumer); | 1154 store_->GetLogins(PasswordForm(), PasswordStore::ALLOW_PROMPT, &consumer); |
| 1081 base::MessageLoop::current()->Run(); | 1155 consumer.WaitOnGetPasswordStoreResults(); |
| 1082 } | 1156 } |
| 1083 | 1157 |
| 1084 TestPasswordStoreMac* store() { return store_.get(); } | 1158 TestPasswordStoreMac* store() { return store_.get(); } |
| 1085 | 1159 |
| 1086 MockAppleKeychain* keychain() { return keychain_; } | |
| 1087 | |
| 1088 protected: | 1160 protected: |
| 1089 base::MessageLoopForUI message_loop_; | 1161 base::MessageLoopForUI message_loop_; |
| 1090 content::TestBrowserThread ui_thread_; | 1162 content::TestBrowserThread ui_thread_; |
| 1091 | 1163 |
| 1092 MockAppleKeychain* keychain_; // Owned by store_. | 1164 base::ScopedTempDir db_dir_; |
| 1093 LoginDatabase* login_db_; // Owned by store_. | |
| 1094 scoped_refptr<TestPasswordStoreMac> store_; | 1165 scoped_refptr<TestPasswordStoreMac> store_; |
| 1095 base::ScopedTempDir db_dir_; | |
| 1096 }; | 1166 }; |
| 1097 | 1167 |
| 1098 TEST_F(PasswordStoreMacTest, TestStoreUpdate) { | 1168 TEST_F(PasswordStoreMacTest, TestStoreUpdate) { |
| 1099 // Insert a password into both the database and the keychain. | 1169 // Insert a password into both the database and the keychain. |
| 1100 // This is done manually, rather than through store_->AddLogin, because the | 1170 // This is done manually, rather than through store_->AddLogin, because the |
| 1101 // Mock Keychain isn't smart enough to be able to support update generically, | 1171 // Mock Keychain isn't smart enough to be able to support update generically, |
| 1102 // so some.domain.com triggers special handling to test it that make inserting | 1172 // so some.domain.com triggers special handling to test it that make inserting |
| 1103 // fail. | 1173 // fail. |
| 1104 PasswordFormData joint_data = { | 1174 PasswordFormData joint_data = { |
| 1105 PasswordForm::SCHEME_HTML, "http://some.domain.com/", | 1175 PasswordForm::SCHEME_HTML, "http://some.domain.com/", |
| 1106 "http://some.domain.com/insecure.html", "login.cgi", | 1176 "http://some.domain.com/insecure.html", "login.cgi", |
| 1107 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1 | 1177 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1 |
| 1108 }; | 1178 }; |
| 1109 scoped_ptr<PasswordForm> joint_form(CreatePasswordFormFromData(joint_data)); | 1179 scoped_ptr<PasswordForm> joint_form(CreatePasswordFormFromData(joint_data)); |
| 1110 login_db_->AddLogin(*joint_form); | 1180 login_db()->AddLogin(*joint_form); |
| 1111 MockAppleKeychain::KeychainTestData joint_keychain_data = { | 1181 MockAppleKeychain::KeychainTestData joint_keychain_data = { |
| 1112 kSecAuthenticationTypeHTMLForm, "some.domain.com", | 1182 kSecAuthenticationTypeHTMLForm, "some.domain.com", |
| 1113 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z", | 1183 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z", |
| 1114 "joe_user", "sekrit", false }; | 1184 "joe_user", "sekrit", false }; |
| 1115 keychain_->AddTestItem(joint_keychain_data); | 1185 keychain()->AddTestItem(joint_keychain_data); |
| 1116 | 1186 |
| 1117 // Insert a password into the keychain only. | 1187 // Insert a password into the keychain only. |
| 1118 MockAppleKeychain::KeychainTestData keychain_only_data = { | 1188 MockAppleKeychain::KeychainTestData keychain_only_data = { |
| 1119 kSecAuthenticationTypeHTMLForm, "keychain.only.com", | 1189 kSecAuthenticationTypeHTMLForm, "keychain.only.com", |
| 1120 kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z", | 1190 kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z", |
| 1121 "keychain", "only", false | 1191 "keychain", "only", false |
| 1122 }; | 1192 }; |
| 1123 keychain_->AddTestItem(keychain_only_data); | 1193 keychain()->AddTestItem(keychain_only_data); |
| 1124 | 1194 |
| 1125 struct UpdateData { | 1195 struct UpdateData { |
| 1126 PasswordFormData form_data; | 1196 PasswordFormData form_data; |
| 1127 const char* password; // NULL indicates no entry should be present. | 1197 const char* password; // NULL indicates no entry should be present. |
| 1128 }; | 1198 }; |
| 1129 | 1199 |
| 1130 // Make a series of update calls. | 1200 // Make a series of update calls. |
| 1131 UpdateData updates[] = { | 1201 UpdateData updates[] = { |
| 1132 // Update the keychain+db passwords (the normal password update case). | 1202 // Update the keychain+db passwords (the normal password update case). |
| 1133 { { PasswordForm::SCHEME_HTML, "http://some.domain.com/", | 1203 { { PasswordForm::SCHEME_HTML, "http://some.domain.com/", |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1153 true, false, 2 }, | 1223 true, false, 2 }, |
| 1154 NULL, | 1224 NULL, |
| 1155 }, | 1225 }, |
| 1156 }; | 1226 }; |
| 1157 for (unsigned int i = 0; i < arraysize(updates); ++i) { | 1227 for (unsigned int i = 0; i < arraysize(updates); ++i) { |
| 1158 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData( | 1228 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData( |
| 1159 updates[i].form_data)); | 1229 updates[i].form_data)); |
| 1160 store_->UpdateLogin(*form); | 1230 store_->UpdateLogin(*form); |
| 1161 } | 1231 } |
| 1162 | 1232 |
| 1163 WaitForStoreUpdate(); | 1233 FinishAsyncProcessing(); |
| 1164 | 1234 |
| 1165 MacKeychainPasswordFormAdapter keychain_adapter(keychain_); | 1235 MacKeychainPasswordFormAdapter keychain_adapter(keychain()); |
| 1166 for (unsigned int i = 0; i < arraysize(updates); ++i) { | 1236 for (unsigned int i = 0; i < arraysize(updates); ++i) { |
| 1167 scoped_ptr<PasswordForm> query_form( | 1237 scoped_ptr<PasswordForm> query_form( |
| 1168 CreatePasswordFormFromData(updates[i].form_data)); | 1238 CreatePasswordFormFromData(updates[i].form_data)); |
| 1169 | 1239 |
| 1170 std::vector<PasswordForm*> matching_items = | 1240 std::vector<PasswordForm*> matching_items = |
| 1171 keychain_adapter.PasswordsFillingForm(query_form->signon_realm, | 1241 keychain_adapter.PasswordsFillingForm(query_form->signon_realm, |
| 1172 query_form->scheme); | 1242 query_form->scheme); |
| 1173 if (updates[i].password) { | 1243 if (updates[i].password) { |
| 1174 EXPECT_GT(matching_items.size(), 0U) << "iteration " << i; | 1244 EXPECT_GT(matching_items.size(), 0U) << "iteration " << i; |
| 1175 if (matching_items.size() >= 1) | 1245 if (matching_items.size() >= 1) |
| 1176 EXPECT_EQ(ASCIIToUTF16(updates[i].password), | 1246 EXPECT_EQ(ASCIIToUTF16(updates[i].password), |
| 1177 matching_items[0]->password_value) << "iteration " << i; | 1247 matching_items[0]->password_value) << "iteration " << i; |
| 1178 } else { | 1248 } else { |
| 1179 EXPECT_EQ(0U, matching_items.size()) << "iteration " << i; | 1249 EXPECT_EQ(0U, matching_items.size()) << "iteration " << i; |
| 1180 } | 1250 } |
| 1181 STLDeleteElements(&matching_items); | 1251 STLDeleteElements(&matching_items); |
| 1182 | 1252 |
| 1183 login_db_->GetLogins(*query_form, &matching_items); | 1253 login_db()->GetLogins(*query_form, &matching_items); |
| 1184 EXPECT_EQ(updates[i].password ? 1U : 0U, matching_items.size()) | 1254 EXPECT_EQ(updates[i].password ? 1U : 0U, matching_items.size()) |
| 1185 << "iteration " << i; | 1255 << "iteration " << i; |
| 1186 STLDeleteElements(&matching_items); | 1256 STLDeleteElements(&matching_items); |
| 1187 } | 1257 } |
| 1188 } | 1258 } |
| 1189 | 1259 |
| 1190 TEST_F(PasswordStoreMacTest, TestDBKeychainAssociation) { | 1260 TEST_F(PasswordStoreMacTest, TestDBKeychainAssociation) { |
| 1191 // Tests that association between the keychain and login database parts of a | 1261 // Tests that association between the keychain and login database parts of a |
| 1192 // password added by fuzzy (PSL) matching works. | 1262 // password added by fuzzy (PSL) matching works. |
| 1193 // 1. Add a password for www.facebook.com | 1263 // 1. Add a password for www.facebook.com |
| 1194 // 2. Get a password for m.facebook.com. This fuzzy matches and returns the | 1264 // 2. Get a password for m.facebook.com. This fuzzy matches and returns the |
| 1195 // www.facebook.com password. | 1265 // www.facebook.com password. |
| 1196 // 3. Add the returned password for m.facebook.com. | 1266 // 3. Add the returned password for m.facebook.com. |
| 1197 // 4. Remove both passwords. | 1267 // 4. Remove both passwords. |
| 1198 // -> check: that both are gone from the login DB and the keychain | 1268 // -> check: that both are gone from the login DB and the keychain |
| 1199 // This test should in particular ensure that we don't keep passwords in the | 1269 // This test should in particular ensure that we don't keep passwords in the |
| 1200 // keychain just before we think we still have other (fuzzy-)matching entries | 1270 // keychain just before we think we still have other (fuzzy-)matching entries |
| 1201 // for them in the login database. (For example, here if we deleted the | 1271 // for them in the login database. (For example, here if we deleted the |
| 1202 // www.facebook.com password from the login database, we should not be blocked | 1272 // www.facebook.com password from the login database, we should not be blocked |
| 1203 // from deleting it from the keystore just becaus the m.facebook.com password | 1273 // from deleting it from the keystore just becaus the m.facebook.com password |
| 1204 // fuzzy-matches the www.facebook.com one.) | 1274 // fuzzy-matches the www.facebook.com one.) |
| 1205 | 1275 |
| 1206 // 1. Add a password for www.facebook.com | 1276 // 1. Add a password for www.facebook.com |
| 1207 PasswordFormData www_form_data = { | 1277 PasswordFormData www_form_data = { |
| 1208 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", | 1278 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", |
| 1209 "http://www.facebook.com/index.html", "login", | 1279 "http://www.facebook.com/index.html", "login", |
| 1210 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1 | 1280 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1 |
| 1211 }; | 1281 }; |
| 1212 scoped_ptr<PasswordForm> www_form(CreatePasswordFormFromData(www_form_data)); | 1282 scoped_ptr<PasswordForm> www_form(CreatePasswordFormFromData(www_form_data)); |
| 1213 login_db_->AddLogin(*www_form); | 1283 login_db()->AddLogin(*www_form); |
| 1214 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_); | 1284 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain()); |
| 1215 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); | 1285 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); |
| 1216 owned_keychain_adapter.AddPassword(*www_form); | 1286 owned_keychain_adapter.AddPassword(*www_form); |
| 1217 | 1287 |
| 1218 // 2. Get a password for m.facebook.com. | 1288 // 2. Get a password for m.facebook.com. |
| 1219 PasswordForm m_form(*www_form); | 1289 PasswordForm m_form(*www_form); |
| 1220 m_form.signon_realm = "http://m.facebook.com"; | 1290 m_form.signon_realm = "http://m.facebook.com"; |
| 1221 m_form.origin = GURL("http://m.facebook.com/index.html"); | 1291 m_form.origin = GURL("http://m.facebook.com/index.html"); |
| 1292 |
| 1222 MockPasswordStoreConsumer consumer; | 1293 MockPasswordStoreConsumer consumer; |
| 1223 EXPECT_CALL(consumer, OnGetPasswordStoreResults(_)).WillOnce(DoAll( | |
| 1224 WithArg<0>(Invoke(&consumer, &MockPasswordStoreConsumer::CopyElements)), | |
| 1225 WithArg<0>(STLDeleteElements0()), | |
| 1226 QuitUIMessageLoop())); | |
| 1227 store_->GetLogins(m_form, PasswordStore::ALLOW_PROMPT, &consumer); | 1294 store_->GetLogins(m_form, PasswordStore::ALLOW_PROMPT, &consumer); |
| 1228 base::MessageLoop::current()->Run(); | 1295 consumer.WaitOnGetPasswordStoreResults(); |
| 1229 EXPECT_EQ(1u, consumer.last_result.size()); | 1296 EXPECT_EQ(1u, consumer.last_result.size()); |
| 1230 | 1297 |
| 1231 // 3. Add the returned password for m.facebook.com. | 1298 // 3. Add the returned password for m.facebook.com. |
| 1232 login_db_->AddLogin(consumer.last_result[0]); | 1299 login_db()->AddLogin(consumer.last_result[0]); |
| 1233 owned_keychain_adapter.AddPassword(m_form); | 1300 owned_keychain_adapter.AddPassword(m_form); |
| 1234 | 1301 |
| 1235 // 4. Remove both passwords. | 1302 // 4. Remove both passwords. |
| 1236 store_->RemoveLogin(*www_form); | 1303 store_->RemoveLogin(*www_form); |
| 1237 store_->RemoveLogin(m_form); | 1304 store_->RemoveLogin(m_form); |
| 1238 WaitForStoreUpdate(); | 1305 FinishAsyncProcessing(); |
| 1239 | 1306 |
| 1240 std::vector<PasswordForm*> matching_items; | 1307 std::vector<PasswordForm*> matching_items; |
| 1241 // No trace of www.facebook.com. | 1308 // No trace of www.facebook.com. |
| 1242 matching_items = owned_keychain_adapter.PasswordsFillingForm( | 1309 matching_items = owned_keychain_adapter.PasswordsFillingForm( |
| 1243 www_form->signon_realm, www_form->scheme); | 1310 www_form->signon_realm, www_form->scheme); |
| 1244 EXPECT_EQ(0u, matching_items.size()); | 1311 EXPECT_EQ(0u, matching_items.size()); |
| 1245 login_db_->GetLogins(*www_form, &matching_items); | 1312 login_db()->GetLogins(*www_form, &matching_items); |
| 1246 EXPECT_EQ(0u, matching_items.size()); | 1313 EXPECT_EQ(0u, matching_items.size()); |
| 1247 // No trace of m.facebook.com. | 1314 // No trace of m.facebook.com. |
| 1248 matching_items = owned_keychain_adapter.PasswordsFillingForm( | 1315 matching_items = owned_keychain_adapter.PasswordsFillingForm( |
| 1249 m_form.signon_realm, m_form.scheme); | 1316 m_form.signon_realm, m_form.scheme); |
| 1250 EXPECT_EQ(0u, matching_items.size()); | 1317 EXPECT_EQ(0u, matching_items.size()); |
| 1251 login_db_->GetLogins(m_form, &matching_items); | 1318 login_db()->GetLogins(m_form, &matching_items); |
| 1252 EXPECT_EQ(0u, matching_items.size()); | 1319 EXPECT_EQ(0u, matching_items.size()); |
| 1253 } | 1320 } |
| 1254 | 1321 |
| 1255 namespace { | 1322 namespace { |
| 1256 | 1323 |
| 1257 class PasswordsChangeObserver : | 1324 class PasswordsChangeObserver : |
| 1258 public password_manager::PasswordStore::Observer { | 1325 public password_manager::PasswordStore::Observer { |
| 1259 public: | 1326 public: |
| 1260 PasswordsChangeObserver(TestPasswordStoreMac* store) : observer_(this) { | 1327 PasswordsChangeObserver(TestPasswordStoreMac* store) : observer_(this) { |
| 1261 observer_.Add(store); | 1328 observer_.Add(store); |
| 1262 } | 1329 } |
| 1263 | 1330 |
| 1264 void WaitAndVerify(PasswordStoreMacTest* test) { | 1331 void WaitAndVerify(PasswordStoreMacTest* test) { |
| 1265 test->WaitForStoreUpdate(); | 1332 test->FinishAsyncProcessing(); |
| 1266 ::testing::Mock::VerifyAndClearExpectations(this); | 1333 ::testing::Mock::VerifyAndClearExpectations(this); |
| 1267 } | 1334 } |
| 1268 | 1335 |
| 1269 // password_manager::PasswordStore::Observer: | 1336 // password_manager::PasswordStore::Observer: |
| 1270 MOCK_METHOD1(OnLoginsChanged, | 1337 MOCK_METHOD1(OnLoginsChanged, |
| 1271 void(const password_manager::PasswordStoreChangeList& changes)); | 1338 void(const password_manager::PasswordStoreChangeList& changes)); |
| 1272 | 1339 |
| 1273 private: | 1340 private: |
| 1274 ScopedObserver<password_manager::PasswordStore, | 1341 ScopedObserver<password_manager::PasswordStore, |
| 1275 PasswordsChangeObserver> observer_; | 1342 PasswordsChangeObserver> observer_; |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1388 | 1455 |
| 1389 TEST_F(PasswordStoreMacTest, TestRemoveLoginsMultiProfile) { | 1456 TEST_F(PasswordStoreMacTest, TestRemoveLoginsMultiProfile) { |
| 1390 // Make sure that RemoveLoginsCreatedBetween does affect only the correct | 1457 // Make sure that RemoveLoginsCreatedBetween does affect only the correct |
| 1391 // profile. | 1458 // profile. |
| 1392 | 1459 |
| 1393 // Add a third-party password. | 1460 // Add a third-party password. |
| 1394 MockAppleKeychain::KeychainTestData keychain_data = { | 1461 MockAppleKeychain::KeychainTestData keychain_data = { |
| 1395 kSecAuthenticationTypeHTMLForm, "some.domain.com", | 1462 kSecAuthenticationTypeHTMLForm, "some.domain.com", |
| 1396 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z", | 1463 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z", |
| 1397 "joe_user", "sekrit", false }; | 1464 "joe_user", "sekrit", false }; |
| 1398 keychain_->AddTestItem(keychain_data); | 1465 keychain()->AddTestItem(keychain_data); |
| 1399 | 1466 |
| 1400 // Add a password through the adapter. It has the "Chrome" creator tag. | 1467 // Add a password through the adapter. It has the "Chrome" creator tag. |
| 1401 // However, it's not referenced by the password database. | 1468 // However, it's not referenced by the password database. |
| 1402 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_); | 1469 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain()); |
| 1403 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); | 1470 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); |
| 1404 PasswordFormData www_form_data1 = { | 1471 PasswordFormData www_form_data1 = { |
| 1405 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", | 1472 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", |
| 1406 "http://www.facebook.com/index.html", "login", L"username", L"password", | 1473 "http://www.facebook.com/index.html", "login", L"username", L"password", |
| 1407 L"submit", L"joe_user", L"sekrit", true, false, 1 }; | 1474 L"submit", L"joe_user", L"sekrit", true, false, 1 }; |
| 1408 scoped_ptr<PasswordForm> www_form(CreatePasswordFormFromData(www_form_data1)); | 1475 scoped_ptr<PasswordForm> www_form(CreatePasswordFormFromData(www_form_data1)); |
| 1409 EXPECT_TRUE(owned_keychain_adapter.AddPassword(*www_form)); | 1476 EXPECT_TRUE(owned_keychain_adapter.AddPassword(*www_form)); |
| 1410 | 1477 |
| 1411 // Add a password from the current profile. | 1478 // Add a password from the current profile. |
| 1412 PasswordFormData www_form_data2 = { | 1479 PasswordFormData www_form_data2 = { |
| 1413 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", | 1480 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", |
| 1414 "http://www.facebook.com/index.html", "login", L"username", L"password", | 1481 "http://www.facebook.com/index.html", "login", L"username", L"password", |
| 1415 L"submit", L"not_joe_user", L"12345", true, false, 1 }; | 1482 L"submit", L"not_joe_user", L"12345", true, false, 1 }; |
| 1416 www_form.reset(CreatePasswordFormFromData(www_form_data2)); | 1483 www_form.reset(CreatePasswordFormFromData(www_form_data2)); |
| 1417 store_->AddLogin(*www_form); | 1484 store_->AddLogin(*www_form); |
| 1418 WaitForStoreUpdate(); | 1485 FinishAsyncProcessing(); |
| 1419 | 1486 |
| 1420 ScopedVector<PasswordForm> matching_items; | 1487 ScopedVector<PasswordForm> matching_items; |
| 1421 login_db_->GetLogins(*www_form, &matching_items.get()); | 1488 login_db()->GetLogins(*www_form, &matching_items.get()); |
| 1422 EXPECT_EQ(1u, matching_items.size()); | 1489 EXPECT_EQ(1u, matching_items.size()); |
| 1423 matching_items.clear(); | 1490 matching_items.clear(); |
| 1424 | 1491 |
| 1425 store_->RemoveLoginsCreatedBetween(base::Time(), base::Time()); | 1492 store_->RemoveLoginsCreatedBetween(base::Time(), base::Time()); |
| 1426 WaitForStoreUpdate(); | 1493 FinishAsyncProcessing(); |
| 1427 | 1494 |
| 1428 // Check the second facebook form is gone. | 1495 // Check the second facebook form is gone. |
| 1429 login_db_->GetLogins(*www_form, &matching_items.get()); | 1496 login_db()->GetLogins(*www_form, &matching_items.get()); |
| 1430 EXPECT_EQ(0u, matching_items.size()); | 1497 EXPECT_EQ(0u, matching_items.size()); |
| 1431 | 1498 |
| 1432 // Check the first facebook form is still there. | 1499 // Check the first facebook form is still there. |
| 1433 matching_items.get() = owned_keychain_adapter.PasswordsFillingForm( | 1500 matching_items.get() = owned_keychain_adapter.PasswordsFillingForm( |
| 1434 www_form->signon_realm, www_form->scheme); | 1501 www_form->signon_realm, www_form->scheme); |
| 1435 ASSERT_EQ(1u, matching_items.size()); | 1502 ASSERT_EQ(1u, matching_items.size()); |
| 1436 EXPECT_EQ(ASCIIToUTF16("joe_user"), matching_items[0]->username_value); | 1503 EXPECT_EQ(ASCIIToUTF16("joe_user"), matching_items[0]->username_value); |
| 1437 matching_items.clear(); | 1504 matching_items.clear(); |
| 1438 | 1505 |
| 1439 // Check the third-party password is still there. | 1506 // Check the third-party password is still there. |
| 1440 owned_keychain_adapter.SetFindsOnlyOwnedItems(false); | 1507 owned_keychain_adapter.SetFindsOnlyOwnedItems(false); |
| 1441 matching_items.get() = owned_keychain_adapter.PasswordsFillingForm( | 1508 matching_items.get() = owned_keychain_adapter.PasswordsFillingForm( |
| 1442 "http://some.domain.com/insecure.html", PasswordForm::SCHEME_HTML); | 1509 "http://some.domain.com/insecure.html", PasswordForm::SCHEME_HTML); |
| 1443 ASSERT_EQ(1u, matching_items.size()); | 1510 ASSERT_EQ(1u, matching_items.size()); |
| 1444 } | 1511 } |
| 1512 |
| 1513 // Open the store and immediately write to it and try to read it back, without |
| 1514 // first waiting for the initialization to finish. If tasks are processed in |
| 1515 // order, read/write operations will correctly be performed only after the |
| 1516 // initialization has finished. |
| 1517 TEST_F(PasswordStoreMacTest, StoreIsUsableImmediatelyAfterConstruction) { |
| 1518 ClosePasswordStore(); |
| 1519 |
| 1520 base::WaitableEvent event(false, false); |
| 1521 CreateAndInitPasswordStore(make_scoped_ptr<password_manager::LoginDatabase>( |
| 1522 new SlowToInitLoginDatabase(test_login_db_file_path(), &event))); |
| 1523 |
| 1524 PasswordFormData www_form_data = { |
| 1525 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", |
| 1526 "http://www.facebook.com/index.html", "login", L"username", L"password", |
| 1527 L"submit", L"not_joe_user", L"12345", true, false, 1}; |
| 1528 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(www_form_data)); |
| 1529 store()->AddLogin(*form); |
| 1530 |
| 1531 MockPasswordStoreConsumer mock_consumer; |
| 1532 store()->GetLogins(*form, PasswordStore::ALLOW_PROMPT, &mock_consumer); |
| 1533 |
| 1534 // Now the read/write tasks are scheduled, let the DB initialization proceed. |
| 1535 event.Signal(); |
| 1536 |
| 1537 mock_consumer.WaitOnGetPasswordStoreResults(); |
| 1538 EXPECT_EQ(1u, mock_consumer.last_result.size()); |
| 1539 EXPECT_TRUE(login_db()); |
| 1540 } |
| 1541 |
| 1542 // Verify that operations on a PasswordStore with a bad database cause no |
| 1543 // explosions, but fail without side effect, return no data and trigger no |
| 1544 // notifications. |
| 1545 TEST_F(PasswordStoreMacTest, OperationsOnABadDatabaseSilentlyFail) { |
| 1546 ClosePasswordStore(); |
| 1547 CreateAndInitPasswordStore( |
| 1548 make_scoped_ptr<password_manager::LoginDatabase>(new BadLoginDatabase)); |
| 1549 FinishAsyncProcessing(); |
| 1550 EXPECT_FALSE(login_db()); |
| 1551 |
| 1552 testing::StrictMock<MockPasswordStoreObserver> mock_observer; |
| 1553 store()->AddObserver(&mock_observer); |
| 1554 |
| 1555 // Add a new autofillable login + a blacklisted login. |
| 1556 PasswordFormData www_form_data = { |
| 1557 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", |
| 1558 "http://www.facebook.com/index.html", "login", L"username", L"password", |
| 1559 L"submit", L"not_joe_user", L"12345", true, false, 1}; |
| 1560 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(www_form_data)); |
| 1561 scoped_ptr<PasswordForm> blacklisted_form(new PasswordForm(*form)); |
| 1562 blacklisted_form->signon_realm = "http://foo.example.com"; |
| 1563 blacklisted_form->origin = GURL("http://foo.example.com/origin"); |
| 1564 blacklisted_form->action = GURL("http://foo.example.com/action"); |
| 1565 blacklisted_form->blacklisted_by_user = true; |
| 1566 store()->AddLogin(*form); |
| 1567 store()->AddLogin(*blacklisted_form); |
| 1568 FinishAsyncProcessing(); |
| 1569 |
| 1570 // Get all logins; autofillable logins; blacklisted logins. |
| 1571 MockPasswordStoreConsumer mock_consumer; |
| 1572 store()->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &mock_consumer); |
| 1573 mock_consumer.WaitOnGetPasswordStoreResults(); |
| 1574 EXPECT_TRUE(mock_consumer.last_result.empty()); |
| 1575 store()->GetAutofillableLogins(&mock_consumer); |
| 1576 mock_consumer.WaitOnGetPasswordStoreResults(); |
| 1577 EXPECT_TRUE(mock_consumer.last_result.empty()); |
| 1578 store()->GetBlacklistLogins(&mock_consumer); |
| 1579 mock_consumer.WaitOnGetPasswordStoreResults(); |
| 1580 EXPECT_TRUE(mock_consumer.last_result.empty()); |
| 1581 |
| 1582 // Report metrics. |
| 1583 store()->ReportMetrics("Test Username", true); |
| 1584 FinishAsyncProcessing(); |
| 1585 |
| 1586 // Change the login. |
| 1587 form->password_value = base::ASCIIToUTF16("a different password"); |
| 1588 store()->UpdateLogin(*form); |
| 1589 FinishAsyncProcessing(); |
| 1590 |
| 1591 // Delete one login; a range of logins. |
| 1592 store()->RemoveLogin(*form); |
| 1593 store()->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max()); |
| 1594 store()->RemoveLoginsSyncedBetween(base::Time(), base::Time::Max()); |
| 1595 FinishAsyncProcessing(); |
| 1596 |
| 1597 // Verify no notifications are fired during shutdown either. |
| 1598 ClosePasswordStore(); |
| 1599 } |
| OLD | NEW |