| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "testing/gmock/include/gmock/gmock.h" |
| 5 #include "testing/gtest/include/gtest/gtest.h" | 6 #include "testing/gtest/include/gtest/gtest.h" |
| 6 | 7 |
| 7 #include "base/basictypes.h" | 8 #include "base/basictypes.h" |
| 9 #include "base/file_util.h" |
| 10 #include "base/path_service.h" |
| 11 #include "base/scoped_temp_dir.h" |
| 8 #include "base/stl_util-inl.h" | 12 #include "base/stl_util-inl.h" |
| 9 #include "base/string_util.h" | 13 #include "base/string_util.h" |
| 10 #include "base/utf_string_conversions.h" | 14 #include "base/utf_string_conversions.h" |
| 15 #include "chrome/browser/chrome_thread.h" |
| 11 #include "chrome/browser/keychain_mock_mac.h" | 16 #include "chrome/browser/keychain_mock_mac.h" |
| 12 #include "chrome/browser/password_manager/password_store_mac.h" | 17 #include "chrome/browser/password_manager/password_store_mac.h" |
| 13 #include "chrome/browser/password_manager/password_store_mac_internal.h" | 18 #include "chrome/browser/password_manager/password_store_mac_internal.h" |
| 19 #include "chrome/common/chrome_paths.h" |
| 14 | 20 |
| 15 using webkit_glue::PasswordForm; | 21 using webkit_glue::PasswordForm; |
| 22 using testing::_; |
| 23 using testing::DoAll; |
| 24 using testing::WithArg; |
| 16 | 25 |
| 17 class PasswordStoreMacTest : public testing::Test { | 26 namespace { |
| 27 |
| 28 class MockPasswordStoreConsumer : public PasswordStoreConsumer { |
| 29 public: |
| 30 MOCK_METHOD2(OnPasswordStoreRequestDone, |
| 31 void(int, const std::vector<webkit_glue::PasswordForm*>&)); |
| 32 }; |
| 33 |
| 34 ACTION(STLDeleteElements0) { |
| 35 STLDeleteContainerPointers(arg0.begin(), arg0.end()); |
| 36 } |
| 37 |
| 38 ACTION(QuitUIMessageLoop) { |
| 39 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 40 MessageLoop::current()->Quit(); |
| 41 } |
| 42 |
| 43 } // namespace |
| 44 |
| 45 #pragma mark - |
| 46 |
| 47 class PasswordStoreMacInternalsTest : public testing::Test { |
| 18 public: | 48 public: |
| 19 virtual void SetUp() { | 49 virtual void SetUp() { |
| 20 MockKeychain::KeychainTestData test_data[] = { | 50 MockKeychain::KeychainTestData test_data[] = { |
| 21 // Basic HTML form. | 51 // Basic HTML form. |
| 22 { kSecAuthenticationTypeHTMLForm, "some.domain.com", | 52 { kSecAuthenticationTypeHTMLForm, "some.domain.com", |
| 23 kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z", | 53 kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z", |
| 24 "joe_user", "sekrit", false }, | 54 "joe_user", "sekrit", false }, |
| 25 // HTML form with path. | 55 // HTML form with path. |
| 26 { kSecAuthenticationTypeHTMLForm, "some.domain.com", | 56 { kSecAuthenticationTypeHTMLForm, "some.domain.com", |
| 27 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "19991231235959Z", | 57 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "19991231235959Z", |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 } | 216 } |
| 187 EXPECT_EQ(expectation->preferred, form->preferred) << test_label; | 217 EXPECT_EQ(expectation->preferred, form->preferred) << test_label; |
| 188 EXPECT_EQ(expectation->ssl_valid, form->ssl_valid) << test_label; | 218 EXPECT_EQ(expectation->ssl_valid, form->ssl_valid) << test_label; |
| 189 EXPECT_DOUBLE_EQ(expectation->creation_time, | 219 EXPECT_DOUBLE_EQ(expectation->creation_time, |
| 190 form->date_created.ToDoubleT()) << test_label; | 220 form->date_created.ToDoubleT()) << test_label; |
| 191 } | 221 } |
| 192 } | 222 } |
| 193 | 223 |
| 194 #pragma mark - | 224 #pragma mark - |
| 195 | 225 |
| 196 TEST_F(PasswordStoreMacTest, TestKeychainToFormTranslation) { | 226 TEST_F(PasswordStoreMacInternalsTest, TestKeychainToFormTranslation) { |
| 197 typedef struct { | 227 typedef struct { |
| 198 const PasswordForm::Scheme scheme; | 228 const PasswordForm::Scheme scheme; |
| 199 const char* signon_realm; | 229 const char* signon_realm; |
| 200 const char* origin; | 230 const char* origin; |
| 201 const wchar_t* username; // Set to NULL to check for a blacklist entry. | 231 const wchar_t* username; // Set to NULL to check for a blacklist entry. |
| 202 const wchar_t* password; | 232 const wchar_t* password; |
| 203 const bool ssl_valid; | 233 const bool ssl_valid; |
| 204 const int creation_year; | 234 const int creation_year; |
| 205 const int creation_month; | 235 const int creation_month; |
| 206 const int creation_day; | 236 const int creation_day; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 { | 314 { |
| 285 // Use an invalid ref, to make sure errors are reported. | 315 // Use an invalid ref, to make sure errors are reported. |
| 286 SecKeychainItemRef keychain_item = reinterpret_cast<SecKeychainItemRef>(99); | 316 SecKeychainItemRef keychain_item = reinterpret_cast<SecKeychainItemRef>(99); |
| 287 PasswordForm form; | 317 PasswordForm form; |
| 288 bool parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem( | 318 bool parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem( |
| 289 *keychain_, keychain_item, &form); | 319 *keychain_, keychain_item, &form); |
| 290 EXPECT_FALSE(parsed); | 320 EXPECT_FALSE(parsed); |
| 291 } | 321 } |
| 292 } | 322 } |
| 293 | 323 |
| 294 TEST_F(PasswordStoreMacTest, TestKeychainSearch) { | 324 TEST_F(PasswordStoreMacInternalsTest, TestKeychainSearch) { |
| 295 struct TestDataAndExpectation { | 325 struct TestDataAndExpectation { |
| 296 const PasswordFormData data; | 326 const PasswordFormData data; |
| 297 const size_t expected_fill_matches; | 327 const size_t expected_fill_matches; |
| 298 const size_t expected_merge_matches; | 328 const size_t expected_merge_matches; |
| 299 }; | 329 }; |
| 300 // Most fields are left blank because we don't care about them for searching. | 330 // Most fields are left blank because we don't care about them for searching. |
| 301 TestDataAndExpectation test_data[] = { | 331 TestDataAndExpectation test_data[] = { |
| 302 // An HTML form we've seen. | 332 // An HTML form we've seen. |
| 303 { { PasswordForm::SCHEME_HTML, "http://some.domain.com/", | 333 { { PasswordForm::SCHEME_HTML, "http://some.domain.com/", |
| 304 NULL, NULL, NULL, NULL, NULL, L"joe_user", NULL, false, false, 0 }, | 334 NULL, NULL, NULL, NULL, NULL, L"joe_user", NULL, false, false, 0 }, |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) { | 375 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) { |
| 346 scoped_ptr<PasswordForm> query_form( | 376 scoped_ptr<PasswordForm> query_form( |
| 347 CreatePasswordFormFromData(test_data[i].data)); | 377 CreatePasswordFormFromData(test_data[i].data)); |
| 348 | 378 |
| 349 // Check matches treating the form as a fill target. | 379 // Check matches treating the form as a fill target. |
| 350 std::vector<PasswordForm*> matching_items = | 380 std::vector<PasswordForm*> matching_items = |
| 351 keychain_adapter.PasswordsFillingForm(*query_form); | 381 keychain_adapter.PasswordsFillingForm(*query_form); |
| 352 EXPECT_EQ(test_data[i].expected_fill_matches, matching_items.size()); | 382 EXPECT_EQ(test_data[i].expected_fill_matches, matching_items.size()); |
| 353 STLDeleteElements(&matching_items); | 383 STLDeleteElements(&matching_items); |
| 354 | 384 |
| 355 // Check matches teating the form as a merging target. | 385 // Check matches treating the form as a merging target. |
| 386 EXPECT_EQ(test_data[i].expected_merge_matches > 0, |
| 387 keychain_adapter.HasPasswordsMergeableWithForm(*query_form)); |
| 356 matching_items = keychain_adapter.PasswordsMergeableWithForm(*query_form); | 388 matching_items = keychain_adapter.PasswordsMergeableWithForm(*query_form); |
| 357 EXPECT_EQ(test_data[i].expected_merge_matches, matching_items.size()); | 389 EXPECT_EQ(test_data[i].expected_merge_matches, matching_items.size()); |
| 358 STLDeleteElements(&matching_items); | 390 STLDeleteElements(&matching_items); |
| 359 | 391 |
| 360 // None of the pre-seeded items are owned by us, so none should match an | 392 // None of the pre-seeded items are owned by us, so none should match an |
| 361 // owned-passwords-only search. | 393 // owned-passwords-only search. |
| 362 matching_items = owned_keychain_adapter.PasswordsFillingForm(*query_form); | 394 matching_items = owned_keychain_adapter.PasswordsFillingForm(*query_form); |
| 363 EXPECT_EQ(0U, matching_items.size()); | 395 EXPECT_EQ(0U, matching_items.size()); |
| 364 STLDeleteElements(&matching_items); | 396 STLDeleteElements(&matching_items); |
| 365 } | 397 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 384 | 416 |
| 385 // Changes just the signon_ream auth realm of |form|. | 417 // Changes just the signon_ream auth realm of |form|. |
| 386 static void SetPasswordFormRealm(PasswordForm* form, const char* realm) { | 418 static void SetPasswordFormRealm(PasswordForm* form, const char* realm) { |
| 387 GURL::Replacements replacement; | 419 GURL::Replacements replacement; |
| 388 std::string new_value(realm); | 420 std::string new_value(realm); |
| 389 replacement.SetPathStr(new_value); | 421 replacement.SetPathStr(new_value); |
| 390 GURL signon_gurl = GURL(form->signon_realm); | 422 GURL signon_gurl = GURL(form->signon_realm); |
| 391 form->signon_realm = signon_gurl.ReplaceComponents(replacement).spec(); | 423 form->signon_realm = signon_gurl.ReplaceComponents(replacement).spec(); |
| 392 } | 424 } |
| 393 | 425 |
| 394 TEST_F(PasswordStoreMacTest, TestKeychainExactSearch) { | 426 TEST_F(PasswordStoreMacInternalsTest, TestKeychainExactSearch) { |
| 395 MacKeychainPasswordFormAdapter keychain_adapter(keychain_); | 427 MacKeychainPasswordFormAdapter keychain_adapter(keychain_); |
| 396 | 428 |
| 397 PasswordFormData base_form_data[] = { | 429 PasswordFormData base_form_data[] = { |
| 398 { PasswordForm::SCHEME_HTML, "http://some.domain.com/", | 430 { PasswordForm::SCHEME_HTML, "http://some.domain.com/", |
| 399 "http://some.domain.com/insecure.html", | 431 "http://some.domain.com/insecure.html", |
| 400 NULL, NULL, NULL, NULL, L"joe_user", NULL, true, false, 0 }, | 432 NULL, NULL, NULL, NULL, L"joe_user", NULL, true, false, 0 }, |
| 401 { PasswordForm::SCHEME_BASIC, "http://some.domain.com:4567/low_security", | 433 { PasswordForm::SCHEME_BASIC, "http://some.domain.com:4567/low_security", |
| 402 "http://some.domain.com:4567/insecure.html", | 434 "http://some.domain.com:4567/insecure.html", |
| 403 NULL, NULL, NULL, NULL, L"basic_auth_user", NULL, true, false, 0 }, | 435 NULL, NULL, NULL, NULL, L"basic_auth_user", NULL, true, false, 0 }, |
| 404 { PasswordForm::SCHEME_DIGEST, "https://some.domain.com/high_security", | 436 { PasswordForm::SCHEME_DIGEST, "https://some.domain.com/high_security", |
| 405 "https://some.domain.com", | 437 "https://some.domain.com", |
| 406 NULL, NULL, NULL, NULL, L"digest_auth_user", NULL, true, true, 0 }, | 438 NULL, NULL, NULL, NULL, L"digest_auth_user", NULL, true, true, 0 }, |
| 407 }; | 439 }; |
| 408 | 440 |
| 409 for (unsigned int i = 0; i < arraysize(base_form_data); ++i) { | 441 for (unsigned int i = 0; i < arraysize(base_form_data); ++i) { |
| 410 // Create a base form and make sure we find a match. | 442 // Create a base form and make sure we find a match. |
| 411 scoped_ptr<PasswordForm> base_form(CreatePasswordFormFromData( | 443 scoped_ptr<PasswordForm> base_form(CreatePasswordFormFromData( |
| 412 base_form_data[i])); | 444 base_form_data[i])); |
| 445 EXPECT_TRUE(keychain_adapter.HasPasswordsMergeableWithForm(*base_form)); |
| 413 PasswordForm* match = | 446 PasswordForm* match = |
| 414 keychain_adapter.PasswordExactlyMatchingForm(*base_form); | 447 keychain_adapter.PasswordExactlyMatchingForm(*base_form); |
| 415 EXPECT_TRUE(match != NULL); | 448 EXPECT_TRUE(match != NULL); |
| 416 if (match) { | 449 if (match) { |
| 417 EXPECT_EQ(base_form->scheme, match->scheme); | 450 EXPECT_EQ(base_form->scheme, match->scheme); |
| 418 EXPECT_EQ(base_form->origin, match->origin); | 451 EXPECT_EQ(base_form->origin, match->origin); |
| 419 EXPECT_EQ(base_form->username_value, match->username_value); | 452 EXPECT_EQ(base_form->username_value, match->username_value); |
| 420 delete match; | 453 delete match; |
| 421 } | 454 } |
| 422 | 455 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 448 for (unsigned int j = 0; j < modified_forms.size(); ++j) { | 481 for (unsigned int j = 0; j < modified_forms.size(); ++j) { |
| 449 PasswordForm* match = | 482 PasswordForm* match = |
| 450 keychain_adapter.PasswordExactlyMatchingForm(*modified_forms[j]); | 483 keychain_adapter.PasswordExactlyMatchingForm(*modified_forms[j]); |
| 451 EXPECT_EQ(NULL, match) << "In modified version " << j << " of base form " | 484 EXPECT_EQ(NULL, match) << "In modified version " << j << " of base form " |
| 452 << i; | 485 << i; |
| 453 } | 486 } |
| 454 STLDeleteElements(&modified_forms); | 487 STLDeleteElements(&modified_forms); |
| 455 } | 488 } |
| 456 } | 489 } |
| 457 | 490 |
| 458 TEST_F(PasswordStoreMacTest, TestKeychainAdd) { | 491 TEST_F(PasswordStoreMacInternalsTest, TestKeychainAdd) { |
| 459 struct TestDataAndExpectation { | 492 struct TestDataAndExpectation { |
| 460 PasswordFormData data; | 493 PasswordFormData data; |
| 461 bool should_succeed; | 494 bool should_succeed; |
| 462 }; | 495 }; |
| 463 TestDataAndExpectation test_data[] = { | 496 TestDataAndExpectation test_data[] = { |
| 464 // Test a variety of scheme/port/protocol/path variations. | 497 // Test a variety of scheme/port/protocol/path variations. |
| 465 { { PasswordForm::SCHEME_HTML, "http://web.site.com/", | 498 { { PasswordForm::SCHEME_HTML, "http://web.site.com/", |
| 466 "http://web.site.com/path/to/page.html", NULL, NULL, NULL, NULL, | 499 "http://web.site.com/path/to/page.html", NULL, NULL, NULL, NULL, |
| 467 L"anonymous", L"knock-knock", false, false, 0 }, true }, | 500 L"anonymous", L"knock-knock", false, false, 0 }, true }, |
| 468 { { PasswordForm::SCHEME_HTML, "https://web.site.com/", | 501 { { PasswordForm::SCHEME_HTML, "https://web.site.com/", |
| (...skipping 18 matching lines...) Expand all Loading... |
| 487 | 520 |
| 488 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_); | 521 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_); |
| 489 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); | 522 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); |
| 490 | 523 |
| 491 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) { | 524 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) { |
| 492 scoped_ptr<PasswordForm> in_form( | 525 scoped_ptr<PasswordForm> in_form( |
| 493 CreatePasswordFormFromData(test_data[i].data)); | 526 CreatePasswordFormFromData(test_data[i].data)); |
| 494 bool add_succeeded = owned_keychain_adapter.AddPassword(*in_form); | 527 bool add_succeeded = owned_keychain_adapter.AddPassword(*in_form); |
| 495 EXPECT_EQ(test_data[i].should_succeed, add_succeeded); | 528 EXPECT_EQ(test_data[i].should_succeed, add_succeeded); |
| 496 if (add_succeeded) { | 529 if (add_succeeded) { |
| 530 EXPECT_TRUE(owned_keychain_adapter.HasPasswordsMergeableWithForm( |
| 531 *in_form)); |
| 497 scoped_ptr<PasswordForm> out_form( | 532 scoped_ptr<PasswordForm> out_form( |
| 498 owned_keychain_adapter.PasswordExactlyMatchingForm(*in_form)); | 533 owned_keychain_adapter.PasswordExactlyMatchingForm(*in_form)); |
| 499 EXPECT_TRUE(out_form.get() != NULL); | 534 EXPECT_TRUE(out_form.get() != NULL); |
| 500 EXPECT_EQ(out_form->scheme, in_form->scheme); | 535 EXPECT_EQ(out_form->scheme, in_form->scheme); |
| 501 EXPECT_EQ(out_form->signon_realm, in_form->signon_realm); | 536 EXPECT_EQ(out_form->signon_realm, in_form->signon_realm); |
| 502 EXPECT_EQ(out_form->origin, in_form->origin); | 537 EXPECT_EQ(out_form->origin, in_form->origin); |
| 503 EXPECT_EQ(out_form->username_value, in_form->username_value); | 538 EXPECT_EQ(out_form->username_value, in_form->username_value); |
| 504 EXPECT_EQ(out_form->password_value, in_form->password_value); | 539 EXPECT_EQ(out_form->password_value, in_form->password_value); |
| 505 } | 540 } |
| 506 } | 541 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 517 EXPECT_TRUE(keychain_adapter.AddPassword(*update_form)); | 552 EXPECT_TRUE(keychain_adapter.AddPassword(*update_form)); |
| 518 SecKeychainItemRef keychain_item = reinterpret_cast<SecKeychainItemRef>(2); | 553 SecKeychainItemRef keychain_item = reinterpret_cast<SecKeychainItemRef>(2); |
| 519 PasswordForm stored_form; | 554 PasswordForm stored_form; |
| 520 internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_, | 555 internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_, |
| 521 keychain_item, | 556 keychain_item, |
| 522 &stored_form); | 557 &stored_form); |
| 523 EXPECT_EQ(update_form->password_value, stored_form.password_value); | 558 EXPECT_EQ(update_form->password_value, stored_form.password_value); |
| 524 } | 559 } |
| 525 } | 560 } |
| 526 | 561 |
| 527 TEST_F(PasswordStoreMacTest, TestKeychainRemove) { | 562 TEST_F(PasswordStoreMacInternalsTest, TestKeychainRemove) { |
| 528 struct TestDataAndExpectation { | 563 struct TestDataAndExpectation { |
| 529 PasswordFormData data; | 564 PasswordFormData data; |
| 530 bool should_succeed; | 565 bool should_succeed; |
| 531 }; | 566 }; |
| 532 TestDataAndExpectation test_data[] = { | 567 TestDataAndExpectation test_data[] = { |
| 533 // Test deletion of an item that we add. | 568 // Test deletion of an item that we add. |
| 534 { { PasswordForm::SCHEME_HTML, "http://web.site.com/", | 569 { { PasswordForm::SCHEME_HTML, "http://web.site.com/", |
| 535 "http://web.site.com/path/to/page.html", NULL, NULL, NULL, NULL, | 570 "http://web.site.com/path/to/page.html", NULL, NULL, NULL, NULL, |
| 536 L"anonymous", L"knock-knock", false, false, 0 }, true }, | 571 L"anonymous", L"knock-knock", false, false, 0 }, true }, |
| 537 // Make sure we don't delete items we don't own. | 572 // Make sure we don't delete items we don't own. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 556 | 591 |
| 557 MacKeychainPasswordFormAdapter keychain_adapter(keychain_); | 592 MacKeychainPasswordFormAdapter keychain_adapter(keychain_); |
| 558 PasswordForm* match = keychain_adapter.PasswordExactlyMatchingForm(*form); | 593 PasswordForm* match = keychain_adapter.PasswordExactlyMatchingForm(*form); |
| 559 EXPECT_EQ(test_data[i].should_succeed, match == NULL); | 594 EXPECT_EQ(test_data[i].should_succeed, match == NULL); |
| 560 if (match) { | 595 if (match) { |
| 561 delete match; | 596 delete match; |
| 562 } | 597 } |
| 563 } | 598 } |
| 564 } | 599 } |
| 565 | 600 |
| 566 TEST_F(PasswordStoreMacTest, TestFormMatch) { | 601 TEST_F(PasswordStoreMacInternalsTest, TestFormMatch) { |
| 567 PasswordForm base_form; | 602 PasswordForm base_form; |
| 568 base_form.signon_realm = std::string("http://some.domain.com/"); | 603 base_form.signon_realm = std::string("http://some.domain.com/"); |
| 569 base_form.origin = GURL("http://some.domain.com/page.html"); | 604 base_form.origin = GURL("http://some.domain.com/page.html"); |
| 570 base_form.username_value = ASCIIToUTF16("joe_user"); | 605 base_form.username_value = ASCIIToUTF16("joe_user"); |
| 571 | 606 |
| 572 { | 607 { |
| 573 // Check that everything unimportant can be changed. | 608 // Check that everything unimportant can be changed. |
| 574 PasswordForm different_form(base_form); | 609 PasswordForm different_form(base_form); |
| 575 different_form.username_element = ASCIIToUTF16("username"); | 610 different_form.username_element = ASCIIToUTF16("username"); |
| 576 different_form.submit_element = ASCIIToUTF16("submit"); | 611 different_form.submit_element = ASCIIToUTF16("submit"); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 618 // Blacklist forms should *never* match for merging, even when identical | 653 // Blacklist forms should *never* match for merging, even when identical |
| 619 // (and certainly not when only one is a blacklist entry). | 654 // (and certainly not when only one is a blacklist entry). |
| 620 { | 655 { |
| 621 PasswordForm form_a(base_form); | 656 PasswordForm form_a(base_form); |
| 622 form_a.blacklisted_by_user = true; | 657 form_a.blacklisted_by_user = true; |
| 623 PasswordForm form_b(form_a); | 658 PasswordForm form_b(form_a); |
| 624 EXPECT_FALSE(internal_keychain_helpers::FormsMatchForMerge(form_a, form_b)); | 659 EXPECT_FALSE(internal_keychain_helpers::FormsMatchForMerge(form_a, form_b)); |
| 625 } | 660 } |
| 626 } | 661 } |
| 627 | 662 |
| 628 TEST_F(PasswordStoreMacTest, TestFormMerge) { | 663 TEST_F(PasswordStoreMacInternalsTest, TestFormMerge) { |
| 629 // Set up a bunch of test data to use in varying combinations. | 664 // Set up a bunch of test data to use in varying combinations. |
| 630 PasswordFormData keychain_user_1 = | 665 PasswordFormData keychain_user_1 = |
| 631 { PasswordForm::SCHEME_HTML, "http://some.domain.com/", | 666 { PasswordForm::SCHEME_HTML, "http://some.domain.com/", |
| 632 "http://some.domain.com/", "", L"", L"", L"", L"joe_user", L"sekrit", | 667 "http://some.domain.com/", "", L"", L"", L"", L"joe_user", L"sekrit", |
| 633 false, false, 1010101010 }; | 668 false, false, 1010101010 }; |
| 634 PasswordFormData keychain_user_1_with_path = | 669 PasswordFormData keychain_user_1_with_path = |
| 635 { PasswordForm::SCHEME_HTML, "http://some.domain.com/", | 670 { PasswordForm::SCHEME_HTML, "http://some.domain.com/", |
| 636 "http://some.domain.com/page.html", | 671 "http://some.domain.com/page.html", |
| 637 "", L"", L"", L"", L"joe_user", L"otherpassword", | 672 "", L"", L"", L"", L"joe_user", L"otherpassword", |
| 638 false, false, 1010101010 }; | 673 false, false, 1010101010 }; |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 773 CHECK_FORMS(database_forms, test_data[DATABASE_OUTPUT][test_case], | 808 CHECK_FORMS(database_forms, test_data[DATABASE_OUTPUT][test_case], |
| 774 test_case); | 809 test_case); |
| 775 CHECK_FORMS(merged_forms, test_data[MERGE_OUTPUT][test_case], test_case); | 810 CHECK_FORMS(merged_forms, test_data[MERGE_OUTPUT][test_case], test_case); |
| 776 | 811 |
| 777 STLDeleteElements(&keychain_forms); | 812 STLDeleteElements(&keychain_forms); |
| 778 STLDeleteElements(&database_forms); | 813 STLDeleteElements(&database_forms); |
| 779 STLDeleteElements(&merged_forms); | 814 STLDeleteElements(&merged_forms); |
| 780 } | 815 } |
| 781 } | 816 } |
| 782 | 817 |
| 783 TEST_F(PasswordStoreMacTest, TestPasswordBulkLookup) { | 818 TEST_F(PasswordStoreMacInternalsTest, TestPasswordBulkLookup) { |
| 784 PasswordFormData db_data[] = { | 819 PasswordFormData db_data[] = { |
| 785 { PasswordForm::SCHEME_HTML, "http://some.domain.com/", | 820 { PasswordForm::SCHEME_HTML, "http://some.domain.com/", |
| 786 "http://some.domain.com/", "http://some.domain.com/action.cgi", | 821 "http://some.domain.com/", "http://some.domain.com/action.cgi", |
| 787 L"submit", L"username", L"password", L"joe_user", L"", | 822 L"submit", L"username", L"password", L"joe_user", L"", |
| 788 true, false, 1212121212 }, | 823 true, false, 1212121212 }, |
| 789 { PasswordForm::SCHEME_HTML, "http://some.domain.com/", | 824 { PasswordForm::SCHEME_HTML, "http://some.domain.com/", |
| 790 "http://some.domain.com/page.html", | 825 "http://some.domain.com/page.html", |
| 791 "http://some.domain.com/handlepage.cgi", | 826 "http://some.domain.com/handlepage.cgi", |
| 792 L"submit", L"username", L"password", L"joe_user", L"", | 827 L"submit", L"username", L"password", L"joe_user", L"", |
| 793 true, false, 1234567890 }, | 828 true, false, 1234567890 }, |
| (...skipping 22 matching lines...) Expand all Loading... |
| 816 EXPECT_EQ(2U, database_forms.size()); | 851 EXPECT_EQ(2U, database_forms.size()); |
| 817 ASSERT_EQ(3U, merged_forms.size()); | 852 ASSERT_EQ(3U, merged_forms.size()); |
| 818 EXPECT_EQ(ASCIIToUTF16("sekrit"), merged_forms[0]->password_value); | 853 EXPECT_EQ(ASCIIToUTF16("sekrit"), merged_forms[0]->password_value); |
| 819 EXPECT_EQ(ASCIIToUTF16("sekrit"), merged_forms[1]->password_value); | 854 EXPECT_EQ(ASCIIToUTF16("sekrit"), merged_forms[1]->password_value); |
| 820 EXPECT_EQ(true, merged_forms[2]->blacklisted_by_user); | 855 EXPECT_EQ(true, merged_forms[2]->blacklisted_by_user); |
| 821 | 856 |
| 822 STLDeleteElements(&database_forms); | 857 STLDeleteElements(&database_forms); |
| 823 STLDeleteElements(&merged_forms); | 858 STLDeleteElements(&merged_forms); |
| 824 } | 859 } |
| 825 | 860 |
| 826 TEST_F(PasswordStoreMacTest, TestPasswordGetAll) { | 861 TEST_F(PasswordStoreMacInternalsTest, TestPasswordGetAll) { |
| 827 MacKeychainPasswordFormAdapter keychain_adapter(keychain_); | 862 MacKeychainPasswordFormAdapter keychain_adapter(keychain_); |
| 828 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_); | 863 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_); |
| 829 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); | 864 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); |
| 830 | 865 |
| 831 // Add a few passwords of various types so that we own some. | 866 // Add a few passwords of various types so that we own some. |
| 832 PasswordFormData owned_password_data[] = { | 867 PasswordFormData owned_password_data[] = { |
| 833 { PasswordForm::SCHEME_HTML, "http://web.site.com/", | 868 { PasswordForm::SCHEME_HTML, "http://web.site.com/", |
| 834 "http://web.site.com/path/to/page.html", NULL, NULL, NULL, NULL, | 869 "http://web.site.com/path/to/page.html", NULL, NULL, NULL, NULL, |
| 835 L"anonymous", L"knock-knock", false, false, 0 }, | 870 L"anonymous", L"knock-knock", false, false, 0 }, |
| 836 { PasswordForm::SCHEME_BASIC, "http://a.site.com:2222/therealm", | 871 { PasswordForm::SCHEME_BASIC, "http://a.site.com:2222/therealm", |
| (...skipping 12 matching lines...) Expand all Loading... |
| 849 std::vector<PasswordForm*> all_passwords = | 884 std::vector<PasswordForm*> all_passwords = |
| 850 keychain_adapter.GetAllPasswordFormPasswords(); | 885 keychain_adapter.GetAllPasswordFormPasswords(); |
| 851 EXPECT_EQ(8 + arraysize(owned_password_data), all_passwords.size()); | 886 EXPECT_EQ(8 + arraysize(owned_password_data), all_passwords.size()); |
| 852 STLDeleteElements(&all_passwords); | 887 STLDeleteElements(&all_passwords); |
| 853 | 888 |
| 854 std::vector<PasswordForm*> owned_passwords = | 889 std::vector<PasswordForm*> owned_passwords = |
| 855 owned_keychain_adapter.GetAllPasswordFormPasswords(); | 890 owned_keychain_adapter.GetAllPasswordFormPasswords(); |
| 856 EXPECT_EQ(arraysize(owned_password_data), owned_passwords.size()); | 891 EXPECT_EQ(arraysize(owned_password_data), owned_passwords.size()); |
| 857 STLDeleteElements(&owned_passwords); | 892 STLDeleteElements(&owned_passwords); |
| 858 } | 893 } |
| 894 |
| 895 #pragma mark - |
| 896 |
| 897 class PasswordStoreMacTest : public testing::Test { |
| 898 public: |
| 899 PasswordStoreMacTest() : ui_thread_(ChromeThread::UI, &message_loop_) {} |
| 900 |
| 901 virtual void SetUp() { |
| 902 login_db_ = new LoginDatabase(); |
| 903 ASSERT_TRUE(db_dir_.CreateUniqueTempDir()); |
| 904 FilePath db_file = db_dir_.path().AppendASCII("login.db"); |
| 905 ASSERT_TRUE(login_db_->Init(db_file)); |
| 906 |
| 907 keychain_ = new MockKeychain(3); |
| 908 |
| 909 store_ = new PasswordStoreMac(keychain_, login_db_); |
| 910 ASSERT_TRUE(store_->Init()); |
| 911 } |
| 912 |
| 913 virtual void TearDown() { |
| 914 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask); |
| 915 MessageLoop::current()->Run(); |
| 916 } |
| 917 |
| 918 protected: |
| 919 MessageLoopForUI message_loop_; |
| 920 ChromeThread ui_thread_; |
| 921 |
| 922 MockKeychain* keychain_; // Owned by store_. |
| 923 LoginDatabase* login_db_; // Owned by store_. |
| 924 scoped_refptr<PasswordStoreMac> store_; |
| 925 ScopedTempDir db_dir_; |
| 926 }; |
| 927 |
| 928 TEST_F(PasswordStoreMacTest, TestStoreUpdate) { |
| 929 // Insert a password into both the database and the keychain. |
| 930 // This is done manually, rather than through store_->AddLogin, because the |
| 931 // Mock Keychain isn't smart enough to be able to support update generically, |
| 932 // so some.domain.com triggers special handling to test it that make inserting |
| 933 // fail. |
| 934 PasswordFormData joint_data = { |
| 935 PasswordForm::SCHEME_HTML, "http://some.domain.com/", |
| 936 "http://some.domain.com/insecure.html", "login.cgi", |
| 937 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1 |
| 938 }; |
| 939 scoped_ptr<PasswordForm> joint_form(CreatePasswordFormFromData(joint_data)); |
| 940 login_db_->AddLogin(*joint_form); |
| 941 MockKeychain::KeychainTestData joint_keychain_data = { |
| 942 kSecAuthenticationTypeHTMLForm, "some.domain.com", |
| 943 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z", |
| 944 "joe_user", "sekrit", false }; |
| 945 keychain_->AddTestItem(joint_keychain_data); |
| 946 |
| 947 // Insert a password into the keychain only. |
| 948 MockKeychain::KeychainTestData keychain_only_data = { |
| 949 kSecAuthenticationTypeHTMLForm, "keychain.only.com", |
| 950 kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z", |
| 951 "keychain", "only", false |
| 952 }; |
| 953 keychain_->AddTestItem(keychain_only_data); |
| 954 |
| 955 struct UpdateData { |
| 956 PasswordFormData form_data; |
| 957 const char* password; // NULL indicates no entry should be present. |
| 958 }; |
| 959 |
| 960 // Make a series of update calls. |
| 961 UpdateData updates[] = { |
| 962 // Update the keychain+db passwords (the normal password update case). |
| 963 { { PasswordForm::SCHEME_HTML, "http://some.domain.com/", |
| 964 "http://some.domain.com/insecure.html", "login.cgi", |
| 965 L"username", L"password", L"submit", L"joe_user", L"53krit", |
| 966 true, false, 2 }, |
| 967 "53krit", |
| 968 }, |
| 969 // Update the keychain-only password; this simulates the initial use of a |
| 970 // password stored by another browsers. |
| 971 { { PasswordForm::SCHEME_HTML, "http://keychain.only.com/", |
| 972 "http://keychain.only.com/login.html", "login.cgi", |
| 973 L"username", L"password", L"submit", L"keychain", L"only", |
| 974 true, false, 2 }, |
| 975 "only", |
| 976 }, |
| 977 // Update a password that doesn't exist in either location. This tests the |
| 978 // case where a form is filled, then the stored login is removed, then the |
| 979 // form is submitted. |
| 980 { { PasswordForm::SCHEME_HTML, "http://different.com/", |
| 981 "http://different.com/index.html", "login.cgi", |
| 982 L"username", L"password", L"submit", L"abc", L"123", |
| 983 true, false, 2 }, |
| 984 NULL, |
| 985 }, |
| 986 }; |
| 987 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(updates); ++i) { |
| 988 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData( |
| 989 updates[i].form_data)); |
| 990 store_->UpdateLogin(*form); |
| 991 } |
| 992 |
| 993 // Do a store-level query to wait for all the operations above to be done. |
| 994 MockPasswordStoreConsumer consumer; |
| 995 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _)).WillByDefault( |
| 996 QuitUIMessageLoop()); |
| 997 EXPECT_CALL(consumer, OnPasswordStoreRequestDone(_, _)).WillOnce( |
| 998 DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop())); |
| 999 store_->GetLogins(*joint_form, &consumer); |
| 1000 MessageLoop::current()->Run(); |
| 1001 |
| 1002 MacKeychainPasswordFormAdapter keychain_adapter(keychain_); |
| 1003 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(updates); ++i) { |
| 1004 scoped_ptr<PasswordForm> query_form( |
| 1005 CreatePasswordFormFromData(updates[i].form_data)); |
| 1006 |
| 1007 std::vector<PasswordForm*> matching_items = |
| 1008 keychain_adapter.PasswordsFillingForm(*query_form); |
| 1009 if (updates[i].password) { |
| 1010 EXPECT_GT(matching_items.size(), 0U) << "iteration " << i; |
| 1011 if (matching_items.size() >= 1) |
| 1012 EXPECT_EQ(ASCIIToUTF16(updates[i].password), |
| 1013 matching_items[0]->password_value) << "iteration " << i; |
| 1014 } else { |
| 1015 EXPECT_EQ(0U, matching_items.size()) << "iteration " << i; |
| 1016 } |
| 1017 STLDeleteElements(&matching_items); |
| 1018 |
| 1019 login_db_->GetLogins(*query_form, &matching_items); |
| 1020 EXPECT_EQ(updates[i].password ? 1U : 0U, matching_items.size()) |
| 1021 << "iteration " << i; |
| 1022 STLDeleteElements(&matching_items); |
| 1023 } |
| 1024 } |
| OLD | NEW |