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 "chrome/browser/password_manager/password_store_mac_internal.h" | 14 #include "chrome/browser/password_manager/password_store_mac_internal.h" |
15 #include "chrome/common/chrome_paths.h" | 15 #include "chrome/common/chrome_paths.h" |
16 #include "components/password_manager/core/browser/login_database.h" | |
16 #include "components/password_manager/core/browser/password_store_consumer.h" | 17 #include "components/password_manager/core/browser/password_store_consumer.h" |
17 #include "content/public/test/test_browser_thread.h" | 18 #include "content/public/test/test_browser_thread.h" |
18 #include "crypto/mock_apple_keychain.h" | 19 #include "crypto/mock_apple_keychain.h" |
19 #include "testing/gmock/include/gmock/gmock.h" | 20 #include "testing/gmock/include/gmock/gmock.h" |
20 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
21 | 22 |
22 using autofill::PasswordForm; | 23 using autofill::PasswordForm; |
23 using base::ASCIIToUTF16; | 24 using base::ASCIIToUTF16; |
24 using base::WideToUTF16; | 25 using base::WideToUTF16; |
25 using content::BrowserThread; | 26 using content::BrowserThread; |
(...skipping 27 matching lines...) Expand all Loading... | |
53 | 54 |
54 ACTION(STLDeleteElements0) { | 55 ACTION(STLDeleteElements0) { |
55 STLDeleteContainerPointers(arg0.begin(), arg0.end()); | 56 STLDeleteContainerPointers(arg0.begin(), arg0.end()); |
56 } | 57 } |
57 | 58 |
58 ACTION(QuitUIMessageLoop) { | 59 ACTION(QuitUIMessageLoop) { |
59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 60 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
60 base::MessageLoop::current()->Quit(); | 61 base::MessageLoop::current()->Quit(); |
61 } | 62 } |
62 | 63 |
64 class MockPasswordStoreObserver : public PasswordStore::Observer { | |
65 public: | |
66 MOCK_METHOD1(OnLoginsChanged, | |
67 void(const password_manager::PasswordStoreChangeList& changes)); | |
68 }; | |
69 | |
70 // A mock LoginDatabase that simulates a failing Init() method. | |
71 class BadLoginDatabase : public password_manager::LoginDatabase { | |
72 public: | |
73 BadLoginDatabase() : password_manager::LoginDatabase(base::FilePath()) {} | |
74 ~BadLoginDatabase() override {} | |
75 | |
76 // LoginDatabase: | |
77 bool Init() override { return false; } | |
78 | |
79 private: | |
80 DISALLOW_COPY_AND_ASSIGN(BadLoginDatabase); | |
81 }; | |
82 | |
63 class TestPasswordStoreMac : public PasswordStoreMac { | 83 class TestPasswordStoreMac : public PasswordStoreMac { |
64 public: | 84 public: |
65 TestPasswordStoreMac( | 85 TestPasswordStoreMac( |
66 scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner, | 86 scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner, |
67 scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner, | 87 scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner, |
68 crypto::AppleKeychain* keychain, | 88 scoped_ptr<crypto::AppleKeychain> keychain, |
69 LoginDatabase* login_db) | 89 scoped_ptr<password_manager::LoginDatabase> login_db) |
70 : PasswordStoreMac(main_thread_runner, | 90 : PasswordStoreMac(main_thread_runner, |
71 db_thread_runner, | 91 db_thread_runner, |
72 keychain, | 92 keychain.Pass(), |
73 login_db) { | 93 login_db.Pass()) {} |
74 } | |
75 | 94 |
76 using PasswordStoreMac::GetBackgroundTaskRunner; | 95 using PasswordStoreMac::GetBackgroundTaskRunner; |
77 | 96 |
78 private: | 97 private: |
79 ~TestPasswordStoreMac() override {} | 98 ~TestPasswordStoreMac() override {} |
80 | 99 |
81 DISALLOW_COPY_AND_ASSIGN(TestPasswordStoreMac); | 100 DISALLOW_COPY_AND_ASSIGN(TestPasswordStoreMac); |
82 }; | 101 }; |
83 | 102 |
84 } // namespace | 103 } // namespace |
(...skipping 960 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1045 STLDeleteElements(&owned_passwords); | 1064 STLDeleteElements(&owned_passwords); |
1046 } | 1065 } |
1047 | 1066 |
1048 #pragma mark - | 1067 #pragma mark - |
1049 | 1068 |
1050 class PasswordStoreMacTest : public testing::Test { | 1069 class PasswordStoreMacTest : public testing::Test { |
1051 public: | 1070 public: |
1052 PasswordStoreMacTest() : ui_thread_(BrowserThread::UI, &message_loop_) {} | 1071 PasswordStoreMacTest() : ui_thread_(BrowserThread::UI, &message_loop_) {} |
1053 | 1072 |
1054 void SetUp() override { | 1073 void SetUp() override { |
1055 login_db_ = new LoginDatabase(); | |
1056 ASSERT_TRUE(db_dir_.CreateUniqueTempDir()); | 1074 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 | 1075 |
1060 keychain_ = new MockAppleKeychain(); | 1076 scoped_ptr<password_manager::LoginDatabase> login_db( |
1061 | 1077 new password_manager::LoginDatabase(test_login_db_file_path())); |
1062 store_ = new TestPasswordStoreMac( | 1078 store_ = new TestPasswordStoreMac( |
1063 base::MessageLoopProxy::current(), | 1079 base::MessageLoopProxy::current(), base::MessageLoopProxy::current(), |
1064 base::MessageLoopProxy::current(), | 1080 make_scoped_ptr<AppleKeychain>(new MockAppleKeychain), login_db.Pass()); |
1065 keychain_, | |
1066 login_db_); | |
1067 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare())); | 1081 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare())); |
1082 // Make sure deferred initialization is performed before some tests start | |
1083 // accessing the |login_db| directly. | |
1084 base::MessageLoop::current()->Run(); | |
1068 } | 1085 } |
1069 | 1086 |
1070 void TearDown() override { | 1087 void TearDown() override { |
1088 ClosePasswordStore(); | |
1089 } | |
1090 | |
1091 void ClosePasswordStore() { | |
1071 store_->Shutdown(); | 1092 store_->Shutdown(); |
1072 EXPECT_FALSE(store_->GetBackgroundTaskRunner().get()); | 1093 EXPECT_FALSE(store_->GetBackgroundTaskRunner().get()); |
vabr (Chromium)
2015/01/20 15:41:35
optional nit: .get() should be unnecessary and is
engedy
2015/01/20 15:48:50
Done.
| |
1094 store_ = nullptr; | |
1095 } | |
1096 | |
1097 base::FilePath test_login_db_file_path() const { | |
1098 return db_dir_.path().Append(FILE_PATH_LITERAL("login.db")); | |
1099 } | |
1100 | |
1101 password_manager::LoginDatabase* login_db() const { | |
1102 return store_->login_metadata_db(); | |
1103 } | |
1104 | |
1105 MockAppleKeychain* keychain() { | |
1106 return static_cast<MockAppleKeychain*>(store_->keychain()); | |
1073 } | 1107 } |
1074 | 1108 |
1075 void WaitForStoreUpdate() { | 1109 void WaitForStoreUpdate() { |
1076 // Do a store-level query to wait for all the operations above to be done. | 1110 // Do a store-level query to wait for all the operations above to be done. |
1077 MockPasswordStoreConsumer consumer; | 1111 MockPasswordStoreConsumer consumer; |
1078 EXPECT_CALL(consumer, OnGetPasswordStoreResults(_)) | 1112 EXPECT_CALL(consumer, OnGetPasswordStoreResults(_)) |
1079 .WillOnce(DoAll(WithArg<0>(STLDeleteElements0()), QuitUIMessageLoop())); | 1113 .WillOnce(DoAll(WithArg<0>(STLDeleteElements0()), QuitUIMessageLoop())); |
1080 store_->GetLogins(PasswordForm(), PasswordStore::ALLOW_PROMPT, &consumer); | 1114 store_->GetLogins(PasswordForm(), PasswordStore::ALLOW_PROMPT, &consumer); |
1081 base::MessageLoop::current()->Run(); | 1115 base::MessageLoop::current()->Run(); |
1082 } | 1116 } |
1083 | 1117 |
1084 TestPasswordStoreMac* store() { return store_.get(); } | 1118 TestPasswordStoreMac* store() { return store_.get(); } |
1085 | 1119 |
1086 MockAppleKeychain* keychain() { return keychain_; } | |
1087 | |
1088 protected: | 1120 protected: |
1089 base::MessageLoopForUI message_loop_; | 1121 base::MessageLoopForUI message_loop_; |
1090 content::TestBrowserThread ui_thread_; | 1122 content::TestBrowserThread ui_thread_; |
1091 | 1123 |
1092 MockAppleKeychain* keychain_; // Owned by store_. | 1124 base::ScopedTempDir db_dir_; |
1093 LoginDatabase* login_db_; // Owned by store_. | |
1094 scoped_refptr<TestPasswordStoreMac> store_; | 1125 scoped_refptr<TestPasswordStoreMac> store_; |
1095 base::ScopedTempDir db_dir_; | |
1096 }; | 1126 }; |
1097 | 1127 |
1098 TEST_F(PasswordStoreMacTest, TestStoreUpdate) { | 1128 TEST_F(PasswordStoreMacTest, TestStoreUpdate) { |
1099 // Insert a password into both the database and the keychain. | 1129 // Insert a password into both the database and the keychain. |
1100 // This is done manually, rather than through store_->AddLogin, because the | 1130 // 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, | 1131 // 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 | 1132 // so some.domain.com triggers special handling to test it that make inserting |
1103 // fail. | 1133 // fail. |
1104 PasswordFormData joint_data = { | 1134 PasswordFormData joint_data = { |
1105 PasswordForm::SCHEME_HTML, "http://some.domain.com/", | 1135 PasswordForm::SCHEME_HTML, "http://some.domain.com/", |
1106 "http://some.domain.com/insecure.html", "login.cgi", | 1136 "http://some.domain.com/insecure.html", "login.cgi", |
1107 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1 | 1137 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1 |
1108 }; | 1138 }; |
1109 scoped_ptr<PasswordForm> joint_form(CreatePasswordFormFromData(joint_data)); | 1139 scoped_ptr<PasswordForm> joint_form(CreatePasswordFormFromData(joint_data)); |
1110 login_db_->AddLogin(*joint_form); | 1140 login_db()->AddLogin(*joint_form); |
1111 MockAppleKeychain::KeychainTestData joint_keychain_data = { | 1141 MockAppleKeychain::KeychainTestData joint_keychain_data = { |
1112 kSecAuthenticationTypeHTMLForm, "some.domain.com", | 1142 kSecAuthenticationTypeHTMLForm, "some.domain.com", |
1113 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z", | 1143 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z", |
1114 "joe_user", "sekrit", false }; | 1144 "joe_user", "sekrit", false }; |
1115 keychain_->AddTestItem(joint_keychain_data); | 1145 keychain()->AddTestItem(joint_keychain_data); |
1116 | 1146 |
1117 // Insert a password into the keychain only. | 1147 // Insert a password into the keychain only. |
1118 MockAppleKeychain::KeychainTestData keychain_only_data = { | 1148 MockAppleKeychain::KeychainTestData keychain_only_data = { |
1119 kSecAuthenticationTypeHTMLForm, "keychain.only.com", | 1149 kSecAuthenticationTypeHTMLForm, "keychain.only.com", |
1120 kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z", | 1150 kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z", |
1121 "keychain", "only", false | 1151 "keychain", "only", false |
1122 }; | 1152 }; |
1123 keychain_->AddTestItem(keychain_only_data); | 1153 keychain()->AddTestItem(keychain_only_data); |
1124 | 1154 |
1125 struct UpdateData { | 1155 struct UpdateData { |
1126 PasswordFormData form_data; | 1156 PasswordFormData form_data; |
1127 const char* password; // NULL indicates no entry should be present. | 1157 const char* password; // NULL indicates no entry should be present. |
1128 }; | 1158 }; |
1129 | 1159 |
1130 // Make a series of update calls. | 1160 // Make a series of update calls. |
1131 UpdateData updates[] = { | 1161 UpdateData updates[] = { |
1132 // Update the keychain+db passwords (the normal password update case). | 1162 // Update the keychain+db passwords (the normal password update case). |
1133 { { PasswordForm::SCHEME_HTML, "http://some.domain.com/", | 1163 { { PasswordForm::SCHEME_HTML, "http://some.domain.com/", |
(...skipping 21 matching lines...) Expand all Loading... | |
1155 }, | 1185 }, |
1156 }; | 1186 }; |
1157 for (unsigned int i = 0; i < arraysize(updates); ++i) { | 1187 for (unsigned int i = 0; i < arraysize(updates); ++i) { |
1158 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData( | 1188 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData( |
1159 updates[i].form_data)); | 1189 updates[i].form_data)); |
1160 store_->UpdateLogin(*form); | 1190 store_->UpdateLogin(*form); |
1161 } | 1191 } |
1162 | 1192 |
1163 WaitForStoreUpdate(); | 1193 WaitForStoreUpdate(); |
1164 | 1194 |
1165 MacKeychainPasswordFormAdapter keychain_adapter(keychain_); | 1195 MacKeychainPasswordFormAdapter keychain_adapter(keychain()); |
1166 for (unsigned int i = 0; i < arraysize(updates); ++i) { | 1196 for (unsigned int i = 0; i < arraysize(updates); ++i) { |
1167 scoped_ptr<PasswordForm> query_form( | 1197 scoped_ptr<PasswordForm> query_form( |
1168 CreatePasswordFormFromData(updates[i].form_data)); | 1198 CreatePasswordFormFromData(updates[i].form_data)); |
1169 | 1199 |
1170 std::vector<PasswordForm*> matching_items = | 1200 std::vector<PasswordForm*> matching_items = |
1171 keychain_adapter.PasswordsFillingForm(query_form->signon_realm, | 1201 keychain_adapter.PasswordsFillingForm(query_form->signon_realm, |
1172 query_form->scheme); | 1202 query_form->scheme); |
1173 if (updates[i].password) { | 1203 if (updates[i].password) { |
1174 EXPECT_GT(matching_items.size(), 0U) << "iteration " << i; | 1204 EXPECT_GT(matching_items.size(), 0U) << "iteration " << i; |
1175 if (matching_items.size() >= 1) | 1205 if (matching_items.size() >= 1) |
1176 EXPECT_EQ(ASCIIToUTF16(updates[i].password), | 1206 EXPECT_EQ(ASCIIToUTF16(updates[i].password), |
1177 matching_items[0]->password_value) << "iteration " << i; | 1207 matching_items[0]->password_value) << "iteration " << i; |
1178 } else { | 1208 } else { |
1179 EXPECT_EQ(0U, matching_items.size()) << "iteration " << i; | 1209 EXPECT_EQ(0U, matching_items.size()) << "iteration " << i; |
1180 } | 1210 } |
1181 STLDeleteElements(&matching_items); | 1211 STLDeleteElements(&matching_items); |
1182 | 1212 |
1183 login_db_->GetLogins(*query_form, &matching_items); | 1213 login_db()->GetLogins(*query_form, &matching_items); |
1184 EXPECT_EQ(updates[i].password ? 1U : 0U, matching_items.size()) | 1214 EXPECT_EQ(updates[i].password ? 1U : 0U, matching_items.size()) |
1185 << "iteration " << i; | 1215 << "iteration " << i; |
1186 STLDeleteElements(&matching_items); | 1216 STLDeleteElements(&matching_items); |
1187 } | 1217 } |
1188 } | 1218 } |
1189 | 1219 |
1190 TEST_F(PasswordStoreMacTest, TestDBKeychainAssociation) { | 1220 TEST_F(PasswordStoreMacTest, TestDBKeychainAssociation) { |
1191 // Tests that association between the keychain and login database parts of a | 1221 // Tests that association between the keychain and login database parts of a |
1192 // password added by fuzzy (PSL) matching works. | 1222 // password added by fuzzy (PSL) matching works. |
1193 // 1. Add a password for www.facebook.com | 1223 // 1. Add a password for www.facebook.com |
1194 // 2. Get a password for m.facebook.com. This fuzzy matches and returns the | 1224 // 2. Get a password for m.facebook.com. This fuzzy matches and returns the |
1195 // www.facebook.com password. | 1225 // www.facebook.com password. |
1196 // 3. Add the returned password for m.facebook.com. | 1226 // 3. Add the returned password for m.facebook.com. |
1197 // 4. Remove both passwords. | 1227 // 4. Remove both passwords. |
1198 // -> check: that both are gone from the login DB and the keychain | 1228 // -> 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 | 1229 // 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 | 1230 // 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 | 1231 // 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 | 1232 // 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 | 1233 // from deleting it from the keystore just becaus the m.facebook.com password |
1204 // fuzzy-matches the www.facebook.com one.) | 1234 // fuzzy-matches the www.facebook.com one.) |
1205 | 1235 |
1206 // 1. Add a password for www.facebook.com | 1236 // 1. Add a password for www.facebook.com |
1207 PasswordFormData www_form_data = { | 1237 PasswordFormData www_form_data = { |
1208 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", | 1238 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", |
1209 "http://www.facebook.com/index.html", "login", | 1239 "http://www.facebook.com/index.html", "login", |
1210 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1 | 1240 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1 |
1211 }; | 1241 }; |
1212 scoped_ptr<PasswordForm> www_form(CreatePasswordFormFromData(www_form_data)); | 1242 scoped_ptr<PasswordForm> www_form(CreatePasswordFormFromData(www_form_data)); |
1213 login_db_->AddLogin(*www_form); | 1243 login_db()->AddLogin(*www_form); |
1214 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_); | 1244 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain()); |
1215 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); | 1245 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); |
1216 owned_keychain_adapter.AddPassword(*www_form); | 1246 owned_keychain_adapter.AddPassword(*www_form); |
1217 | 1247 |
1218 // 2. Get a password for m.facebook.com. | 1248 // 2. Get a password for m.facebook.com. |
1219 PasswordForm m_form(*www_form); | 1249 PasswordForm m_form(*www_form); |
1220 m_form.signon_realm = "http://m.facebook.com"; | 1250 m_form.signon_realm = "http://m.facebook.com"; |
1221 m_form.origin = GURL("http://m.facebook.com/index.html"); | 1251 m_form.origin = GURL("http://m.facebook.com/index.html"); |
1222 MockPasswordStoreConsumer consumer; | 1252 MockPasswordStoreConsumer consumer; |
1223 EXPECT_CALL(consumer, OnGetPasswordStoreResults(_)).WillOnce(DoAll( | 1253 EXPECT_CALL(consumer, OnGetPasswordStoreResults(_)).WillOnce(DoAll( |
1224 WithArg<0>(Invoke(&consumer, &MockPasswordStoreConsumer::CopyElements)), | 1254 WithArg<0>(Invoke(&consumer, &MockPasswordStoreConsumer::CopyElements)), |
1225 WithArg<0>(STLDeleteElements0()), | 1255 WithArg<0>(STLDeleteElements0()), |
1226 QuitUIMessageLoop())); | 1256 QuitUIMessageLoop())); |
1227 store_->GetLogins(m_form, PasswordStore::ALLOW_PROMPT, &consumer); | 1257 store_->GetLogins(m_form, PasswordStore::ALLOW_PROMPT, &consumer); |
1228 base::MessageLoop::current()->Run(); | 1258 base::MessageLoop::current()->Run(); |
1229 EXPECT_EQ(1u, consumer.last_result.size()); | 1259 EXPECT_EQ(1u, consumer.last_result.size()); |
1230 | 1260 |
1231 // 3. Add the returned password for m.facebook.com. | 1261 // 3. Add the returned password for m.facebook.com. |
1232 login_db_->AddLogin(consumer.last_result[0]); | 1262 login_db()->AddLogin(consumer.last_result[0]); |
1233 owned_keychain_adapter.AddPassword(m_form); | 1263 owned_keychain_adapter.AddPassword(m_form); |
1234 | 1264 |
1235 // 4. Remove both passwords. | 1265 // 4. Remove both passwords. |
1236 store_->RemoveLogin(*www_form); | 1266 store_->RemoveLogin(*www_form); |
1237 store_->RemoveLogin(m_form); | 1267 store_->RemoveLogin(m_form); |
1238 WaitForStoreUpdate(); | 1268 WaitForStoreUpdate(); |
1239 | 1269 |
1240 std::vector<PasswordForm*> matching_items; | 1270 std::vector<PasswordForm*> matching_items; |
1241 // No trace of www.facebook.com. | 1271 // No trace of www.facebook.com. |
1242 matching_items = owned_keychain_adapter.PasswordsFillingForm( | 1272 matching_items = owned_keychain_adapter.PasswordsFillingForm( |
1243 www_form->signon_realm, www_form->scheme); | 1273 www_form->signon_realm, www_form->scheme); |
1244 EXPECT_EQ(0u, matching_items.size()); | 1274 EXPECT_EQ(0u, matching_items.size()); |
1245 login_db_->GetLogins(*www_form, &matching_items); | 1275 login_db()->GetLogins(*www_form, &matching_items); |
1246 EXPECT_EQ(0u, matching_items.size()); | 1276 EXPECT_EQ(0u, matching_items.size()); |
1247 // No trace of m.facebook.com. | 1277 // No trace of m.facebook.com. |
1248 matching_items = owned_keychain_adapter.PasswordsFillingForm( | 1278 matching_items = owned_keychain_adapter.PasswordsFillingForm( |
1249 m_form.signon_realm, m_form.scheme); | 1279 m_form.signon_realm, m_form.scheme); |
1250 EXPECT_EQ(0u, matching_items.size()); | 1280 EXPECT_EQ(0u, matching_items.size()); |
1251 login_db_->GetLogins(m_form, &matching_items); | 1281 login_db()->GetLogins(m_form, &matching_items); |
1252 EXPECT_EQ(0u, matching_items.size()); | 1282 EXPECT_EQ(0u, matching_items.size()); |
1253 } | 1283 } |
1254 | 1284 |
1255 namespace { | 1285 namespace { |
1256 | 1286 |
1257 class PasswordsChangeObserver : | 1287 class PasswordsChangeObserver : |
1258 public password_manager::PasswordStore::Observer { | 1288 public password_manager::PasswordStore::Observer { |
1259 public: | 1289 public: |
1260 PasswordsChangeObserver(TestPasswordStoreMac* store) : observer_(this) { | 1290 PasswordsChangeObserver(TestPasswordStoreMac* store) : observer_(this) { |
1261 observer_.Add(store); | 1291 observer_.Add(store); |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1388 | 1418 |
1389 TEST_F(PasswordStoreMacTest, TestRemoveLoginsMultiProfile) { | 1419 TEST_F(PasswordStoreMacTest, TestRemoveLoginsMultiProfile) { |
1390 // Make sure that RemoveLoginsCreatedBetween does affect only the correct | 1420 // Make sure that RemoveLoginsCreatedBetween does affect only the correct |
1391 // profile. | 1421 // profile. |
1392 | 1422 |
1393 // Add a third-party password. | 1423 // Add a third-party password. |
1394 MockAppleKeychain::KeychainTestData keychain_data = { | 1424 MockAppleKeychain::KeychainTestData keychain_data = { |
1395 kSecAuthenticationTypeHTMLForm, "some.domain.com", | 1425 kSecAuthenticationTypeHTMLForm, "some.domain.com", |
1396 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z", | 1426 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z", |
1397 "joe_user", "sekrit", false }; | 1427 "joe_user", "sekrit", false }; |
1398 keychain_->AddTestItem(keychain_data); | 1428 keychain()->AddTestItem(keychain_data); |
1399 | 1429 |
1400 // Add a password through the adapter. It has the "Chrome" creator tag. | 1430 // Add a password through the adapter. It has the "Chrome" creator tag. |
1401 // However, it's not referenced by the password database. | 1431 // However, it's not referenced by the password database. |
1402 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_); | 1432 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain()); |
1403 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); | 1433 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); |
1404 PasswordFormData www_form_data1 = { | 1434 PasswordFormData www_form_data1 = { |
1405 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", | 1435 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", |
1406 "http://www.facebook.com/index.html", "login", L"username", L"password", | 1436 "http://www.facebook.com/index.html", "login", L"username", L"password", |
1407 L"submit", L"joe_user", L"sekrit", true, false, 1 }; | 1437 L"submit", L"joe_user", L"sekrit", true, false, 1 }; |
1408 scoped_ptr<PasswordForm> www_form(CreatePasswordFormFromData(www_form_data1)); | 1438 scoped_ptr<PasswordForm> www_form(CreatePasswordFormFromData(www_form_data1)); |
1409 EXPECT_TRUE(owned_keychain_adapter.AddPassword(*www_form)); | 1439 EXPECT_TRUE(owned_keychain_adapter.AddPassword(*www_form)); |
1410 | 1440 |
1411 // Add a password from the current profile. | 1441 // Add a password from the current profile. |
1412 PasswordFormData www_form_data2 = { | 1442 PasswordFormData www_form_data2 = { |
1413 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", | 1443 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", |
1414 "http://www.facebook.com/index.html", "login", L"username", L"password", | 1444 "http://www.facebook.com/index.html", "login", L"username", L"password", |
1415 L"submit", L"not_joe_user", L"12345", true, false, 1 }; | 1445 L"submit", L"not_joe_user", L"12345", true, false, 1 }; |
1416 www_form.reset(CreatePasswordFormFromData(www_form_data2)); | 1446 www_form.reset(CreatePasswordFormFromData(www_form_data2)); |
1417 store_->AddLogin(*www_form); | 1447 store_->AddLogin(*www_form); |
1418 WaitForStoreUpdate(); | 1448 WaitForStoreUpdate(); |
1419 | 1449 |
1420 ScopedVector<PasswordForm> matching_items; | 1450 ScopedVector<PasswordForm> matching_items; |
1421 login_db_->GetLogins(*www_form, &matching_items.get()); | 1451 login_db()->GetLogins(*www_form, &matching_items.get()); |
1422 EXPECT_EQ(1u, matching_items.size()); | 1452 EXPECT_EQ(1u, matching_items.size()); |
1423 matching_items.clear(); | 1453 matching_items.clear(); |
1424 | 1454 |
1425 store_->RemoveLoginsCreatedBetween(base::Time(), base::Time()); | 1455 store_->RemoveLoginsCreatedBetween(base::Time(), base::Time()); |
1426 WaitForStoreUpdate(); | 1456 WaitForStoreUpdate(); |
1427 | 1457 |
1428 // Check the second facebook form is gone. | 1458 // Check the second facebook form is gone. |
1429 login_db_->GetLogins(*www_form, &matching_items.get()); | 1459 login_db()->GetLogins(*www_form, &matching_items.get()); |
1430 EXPECT_EQ(0u, matching_items.size()); | 1460 EXPECT_EQ(0u, matching_items.size()); |
1431 | 1461 |
1432 // Check the first facebook form is still there. | 1462 // Check the first facebook form is still there. |
1433 matching_items.get() = owned_keychain_adapter.PasswordsFillingForm( | 1463 matching_items.get() = owned_keychain_adapter.PasswordsFillingForm( |
1434 www_form->signon_realm, www_form->scheme); | 1464 www_form->signon_realm, www_form->scheme); |
1435 ASSERT_EQ(1u, matching_items.size()); | 1465 ASSERT_EQ(1u, matching_items.size()); |
1436 EXPECT_EQ(ASCIIToUTF16("joe_user"), matching_items[0]->username_value); | 1466 EXPECT_EQ(ASCIIToUTF16("joe_user"), matching_items[0]->username_value); |
1437 matching_items.clear(); | 1467 matching_items.clear(); |
1438 | 1468 |
1439 // Check the third-party password is still there. | 1469 // Check the third-party password is still there. |
1440 owned_keychain_adapter.SetFindsOnlyOwnedItems(false); | 1470 owned_keychain_adapter.SetFindsOnlyOwnedItems(false); |
1441 matching_items.get() = owned_keychain_adapter.PasswordsFillingForm( | 1471 matching_items.get() = owned_keychain_adapter.PasswordsFillingForm( |
1442 "http://some.domain.com/insecure.html", PasswordForm::SCHEME_HTML); | 1472 "http://some.domain.com/insecure.html", PasswordForm::SCHEME_HTML); |
1443 ASSERT_EQ(1u, matching_items.size()); | 1473 ASSERT_EQ(1u, matching_items.size()); |
1444 } | 1474 } |
1475 | |
1476 TEST_F(PasswordStoreMacTest, StoreIsUsableImmediatelyAfterConstruction) { | |
1477 PasswordFormData password_form_data = { | |
1478 PasswordForm::SCHEME_HTML, "http://example.com/", | |
1479 "http://example.com/login.html", "login.cgi", | |
1480 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1 | |
1481 }; | |
1482 scoped_ptr<PasswordForm> password_form( | |
1483 CreatePasswordFormFromData(password_form_data)); | |
1484 store()->AddLogin(*password_form); | |
1485 | |
1486 // Close the store. | |
1487 ClosePasswordStore(); | |
1488 base::MessageLoop::current()->RunUntilIdle(); | |
1489 | |
1490 // Reopen the store and immediately try to read its contents without running | |
1491 // the message loop in-between. This simulates the scenario where the DB | |
1492 // thread is busy during initialization so the GetLogins task gets scheduled | |
1493 // to the DB thread while the store is still uninitialized. If tasks are | |
1494 // correctly processed in order, this should of no concern. | |
vabr (Chromium)
2015/01/20 15:41:35
typo: should of -> should be of
engedy
2015/01/20 15:48:50
Done.
| |
1495 scoped_ptr<password_manager::LoginDatabase> login_db( | |
1496 new password_manager::LoginDatabase(test_login_db_file_path())); | |
1497 scoped_refptr<TestPasswordStoreMac> reopened_store(new TestPasswordStoreMac( | |
1498 base::MessageLoopProxy::current(), base::MessageLoopProxy::current(), | |
1499 make_scoped_ptr<crypto::AppleKeychain>(new MockAppleKeychain), | |
1500 login_db.Pass())); | |
1501 reopened_store->Init(syncer::SyncableService::StartSyncFlare()); | |
1502 | |
1503 MockPasswordStoreConsumer consumer; | |
1504 EXPECT_CALL(consumer, OnGetPasswordStoreResults(_)) | |
1505 .WillOnce(DoAll(WithArg<0>(Invoke( | |
1506 &consumer, &MockPasswordStoreConsumer::CopyElements)), | |
1507 WithArg<0>(STLDeleteElements0()))); | |
1508 reopened_store->GetLogins(*password_form, PasswordStore::ALLOW_PROMPT, | |
1509 &consumer); | |
1510 base::MessageLoop::current()->RunUntilIdle(); | |
1511 EXPECT_EQ(1u, consumer.last_result.size()); | |
1512 } | |
1513 | |
1514 // Verify that operations on a PasswordStore with a bad database cause no | |
1515 // explosions, but fail without side effect, return no data and trigger no | |
1516 // notifications. | |
1517 TEST_F(PasswordStoreMacTest, OperationsOnABadDatabaseSilentlyFail) { | |
1518 scoped_refptr<TestPasswordStoreMac> bad_store(new TestPasswordStoreMac( | |
1519 base::MessageLoopProxy::current(), base::MessageLoopProxy::current(), | |
1520 make_scoped_ptr<crypto::AppleKeychain>(new MockAppleKeychain), | |
1521 make_scoped_ptr<password_manager::LoginDatabase>(new BadLoginDatabase))); | |
1522 | |
1523 bad_store->Init(syncer::SyncableService::StartSyncFlare()); | |
1524 base::MessageLoop::current()->RunUntilIdle(); | |
1525 ASSERT_EQ(nullptr, bad_store->login_metadata_db()); | |
1526 | |
1527 testing::StrictMock<MockPasswordStoreObserver> mock_observer; | |
1528 bad_store->AddObserver(&mock_observer); | |
1529 | |
1530 // Add a new autofillable login + a blacklisted login. | |
1531 PasswordFormData www_form_data = { | |
1532 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", | |
1533 "http://www.facebook.com/index.html", "login", L"username", L"password", | |
1534 L"submit", L"not_joe_user", L"12345", true, false, 1}; | |
1535 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(www_form_data)); | |
1536 scoped_ptr<PasswordForm> blacklisted_form(new PasswordForm(*form)); | |
1537 blacklisted_form->signon_realm = "http://foo.example.com"; | |
1538 blacklisted_form->origin = GURL("http://foo.example.com/origin"); | |
1539 blacklisted_form->action = GURL("http://foo.example.com/action"); | |
1540 blacklisted_form->blacklisted_by_user = true; | |
1541 bad_store->AddLogin(*form); | |
1542 bad_store->AddLogin(*blacklisted_form); | |
1543 base::MessageLoop::current()->RunUntilIdle(); | |
1544 | |
1545 // Get all logins; autofillable logins; blacklisted logins. | |
1546 testing::StrictMock<MockPasswordStoreConsumer> mock_consumer; | |
1547 EXPECT_CALL(mock_consumer, OnGetPasswordStoreResults(testing::ElementsAre())); | |
1548 bad_store->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &mock_consumer); | |
1549 base::MessageLoop::current()->RunUntilIdle(); | |
1550 testing::Mock::VerifyAndClearExpectations(&mock_consumer); | |
1551 EXPECT_CALL(mock_consumer, OnGetPasswordStoreResults(testing::ElementsAre())); | |
1552 bad_store->GetAutofillableLogins(&mock_consumer); | |
1553 base::MessageLoop::current()->RunUntilIdle(); | |
1554 testing::Mock::VerifyAndClearExpectations(&mock_consumer); | |
1555 EXPECT_CALL(mock_consumer, OnGetPasswordStoreResults(testing::ElementsAre())); | |
1556 bad_store->GetBlacklistLogins(&mock_consumer); | |
1557 base::MessageLoop::current()->RunUntilIdle(); | |
1558 | |
1559 // Report metrics. | |
1560 bad_store->ReportMetrics("Test Username", true); | |
1561 base::MessageLoop::current()->RunUntilIdle(); | |
1562 | |
1563 // Change the login. | |
1564 form->password_value = base::ASCIIToUTF16("a different password"); | |
1565 bad_store->UpdateLogin(*form); | |
1566 base::MessageLoop::current()->RunUntilIdle(); | |
1567 | |
1568 // Delete one login; a range of logins. | |
1569 bad_store->RemoveLogin(*form); | |
1570 base::MessageLoop::current()->RunUntilIdle(); | |
1571 bad_store->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max()); | |
1572 base::MessageLoop::current()->RunUntilIdle(); | |
1573 bad_store->RemoveLoginsSyncedBetween(base::Time(), base::Time::Max()); | |
1574 base::MessageLoop::current()->RunUntilIdle(); | |
1575 | |
1576 // Ensure no notifications and no explosions during shutdown either. | |
1577 bad_store->RemoveObserver(&mock_observer); | |
1578 bad_store->Shutdown(); | |
1579 base::MessageLoop::current()->RunUntilIdle(); | |
1580 } | |
OLD | NEW |