| 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 "chrome/browser/keychain_mock_mac.h" | 9 #include "chrome/browser/keychain_mock_mac.h" |
| 9 #include "chrome/browser/password_manager/password_store_mac.h" | 10 #include "chrome/browser/password_manager/password_store_mac.h" |
| 10 #include "chrome/browser/password_manager/password_store_mac_internal.h" | 11 #include "chrome/browser/password_manager/password_store_mac_internal.h" |
| 11 | 12 |
| 12 using webkit_glue::PasswordForm; | 13 using webkit_glue::PasswordForm; |
| 13 | 14 |
| 14 class PasswordStoreMacTest : public testing::Test { | 15 class PasswordStoreMacTest : public testing::Test { |
| 15 public: | 16 public: |
| 16 virtual void SetUp() { | 17 virtual void SetUp() { |
| 17 MockKeychain::KeychainTestData test_data[] = { | 18 MockKeychain::KeychainTestData test_data[] = { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 41 "Password Not Stored", " ", false }, | 42 "Password Not Stored", " ", false }, |
| 42 // HTTP auth basic, with port and path. | 43 // HTTP auth basic, with port and path. |
| 43 { kSecAuthenticationTypeHTTPBasic, "some.domain.com", | 44 { kSecAuthenticationTypeHTTPBasic, "some.domain.com", |
| 44 kSecProtocolTypeHTTP, "/insecure.html", 4567, "low_security", | 45 kSecProtocolTypeHTTP, "/insecure.html", 4567, "low_security", |
| 45 "19980330100000Z", | 46 "19980330100000Z", |
| 46 "basic_auth_user", "basic", false }, | 47 "basic_auth_user", "basic", false }, |
| 47 // HTTP auth digest, secure. | 48 // HTTP auth digest, secure. |
| 48 { kSecAuthenticationTypeHTTPDigest, "some.domain.com", | 49 { kSecAuthenticationTypeHTTPDigest, "some.domain.com", |
| 49 kSecProtocolTypeHTTPS, NULL, 0, "high_security", "19980330100000Z", | 50 kSecProtocolTypeHTTPS, NULL, 0, "high_security", "19980330100000Z", |
| 50 "digest_auth_user", "digest", false }, | 51 "digest_auth_user", "digest", false }, |
| 52 // An FTP password with an invalid date, for edge-case testing. |
| 53 { kSecAuthenticationTypeDefault, "a.server.com", |
| 54 kSecProtocolTypeFTP, NULL, 0, NULL, "20010203040", |
| 55 "abc", "123", false }, |
| 51 }; | 56 }; |
| 52 | 57 |
| 53 // Save one slot for use by AddInternetPassword. | 58 // Save one slot for use by AddInternetPassword. |
| 54 unsigned int capacity = arraysize(test_data) + 1; | 59 unsigned int capacity = arraysize(test_data) + 1; |
| 55 keychain_ = new MockKeychain(capacity); | 60 keychain_ = new MockKeychain(capacity); |
| 56 | 61 |
| 57 for (unsigned int i = 0; i < arraysize(test_data); ++i) { | 62 for (unsigned int i = 0; i < arraysize(test_data); ++i) { |
| 58 keychain_->AddTestItem(test_data[i]); | 63 keychain_->AddTestItem(test_data[i]); |
| 59 } | 64 } |
| 60 } | 65 } |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 } else { | 175 } else { |
| 171 EXPECT_TRUE(form->blacklisted_by_user) << test_label; | 176 EXPECT_TRUE(form->blacklisted_by_user) << test_label; |
| 172 } | 177 } |
| 173 EXPECT_EQ(expectation->preferred, form->preferred) << test_label; | 178 EXPECT_EQ(expectation->preferred, form->preferred) << test_label; |
| 174 EXPECT_EQ(expectation->ssl_valid, form->ssl_valid) << test_label; | 179 EXPECT_EQ(expectation->ssl_valid, form->ssl_valid) << test_label; |
| 175 EXPECT_DOUBLE_EQ(expectation->creation_time, | 180 EXPECT_DOUBLE_EQ(expectation->creation_time, |
| 176 form->date_created.ToDoubleT()) << test_label; | 181 form->date_created.ToDoubleT()) << test_label; |
| 177 } | 182 } |
| 178 } | 183 } |
| 179 | 184 |
| 180 // Frees all the Keychain items in |items|, and clears the vector. | |
| 181 static void FreeKeychainItems(const MacKeychain& keychain, | |
| 182 std::vector<SecKeychainItemRef>* items) { | |
| 183 CHECK(items); | |
| 184 for (std::vector<SecKeychainItemRef>::iterator i = items->begin(); | |
| 185 i != items->end(); ++i) { | |
| 186 keychain.Free(*i); | |
| 187 } | |
| 188 items->clear(); | |
| 189 } | |
| 190 | |
| 191 // Deletes all the PasswordForms in |forms|, and clears the vector. | |
| 192 static void DeletePasswordForms(std::vector<PasswordForm*>* forms) { | |
| 193 CHECK(forms); | |
| 194 for (std::vector<PasswordForm*>::iterator i = forms->begin(); | |
| 195 i != forms->end(); ++i) { | |
| 196 delete *i; | |
| 197 } | |
| 198 forms->clear(); | |
| 199 } | |
| 200 | |
| 201 #pragma mark - | 185 #pragma mark - |
| 202 | 186 |
| 203 TEST_F(PasswordStoreMacTest, TestSignonRealmParsing) { | |
| 204 typedef struct { | |
| 205 const char* signon_realm; | |
| 206 const bool expected_parsed; | |
| 207 const char* expected_server; | |
| 208 const bool expected_is_secure; | |
| 209 const int expected_port; | |
| 210 const char* expected_security_domain; | |
| 211 } TestData; | |
| 212 | |
| 213 TestData test_data[] = { | |
| 214 // HTML form signon realms. | |
| 215 { "http://www.domain.com/", | |
| 216 true, "www.domain.com", false, 0, "" }, | |
| 217 { "https://foo.org:9999/", | |
| 218 true, "foo.org", true, 9999, "" }, | |
| 219 // HTTP auth signon realms. | |
| 220 { "http://httpauth.com:8080/lowsecurity", | |
| 221 true, "httpauth.com", false, 8080, "lowsecurity" }, | |
| 222 { "https://httpauth.com/highsecurity", | |
| 223 true, "httpauth.com", true, 0 , "highsecurity" }, | |
| 224 // Bogus realms | |
| 225 { "blahblahblah", | |
| 226 false, false, "", 0, "" }, | |
| 227 { "foo/bar/baz", | |
| 228 false, false, "", 0, "" }, | |
| 229 }; | |
| 230 | |
| 231 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) { | |
| 232 std::string server; | |
| 233 std::string security_domain; | |
| 234 bool is_secure = false; | |
| 235 int port = -1; | |
| 236 bool parsed = internal_keychain_helpers::ExtractSignonRealmComponents( | |
| 237 std::string(test_data[i].signon_realm), &server, &port, &is_secure, | |
| 238 &security_domain); | |
| 239 EXPECT_EQ(test_data[i].expected_parsed, parsed) << "In iteration " << i; | |
| 240 | |
| 241 if (!parsed) { | |
| 242 continue; // If parse failed, out params are undefined. | |
| 243 } | |
| 244 EXPECT_EQ(std::string(test_data[i].expected_server), server) | |
| 245 << "In iteration " << i; | |
| 246 EXPECT_EQ(std::string(test_data[i].expected_security_domain), | |
| 247 security_domain) | |
| 248 << "In iteration " << i; | |
| 249 EXPECT_EQ(test_data[i].expected_is_secure, is_secure) | |
| 250 << "In iteration " << i; | |
| 251 EXPECT_EQ(test_data[i].expected_port, port) << "In iteration " << i; | |
| 252 } | |
| 253 | |
| 254 // NULLs are allowed for out params. | |
| 255 bool parsed = internal_keychain_helpers::ExtractSignonRealmComponents( | |
| 256 std::string("http://foo.bar.com:1234/baz"), NULL, NULL, NULL, NULL); | |
| 257 EXPECT_TRUE(parsed); | |
| 258 } | |
| 259 | |
| 260 TEST_F(PasswordStoreMacTest, TestURLConstruction) { | |
| 261 std::string host("exampledomain.com"); | |
| 262 std::string path("/path/to/page.html"); | |
| 263 | |
| 264 GURL full_url = internal_keychain_helpers::URLFromComponents(false, host, | |
| 265 1234, path); | |
| 266 EXPECT_TRUE(full_url.is_valid()); | |
| 267 EXPECT_EQ(GURL("http://exampledomain.com:1234/path/to/page.html"), full_url); | |
| 268 | |
| 269 GURL simple_secure_url = internal_keychain_helpers::URLFromComponents( | |
| 270 true, host, 0, std::string("")); | |
| 271 EXPECT_TRUE(simple_secure_url.is_valid()); | |
| 272 EXPECT_EQ(GURL("https://exampledomain.com/"), simple_secure_url); | |
| 273 } | |
| 274 | |
| 275 TEST_F(PasswordStoreMacTest, TestKeychainTime) { | |
| 276 typedef struct { | |
| 277 const char* time_string; | |
| 278 const bool expected_parsed; | |
| 279 const int expected_year; | |
| 280 const int expected_month; | |
| 281 const int expected_day; | |
| 282 const int expected_hour; | |
| 283 const int expected_minute; | |
| 284 const int expected_second; | |
| 285 } TestData; | |
| 286 | |
| 287 TestData test_data[] = { | |
| 288 // HTML form signon realms. | |
| 289 { "19980330100000Z", true, 1998, 3, 30, 10, 0, 0 }, | |
| 290 { "19991231235959Z", true, 1999, 12, 31, 23, 59, 59 }, | |
| 291 { "20000101000000Z", true, 2000, 1, 1, 0, 0, 0 }, | |
| 292 { "20011112012843Z", true, 2001, 11, 12, 1, 28, 43 }, | |
| 293 { "20020601171530Z", true, 2002, 6, 1, 17, 15, 30 }, | |
| 294 { "20100908070605Z", true, 2010, 9, 8, 7, 6, 5 }, | |
| 295 { "20010203040", false, 0, 0, 0, 0, 0, 0 }, | |
| 296 }; | |
| 297 | |
| 298 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) { | |
| 299 base::Time time; | |
| 300 bool parsed = internal_keychain_helpers::TimeFromKeychainTimeString( | |
| 301 test_data[i].time_string, strlen(test_data[i].time_string), &time); | |
| 302 EXPECT_EQ(test_data[i].expected_parsed, parsed) << "In iteration " << i; | |
| 303 if (!parsed) { | |
| 304 continue; | |
| 305 } | |
| 306 | |
| 307 base::Time::Exploded exploded_time; | |
| 308 time.UTCExplode(&exploded_time); | |
| 309 EXPECT_EQ(test_data[i].expected_year, exploded_time.year) | |
| 310 << "In iteration " << i; | |
| 311 EXPECT_EQ(test_data[i].expected_month, exploded_time.month) | |
| 312 << "In iteration " << i; | |
| 313 EXPECT_EQ(test_data[i].expected_day, exploded_time.day_of_month) | |
| 314 << "In iteration " << i; | |
| 315 EXPECT_EQ(test_data[i].expected_hour, exploded_time.hour) | |
| 316 << "In iteration " << i; | |
| 317 EXPECT_EQ(test_data[i].expected_minute, exploded_time.minute) | |
| 318 << "In iteration " << i; | |
| 319 EXPECT_EQ(test_data[i].expected_second, exploded_time.second) | |
| 320 << "In iteration " << i; | |
| 321 } | |
| 322 } | |
| 323 | |
| 324 TEST_F(PasswordStoreMacTest, TestAuthTypeSchemeTranslation) { | |
| 325 // Our defined types should round-trip correctly. | |
| 326 SecAuthenticationType auth_types[] = { kSecAuthenticationTypeHTMLForm, | |
| 327 kSecAuthenticationTypeHTTPBasic, | |
| 328 kSecAuthenticationTypeHTTPDigest }; | |
| 329 const int auth_count = sizeof(auth_types) / sizeof(SecAuthenticationType); | |
| 330 for (int i = 0; i < auth_count; ++i) { | |
| 331 SecAuthenticationType round_tripped_auth_type = | |
| 332 internal_keychain_helpers::AuthTypeForScheme( | |
| 333 internal_keychain_helpers::SchemeForAuthType(auth_types[i])); | |
| 334 EXPECT_EQ(auth_types[i], round_tripped_auth_type); | |
| 335 } | |
| 336 // Anything else should become SCHEME_OTHER and come back as Default. | |
| 337 PasswordForm::Scheme scheme_for_other_auth_type = | |
| 338 internal_keychain_helpers::SchemeForAuthType(kSecAuthenticationTypeNTLM); | |
| 339 SecAuthenticationType round_tripped_other_auth_type = | |
| 340 internal_keychain_helpers::AuthTypeForScheme(scheme_for_other_auth_type); | |
| 341 EXPECT_EQ(PasswordForm::SCHEME_OTHER, scheme_for_other_auth_type); | |
| 342 EXPECT_EQ(kSecAuthenticationTypeDefault, round_tripped_other_auth_type); | |
| 343 } | |
| 344 | |
| 345 TEST_F(PasswordStoreMacTest, TestKeychainToFormTranslation) { | 187 TEST_F(PasswordStoreMacTest, TestKeychainToFormTranslation) { |
| 346 typedef struct { | 188 typedef struct { |
| 347 const PasswordForm::Scheme scheme; | 189 const PasswordForm::Scheme scheme; |
| 348 const char* signon_realm; | 190 const char* signon_realm; |
| 349 const char* origin; | 191 const char* origin; |
| 350 const wchar_t* username; // Set to NULL to check for a blacklist entry. | 192 const wchar_t* username; // Set to NULL to check for a blacklist entry. |
| 351 const wchar_t* password; | 193 const wchar_t* password; |
| 352 const bool ssl_valid; | 194 const bool ssl_valid; |
| 353 const int creation_year; | 195 const int creation_year; |
| 354 const int creation_month; | 196 const int creation_month; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 376 2000, 1, 1, 0, 0, 0 }, | 218 2000, 1, 1, 0, 0, 0 }, |
| 377 { PasswordForm::SCHEME_HTML, "https://dont.remember.com/", | 219 { PasswordForm::SCHEME_HTML, "https://dont.remember.com/", |
| 378 "https://dont.remember.com/", NULL, NULL, true, | 220 "https://dont.remember.com/", NULL, NULL, true, |
| 379 2000, 1, 1, 0, 0, 0 }, | 221 2000, 1, 1, 0, 0, 0 }, |
| 380 { PasswordForm::SCHEME_BASIC, "http://some.domain.com:4567/low_security", | 222 { PasswordForm::SCHEME_BASIC, "http://some.domain.com:4567/low_security", |
| 381 "http://some.domain.com:4567/insecure.html", L"basic_auth_user", L"basic", | 223 "http://some.domain.com:4567/insecure.html", L"basic_auth_user", L"basic", |
| 382 false, 1998, 03, 30, 10, 00, 00 }, | 224 false, 1998, 03, 30, 10, 00, 00 }, |
| 383 { PasswordForm::SCHEME_DIGEST, "https://some.domain.com/high_security", | 225 { PasswordForm::SCHEME_DIGEST, "https://some.domain.com/high_security", |
| 384 "https://some.domain.com/", L"digest_auth_user", L"digest", true, | 226 "https://some.domain.com/", L"digest_auth_user", L"digest", true, |
| 385 1998, 3, 30, 10, 0, 0 }, | 227 1998, 3, 30, 10, 0, 0 }, |
| 228 { PasswordForm::SCHEME_OTHER, "http://a.server.com/", |
| 229 "http://a.server.com/", L"abc", L"123", false, |
| 230 1970, 1, 1, 0, 0, 0 }, |
| 386 }; | 231 }; |
| 387 | 232 |
| 388 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(expected); ++i) { | 233 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(expected); ++i) { |
| 389 // Create our fake KeychainItemRef; see MockKeychain docs. | 234 // Create our fake KeychainItemRef; see MockKeychain docs. |
| 390 SecKeychainItemRef keychain_item = | 235 SecKeychainItemRef keychain_item = |
| 391 reinterpret_cast<SecKeychainItemRef>(i + 1); | 236 reinterpret_cast<SecKeychainItemRef>(i + 1); |
| 392 PasswordForm form; | 237 PasswordForm form; |
| 393 bool parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem( | 238 bool parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem( |
| 394 *keychain_, keychain_item, &form); | 239 *keychain_, keychain_item, &form); |
| 395 | 240 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 // Use an invalid ref, to make sure errors are reported. | 274 // Use an invalid ref, to make sure errors are reported. |
| 430 SecKeychainItemRef keychain_item = reinterpret_cast<SecKeychainItemRef>(99); | 275 SecKeychainItemRef keychain_item = reinterpret_cast<SecKeychainItemRef>(99); |
| 431 PasswordForm form; | 276 PasswordForm form; |
| 432 bool parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem( | 277 bool parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem( |
| 433 *keychain_, keychain_item, &form); | 278 *keychain_, keychain_item, &form); |
| 434 EXPECT_FALSE(parsed); | 279 EXPECT_FALSE(parsed); |
| 435 } | 280 } |
| 436 } | 281 } |
| 437 | 282 |
| 438 TEST_F(PasswordStoreMacTest, TestKeychainSearch) { | 283 TEST_F(PasswordStoreMacTest, TestKeychainSearch) { |
| 439 { // An HTML form we've seen. | 284 struct TestDataAndExpectation { |
| 440 std::vector<SecKeychainItemRef> matching_items; | 285 const PasswordFormData data; |
| 441 internal_keychain_helpers::FindMatchingKeychainItems( | 286 const size_t expected_matches; |
| 442 *keychain_, std::string("http://some.domain.com/"), | 287 }; |
| 443 PasswordForm::SCHEME_HTML, &matching_items); | 288 // Most fields are left blank because we don't care about them for searching. |
| 444 EXPECT_EQ(static_cast<size_t>(2), matching_items.size()); | 289 TestDataAndExpectation test_data[] = { |
| 445 FreeKeychainItems(*keychain_, &matching_items); | 290 // An HTML form we've seen. |
| 446 } | 291 { { PasswordForm::SCHEME_HTML, "http://some.domain.com/", |
| 292 NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, false, 0 }, 2 }, |
| 293 // An HTML form we haven't seen |
| 294 { { PasswordForm::SCHEME_HTML, "http://www.unseendomain.com/", |
| 295 NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, false, 0 }, 0 }, |
| 296 // Basic auth that should match. |
| 297 { { PasswordForm::SCHEME_BASIC, "http://some.domain.com:4567/low_security", |
| 298 NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, false, 0 }, 1 }, |
| 299 // Basic auth with the wrong port. |
| 300 { { PasswordForm::SCHEME_BASIC, "http://some.domain.com:1111/low_security", |
| 301 NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, false, 0 }, 0 }, |
| 302 // Digest auth we've saved under https, visited with http. |
| 303 { { PasswordForm::SCHEME_DIGEST, "http://some.domain.com/high_security", |
| 304 NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, false, 0 }, 0 }, |
| 305 // Digest auth that should match. |
| 306 { { PasswordForm::SCHEME_DIGEST, "https://some.domain.com/high_security", |
| 307 NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, true, 0 }, 1 }, |
| 308 // Digest auth with the wrong domain. |
| 309 { { PasswordForm::SCHEME_DIGEST, "https://some.domain.com/other_domain", |
| 310 NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, true, 0 }, 0 }, |
| 311 // Garbage forms should have no matches. |
| 312 { { PasswordForm::SCHEME_HTML, "foo/bar/baz", |
| 313 NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, false, 0 }, 0 }, |
| 314 }; |
| 447 | 315 |
| 448 { // An HTML form we haven't seen | 316 MacKeychainPasswordFormAdapter keychainAdapter(keychain_); |
| 449 std::vector<SecKeychainItemRef> matching_items; | 317 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) { |
| 450 internal_keychain_helpers::FindMatchingKeychainItems( | 318 scoped_ptr<PasswordForm> query_form( |
| 451 *keychain_, std::string("http://www.unseendomain.com/"), | 319 CreatePasswordFormFromData(test_data[i].data)); |
| 452 PasswordForm::SCHEME_HTML, &matching_items); | 320 std::vector<PasswordForm*> matching_items = |
| 453 EXPECT_EQ(static_cast<size_t>(0), matching_items.size()); | 321 keychainAdapter.PasswordsMatchingForm(*query_form); |
| 454 FreeKeychainItems(*keychain_, &matching_items); | 322 EXPECT_EQ(test_data[i].expected_matches, matching_items.size()); |
| 455 } | 323 STLDeleteElements(&matching_items); |
| 456 | |
| 457 { // Basic auth that should match. | |
| 458 std::vector<SecKeychainItemRef> matching_items; | |
| 459 internal_keychain_helpers::FindMatchingKeychainItems( | |
| 460 *keychain_, std::string("http://some.domain.com:4567/low_security"), | |
| 461 PasswordForm::SCHEME_BASIC, &matching_items); | |
| 462 EXPECT_EQ(static_cast<size_t>(1), matching_items.size()); | |
| 463 FreeKeychainItems(*keychain_, &matching_items); | |
| 464 } | |
| 465 | |
| 466 { // Basic auth with the wrong port. | |
| 467 std::vector<SecKeychainItemRef> matching_items; | |
| 468 internal_keychain_helpers::FindMatchingKeychainItems( | |
| 469 *keychain_, std::string("http://some.domain.com:1111/low_security"), | |
| 470 PasswordForm::SCHEME_BASIC, &matching_items); | |
| 471 EXPECT_EQ(static_cast<size_t>(0), matching_items.size()); | |
| 472 FreeKeychainItems(*keychain_, &matching_items); | |
| 473 } | |
| 474 | |
| 475 { // Digest auth we've saved under https, visited with http. | |
| 476 std::vector<SecKeychainItemRef> matching_items; | |
| 477 internal_keychain_helpers::FindMatchingKeychainItems( | |
| 478 *keychain_, std::string("http://some.domain.com/high_security"), | |
| 479 PasswordForm::SCHEME_DIGEST, &matching_items); | |
| 480 EXPECT_EQ(static_cast<size_t>(0), matching_items.size()); | |
| 481 FreeKeychainItems(*keychain_, &matching_items); | |
| 482 } | |
| 483 | |
| 484 { // Digest auth that should match. | |
| 485 std::vector<SecKeychainItemRef> matching_items; | |
| 486 internal_keychain_helpers::FindMatchingKeychainItems( | |
| 487 *keychain_, std::string("https://some.domain.com/high_security"), | |
| 488 PasswordForm::SCHEME_DIGEST, &matching_items); | |
| 489 EXPECT_EQ(static_cast<size_t>(1), matching_items.size()); | |
| 490 FreeKeychainItems(*keychain_, &matching_items); | |
| 491 } | 324 } |
| 492 } | 325 } |
| 493 | 326 |
| 494 TEST_F(PasswordStoreMacTest, TestKeychainExactSearch) { | 327 TEST_F(PasswordStoreMacTest, TestKeychainExactSearch) { |
| 495 // Test a web form entry (SCHEME_HTML). | 328 // Test a web form entry (SCHEME_HTML). |
| 496 { | 329 { |
| 497 PasswordForm search_form; | 330 PasswordForm search_form; |
| 498 search_form.signon_realm = std::string("http://some.domain.com/"); | 331 search_form.signon_realm = std::string("http://some.domain.com/"); |
| 499 search_form.origin = GURL("http://some.domain.com/insecure.html"); | 332 search_form.origin = GURL("http://some.domain.com/insecure.html"); |
| 500 search_form.action = GURL("http://some.domain.com/submit.cgi"); | 333 search_form.action = GURL("http://some.domain.com/submit.cgi"); |
| 501 search_form.username_element = std::wstring(L"username"); | 334 search_form.username_element = std::wstring(L"username"); |
| 502 search_form.username_value = std::wstring(L"joe_user"); | 335 search_form.username_value = std::wstring(L"joe_user"); |
| 503 search_form.password_element = std::wstring(L"password"); | 336 search_form.password_element = std::wstring(L"password"); |
| 504 search_form.preferred = true; | 337 search_form.preferred = true; |
| 505 SecKeychainItemRef match; | 338 SecKeychainItemRef match; |
| 506 match = internal_keychain_helpers::FindMatchingKeychainItem(*keychain_, | 339 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, |
| 507 search_form); | 340 search_form); |
| 508 EXPECT_EQ(reinterpret_cast<SecKeychainItemRef>(2), match); | 341 EXPECT_EQ(reinterpret_cast<SecKeychainItemRef>(2), match); |
| 509 keychain_->Free(match); | 342 keychain_->Free(match); |
| 510 | 343 |
| 511 // Make sure that the matching isn't looser than it should be. | 344 // Make sure that the matching isn't looser than it should be. |
| 512 PasswordForm wrong_username(search_form); | 345 PasswordForm wrong_username(search_form); |
| 513 wrong_username.username_value = std::wstring(L"wrong_user"); | 346 wrong_username.username_value = std::wstring(L"wrong_user"); |
| 514 match = internal_keychain_helpers::FindMatchingKeychainItem(*keychain_, | 347 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, |
| 515 wrong_username); | 348 wrong_username); |
| 516 EXPECT_EQ(NULL, match); | 349 EXPECT_EQ(NULL, match); |
| 517 | 350 |
| 518 PasswordForm wrong_path(search_form); | 351 PasswordForm wrong_path(search_form); |
| 519 wrong_path.origin = GURL("http://some.domain.com/elsewhere.html"); | 352 wrong_path.origin = GURL("http://some.domain.com/elsewhere.html"); |
| 520 match = internal_keychain_helpers::FindMatchingKeychainItem(*keychain_, | 353 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, |
| 521 wrong_path); | 354 wrong_path); |
| 522 EXPECT_EQ(NULL, match); | 355 EXPECT_EQ(NULL, match); |
| 523 | 356 |
| 524 PasswordForm wrong_scheme(search_form); | 357 PasswordForm wrong_scheme(search_form); |
| 525 wrong_scheme.scheme = PasswordForm::SCHEME_BASIC; | 358 wrong_scheme.scheme = PasswordForm::SCHEME_BASIC; |
| 526 match = internal_keychain_helpers::FindMatchingKeychainItem(*keychain_, | 359 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, |
| 527 wrong_scheme); | 360 wrong_scheme); |
| 528 EXPECT_EQ(NULL, match); | 361 EXPECT_EQ(NULL, match); |
| 529 | 362 |
| 530 // With no path, we should match the pathless Keychain entry. | 363 // With no path, we should match the pathless Keychain entry. |
| 531 PasswordForm no_path(search_form); | 364 PasswordForm no_path(search_form); |
| 532 no_path.origin = GURL("http://some.domain.com/"); | 365 no_path.origin = GURL("http://some.domain.com/"); |
| 533 match = internal_keychain_helpers::FindMatchingKeychainItem(*keychain_, | 366 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, |
| 534 no_path); | 367 no_path); |
| 535 EXPECT_EQ(reinterpret_cast<SecKeychainItemRef>(1), match); | 368 EXPECT_EQ(reinterpret_cast<SecKeychainItemRef>(1), match); |
| 536 keychain_->Free(match); | 369 keychain_->Free(match); |
| 537 | 370 |
| 538 // We don't store blacklist entries in the keychain, and we want to ignore | 371 // We don't store blacklist entries in the keychain, and we want to ignore |
| 539 // those stored by other browsers. | 372 // those stored by other browsers. |
| 540 PasswordForm blacklist(search_form); | 373 PasswordForm blacklist(search_form); |
| 541 blacklist.blacklisted_by_user = true; | 374 blacklist.blacklisted_by_user = true; |
| 542 match = internal_keychain_helpers::FindMatchingKeychainItem(*keychain_, | 375 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, |
| 543 blacklist); | 376 blacklist); |
| 544 EXPECT_EQ(NULL, match); | 377 EXPECT_EQ(NULL, match); |
| 545 } | 378 } |
| 546 | 379 |
| 547 // Test an http auth entry (SCHEME_BASIC, but SCHEME_DIGEST works is searched | 380 // Test an http auth entry (SCHEME_BASIC, but SCHEME_DIGEST works is searched |
| 548 // the same way, so this gives sufficient coverage of both). | 381 // the same way, so this gives sufficient coverage of both). |
| 549 { | 382 { |
| 550 PasswordForm search_form; | 383 PasswordForm search_form; |
| 551 search_form.signon_realm = | 384 search_form.signon_realm = |
| 552 std::string("http://some.domain.com:4567/low_security"); | 385 std::string("http://some.domain.com:4567/low_security"); |
| 553 search_form.origin = GURL("http://some.domain.com:4567/insecure.html"); | 386 search_form.origin = GURL("http://some.domain.com:4567/insecure.html"); |
| 554 search_form.username_value = std::wstring(L"basic_auth_user"); | 387 search_form.username_value = std::wstring(L"basic_auth_user"); |
| 555 search_form.scheme = PasswordForm::SCHEME_BASIC; | 388 search_form.scheme = PasswordForm::SCHEME_BASIC; |
| 556 SecKeychainItemRef match; | 389 SecKeychainItemRef match; |
| 557 match = internal_keychain_helpers::FindMatchingKeychainItem(*keychain_, | 390 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, |
| 558 search_form); | 391 search_form); |
| 559 EXPECT_EQ(reinterpret_cast<SecKeychainItemRef>(7), match); | 392 EXPECT_EQ(reinterpret_cast<SecKeychainItemRef>(7), match); |
| 560 keychain_->Free(match); | 393 keychain_->Free(match); |
| 561 | 394 |
| 562 // Make sure that the matching isn't looser than it should be. | 395 // Make sure that the matching isn't looser than it should be. |
| 563 PasswordForm wrong_username(search_form); | 396 PasswordForm wrong_username(search_form); |
| 564 wrong_username.username_value = std::wstring(L"wrong_user"); | 397 wrong_username.username_value = std::wstring(L"wrong_user"); |
| 565 match = internal_keychain_helpers::FindMatchingKeychainItem(*keychain_, | 398 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, |
| 566 wrong_username); | 399 wrong_username); |
| 567 EXPECT_EQ(NULL, match); | 400 EXPECT_EQ(NULL, match); |
| 568 | 401 |
| 569 PasswordForm wrong_path(search_form); | 402 PasswordForm wrong_path(search_form); |
| 570 wrong_path.origin = GURL("http://some.domain.com:4567/elsewhere.html"); | 403 wrong_path.origin = GURL("http://some.domain.com:4567/elsewhere.html"); |
| 571 match = internal_keychain_helpers::FindMatchingKeychainItem(*keychain_, | 404 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, |
| 572 wrong_path); | 405 wrong_path); |
| 573 EXPECT_EQ(NULL, match); | 406 EXPECT_EQ(NULL, match); |
| 574 | 407 |
| 575 PasswordForm wrong_scheme(search_form); | 408 PasswordForm wrong_scheme(search_form); |
| 576 wrong_scheme.scheme = PasswordForm::SCHEME_DIGEST; | 409 wrong_scheme.scheme = PasswordForm::SCHEME_DIGEST; |
| 577 match = internal_keychain_helpers::FindMatchingKeychainItem(*keychain_, | 410 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, |
| 578 wrong_scheme); | 411 wrong_scheme); |
| 579 EXPECT_EQ(NULL, match); | 412 EXPECT_EQ(NULL, match); |
| 580 | 413 |
| 581 PasswordForm wrong_port(search_form); | 414 PasswordForm wrong_port(search_form); |
| 582 wrong_port.signon_realm = | 415 wrong_port.signon_realm = |
| 583 std::string("http://some.domain.com:1234/low_security"); | 416 std::string("http://some.domain.com:1234/low_security"); |
| 584 match = internal_keychain_helpers::FindMatchingKeychainItem(*keychain_, | 417 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, |
| 585 wrong_port); | 418 wrong_port); |
| 586 EXPECT_EQ(NULL, match); | 419 EXPECT_EQ(NULL, match); |
| 587 | 420 |
| 588 PasswordForm wrong_realm(search_form); | 421 PasswordForm wrong_realm(search_form); |
| 589 wrong_realm.signon_realm = | 422 wrong_realm.signon_realm = |
| 590 std::string("http://some.domain.com:4567/incorrect"); | 423 std::string("http://some.domain.com:4567/incorrect"); |
| 591 match = internal_keychain_helpers::FindMatchingKeychainItem(*keychain_, | 424 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, |
| 592 wrong_realm); | 425 wrong_realm); |
| 593 EXPECT_EQ(NULL, match); | 426 EXPECT_EQ(NULL, match); |
| 594 | 427 |
| 595 // We don't store blacklist entries in the keychain, and we want to ignore | 428 // We don't store blacklist entries in the keychain, and we want to ignore |
| 596 // those stored by other browsers. | 429 // those stored by other browsers. |
| 597 PasswordForm blacklist(search_form); | 430 PasswordForm blacklist(search_form); |
| 598 blacklist.blacklisted_by_user = true; | 431 blacklist.blacklisted_by_user = true; |
| 599 match = internal_keychain_helpers::FindMatchingKeychainItem(*keychain_, | 432 match = internal_keychain_helpers::MatchingKeychainItem(*keychain_, |
| 600 blacklist); | 433 blacklist); |
| 601 EXPECT_EQ(NULL, match); | 434 EXPECT_EQ(NULL, match); |
| 602 } | 435 } |
| 603 } | 436 } |
| 604 | 437 |
| 605 TEST_F(PasswordStoreMacTest, TestKeychainModify) { | |
| 606 SecKeychainItemRef keychain_item = reinterpret_cast<SecKeychainItemRef>(1); | |
| 607 EXPECT_TRUE(internal_keychain_helpers::SetKeychainItemPassword( | |
| 608 *keychain_, keychain_item, std::string("allnewpassword"))); | |
| 609 PasswordForm form; | |
| 610 internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_, | |
| 611 keychain_item, | |
| 612 &form); | |
| 613 EXPECT_EQ(L"allnewpassword", form.password_value); | |
| 614 | |
| 615 // Check that invalid items fail to update | |
| 616 SecKeychainItemRef invalid_item = reinterpret_cast<SecKeychainItemRef>(1000); | |
| 617 EXPECT_FALSE(internal_keychain_helpers::SetKeychainItemPassword( | |
| 618 *keychain_, invalid_item, std::string("allnewpassword"))); | |
| 619 | |
| 620 // Check that other errors are reported (using the magic failure value). | |
| 621 EXPECT_FALSE(internal_keychain_helpers::SetKeychainItemPassword( | |
| 622 *keychain_, keychain_item, std::string("fail_me"))); | |
| 623 } | |
| 624 | |
| 625 TEST_F(PasswordStoreMacTest, TestKeychainAdd) { | 438 TEST_F(PasswordStoreMacTest, TestKeychainAdd) { |
| 626 struct TestDataAndExpectation { | 439 struct TestDataAndExpectation { |
| 627 PasswordFormData data; | 440 PasswordFormData data; |
| 628 bool should_succeed; | 441 bool should_succeed; |
| 629 }; | 442 }; |
| 630 TestDataAndExpectation test_data[] = { | 443 TestDataAndExpectation test_data[] = { |
| 631 // Test a variety of scheme/port/protocol/path variations. | 444 // Test a variety of scheme/port/protocol/path variations. |
| 632 { { PasswordForm::SCHEME_HTML, "http://web.site.com/", | 445 { { PasswordForm::SCHEME_HTML, "http://web.site.com/", |
| 633 "http://web.site.com/path/to/page.html", NULL, NULL, NULL, NULL, | 446 "http://web.site.com/path/to/page.html", NULL, NULL, NULL, NULL, |
| 634 L"anonymous", L"knock-knock", false, false, 0 }, true }, | 447 L"anonymous", L"knock-knock", false, false, 0 }, true }, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 645 { { PasswordForm::SCHEME_HTML, "gobbledygook", | 458 { { PasswordForm::SCHEME_HTML, "gobbledygook", |
| 646 "gobbledygook", NULL, NULL, NULL, NULL, | 459 "gobbledygook", NULL, NULL, NULL, NULL, |
| 647 L"anonymous", L"knock-knock", false, false, 0 }, false }, | 460 L"anonymous", L"knock-knock", false, false, 0 }, false }, |
| 648 // Test that failing to update a duplicate (forced using the magic failure | 461 // Test that failing to update a duplicate (forced using the magic failure |
| 649 // password; see MockKeychain::ItemModifyAttributesAndData) is reported. | 462 // password; see MockKeychain::ItemModifyAttributesAndData) is reported. |
| 650 { { PasswordForm::SCHEME_HTML, "http://some.domain.com", | 463 { { PasswordForm::SCHEME_HTML, "http://some.domain.com", |
| 651 "http://some.domain.com/insecure.html", NULL, NULL, NULL, NULL, | 464 "http://some.domain.com/insecure.html", NULL, NULL, NULL, NULL, |
| 652 L"joe_user", L"fail_me", false, false, 0 }, false }, | 465 L"joe_user", L"fail_me", false, false, 0 }, false }, |
| 653 }; | 466 }; |
| 654 | 467 |
| 468 MacKeychainPasswordFormAdapter keychainAdapter(keychain_); |
| 469 |
| 655 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) { | 470 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) { |
| 656 PasswordForm* in_form = CreatePasswordFormFromData(test_data[i].data); | 471 PasswordForm* in_form = CreatePasswordFormFromData(test_data[i].data); |
| 657 bool add_succeeded = | 472 bool add_succeeded = keychainAdapter.AddLogin(*in_form); |
| 658 internal_keychain_helpers::AddKeychainEntryForForm(*keychain_, | |
| 659 *in_form); | |
| 660 EXPECT_EQ(test_data[i].should_succeed, add_succeeded); | 473 EXPECT_EQ(test_data[i].should_succeed, add_succeeded); |
| 661 if (add_succeeded) { | 474 if (add_succeeded) { |
| 662 SecKeychainItemRef matching_item; | 475 SecKeychainItemRef matching_item; |
| 663 matching_item = internal_keychain_helpers::FindMatchingKeychainItem( | 476 matching_item = internal_keychain_helpers::MatchingKeychainItem( |
| 664 *keychain_, *in_form); | 477 *keychain_, *in_form); |
| 665 EXPECT_TRUE(matching_item != NULL); | 478 EXPECT_TRUE(matching_item != NULL); |
| 666 PasswordForm out_form; | 479 PasswordForm out_form; |
| 667 internal_keychain_helpers::FillPasswordFormFromKeychainItem( | 480 internal_keychain_helpers::FillPasswordFormFromKeychainItem( |
| 668 *keychain_, matching_item, &out_form); | 481 *keychain_, matching_item, &out_form); |
| 669 EXPECT_EQ(out_form.scheme, in_form->scheme); | 482 EXPECT_EQ(out_form.scheme, in_form->scheme); |
| 670 EXPECT_EQ(out_form.signon_realm, in_form->signon_realm); | 483 EXPECT_EQ(out_form.signon_realm, in_form->signon_realm); |
| 671 EXPECT_EQ(out_form.origin, in_form->origin); | 484 EXPECT_EQ(out_form.origin, in_form->origin); |
| 672 EXPECT_EQ(out_form.username_value, in_form->username_value); | 485 EXPECT_EQ(out_form.username_value, in_form->username_value); |
| 673 EXPECT_EQ(out_form.password_value, in_form->password_value); | 486 EXPECT_EQ(out_form.password_value, in_form->password_value); |
| 674 keychain_->Free(matching_item); | 487 keychain_->Free(matching_item); |
| 675 } | 488 } |
| 676 delete in_form; | 489 delete in_form; |
| 677 } | 490 } |
| 678 | 491 |
| 679 // Test that adding duplicate item updates the existing item. | 492 // Test that adding duplicate item updates the existing item. |
| 680 { | 493 { |
| 681 PasswordFormData data = { | 494 PasswordFormData data = { |
| 682 PasswordForm::SCHEME_HTML, "http://some.domain.com", | 495 PasswordForm::SCHEME_HTML, "http://some.domain.com", |
| 683 "http://some.domain.com/insecure.html", NULL, | 496 "http://some.domain.com/insecure.html", NULL, |
| 684 NULL, NULL, NULL, L"joe_user", L"updated_password", false, false, 0 | 497 NULL, NULL, NULL, L"joe_user", L"updated_password", false, false, 0 |
| 685 }; | 498 }; |
| 686 PasswordForm* update_form = CreatePasswordFormFromData(data); | 499 PasswordForm* update_form = CreatePasswordFormFromData(data); |
| 687 EXPECT_TRUE(internal_keychain_helpers::AddKeychainEntryForForm( | 500 EXPECT_TRUE(keychainAdapter.AddLogin(*update_form)); |
| 688 *keychain_, *update_form)); | |
| 689 SecKeychainItemRef keychain_item = reinterpret_cast<SecKeychainItemRef>(2); | 501 SecKeychainItemRef keychain_item = reinterpret_cast<SecKeychainItemRef>(2); |
| 690 PasswordForm stored_form; | 502 PasswordForm stored_form; |
| 691 internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_, | 503 internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_, |
| 692 keychain_item, | 504 keychain_item, |
| 693 &stored_form); | 505 &stored_form); |
| 694 EXPECT_EQ(update_form->password_value, stored_form.password_value); | 506 EXPECT_EQ(update_form->password_value, stored_form.password_value); |
| 695 delete update_form; | 507 delete update_form; |
| 696 } | 508 } |
| 697 } | 509 } |
| 698 | 510 |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 910 internal_keychain_helpers::MergePasswordForms(&keychain_forms, | 722 internal_keychain_helpers::MergePasswordForms(&keychain_forms, |
| 911 &database_forms, | 723 &database_forms, |
| 912 &merged_forms); | 724 &merged_forms); |
| 913 | 725 |
| 914 CHECK_FORMS(keychain_forms, test_data[KEYCHAIN_OUTPUT][test_case], | 726 CHECK_FORMS(keychain_forms, test_data[KEYCHAIN_OUTPUT][test_case], |
| 915 test_case); | 727 test_case); |
| 916 CHECK_FORMS(database_forms, test_data[DATABASE_OUTPUT][test_case], | 728 CHECK_FORMS(database_forms, test_data[DATABASE_OUTPUT][test_case], |
| 917 test_case); | 729 test_case); |
| 918 CHECK_FORMS(merged_forms, test_data[MERGE_OUTPUT][test_case], test_case); | 730 CHECK_FORMS(merged_forms, test_data[MERGE_OUTPUT][test_case], test_case); |
| 919 | 731 |
| 920 DeletePasswordForms(&keychain_forms); | 732 STLDeleteElements(&keychain_forms); |
| 921 DeletePasswordForms(&database_forms); | 733 STLDeleteElements(&database_forms); |
| 922 DeletePasswordForms(&merged_forms); | 734 STLDeleteElements(&merged_forms); |
| 923 } | 735 } |
| 924 } | 736 } |
| OLD | NEW |