login_database_unittest.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "components/password_manager/core/browser/login_database.h" 6 7#include "base/basictypes.h" 8#include "base/file_util.h" 9#include "base/files/scoped_temp_dir.h" 10#include "base/memory/scoped_vector.h" 11#include "base/path_service.h" 12#include "base/strings/string_number_conversions.h" 13#include "base/strings/utf_string_conversions.h" 14#include "base/time/time.h" 15#include "components/autofill/core/common/password_form.h" 16#include "components/password_manager/core/browser/psl_matching_helper.h" 17#include "testing/gmock/include/gmock/gmock.h" 18#include "testing/gtest/include/gtest/gtest.h" 19 20using autofill::PasswordForm; 21using base::ASCIIToUTF16; 22using ::testing::Eq; 23 24namespace password_manager { 25namespace { 26PasswordStoreChangeList AddChangeForForm(const PasswordForm& form) { 27 return PasswordStoreChangeList(1, 28 PasswordStoreChange(PasswordStoreChange::ADD, 29 form)); 30} 31 32PasswordStoreChangeList UpdateChangeForForm(const PasswordForm& form) { 33 return PasswordStoreChangeList(1, PasswordStoreChange( 34 PasswordStoreChange::UPDATE, form)); 35} 36 37} // namespace 38 39// Serialization routines for vectors implemented in login_database.cc. 40Pickle SerializeVector(const std::vector<base::string16>& vec); 41std::vector<base::string16> DeserializeVector(const Pickle& pickle); 42 43class LoginDatabaseTest : public testing::Test { 44 protected: 45 virtual void SetUp() { 46 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 47 file_ = temp_dir_.path().AppendASCII("TestMetadataStoreMacDatabase"); 48 49 ASSERT_TRUE(db_.Init(file_)); 50 } 51 52 void FormsAreEqual(const PasswordForm& expected, const PasswordForm& actual) { 53 PasswordForm expected_copy(expected); 54#if defined(OS_MACOSX) && !defined(OS_IOS) 55 // On the Mac we should never be storing passwords in the database. 56 expected_copy.password_value = ASCIIToUTF16(""); 57#endif 58 EXPECT_EQ(expected_copy, actual); 59 } 60 61 void TestNonHTMLFormPSLMatching(const PasswordForm::Scheme& scheme) { 62 ScopedVector<PasswordForm> result; 63 64 base::Time now = base::Time::Now(); 65 66 // Simple non-html auth form. 67 PasswordForm non_html_auth; 68 non_html_auth.origin = GURL("http://example.com"); 69 non_html_auth.username_value = ASCIIToUTF16("test@gmail.com"); 70 non_html_auth.password_value = ASCIIToUTF16("test"); 71 non_html_auth.signon_realm = "http://example.com/Realm"; 72 non_html_auth.scheme = scheme; 73 non_html_auth.date_created = now; 74 75 // Simple password form. 76 PasswordForm html_form(non_html_auth); 77 html_form.action = GURL("http://example.com/login"); 78 html_form.username_element = ASCIIToUTF16("username"); 79 html_form.username_value = ASCIIToUTF16("test2@gmail.com"); 80 html_form.password_element = ASCIIToUTF16("password"); 81 html_form.submit_element = ASCIIToUTF16(""); 82 html_form.signon_realm = "http://example.com/"; 83 html_form.scheme = PasswordForm::SCHEME_HTML; 84 html_form.date_created = now; 85 86 // Add them and make sure they are there. 87 EXPECT_EQ(AddChangeForForm(non_html_auth), db_.AddLogin(non_html_auth)); 88 EXPECT_EQ(AddChangeForForm(html_form), db_.AddLogin(html_form)); 89 EXPECT_TRUE(db_.GetAutofillableLogins(&result.get())); 90 EXPECT_EQ(2U, result.size()); 91 result.clear(); 92 93 PasswordForm second_non_html_auth(non_html_auth); 94 second_non_html_auth.origin = GURL("http://second.example.com"); 95 second_non_html_auth.signon_realm = "http://second.example.com/Realm"; 96 97 // This shouldn't match anything. 98 EXPECT_TRUE(db_.GetLogins(second_non_html_auth, &result.get())); 99 EXPECT_EQ(0U, result.size()); 100 101 // non-html auth still matches again itself. 102 EXPECT_TRUE(db_.GetLogins(non_html_auth, &result.get())); 103 ASSERT_EQ(1U, result.size()); 104 EXPECT_EQ(result[0]->signon_realm, "http://example.com/Realm"); 105 106 // Clear state. 107 db_.RemoveLoginsCreatedBetween(now, base::Time()); 108 } 109 110 base::ScopedTempDir temp_dir_; 111 base::FilePath file_; 112 LoginDatabase db_; 113}; 114 115TEST_F(LoginDatabaseTest, Logins) { 116 std::vector<PasswordForm*> result; 117 118 // Verify the database is empty. 119 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 120 EXPECT_EQ(0U, result.size()); 121 122 // Example password form. 123 PasswordForm form; 124 form.origin = GURL("http://accounts.google.com/LoginAuth"); 125 form.action = GURL("http://accounts.google.com/Login"); 126 form.username_element = ASCIIToUTF16("Email"); 127 form.username_value = ASCIIToUTF16("test@gmail.com"); 128 form.password_element = ASCIIToUTF16("Passwd"); 129 form.password_value = ASCIIToUTF16("test"); 130 form.submit_element = ASCIIToUTF16("signIn"); 131 form.signon_realm = "http://www.google.com/"; 132 form.ssl_valid = false; 133 form.preferred = false; 134 form.scheme = PasswordForm::SCHEME_HTML; 135 form.times_used = 1; 136 form.form_data.name = ASCIIToUTF16("form_name"); 137 form.form_data.method = ASCIIToUTF16("POST"); 138 139 // Add it and make sure it is there and that all the fields were retrieved 140 // correctly. 141 EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form)); 142 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 143 EXPECT_EQ(1U, result.size()); 144 FormsAreEqual(form, *result[0]); 145 delete result[0]; 146 result.clear(); 147 148 // Match against an exact copy. 149 EXPECT_TRUE(db_.GetLogins(form, &result)); 150 EXPECT_EQ(1U, result.size()); 151 delete result[0]; 152 result.clear(); 153 154 // The example site changes... 155 PasswordForm form2(form); 156 form2.origin = GURL("http://www.google.com/new/accounts/LoginAuth"); 157 form2.submit_element = ASCIIToUTF16("reallySignIn"); 158 159 // Match against an inexact copy 160 EXPECT_TRUE(db_.GetLogins(form2, &result)); 161 EXPECT_EQ(1U, result.size()); 162 delete result[0]; 163 result.clear(); 164 165 // Uh oh, the site changed origin & action URLs all at once! 166 PasswordForm form3(form2); 167 form3.action = GURL("http://www.google.com/new/accounts/Login"); 168 169 // signon_realm is the same, should match. 170 EXPECT_TRUE(db_.GetLogins(form3, &result)); 171 EXPECT_EQ(1U, result.size()); 172 delete result[0]; 173 result.clear(); 174 175 // Imagine the site moves to a secure server for login. 176 PasswordForm form4(form3); 177 form4.signon_realm = "https://www.google.com/"; 178 form4.ssl_valid = true; 179 180 // We have only an http record, so no match for this. 181 EXPECT_TRUE(db_.GetLogins(form4, &result)); 182 EXPECT_EQ(0U, result.size()); 183 184 // Let's imagine the user logs into the secure site. 185 EXPECT_EQ(AddChangeForForm(form4), db_.AddLogin(form4)); 186 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 187 EXPECT_EQ(2U, result.size()); 188 delete result[0]; 189 delete result[1]; 190 result.clear(); 191 192 // Now the match works 193 EXPECT_TRUE(db_.GetLogins(form4, &result)); 194 EXPECT_EQ(1U, result.size()); 195 delete result[0]; 196 result.clear(); 197 198 // The user chose to forget the original but not the new. 199 EXPECT_TRUE(db_.RemoveLogin(form)); 200 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 201 EXPECT_EQ(1U, result.size()); 202 delete result[0]; 203 result.clear(); 204 205 // The old form wont match the new site (http vs https). 206 EXPECT_TRUE(db_.GetLogins(form, &result)); 207 EXPECT_EQ(0U, result.size()); 208 209 // The user's request for the HTTPS site is intercepted 210 // by an attacker who presents an invalid SSL cert. 211 PasswordForm form5(form4); 212 form5.ssl_valid = 0; 213 214 // It will match in this case. 215 EXPECT_TRUE(db_.GetLogins(form5, &result)); 216 EXPECT_EQ(1U, result.size()); 217 delete result[0]; 218 result.clear(); 219 220 // User changes his password. 221 PasswordForm form6(form5); 222 form6.password_value = ASCIIToUTF16("test6"); 223 form6.preferred = true; 224 225 // We update, and check to make sure it matches the 226 // old form, and there is only one record. 227 EXPECT_EQ(UpdateChangeForForm(form6), db_.UpdateLogin(form6)); 228 // matches 229 EXPECT_TRUE(db_.GetLogins(form5, &result)); 230 EXPECT_EQ(1U, result.size()); 231 delete result[0]; 232 result.clear(); 233 // Only one record. 234 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 235 EXPECT_EQ(1U, result.size()); 236 // Password element was updated. 237#if defined(OS_MACOSX) && !defined(OS_IOS) 238 // On the Mac we should never be storing passwords in the database. 239 EXPECT_EQ(base::string16(), result[0]->password_value); 240#else 241 EXPECT_EQ(form6.password_value, result[0]->password_value); 242#endif 243 // Preferred login. 244 EXPECT_TRUE(form6.preferred); 245 delete result[0]; 246 result.clear(); 247 248 // Make sure everything can disappear. 249 EXPECT_TRUE(db_.RemoveLogin(form4)); 250 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 251 EXPECT_EQ(0U, result.size()); 252} 253 254TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatching) { 255 PSLMatchingHelper::EnablePublicSuffixDomainMatchingForTesting(); 256 std::vector<PasswordForm*> result; 257 258 // Verify the database is empty. 259 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 260 EXPECT_EQ(0U, result.size()); 261 262 // Example password form. 263 PasswordForm form; 264 form.origin = GURL("https://foo.com/"); 265 form.action = GURL("https://foo.com/login"); 266 form.username_element = ASCIIToUTF16("username"); 267 form.username_value = ASCIIToUTF16("test@gmail.com"); 268 form.password_element = ASCIIToUTF16("password"); 269 form.password_value = ASCIIToUTF16("test"); 270 form.submit_element = ASCIIToUTF16(""); 271 form.signon_realm = "https://foo.com/"; 272 form.ssl_valid = true; 273 form.preferred = false; 274 form.scheme = PasswordForm::SCHEME_HTML; 275 276 // Add it and make sure it is there. 277 EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form)); 278 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 279 EXPECT_EQ(1U, result.size()); 280 delete result[0]; 281 result.clear(); 282 283 // Match against an exact copy. 284 EXPECT_TRUE(db_.GetLogins(form, &result)); 285 EXPECT_EQ(1U, result.size()); 286 delete result[0]; 287 result.clear(); 288 289 // We go to the mobile site. 290 PasswordForm form2(form); 291 form2.origin = GURL("https://mobile.foo.com/"); 292 form2.action = GURL("https://mobile.foo.com/login"); 293 form2.signon_realm = "https://mobile.foo.com/"; 294 295 // Match against the mobile site. 296 EXPECT_TRUE(db_.GetLogins(form2, &result)); 297 EXPECT_EQ(1U, result.size()); 298 EXPECT_EQ("https://mobile.foo.com/", result[0]->signon_realm); 299 EXPECT_EQ("https://foo.com/", result[0]->original_signon_realm); 300 delete result[0]; 301 result.clear(); 302} 303 304TEST_F(LoginDatabaseTest, TestPublicSuffixDisabledForNonHTMLForms) { 305 PSLMatchingHelper::EnablePublicSuffixDomainMatchingForTesting(); 306 307 TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_BASIC); 308 TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_DIGEST); 309 TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_OTHER); 310} 311 312TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingShouldMatchingApply) { 313 PSLMatchingHelper::EnablePublicSuffixDomainMatchingForTesting(); 314 std::vector<PasswordForm*> result; 315 316 // Verify the database is empty. 317 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 318 EXPECT_EQ(0U, result.size()); 319 320 // Example password form. 321 PasswordForm form; 322 form.origin = GURL("https://accounts.google.com/"); 323 form.action = GURL("https://accounts.google.com/login"); 324 form.username_element = ASCIIToUTF16("username"); 325 form.username_value = ASCIIToUTF16("test@gmail.com"); 326 form.password_element = ASCIIToUTF16("password"); 327 form.password_value = ASCIIToUTF16("test"); 328 form.submit_element = ASCIIToUTF16(""); 329 form.signon_realm = "https://accounts.google.com/"; 330 form.ssl_valid = true; 331 form.preferred = false; 332 form.scheme = PasswordForm::SCHEME_HTML; 333 334 // Add it and make sure it is there. 335 EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form)); 336 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 337 EXPECT_EQ(1U, result.size()); 338 delete result[0]; 339 result.clear(); 340 341 // Match against an exact copy. 342 EXPECT_TRUE(db_.GetLogins(form, &result)); 343 EXPECT_EQ(1U, result.size()); 344 delete result[0]; 345 result.clear(); 346 347 // We go to a different site on the same domain where feature is not needed. 348 PasswordForm form2(form); 349 form2.origin = GURL("https://some.other.google.com/"); 350 form2.action = GURL("https://some.other.google.com/login"); 351 form2.signon_realm = "https://some.other.google.com/"; 352 353 // Match against the other site. Should not match since feature should not be 354 // enabled for this domain. 355 EXPECT_TRUE(db_.GetLogins(form2, &result)); 356 EXPECT_EQ(0U, result.size()); 357} 358 359// This test fails if the implementation of GetLogins uses GetCachedStatement 360// instead of GetUniqueStatement, since REGEXP is in use. See 361// http://crbug.com/248608. 362TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingDifferentSites) { 363 PSLMatchingHelper::EnablePublicSuffixDomainMatchingForTesting(); 364 std::vector<PasswordForm*> result; 365 366 // Verify the database is empty. 367 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 368 EXPECT_EQ(0U, result.size()); 369 370 // Example password form. 371 PasswordForm form; 372 form.origin = GURL("https://foo.com/"); 373 form.action = GURL("https://foo.com/login"); 374 form.username_element = ASCIIToUTF16("username"); 375 form.username_value = ASCIIToUTF16("test@gmail.com"); 376 form.password_element = ASCIIToUTF16("password"); 377 form.password_value = ASCIIToUTF16("test"); 378 form.submit_element = ASCIIToUTF16(""); 379 form.signon_realm = "https://foo.com/"; 380 form.ssl_valid = true; 381 form.preferred = false; 382 form.scheme = PasswordForm::SCHEME_HTML; 383 384 // Add it and make sure it is there. 385 EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form)); 386 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 387 EXPECT_EQ(1U, result.size()); 388 delete result[0]; 389 result.clear(); 390 391 // Match against an exact copy. 392 EXPECT_TRUE(db_.GetLogins(form, &result)); 393 EXPECT_EQ(1U, result.size()); 394 delete result[0]; 395 result.clear(); 396 397 // We go to the mobile site. 398 PasswordForm form2(form); 399 form2.origin = GURL("https://mobile.foo.com/"); 400 form2.action = GURL("https://mobile.foo.com/login"); 401 form2.signon_realm = "https://mobile.foo.com/"; 402 403 // Match against the mobile site. 404 EXPECT_TRUE(db_.GetLogins(form2, &result)); 405 EXPECT_EQ(1U, result.size()); 406 EXPECT_EQ("https://mobile.foo.com/", result[0]->signon_realm); 407 EXPECT_EQ("https://foo.com/", result[0]->original_signon_realm); 408 delete result[0]; 409 result.clear(); 410 411 // Add baz.com desktop site. 412 form.origin = GURL("https://baz.com/login/"); 413 form.action = GURL("https://baz.com/login/"); 414 form.username_element = ASCIIToUTF16("email"); 415 form.username_value = ASCIIToUTF16("test@gmail.com"); 416 form.password_element = ASCIIToUTF16("password"); 417 form.password_value = ASCIIToUTF16("test"); 418 form.submit_element = ASCIIToUTF16(""); 419 form.signon_realm = "https://baz.com/"; 420 form.ssl_valid = true; 421 form.preferred = false; 422 form.scheme = PasswordForm::SCHEME_HTML; 423 424 // Add it and make sure it is there. 425 EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form)); 426 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 427 EXPECT_EQ(2U, result.size()); 428 delete result[0]; 429 delete result[1]; 430 result.clear(); 431 432 // We go to the mobile site of baz.com. 433 PasswordForm form3(form); 434 form3.origin = GURL("https://m.baz.com/login/"); 435 form3.action = GURL("https://m.baz.com/login/"); 436 form3.signon_realm = "https://m.baz.com/"; 437 438 // Match against the mobile site of baz.com. 439 EXPECT_TRUE(db_.GetLogins(form3, &result)); 440 EXPECT_EQ(1U, result.size()); 441 EXPECT_EQ("https://m.baz.com/", result[0]->signon_realm); 442 EXPECT_EQ("https://baz.com/", result[0]->original_signon_realm); 443 delete result[0]; 444 result.clear(); 445} 446 447PasswordForm GetFormWithNewSignonRealm(PasswordForm form, 448 std::string signon_realm) { 449 PasswordForm form2(form); 450 form2.origin = GURL(signon_realm); 451 form2.action = GURL(signon_realm); 452 form2.signon_realm = signon_realm; 453 return form2; 454} 455 456TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingRegexp) { 457 PSLMatchingHelper::EnablePublicSuffixDomainMatchingForTesting(); 458 std::vector<PasswordForm*> result; 459 460 // Verify the database is empty. 461 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 462 EXPECT_EQ(0U, result.size()); 463 464 // Example password form. 465 PasswordForm form; 466 form.origin = GURL("http://foo.com/"); 467 form.action = GURL("http://foo.com/login"); 468 form.username_element = ASCIIToUTF16("username"); 469 form.username_value = ASCIIToUTF16("test@gmail.com"); 470 form.password_element = ASCIIToUTF16("password"); 471 form.password_value = ASCIIToUTF16("test"); 472 form.submit_element = ASCIIToUTF16(""); 473 form.signon_realm = "http://foo.com/"; 474 form.ssl_valid = false; 475 form.preferred = false; 476 form.scheme = PasswordForm::SCHEME_HTML; 477 478 // Add it and make sure it is there. 479 EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form)); 480 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 481 EXPECT_EQ(1U, result.size()); 482 delete result[0]; 483 result.clear(); 484 485 // Example password form that has - in the domain name. 486 PasswordForm form_dash = 487 GetFormWithNewSignonRealm(form, "http://www.foo-bar.com/"); 488 489 // Add it and make sure it is there. 490 EXPECT_EQ(AddChangeForForm(form_dash), db_.AddLogin(form_dash)); 491 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 492 EXPECT_EQ(2U, result.size()); 493 delete result[0]; 494 delete result[1]; 495 result.clear(); 496 497 // Match against an exact copy. 498 EXPECT_TRUE(db_.GetLogins(form, &result)); 499 EXPECT_EQ(1U, result.size()); 500 delete result[0]; 501 result.clear(); 502 503 // www.foo.com should match. 504 PasswordForm form2 = GetFormWithNewSignonRealm(form, "http://www.foo.com/"); 505 EXPECT_TRUE(db_.GetLogins(form2, &result)); 506 EXPECT_EQ(1U, result.size()); 507 delete result[0]; 508 result.clear(); 509 510 // a.b.foo.com should match. 511 form2 = GetFormWithNewSignonRealm(form, "http://a.b.foo.com/"); 512 EXPECT_TRUE(db_.GetLogins(form2, &result)); 513 EXPECT_EQ(1U, result.size()); 514 delete result[0]; 515 result.clear(); 516 517 // a-b.foo.com should match. 518 form2 = GetFormWithNewSignonRealm(form, "http://a-b.foo.com/"); 519 EXPECT_TRUE(db_.GetLogins(form2, &result)); 520 EXPECT_EQ(1U, result.size()); 521 delete result[0]; 522 result.clear(); 523 524 // foo-bar.com should match. 525 form2 = GetFormWithNewSignonRealm(form, "http://foo-bar.com/"); 526 EXPECT_TRUE(db_.GetLogins(form2, &result)); 527 EXPECT_EQ(1U, result.size()); 528 delete result[0]; 529 result.clear(); 530 531 // www.foo-bar.com should match. 532 form2 = GetFormWithNewSignonRealm(form, "http://www.foo-bar.com/"); 533 EXPECT_TRUE(db_.GetLogins(form2, &result)); 534 EXPECT_EQ(1U, result.size()); 535 delete result[0]; 536 result.clear(); 537 538 // a.b.foo-bar.com should match. 539 form2 = GetFormWithNewSignonRealm(form, "http://a.b.foo-bar.com/"); 540 EXPECT_TRUE(db_.GetLogins(form2, &result)); 541 EXPECT_EQ(1U, result.size()); 542 delete result[0]; 543 result.clear(); 544 545 // a-b.foo-bar.com should match. 546 form2 = GetFormWithNewSignonRealm(form, "http://a-b.foo-bar.com/"); 547 EXPECT_TRUE(db_.GetLogins(form2, &result)); 548 EXPECT_EQ(1U, result.size()); 549 delete result[0]; 550 result.clear(); 551 552 // foo.com with port 1337 should not match. 553 form2 = GetFormWithNewSignonRealm(form, "http://foo.com:1337/"); 554 EXPECT_TRUE(db_.GetLogins(form2, &result)); 555 EXPECT_EQ(0U, result.size()); 556 557 // http://foo.com should not match since the scheme is wrong. 558 form2 = GetFormWithNewSignonRealm(form, "https://foo.com/"); 559 EXPECT_TRUE(db_.GetLogins(form2, &result)); 560 EXPECT_EQ(0U, result.size()); 561 562 // notfoo.com should not match. 563 form2 = GetFormWithNewSignonRealm(form, "http://notfoo.com/"); 564 EXPECT_TRUE(db_.GetLogins(form2, &result)); 565 EXPECT_EQ(0U, result.size()); 566 567 // baz.com should not match. 568 form2 = GetFormWithNewSignonRealm(form, "http://baz.com/"); 569 EXPECT_TRUE(db_.GetLogins(form2, &result)); 570 EXPECT_EQ(0U, result.size()); 571 572 // foo-baz.com should not match. 573 form2 = GetFormWithNewSignonRealm(form, "http://foo-baz.com/"); 574 EXPECT_TRUE(db_.GetLogins(form2, &result)); 575 EXPECT_EQ(0U, result.size()); 576} 577 578static bool AddTimestampedLogin(LoginDatabase* db, std::string url, 579 const std::string& unique_string, 580 const base::Time& time) { 581 // Example password form. 582 PasswordForm form; 583 form.origin = GURL(url + std::string("/LoginAuth")); 584 form.username_element = ASCIIToUTF16(unique_string); 585 form.username_value = ASCIIToUTF16(unique_string); 586 form.password_element = ASCIIToUTF16(unique_string); 587 form.submit_element = ASCIIToUTF16("signIn"); 588 form.signon_realm = url; 589 form.date_created = time; 590 return db->AddLogin(form) == AddChangeForForm(form); 591} 592 593static void ClearResults(std::vector<PasswordForm*>* results) { 594 for (size_t i = 0; i < results->size(); ++i) { 595 delete (*results)[i]; 596 } 597 results->clear(); 598} 599 600TEST_F(LoginDatabaseTest, ClearPrivateData_SavedPasswords) { 601 std::vector<PasswordForm*> result; 602 603 // Verify the database is empty. 604 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 605 EXPECT_EQ(0U, result.size()); 606 607 base::Time now = base::Time::Now(); 608 base::TimeDelta one_day = base::TimeDelta::FromDays(1); 609 610 // Create one with a 0 time. 611 EXPECT_TRUE(AddTimestampedLogin(&db_, "1", "foo1", base::Time())); 612 // Create one for now and +/- 1 day. 613 EXPECT_TRUE(AddTimestampedLogin(&db_, "2", "foo2", now - one_day)); 614 EXPECT_TRUE(AddTimestampedLogin(&db_, "3", "foo3", now)); 615 EXPECT_TRUE(AddTimestampedLogin(&db_, "4", "foo4", now + one_day)); 616 617 // Verify inserts worked. 618 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 619 EXPECT_EQ(4U, result.size()); 620 ClearResults(&result); 621 622 // Get everything from today's date and on. 623 EXPECT_TRUE(db_.GetLoginsCreatedBetween(now, base::Time(), &result)); 624 EXPECT_EQ(2U, result.size()); 625 ClearResults(&result); 626 627 // Delete everything from today's date and on. 628 db_.RemoveLoginsCreatedBetween(now, base::Time()); 629 630 // Should have deleted half of what we inserted. 631 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 632 EXPECT_EQ(2U, result.size()); 633 ClearResults(&result); 634 635 // Delete with 0 date (should delete all). 636 db_.RemoveLoginsCreatedBetween(base::Time(), base::Time()); 637 638 // Verify nothing is left. 639 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 640 EXPECT_EQ(0U, result.size()); 641} 642 643TEST_F(LoginDatabaseTest, BlacklistedLogins) { 644 std::vector<PasswordForm*> result; 645 646 // Verify the database is empty. 647 EXPECT_TRUE(db_.GetBlacklistLogins(&result)); 648 ASSERT_EQ(0U, result.size()); 649 650 // Save a form as blacklisted. 651 PasswordForm form; 652 form.origin = GURL("http://accounts.google.com/LoginAuth"); 653 form.action = GURL("http://accounts.google.com/Login"); 654 form.username_element = ASCIIToUTF16("Email"); 655 form.password_element = ASCIIToUTF16("Passwd"); 656 form.submit_element = ASCIIToUTF16("signIn"); 657 form.signon_realm = "http://www.google.com/"; 658 form.ssl_valid = false; 659 form.preferred = true; 660 form.blacklisted_by_user = true; 661 form.scheme = PasswordForm::SCHEME_HTML; 662 EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form)); 663 664 // Get all non-blacklisted logins (should be none). 665 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 666 ASSERT_EQ(0U, result.size()); 667 668 // GetLogins should give the blacklisted result. 669 EXPECT_TRUE(db_.GetLogins(form, &result)); 670 EXPECT_EQ(1U, result.size()); 671 ClearResults(&result); 672 673 // So should GetAllBlacklistedLogins. 674 EXPECT_TRUE(db_.GetBlacklistLogins(&result)); 675 EXPECT_EQ(1U, result.size()); 676 ClearResults(&result); 677} 678 679TEST_F(LoginDatabaseTest, VectorSerialization) { 680 // Empty vector. 681 std::vector<base::string16> vec; 682 Pickle temp = SerializeVector(vec); 683 std::vector<base::string16> output = DeserializeVector(temp); 684 EXPECT_THAT(output, Eq(vec)); 685 686 // Normal data. 687 vec.push_back(ASCIIToUTF16("first")); 688 vec.push_back(ASCIIToUTF16("second")); 689 vec.push_back(ASCIIToUTF16("third")); 690 691 temp = SerializeVector(vec); 692 output = DeserializeVector(temp); 693 EXPECT_THAT(output, Eq(vec)); 694} 695 696TEST_F(LoginDatabaseTest, UpdateIncompleteCredentials) { 697 std::vector<autofill::PasswordForm*> result; 698 // Verify the database is empty. 699 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 700 ASSERT_EQ(0U, result.size()); 701 702 // Save an incomplete form. Note that it only has a few fields set, ex. it's 703 // missing 'action', 'username_element' and 'password_element'. Such forms 704 // are sometimes inserted during import from other browsers (which may not 705 // store this info). 706 PasswordForm incomplete_form; 707 incomplete_form.origin = GURL("http://accounts.google.com/LoginAuth"); 708 incomplete_form.signon_realm = "http://accounts.google.com/"; 709 incomplete_form.username_value = ASCIIToUTF16("my_username"); 710 incomplete_form.password_value = ASCIIToUTF16("my_password"); 711 incomplete_form.ssl_valid = false; 712 incomplete_form.preferred = true; 713 incomplete_form.blacklisted_by_user = false; 714 incomplete_form.scheme = PasswordForm::SCHEME_HTML; 715 EXPECT_EQ(AddChangeForForm(incomplete_form), db_.AddLogin(incomplete_form)); 716 717 // A form on some website. It should trigger a match with the stored one. 718 PasswordForm encountered_form; 719 encountered_form.origin = GURL("http://accounts.google.com/LoginAuth"); 720 encountered_form.signon_realm = "http://accounts.google.com/"; 721 encountered_form.action = GURL("http://accounts.google.com/Login"); 722 encountered_form.username_element = ASCIIToUTF16("Email"); 723 encountered_form.password_element = ASCIIToUTF16("Passwd"); 724 encountered_form.submit_element = ASCIIToUTF16("signIn"); 725 726 // Get matches for encountered_form. 727 EXPECT_TRUE(db_.GetLogins(encountered_form, &result)); 728 ASSERT_EQ(1U, result.size()); 729 EXPECT_EQ(incomplete_form.origin, result[0]->origin); 730 EXPECT_EQ(incomplete_form.signon_realm, result[0]->signon_realm); 731 EXPECT_EQ(incomplete_form.username_value, result[0]->username_value); 732#if defined(OS_MACOSX) && !defined(OS_IOS) 733 // On Mac, passwords are not stored in login database, instead they're in 734 // the keychain. 735 EXPECT_TRUE(result[0]->password_value.empty()); 736#else 737 EXPECT_EQ(incomplete_form.password_value, result[0]->password_value); 738#endif // OS_MACOSX && !OS_IOS 739 EXPECT_TRUE(result[0]->preferred); 740 EXPECT_FALSE(result[0]->ssl_valid); 741 742 // We should return empty 'action', 'username_element', 'password_element' 743 // and 'submit_element' as we can't be sure if the credentials were entered 744 // in this particular form on the page. 745 EXPECT_EQ(GURL(), result[0]->action); 746 EXPECT_TRUE(result[0]->username_element.empty()); 747 EXPECT_TRUE(result[0]->password_element.empty()); 748 EXPECT_TRUE(result[0]->submit_element.empty()); 749 ClearResults(&result); 750 751 // Let's say this login form worked. Now update the stored credentials with 752 // 'action', 'username_element', 'password_element' and 'submit_element' from 753 // the encountered form. 754 PasswordForm completed_form(incomplete_form); 755 completed_form.action = encountered_form.action; 756 completed_form.username_element = encountered_form.username_element; 757 completed_form.password_element = encountered_form.password_element; 758 completed_form.submit_element = encountered_form.submit_element; 759 EXPECT_EQ(AddChangeForForm(completed_form), db_.AddLogin(completed_form)); 760 EXPECT_TRUE(db_.RemoveLogin(incomplete_form)); 761 762 // Get matches for encountered_form again. 763 EXPECT_TRUE(db_.GetLogins(encountered_form, &result)); 764 ASSERT_EQ(1U, result.size()); 765 766 // This time we should have all the info available. 767 PasswordForm expected_form(completed_form); 768#if defined(OS_MACOSX) && !defined(OS_IOS) 769 expected_form.password_value.clear(); 770#endif // OS_MACOSX && !OS_IOS 771 EXPECT_EQ(expected_form, *result[0]); 772 ClearResults(&result); 773} 774 775TEST_F(LoginDatabaseTest, UpdateOverlappingCredentials) { 776 // Save an incomplete form. Note that it only has a few fields set, ex. it's 777 // missing 'action', 'username_element' and 'password_element'. Such forms 778 // are sometimes inserted during import from other browsers (which may not 779 // store this info). 780 PasswordForm incomplete_form; 781 incomplete_form.origin = GURL("http://accounts.google.com/LoginAuth"); 782 incomplete_form.signon_realm = "http://accounts.google.com/"; 783 incomplete_form.username_value = ASCIIToUTF16("my_username"); 784 incomplete_form.password_value = ASCIIToUTF16("my_password"); 785 incomplete_form.ssl_valid = false; 786 incomplete_form.preferred = true; 787 incomplete_form.blacklisted_by_user = false; 788 incomplete_form.scheme = PasswordForm::SCHEME_HTML; 789 EXPECT_EQ(AddChangeForForm(incomplete_form), db_.AddLogin(incomplete_form)); 790 791 // Save a complete version of the previous form. Both forms could exist if 792 // the user created the complete version before importing the incomplete 793 // version from a different browser. 794 PasswordForm complete_form = incomplete_form; 795 complete_form.action = GURL("http://accounts.google.com/Login"); 796 complete_form.username_element = ASCIIToUTF16("username_element"); 797 complete_form.password_element = ASCIIToUTF16("password_element"); 798 complete_form.submit_element = ASCIIToUTF16("submit"); 799 800 // An update fails because the primary key for |complete_form| is different. 801 EXPECT_EQ(PasswordStoreChangeList(), db_.UpdateLogin(complete_form)); 802 EXPECT_EQ(AddChangeForForm(complete_form), db_.AddLogin(complete_form)); 803 804 // Make sure both passwords exist. 805 ScopedVector<autofill::PasswordForm> result; 806 EXPECT_TRUE(db_.GetAutofillableLogins(&result.get())); 807 ASSERT_EQ(2U, result.size()); 808 result.clear(); 809 810 // Simulate the user changing their password. 811 complete_form.password_value = ASCIIToUTF16("new_password"); 812 EXPECT_EQ(UpdateChangeForForm(complete_form), db_.UpdateLogin(complete_form)); 813 814 // Both still exist now. 815 EXPECT_TRUE(db_.GetAutofillableLogins(&result.get())); 816 ASSERT_EQ(2U, result.size()); 817 818#if defined(OS_MACOSX) && !defined(OS_IOS) 819 // On Mac, passwords are not stored in login database, instead they're in 820 // the keychain. 821 complete_form.password_value.clear(); 822 incomplete_form.password_value.clear(); 823#endif // OS_MACOSX && !OS_IOS 824 if (result[0]->username_element.empty()) 825 std::swap(result[0], result[1]); 826 EXPECT_EQ(complete_form, *result[0]); 827 EXPECT_EQ(incomplete_form, *result[1]); 828} 829 830TEST_F(LoginDatabaseTest, DoubleAdd) { 831 PasswordForm form; 832 form.origin = GURL("http://accounts.google.com/LoginAuth"); 833 form.signon_realm = "http://accounts.google.com/"; 834 form.username_value = ASCIIToUTF16("my_username"); 835 form.password_value = ASCIIToUTF16("my_password"); 836 form.ssl_valid = false; 837 form.preferred = true; 838 form.blacklisted_by_user = false; 839 form.scheme = PasswordForm::SCHEME_HTML; 840 EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form)); 841 842 // Add almost the same form again. 843 form.times_used++; 844 PasswordStoreChangeList list; 845 list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form)); 846 list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form)); 847 EXPECT_EQ(list, db_.AddLogin(form)); 848} 849 850#if defined(OS_POSIX) 851// Only the current user has permission to read the database. 852// 853// Only POSIX because GetPosixFilePermissions() only exists on POSIX. 854// This tests that sql::Connection::set_restrict_to_user() was called, 855// and that function is a noop on non-POSIX platforms in any case. 856TEST_F(LoginDatabaseTest, FilePermissions) { 857 int mode = base::FILE_PERMISSION_MASK; 858 EXPECT_TRUE(base::GetPosixFilePermissions(file_, &mode)); 859 EXPECT_EQ((mode & base::FILE_PERMISSION_USER_MASK), mode); 860} 861#endif // defined(OS_POSIX) 862 863} // namespace password_manager 864