| 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/gtest/include/gtest/gtest.h" | 5 #include "testing/gtest/include/gtest/gtest.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/stl_util-inl.h" | 8 #include "base/stl_util-inl.h" |
| 9 #include "chrome/browser/keychain_mock_mac.h" | 9 #include "chrome/browser/keychain_mock_mac.h" |
| 10 #include "chrome/browser/password_manager/password_store_mac.h" | 10 #include "chrome/browser/password_manager/password_store_mac.h" |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 324 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) { | 324 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) { |
| 325 scoped_ptr<PasswordForm> query_form( | 325 scoped_ptr<PasswordForm> query_form( |
| 326 CreatePasswordFormFromData(test_data[i].data)); | 326 CreatePasswordFormFromData(test_data[i].data)); |
| 327 std::vector<PasswordForm*> matching_items = | 327 std::vector<PasswordForm*> matching_items = |
| 328 keychainAdapter.PasswordsMatchingForm(*query_form); | 328 keychainAdapter.PasswordsMatchingForm(*query_form); |
| 329 EXPECT_EQ(test_data[i].expected_matches, matching_items.size()); | 329 EXPECT_EQ(test_data[i].expected_matches, matching_items.size()); |
| 330 STLDeleteElements(&matching_items); | 330 STLDeleteElements(&matching_items); |
| 331 } | 331 } |
| 332 } | 332 } |
| 333 | 333 |
| 334 // Changes just the origin path of |form|. |
| 335 static void SetPasswordFormPath(PasswordForm* form, const char* path) { |
| 336 GURL::Replacements replacement; |
| 337 std::string new_value(path); |
| 338 replacement.SetPathStr(new_value); |
| 339 form->origin = form->origin.ReplaceComponents(replacement); |
| 340 } |
| 341 |
| 342 // Changes just the signon_realm port of |form|. |
| 343 static void SetPasswordFormPort(PasswordForm* form, const char* port) { |
| 344 GURL::Replacements replacement; |
| 345 std::string new_value(port); |
| 346 replacement.SetPortStr(new_value); |
| 347 GURL signon_gurl = GURL(form->signon_realm); |
| 348 form->signon_realm = signon_gurl.ReplaceComponents(replacement).spec(); |
| 349 } |
| 350 |
| 351 // Changes just the signon_ream auth realm of |form|. |
| 352 static void SetPasswordFormRealm(PasswordForm* form, const char* realm) { |
| 353 GURL::Replacements replacement; |
| 354 std::string new_value(realm); |
| 355 replacement.SetPathStr(new_value); |
| 356 GURL signon_gurl = GURL(form->signon_realm); |
| 357 form->signon_realm = signon_gurl.ReplaceComponents(replacement).spec(); |
| 358 } |
| 359 |
| 334 TEST_F(PasswordStoreMacTest, TestKeychainExactSearch) { | 360 TEST_F(PasswordStoreMacTest, TestKeychainExactSearch) { |
| 335 // Test a web form entry (SCHEME_HTML). | 361 MacKeychainPasswordFormAdapter keychainAdapter(keychain_); |
| 336 { | |
| 337 PasswordForm search_form; | |
| 338 search_form.signon_realm = std::string("http://some.domain.com/"); | |
| 339 search_form.origin = GURL("http://some.domain.com/insecure.html"); | |
| 340 search_form.action = GURL("http://some.domain.com/submit.cgi"); | |
| 341 search_form.username_element = std::wstring(L"username"); | |
| 342 search_form.username_value = std::wstring(L"joe_user"); | |
| 343 search_form.password_element = std::wstring(L"password"); | |
| 344 search_form.preferred = true; | |
| 345 SecKeychainItemRef match; | |
| 346 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, | |
| 347 search_form); | |
| 348 EXPECT_EQ(reinterpret_cast<SecKeychainItemRef>(2), match); | |
| 349 keychain_->Free(match); | |
| 350 | 362 |
| 351 // Make sure that the matching isn't looser than it should be. | 363 PasswordFormData base_form_data[] = { |
| 352 PasswordForm wrong_username(search_form); | 364 { PasswordForm::SCHEME_HTML, "http://some.domain.com/", |
| 353 wrong_username.username_value = std::wstring(L"wrong_user"); | 365 "http://some.domain.com/insecure.html", |
| 354 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, | 366 NULL, NULL, NULL, NULL, L"joe_user", NULL, true, false, 0 }, |
| 355 wrong_username); | 367 { PasswordForm::SCHEME_BASIC, "http://some.domain.com:4567/low_security", |
| 356 EXPECT_EQ(NULL, match); | 368 "http://some.domain.com:4567/insecure.html", |
| 369 NULL, NULL, NULL, NULL, L"basic_auth_user", NULL, true, false, 0 }, |
| 370 { PasswordForm::SCHEME_DIGEST, "https://some.domain.com/high_security", |
| 371 "https://some.domain.com", |
| 372 NULL, NULL, NULL, NULL, L"digest_auth_user", NULL, true, true, 0 }, |
| 373 }; |
| 357 | 374 |
| 358 PasswordForm wrong_path(search_form); | 375 for (unsigned int i = 0; i < arraysize(base_form_data); ++i) { |
| 359 wrong_path.origin = GURL("http://some.domain.com/elsewhere.html"); | 376 // Create a base form and make sure we find a match. |
| 360 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, | 377 scoped_ptr<PasswordForm> base_form(CreatePasswordFormFromData( |
| 361 wrong_path); | 378 base_form_data[i])); |
| 362 EXPECT_EQ(NULL, match); | 379 PasswordForm* match = |
| 380 keychainAdapter.PasswordExactlyMatchingForm(*base_form); |
| 381 EXPECT_TRUE(match != NULL); |
| 382 if (match) { |
| 383 EXPECT_EQ(base_form->scheme, match->scheme); |
| 384 EXPECT_EQ(base_form->origin, match->origin); |
| 385 EXPECT_EQ(base_form->username_value, match->username_value); |
| 386 delete match; |
| 387 } |
| 363 | 388 |
| 364 PasswordForm wrong_scheme(search_form); | 389 // Make sure that the matching isn't looser than it should be by checking |
| 365 wrong_scheme.scheme = PasswordForm::SCHEME_BASIC; | 390 // that slightly altered forms don't match. |
| 366 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, | 391 std::vector<PasswordForm*> modified_forms; |
| 367 wrong_scheme); | |
| 368 EXPECT_EQ(NULL, match); | |
| 369 | 392 |
| 370 // With no path, we should match the pathless Keychain entry. | 393 modified_forms.push_back(new PasswordForm(*base_form)); |
| 371 PasswordForm no_path(search_form); | 394 modified_forms.back()->username_value = std::wstring(L"wrong_user"); |
| 372 no_path.origin = GURL("http://some.domain.com/"); | |
| 373 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, | |
| 374 no_path); | |
| 375 EXPECT_EQ(reinterpret_cast<SecKeychainItemRef>(1), match); | |
| 376 keychain_->Free(match); | |
| 377 | 395 |
| 378 // We don't store blacklist entries in the keychain, and we want to ignore | 396 modified_forms.push_back(new PasswordForm(*base_form)); |
| 379 // those stored by other browsers. | 397 SetPasswordFormPath(modified_forms.back(), "elsewhere.html"); |
| 380 PasswordForm blacklist(search_form); | |
| 381 blacklist.blacklisted_by_user = true; | |
| 382 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, | |
| 383 blacklist); | |
| 384 EXPECT_EQ(NULL, match); | |
| 385 } | |
| 386 | 398 |
| 387 // Test an http auth entry (SCHEME_BASIC, but SCHEME_DIGEST works is searched | 399 modified_forms.push_back(new PasswordForm(*base_form)); |
| 388 // the same way, so this gives sufficient coverage of both). | 400 modified_forms.back()->scheme = PasswordForm::SCHEME_OTHER; |
| 389 { | |
| 390 PasswordForm search_form; | |
| 391 search_form.signon_realm = | |
| 392 std::string("http://some.domain.com:4567/low_security"); | |
| 393 search_form.origin = GURL("http://some.domain.com:4567/insecure.html"); | |
| 394 search_form.username_value = std::wstring(L"basic_auth_user"); | |
| 395 search_form.scheme = PasswordForm::SCHEME_BASIC; | |
| 396 SecKeychainItemRef match; | |
| 397 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, | |
| 398 search_form); | |
| 399 EXPECT_EQ(reinterpret_cast<SecKeychainItemRef>(7), match); | |
| 400 keychain_->Free(match); | |
| 401 | 401 |
| 402 // Make sure that the matching isn't looser than it should be. | 402 modified_forms.push_back(new PasswordForm(*base_form)); |
| 403 PasswordForm wrong_username(search_form); | 403 SetPasswordFormPort(modified_forms.back(), "1234"); |
| 404 wrong_username.username_value = std::wstring(L"wrong_user"); | |
| 405 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, | |
| 406 wrong_username); | |
| 407 EXPECT_EQ(NULL, match); | |
| 408 | 404 |
| 409 PasswordForm wrong_path(search_form); | 405 modified_forms.push_back(new PasswordForm(*base_form)); |
| 410 wrong_path.origin = GURL("http://some.domain.com:4567/elsewhere.html"); | 406 modified_forms.back()->blacklisted_by_user = true; |
| 411 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, | |
| 412 wrong_path); | |
| 413 EXPECT_EQ(NULL, match); | |
| 414 | 407 |
| 415 PasswordForm wrong_scheme(search_form); | 408 if (base_form->scheme == PasswordForm::SCHEME_BASIC || |
| 416 wrong_scheme.scheme = PasswordForm::SCHEME_DIGEST; | 409 base_form->scheme == PasswordForm::SCHEME_DIGEST) { |
| 417 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, | 410 modified_forms.push_back(new PasswordForm(*base_form)); |
| 418 wrong_scheme); | 411 SetPasswordFormRealm(modified_forms.back(), "incorrect"); |
| 419 EXPECT_EQ(NULL, match); | 412 } |
| 420 | 413 |
| 421 PasswordForm wrong_port(search_form); | 414 for (unsigned int j = 0; j < modified_forms.size(); ++j) { |
| 422 wrong_port.signon_realm = | 415 PasswordForm* match = |
| 423 std::string("http://some.domain.com:1234/low_security"); | 416 keychainAdapter.PasswordExactlyMatchingForm(*modified_forms[j]); |
| 424 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, | 417 EXPECT_EQ(NULL, match) << "In modified version " << j << " of base form " |
| 425 wrong_port); | 418 << i; |
| 426 EXPECT_EQ(NULL, match); | 419 } |
| 427 | 420 STLDeleteElements(&modified_forms); |
| 428 PasswordForm wrong_realm(search_form); | |
| 429 wrong_realm.signon_realm = | |
| 430 std::string("http://some.domain.com:4567/incorrect"); | |
| 431 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, | |
| 432 wrong_realm); | |
| 433 EXPECT_EQ(NULL, match); | |
| 434 | |
| 435 // We don't store blacklist entries in the keychain, and we want to ignore | |
| 436 // those stored by other browsers. | |
| 437 PasswordForm blacklist(search_form); | |
| 438 blacklist.blacklisted_by_user = true; | |
| 439 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, | |
| 440 blacklist); | |
| 441 EXPECT_EQ(NULL, match); | |
| 442 } | 421 } |
| 443 } | 422 } |
| 444 | 423 |
| 445 TEST_F(PasswordStoreMacTest, TestKeychainAdd) { | 424 TEST_F(PasswordStoreMacTest, TestKeychainAdd) { |
| 446 struct TestDataAndExpectation { | 425 struct TestDataAndExpectation { |
| 447 PasswordFormData data; | 426 PasswordFormData data; |
| 448 bool should_succeed; | 427 bool should_succeed; |
| 449 }; | 428 }; |
| 450 TestDataAndExpectation test_data[] = { | 429 TestDataAndExpectation test_data[] = { |
| 451 // Test a variety of scheme/port/protocol/path variations. | 430 // Test a variety of scheme/port/protocol/path variations. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 472 L"joe_user", L"fail_me", false, false, 0 }, false }, | 451 L"joe_user", L"fail_me", false, false, 0 }, false }, |
| 473 }; | 452 }; |
| 474 | 453 |
| 475 MacKeychainPasswordFormAdapter keychainAdapter(keychain_); | 454 MacKeychainPasswordFormAdapter keychainAdapter(keychain_); |
| 476 | 455 |
| 477 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) { | 456 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) { |
| 478 PasswordForm* in_form = CreatePasswordFormFromData(test_data[i].data); | 457 PasswordForm* in_form = CreatePasswordFormFromData(test_data[i].data); |
| 479 bool add_succeeded = keychainAdapter.AddLogin(*in_form); | 458 bool add_succeeded = keychainAdapter.AddLogin(*in_form); |
| 480 EXPECT_EQ(test_data[i].should_succeed, add_succeeded); | 459 EXPECT_EQ(test_data[i].should_succeed, add_succeeded); |
| 481 if (add_succeeded) { | 460 if (add_succeeded) { |
| 482 SecKeychainItemRef matching_item; | 461 scoped_ptr<PasswordForm> out_form( |
| 483 matching_item = internal_keychain_helpers::MatchingKeychainItem( | 462 keychainAdapter.PasswordExactlyMatchingForm(*in_form)); |
| 484 *keychain_, *in_form); | 463 EXPECT_TRUE(out_form.get() != NULL); |
| 485 EXPECT_TRUE(matching_item != NULL); | 464 EXPECT_EQ(out_form->scheme, in_form->scheme); |
| 486 PasswordForm out_form; | 465 EXPECT_EQ(out_form->signon_realm, in_form->signon_realm); |
| 487 internal_keychain_helpers::FillPasswordFormFromKeychainItem( | 466 EXPECT_EQ(out_form->origin, in_form->origin); |
| 488 *keychain_, matching_item, &out_form); | 467 EXPECT_EQ(out_form->username_value, in_form->username_value); |
| 489 EXPECT_EQ(out_form.scheme, in_form->scheme); | 468 EXPECT_EQ(out_form->password_value, in_form->password_value); |
| 490 EXPECT_EQ(out_form.signon_realm, in_form->signon_realm); | |
| 491 EXPECT_EQ(out_form.origin, in_form->origin); | |
| 492 EXPECT_EQ(out_form.username_value, in_form->username_value); | |
| 493 EXPECT_EQ(out_form.password_value, in_form->password_value); | |
| 494 keychain_->Free(matching_item); | |
| 495 } | 469 } |
| 496 delete in_form; | 470 delete in_form; |
| 497 } | 471 } |
| 498 | 472 |
| 499 // Test that adding duplicate item updates the existing item. | 473 // Test that adding duplicate item updates the existing item. |
| 500 { | 474 { |
| 501 PasswordFormData data = { | 475 PasswordFormData data = { |
| 502 PasswordForm::SCHEME_HTML, "http://some.domain.com", | 476 PasswordForm::SCHEME_HTML, "http://some.domain.com", |
| 503 "http://some.domain.com/insecure.html", NULL, | 477 "http://some.domain.com/insecure.html", NULL, |
| 504 NULL, NULL, NULL, L"joe_user", L"updated_password", false, false, 0 | 478 NULL, NULL, NULL, L"joe_user", L"updated_password", false, false, 0 |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 734 test_case); | 708 test_case); |
| 735 CHECK_FORMS(database_forms, test_data[DATABASE_OUTPUT][test_case], | 709 CHECK_FORMS(database_forms, test_data[DATABASE_OUTPUT][test_case], |
| 736 test_case); | 710 test_case); |
| 737 CHECK_FORMS(merged_forms, test_data[MERGE_OUTPUT][test_case], test_case); | 711 CHECK_FORMS(merged_forms, test_data[MERGE_OUTPUT][test_case], test_case); |
| 738 | 712 |
| 739 STLDeleteElements(&keychain_forms); | 713 STLDeleteElements(&keychain_forms); |
| 740 STLDeleteElements(&database_forms); | 714 STLDeleteElements(&database_forms); |
| 741 STLDeleteElements(&merged_forms); | 715 STLDeleteElements(&merged_forms); |
| 742 } | 716 } |
| 743 } | 717 } |
| OLD | NEW |