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 |