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/files/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 20 using autofill::PasswordForm; 21 using base::ASCIIToUTF16; 22 using ::testing::Eq; 23 24 namespace password_manager { 25 namespace { 26 PasswordStoreChangeList AddChangeForForm(const PasswordForm& form) { 27 return PasswordStoreChangeList(1, 28 PasswordStoreChange(PasswordStoreChange::ADD, 29 form)); 30 } 31 32 PasswordStoreChangeList 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. 40 Pickle SerializeVector(const std::vector<base::string16>& vec); 41 std::vector<base::string16> DeserializeVector(const Pickle& pickle); 42 43 class 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 (at) 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 (at) 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 115 TEST_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 (at) 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.date_synced = base::Time::Now(); 138 form.display_name = ASCIIToUTF16("Mr. Smith"); 139 form.avatar_url = GURL("https://accounts.google.com/Avatar"); 140 form.federation_url = GURL("https://accounts.google.com/federation"); 141 form.is_zero_click = true; 142 143 // Add it and make sure it is there and that all the fields were retrieved 144 // correctly. 145 EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form)); 146 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 147 ASSERT_EQ(1U, result.size()); 148 FormsAreEqual(form, *result[0]); 149 delete result[0]; 150 result.clear(); 151 152 // Match against an exact copy. 153 EXPECT_TRUE(db_.GetLogins(form, &result)); 154 ASSERT_EQ(1U, result.size()); 155 FormsAreEqual(form, *result[0]); 156 delete result[0]; 157 result.clear(); 158 159 // The example site changes... 160 PasswordForm form2(form); 161 form2.origin = GURL("http://www.google.com/new/accounts/LoginAuth"); 162 form2.submit_element = ASCIIToUTF16("reallySignIn"); 163 164 // Match against an inexact copy 165 EXPECT_TRUE(db_.GetLogins(form2, &result)); 166 EXPECT_EQ(1U, result.size()); 167 delete result[0]; 168 result.clear(); 169 170 // Uh oh, the site changed origin & action URLs all at once! 171 PasswordForm form3(form2); 172 form3.action = GURL("http://www.google.com/new/accounts/Login"); 173 174 // signon_realm is the same, should match. 175 EXPECT_TRUE(db_.GetLogins(form3, &result)); 176 EXPECT_EQ(1U, result.size()); 177 delete result[0]; 178 result.clear(); 179 180 // Imagine the site moves to a secure server for login. 181 PasswordForm form4(form3); 182 form4.signon_realm = "https://www.google.com/"; 183 form4.ssl_valid = true; 184 185 // We have only an http record, so no match for this. 186 EXPECT_TRUE(db_.GetLogins(form4, &result)); 187 EXPECT_EQ(0U, result.size()); 188 189 // Let's imagine the user logs into the secure site. 190 EXPECT_EQ(AddChangeForForm(form4), db_.AddLogin(form4)); 191 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 192 EXPECT_EQ(2U, result.size()); 193 delete result[0]; 194 delete result[1]; 195 result.clear(); 196 197 // Now the match works 198 EXPECT_TRUE(db_.GetLogins(form4, &result)); 199 EXPECT_EQ(1U, result.size()); 200 delete result[0]; 201 result.clear(); 202 203 // The user chose to forget the original but not the new. 204 EXPECT_TRUE(db_.RemoveLogin(form)); 205 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 206 EXPECT_EQ(1U, result.size()); 207 delete result[0]; 208 result.clear(); 209 210 // The old form wont match the new site (http vs https). 211 EXPECT_TRUE(db_.GetLogins(form, &result)); 212 EXPECT_EQ(0U, result.size()); 213 214 // The user's request for the HTTPS site is intercepted 215 // by an attacker who presents an invalid SSL cert. 216 PasswordForm form5(form4); 217 form5.ssl_valid = 0; 218 219 // It will match in this case. 220 EXPECT_TRUE(db_.GetLogins(form5, &result)); 221 EXPECT_EQ(1U, result.size()); 222 delete result[0]; 223 result.clear(); 224 225 // User changes his password. 226 PasswordForm form6(form5); 227 form6.password_value = ASCIIToUTF16("test6"); 228 form6.preferred = true; 229 230 // We update, and check to make sure it matches the 231 // old form, and there is only one record. 232 EXPECT_EQ(UpdateChangeForForm(form6), db_.UpdateLogin(form6)); 233 // matches 234 EXPECT_TRUE(db_.GetLogins(form5, &result)); 235 EXPECT_EQ(1U, result.size()); 236 delete result[0]; 237 result.clear(); 238 // Only one record. 239 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 240 EXPECT_EQ(1U, result.size()); 241 // Password element was updated. 242 #if defined(OS_MACOSX) && !defined(OS_IOS) 243 // On the Mac we should never be storing passwords in the database. 244 EXPECT_EQ(base::string16(), result[0]->password_value); 245 #else 246 EXPECT_EQ(form6.password_value, result[0]->password_value); 247 #endif 248 // Preferred login. 249 EXPECT_TRUE(form6.preferred); 250 delete result[0]; 251 result.clear(); 252 253 // Make sure everything can disappear. 254 EXPECT_TRUE(db_.RemoveLogin(form4)); 255 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 256 EXPECT_EQ(0U, result.size()); 257 } 258 259 TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatching) { 260 std::vector<PasswordForm*> result; 261 262 // Verify the database is empty. 263 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 264 EXPECT_EQ(0U, result.size()); 265 266 // Example password form. 267 PasswordForm form; 268 form.origin = GURL("https://foo.com/"); 269 form.action = GURL("https://foo.com/login"); 270 form.username_element = ASCIIToUTF16("username"); 271 form.username_value = ASCIIToUTF16("test (at) gmail.com"); 272 form.password_element = ASCIIToUTF16("password"); 273 form.password_value = ASCIIToUTF16("test"); 274 form.submit_element = ASCIIToUTF16(""); 275 form.signon_realm = "https://foo.com/"; 276 form.ssl_valid = true; 277 form.preferred = false; 278 form.scheme = PasswordForm::SCHEME_HTML; 279 280 // Add it and make sure it is there. 281 EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form)); 282 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 283 EXPECT_EQ(1U, result.size()); 284 delete result[0]; 285 result.clear(); 286 287 // Match against an exact copy. 288 EXPECT_TRUE(db_.GetLogins(form, &result)); 289 EXPECT_EQ(1U, result.size()); 290 delete result[0]; 291 result.clear(); 292 293 // We go to the mobile site. 294 PasswordForm form2(form); 295 form2.origin = GURL("https://mobile.foo.com/"); 296 form2.action = GURL("https://mobile.foo.com/login"); 297 form2.signon_realm = "https://mobile.foo.com/"; 298 299 // Match against the mobile site. 300 EXPECT_TRUE(db_.GetLogins(form2, &result)); 301 EXPECT_EQ(1U, result.size()); 302 EXPECT_EQ("https://mobile.foo.com/", result[0]->signon_realm); 303 EXPECT_EQ("https://foo.com/", result[0]->original_signon_realm); 304 delete result[0]; 305 result.clear(); 306 } 307 308 TEST_F(LoginDatabaseTest, TestPublicSuffixDisabledForNonHTMLForms) { 309 TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_BASIC); 310 TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_DIGEST); 311 TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_OTHER); 312 } 313 314 TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingShouldMatchingApply) { 315 std::vector<PasswordForm*> result; 316 317 // Verify the database is empty. 318 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 319 EXPECT_EQ(0U, result.size()); 320 321 // Example password form. 322 PasswordForm form; 323 form.origin = GURL("https://accounts.google.com/"); 324 form.action = GURL("https://accounts.google.com/login"); 325 form.username_element = ASCIIToUTF16("username"); 326 form.username_value = ASCIIToUTF16("test (at) gmail.com"); 327 form.password_element = ASCIIToUTF16("password"); 328 form.password_value = ASCIIToUTF16("test"); 329 form.submit_element = ASCIIToUTF16(""); 330 form.signon_realm = "https://accounts.google.com/"; 331 form.ssl_valid = true; 332 form.preferred = false; 333 form.scheme = PasswordForm::SCHEME_HTML; 334 335 // Add it and make sure it is there. 336 EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form)); 337 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 338 EXPECT_EQ(1U, result.size()); 339 delete result[0]; 340 result.clear(); 341 342 // Match against an exact copy. 343 EXPECT_TRUE(db_.GetLogins(form, &result)); 344 EXPECT_EQ(1U, result.size()); 345 delete result[0]; 346 result.clear(); 347 348 // We go to a different site on the same domain where feature is not needed. 349 PasswordForm form2(form); 350 form2.origin = GURL("https://some.other.google.com/"); 351 form2.action = GURL("https://some.other.google.com/login"); 352 form2.signon_realm = "https://some.other.google.com/"; 353 354 // Match against the other site. Should not match since feature should not be 355 // enabled for this domain. 356 EXPECT_TRUE(db_.GetLogins(form2, &result)); 357 EXPECT_EQ(0U, result.size()); 358 } 359 360 // This test fails if the implementation of GetLogins uses GetCachedStatement 361 // instead of GetUniqueStatement, since REGEXP is in use. See 362 // http://crbug.com/248608. 363 TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingDifferentSites) { 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 (at) 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 (at) 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 447 PasswordForm 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 456 TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingRegexp) { 457 std::vector<PasswordForm*> result; 458 459 // Verify the database is empty. 460 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 461 EXPECT_EQ(0U, result.size()); 462 463 // Example password form. 464 PasswordForm form; 465 form.origin = GURL("http://foo.com/"); 466 form.action = GURL("http://foo.com/login"); 467 form.username_element = ASCIIToUTF16("username"); 468 form.username_value = ASCIIToUTF16("test (at) gmail.com"); 469 form.password_element = ASCIIToUTF16("password"); 470 form.password_value = ASCIIToUTF16("test"); 471 form.submit_element = ASCIIToUTF16(""); 472 form.signon_realm = "http://foo.com/"; 473 form.ssl_valid = false; 474 form.preferred = false; 475 form.scheme = PasswordForm::SCHEME_HTML; 476 477 // Add it and make sure it is there. 478 EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form)); 479 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 480 EXPECT_EQ(1U, result.size()); 481 delete result[0]; 482 result.clear(); 483 484 // Example password form that has - in the domain name. 485 PasswordForm form_dash = 486 GetFormWithNewSignonRealm(form, "http://www.foo-bar.com/"); 487 488 // Add it and make sure it is there. 489 EXPECT_EQ(AddChangeForForm(form_dash), db_.AddLogin(form_dash)); 490 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 491 EXPECT_EQ(2U, result.size()); 492 delete result[0]; 493 delete result[1]; 494 result.clear(); 495 496 // Match against an exact copy. 497 EXPECT_TRUE(db_.GetLogins(form, &result)); 498 EXPECT_EQ(1U, result.size()); 499 delete result[0]; 500 result.clear(); 501 502 // www.foo.com should match. 503 PasswordForm form2 = GetFormWithNewSignonRealm(form, "http://www.foo.com/"); 504 EXPECT_TRUE(db_.GetLogins(form2, &result)); 505 EXPECT_EQ(1U, result.size()); 506 delete result[0]; 507 result.clear(); 508 509 // a.b.foo.com should match. 510 form2 = GetFormWithNewSignonRealm(form, "http://a.b.foo.com/"); 511 EXPECT_TRUE(db_.GetLogins(form2, &result)); 512 EXPECT_EQ(1U, result.size()); 513 delete result[0]; 514 result.clear(); 515 516 // a-b.foo.com should match. 517 form2 = GetFormWithNewSignonRealm(form, "http://a-b.foo.com/"); 518 EXPECT_TRUE(db_.GetLogins(form2, &result)); 519 EXPECT_EQ(1U, result.size()); 520 delete result[0]; 521 result.clear(); 522 523 // foo-bar.com should match. 524 form2 = GetFormWithNewSignonRealm(form, "http://foo-bar.com/"); 525 EXPECT_TRUE(db_.GetLogins(form2, &result)); 526 EXPECT_EQ(1U, result.size()); 527 delete result[0]; 528 result.clear(); 529 530 // www.foo-bar.com should match. 531 form2 = GetFormWithNewSignonRealm(form, "http://www.foo-bar.com/"); 532 EXPECT_TRUE(db_.GetLogins(form2, &result)); 533 EXPECT_EQ(1U, result.size()); 534 delete result[0]; 535 result.clear(); 536 537 // a.b.foo-bar.com should match. 538 form2 = GetFormWithNewSignonRealm(form, "http://a.b.foo-bar.com/"); 539 EXPECT_TRUE(db_.GetLogins(form2, &result)); 540 EXPECT_EQ(1U, result.size()); 541 delete result[0]; 542 result.clear(); 543 544 // a-b.foo-bar.com should match. 545 form2 = GetFormWithNewSignonRealm(form, "http://a-b.foo-bar.com/"); 546 EXPECT_TRUE(db_.GetLogins(form2, &result)); 547 EXPECT_EQ(1U, result.size()); 548 delete result[0]; 549 result.clear(); 550 551 // foo.com with port 1337 should not match. 552 form2 = GetFormWithNewSignonRealm(form, "http://foo.com:1337/"); 553 EXPECT_TRUE(db_.GetLogins(form2, &result)); 554 EXPECT_EQ(0U, result.size()); 555 556 // http://foo.com should not match since the scheme is wrong. 557 form2 = GetFormWithNewSignonRealm(form, "https://foo.com/"); 558 EXPECT_TRUE(db_.GetLogins(form2, &result)); 559 EXPECT_EQ(0U, result.size()); 560 561 // notfoo.com should not match. 562 form2 = GetFormWithNewSignonRealm(form, "http://notfoo.com/"); 563 EXPECT_TRUE(db_.GetLogins(form2, &result)); 564 EXPECT_EQ(0U, result.size()); 565 566 // baz.com should not match. 567 form2 = GetFormWithNewSignonRealm(form, "http://baz.com/"); 568 EXPECT_TRUE(db_.GetLogins(form2, &result)); 569 EXPECT_EQ(0U, result.size()); 570 571 // foo-baz.com should not match. 572 form2 = GetFormWithNewSignonRealm(form, "http://foo-baz.com/"); 573 EXPECT_TRUE(db_.GetLogins(form2, &result)); 574 EXPECT_EQ(0U, result.size()); 575 } 576 577 static bool AddTimestampedLogin(LoginDatabase* db, 578 std::string url, 579 const std::string& unique_string, 580 const base::Time& time, 581 bool date_is_creation) { 582 // Example password form. 583 PasswordForm form; 584 form.origin = GURL(url + std::string("/LoginAuth")); 585 form.username_element = ASCIIToUTF16(unique_string); 586 form.username_value = ASCIIToUTF16(unique_string); 587 form.password_element = ASCIIToUTF16(unique_string); 588 form.submit_element = ASCIIToUTF16("signIn"); 589 form.signon_realm = url; 590 form.display_name = ASCIIToUTF16(unique_string); 591 form.avatar_url = GURL("https://accounts.google.com/Avatar"); 592 form.federation_url = GURL("https://accounts.google.com/federation"); 593 form.is_zero_click = true; 594 595 if (date_is_creation) 596 form.date_created = time; 597 else 598 form.date_synced = time; 599 return db->AddLogin(form) == AddChangeForForm(form); 600 } 601 602 static void ClearResults(std::vector<PasswordForm*>* results) { 603 for (size_t i = 0; i < results->size(); ++i) { 604 delete (*results)[i]; 605 } 606 results->clear(); 607 } 608 609 TEST_F(LoginDatabaseTest, ClearPrivateData_SavedPasswords) { 610 std::vector<PasswordForm*> result; 611 612 // Verify the database is empty. 613 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 614 EXPECT_EQ(0U, result.size()); 615 616 base::Time now = base::Time::Now(); 617 base::TimeDelta one_day = base::TimeDelta::FromDays(1); 618 619 // Create one with a 0 time. 620 EXPECT_TRUE(AddTimestampedLogin(&db_, "1", "foo1", base::Time(), true)); 621 // Create one for now and +/- 1 day. 622 EXPECT_TRUE(AddTimestampedLogin(&db_, "2", "foo2", now - one_day, true)); 623 EXPECT_TRUE(AddTimestampedLogin(&db_, "3", "foo3", now, true)); 624 EXPECT_TRUE(AddTimestampedLogin(&db_, "4", "foo4", now + one_day, true)); 625 626 // Verify inserts worked. 627 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 628 EXPECT_EQ(4U, result.size()); 629 ClearResults(&result); 630 631 // Get everything from today's date and on. 632 EXPECT_TRUE(db_.GetLoginsCreatedBetween(now, base::Time(), &result)); 633 EXPECT_EQ(2U, result.size()); 634 ClearResults(&result); 635 636 // Delete everything from today's date and on. 637 db_.RemoveLoginsCreatedBetween(now, base::Time()); 638 639 // Should have deleted half of what we inserted. 640 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 641 EXPECT_EQ(2U, result.size()); 642 ClearResults(&result); 643 644 // Delete with 0 date (should delete all). 645 db_.RemoveLoginsCreatedBetween(base::Time(), base::Time()); 646 647 // Verify nothing is left. 648 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 649 EXPECT_EQ(0U, result.size()); 650 } 651 652 TEST_F(LoginDatabaseTest, RemoveLoginsSyncedBetween) { 653 ScopedVector<autofill::PasswordForm> result; 654 655 base::Time now = base::Time::Now(); 656 base::TimeDelta one_day = base::TimeDelta::FromDays(1); 657 658 // Create one with a 0 time. 659 EXPECT_TRUE(AddTimestampedLogin(&db_, "1", "foo1", base::Time(), false)); 660 // Create one for now and +/- 1 day. 661 EXPECT_TRUE(AddTimestampedLogin(&db_, "2", "foo2", now - one_day, false)); 662 EXPECT_TRUE(AddTimestampedLogin(&db_, "3", "foo3", now, false)); 663 EXPECT_TRUE(AddTimestampedLogin(&db_, "4", "foo4", now + one_day, false)); 664 665 // Verify inserts worked. 666 EXPECT_TRUE(db_.GetAutofillableLogins(&result.get())); 667 EXPECT_EQ(4U, result.size()); 668 result.clear(); 669 670 // Get everything from today's date and on. 671 EXPECT_TRUE(db_.GetLoginsSyncedBetween(now, base::Time(), &result.get())); 672 ASSERT_EQ(2U, result.size()); 673 EXPECT_EQ("3", result[0]->signon_realm); 674 EXPECT_EQ("4", result[1]->signon_realm); 675 result.clear(); 676 677 // Delete everything from today's date and on. 678 db_.RemoveLoginsSyncedBetween(now, base::Time()); 679 680 // Should have deleted half of what we inserted. 681 EXPECT_TRUE(db_.GetAutofillableLogins(&result.get())); 682 ASSERT_EQ(2U, result.size()); 683 EXPECT_EQ("1", result[0]->signon_realm); 684 EXPECT_EQ("2", result[1]->signon_realm); 685 result.clear(); 686 687 // Delete with 0 date (should delete all). 688 db_.RemoveLoginsSyncedBetween(base::Time(), now); 689 690 // Verify nothing is left. 691 EXPECT_TRUE(db_.GetAutofillableLogins(&result.get())); 692 EXPECT_EQ(0U, result.size()); 693 } 694 695 TEST_F(LoginDatabaseTest, BlacklistedLogins) { 696 std::vector<PasswordForm*> result; 697 698 // Verify the database is empty. 699 EXPECT_TRUE(db_.GetBlacklistLogins(&result)); 700 ASSERT_EQ(0U, result.size()); 701 702 // Save a form as blacklisted. 703 PasswordForm form; 704 form.origin = GURL("http://accounts.google.com/LoginAuth"); 705 form.action = GURL("http://accounts.google.com/Login"); 706 form.username_element = ASCIIToUTF16("Email"); 707 form.password_element = ASCIIToUTF16("Passwd"); 708 form.submit_element = ASCIIToUTF16("signIn"); 709 form.signon_realm = "http://www.google.com/"; 710 form.ssl_valid = false; 711 form.preferred = true; 712 form.blacklisted_by_user = true; 713 form.scheme = PasswordForm::SCHEME_HTML; 714 form.date_synced = base::Time::Now(); 715 form.display_name = ASCIIToUTF16("Mr. Smith"); 716 form.avatar_url = GURL("https://accounts.google.com/Avatar"); 717 form.federation_url = GURL("https://accounts.google.com/federation"); 718 form.is_zero_click = true; 719 EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form)); 720 721 // Get all non-blacklisted logins (should be none). 722 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 723 ASSERT_EQ(0U, result.size()); 724 725 // GetLogins should give the blacklisted result. 726 EXPECT_TRUE(db_.GetLogins(form, &result)); 727 ASSERT_EQ(1U, result.size()); 728 FormsAreEqual(form, *result[0]); 729 ClearResults(&result); 730 731 // So should GetAllBlacklistedLogins. 732 EXPECT_TRUE(db_.GetBlacklistLogins(&result)); 733 ASSERT_EQ(1U, result.size()); 734 FormsAreEqual(form, *result[0]); 735 ClearResults(&result); 736 } 737 738 TEST_F(LoginDatabaseTest, VectorSerialization) { 739 // Empty vector. 740 std::vector<base::string16> vec; 741 Pickle temp = SerializeVector(vec); 742 std::vector<base::string16> output = DeserializeVector(temp); 743 EXPECT_THAT(output, Eq(vec)); 744 745 // Normal data. 746 vec.push_back(ASCIIToUTF16("first")); 747 vec.push_back(ASCIIToUTF16("second")); 748 vec.push_back(ASCIIToUTF16("third")); 749 750 temp = SerializeVector(vec); 751 output = DeserializeVector(temp); 752 EXPECT_THAT(output, Eq(vec)); 753 } 754 755 TEST_F(LoginDatabaseTest, UpdateIncompleteCredentials) { 756 std::vector<autofill::PasswordForm*> result; 757 // Verify the database is empty. 758 EXPECT_TRUE(db_.GetAutofillableLogins(&result)); 759 ASSERT_EQ(0U, result.size()); 760 761 // Save an incomplete form. Note that it only has a few fields set, ex. it's 762 // missing 'action', 'username_element' and 'password_element'. Such forms 763 // are sometimes inserted during import from other browsers (which may not 764 // store this info). 765 PasswordForm incomplete_form; 766 incomplete_form.origin = GURL("http://accounts.google.com/LoginAuth"); 767 incomplete_form.signon_realm = "http://accounts.google.com/"; 768 incomplete_form.username_value = ASCIIToUTF16("my_username"); 769 incomplete_form.password_value = ASCIIToUTF16("my_password"); 770 incomplete_form.ssl_valid = false; 771 incomplete_form.preferred = true; 772 incomplete_form.blacklisted_by_user = false; 773 incomplete_form.scheme = PasswordForm::SCHEME_HTML; 774 EXPECT_EQ(AddChangeForForm(incomplete_form), db_.AddLogin(incomplete_form)); 775 776 // A form on some website. It should trigger a match with the stored one. 777 PasswordForm encountered_form; 778 encountered_form.origin = GURL("http://accounts.google.com/LoginAuth"); 779 encountered_form.signon_realm = "http://accounts.google.com/"; 780 encountered_form.action = GURL("http://accounts.google.com/Login"); 781 encountered_form.username_element = ASCIIToUTF16("Email"); 782 encountered_form.password_element = ASCIIToUTF16("Passwd"); 783 encountered_form.submit_element = ASCIIToUTF16("signIn"); 784 785 // Get matches for encountered_form. 786 EXPECT_TRUE(db_.GetLogins(encountered_form, &result)); 787 ASSERT_EQ(1U, result.size()); 788 EXPECT_EQ(incomplete_form.origin, result[0]->origin); 789 EXPECT_EQ(incomplete_form.signon_realm, result[0]->signon_realm); 790 EXPECT_EQ(incomplete_form.username_value, result[0]->username_value); 791 #if defined(OS_MACOSX) && !defined(OS_IOS) 792 // On Mac, passwords are not stored in login database, instead they're in 793 // the keychain. 794 EXPECT_TRUE(result[0]->password_value.empty()); 795 #else 796 EXPECT_EQ(incomplete_form.password_value, result[0]->password_value); 797 #endif // OS_MACOSX && !OS_IOS 798 EXPECT_TRUE(result[0]->preferred); 799 EXPECT_FALSE(result[0]->ssl_valid); 800 801 // We should return empty 'action', 'username_element', 'password_element' 802 // and 'submit_element' as we can't be sure if the credentials were entered 803 // in this particular form on the page. 804 EXPECT_EQ(GURL(), result[0]->action); 805 EXPECT_TRUE(result[0]->username_element.empty()); 806 EXPECT_TRUE(result[0]->password_element.empty()); 807 EXPECT_TRUE(result[0]->submit_element.empty()); 808 ClearResults(&result); 809 810 // Let's say this login form worked. Now update the stored credentials with 811 // 'action', 'username_element', 'password_element' and 'submit_element' from 812 // the encountered form. 813 PasswordForm completed_form(incomplete_form); 814 completed_form.action = encountered_form.action; 815 completed_form.username_element = encountered_form.username_element; 816 completed_form.password_element = encountered_form.password_element; 817 completed_form.submit_element = encountered_form.submit_element; 818 EXPECT_EQ(AddChangeForForm(completed_form), db_.AddLogin(completed_form)); 819 EXPECT_TRUE(db_.RemoveLogin(incomplete_form)); 820 821 // Get matches for encountered_form again. 822 EXPECT_TRUE(db_.GetLogins(encountered_form, &result)); 823 ASSERT_EQ(1U, result.size()); 824 825 // This time we should have all the info available. 826 PasswordForm expected_form(completed_form); 827 #if defined(OS_MACOSX) && !defined(OS_IOS) 828 expected_form.password_value.clear(); 829 #endif // OS_MACOSX && !OS_IOS 830 EXPECT_EQ(expected_form, *result[0]); 831 ClearResults(&result); 832 } 833 834 TEST_F(LoginDatabaseTest, UpdateOverlappingCredentials) { 835 // Save an incomplete form. Note that it only has a few fields set, ex. it's 836 // missing 'action', 'username_element' and 'password_element'. Such forms 837 // are sometimes inserted during import from other browsers (which may not 838 // store this info). 839 PasswordForm incomplete_form; 840 incomplete_form.origin = GURL("http://accounts.google.com/LoginAuth"); 841 incomplete_form.signon_realm = "http://accounts.google.com/"; 842 incomplete_form.username_value = ASCIIToUTF16("my_username"); 843 incomplete_form.password_value = ASCIIToUTF16("my_password"); 844 incomplete_form.ssl_valid = false; 845 incomplete_form.preferred = true; 846 incomplete_form.blacklisted_by_user = false; 847 incomplete_form.scheme = PasswordForm::SCHEME_HTML; 848 EXPECT_EQ(AddChangeForForm(incomplete_form), db_.AddLogin(incomplete_form)); 849 850 // Save a complete version of the previous form. Both forms could exist if 851 // the user created the complete version before importing the incomplete 852 // version from a different browser. 853 PasswordForm complete_form = incomplete_form; 854 complete_form.action = GURL("http://accounts.google.com/Login"); 855 complete_form.username_element = ASCIIToUTF16("username_element"); 856 complete_form.password_element = ASCIIToUTF16("password_element"); 857 complete_form.submit_element = ASCIIToUTF16("submit"); 858 859 // An update fails because the primary key for |complete_form| is different. 860 EXPECT_EQ(PasswordStoreChangeList(), db_.UpdateLogin(complete_form)); 861 EXPECT_EQ(AddChangeForForm(complete_form), db_.AddLogin(complete_form)); 862 863 // Make sure both passwords exist. 864 ScopedVector<autofill::PasswordForm> result; 865 EXPECT_TRUE(db_.GetAutofillableLogins(&result.get())); 866 ASSERT_EQ(2U, result.size()); 867 result.clear(); 868 869 // Simulate the user changing their password. 870 complete_form.password_value = ASCIIToUTF16("new_password"); 871 complete_form.date_synced = base::Time::Now(); 872 EXPECT_EQ(UpdateChangeForForm(complete_form), db_.UpdateLogin(complete_form)); 873 874 // Both still exist now. 875 EXPECT_TRUE(db_.GetAutofillableLogins(&result.get())); 876 ASSERT_EQ(2U, result.size()); 877 878 #if defined(OS_MACOSX) && !defined(OS_IOS) 879 // On Mac, passwords are not stored in login database, instead they're in 880 // the keychain. 881 complete_form.password_value.clear(); 882 incomplete_form.password_value.clear(); 883 #endif // OS_MACOSX && !OS_IOS 884 if (result[0]->username_element.empty()) 885 std::swap(result[0], result[1]); 886 EXPECT_EQ(complete_form, *result[0]); 887 EXPECT_EQ(incomplete_form, *result[1]); 888 } 889 890 TEST_F(LoginDatabaseTest, DoubleAdd) { 891 PasswordForm form; 892 form.origin = GURL("http://accounts.google.com/LoginAuth"); 893 form.signon_realm = "http://accounts.google.com/"; 894 form.username_value = ASCIIToUTF16("my_username"); 895 form.password_value = ASCIIToUTF16("my_password"); 896 form.ssl_valid = false; 897 form.preferred = true; 898 form.blacklisted_by_user = false; 899 form.scheme = PasswordForm::SCHEME_HTML; 900 EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form)); 901 902 // Add almost the same form again. 903 form.times_used++; 904 PasswordStoreChangeList list; 905 list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form)); 906 list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form)); 907 EXPECT_EQ(list, db_.AddLogin(form)); 908 } 909 910 TEST_F(LoginDatabaseTest, UpdateLogin) { 911 PasswordForm form; 912 form.origin = GURL("http://accounts.google.com/LoginAuth"); 913 form.signon_realm = "http://accounts.google.com/"; 914 form.username_value = ASCIIToUTF16("my_username"); 915 form.password_value = ASCIIToUTF16("my_password"); 916 form.ssl_valid = false; 917 form.preferred = true; 918 form.blacklisted_by_user = false; 919 form.scheme = PasswordForm::SCHEME_HTML; 920 EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form)); 921 922 form.action = GURL("http://accounts.google.com/login"); 923 form.password_value = ASCIIToUTF16("my_new_password"); 924 form.ssl_valid = true; 925 form.preferred = false; 926 form.other_possible_usernames.push_back(ASCIIToUTF16("my_new_username")); 927 form.times_used = 20; 928 form.submit_element = ASCIIToUTF16("submit_element"); 929 form.date_synced = base::Time::Now(); 930 form.date_created = base::Time::Now() - base::TimeDelta::FromDays(1); 931 // Remove this line after crbug/374132 is fixed. 932 form.date_created = base::Time::FromTimeT(form.date_created.ToTimeT()); 933 form.blacklisted_by_user = true; 934 form.scheme = PasswordForm::SCHEME_BASIC; 935 form.type = PasswordForm::TYPE_GENERATED; 936 form.display_name = ASCIIToUTF16("Mr. Smith"); 937 form.avatar_url = GURL("https://accounts.google.com/Avatar"); 938 form.federation_url = GURL("https://accounts.google.com/federation"); 939 form.is_zero_click = true; 940 EXPECT_EQ(UpdateChangeForForm(form), db_.UpdateLogin(form)); 941 942 ScopedVector<autofill::PasswordForm> result; 943 EXPECT_TRUE(db_.GetLogins(form, &result.get())); 944 ASSERT_EQ(1U, result.size()); 945 #if defined(OS_MACOSX) && !defined(OS_IOS) 946 // On Mac, passwords are not stored in login database, instead they're in 947 // the keychain. 948 form.password_value.clear(); 949 #endif // OS_MACOSX && !OS_IOS 950 EXPECT_EQ(form, *result[0]); 951 } 952 953 #if defined(OS_POSIX) 954 // Only the current user has permission to read the database. 955 // 956 // Only POSIX because GetPosixFilePermissions() only exists on POSIX. 957 // This tests that sql::Connection::set_restrict_to_user() was called, 958 // and that function is a noop on non-POSIX platforms in any case. 959 TEST_F(LoginDatabaseTest, FilePermissions) { 960 int mode = base::FILE_PERMISSION_MASK; 961 EXPECT_TRUE(base::GetPosixFilePermissions(file_, &mode)); 962 EXPECT_EQ((mode & base::FILE_PERMISSION_USER_MASK), mode); 963 } 964 #endif // defined(OS_POSIX) 965 966 } // namespace password_manager 967