password_form_manager_unittest.cc revision 010d83a9304c5a91596085d917d248abff47903a
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/memory/scoped_ptr.h" 6#include "base/message_loop/message_loop.h" 7#include "base/prefs/pref_registry_simple.h" 8#include "base/prefs/pref_service.h" 9#include "base/prefs/testing_pref_service.h" 10#include "base/run_loop.h" 11#include "base/strings/string_util.h" 12#include "base/strings/utf_string_conversions.h" 13#include "components/autofill/core/common/password_form.h" 14#include "components/password_manager/core/browser/mock_password_manager_driver.h" 15#include "components/password_manager/core/browser/mock_password_store.h" 16#include "components/password_manager/core/browser/password_form_manager.h" 17#include "components/password_manager/core/browser/password_manager.h" 18#include "components/password_manager/core/browser/password_manager_driver.h" 19#include "components/password_manager/core/browser/password_store.h" 20#include "components/password_manager/core/browser/stub_password_manager_client.h" 21#include "components/password_manager/core/browser/test_password_store.h" 22#include "components/password_manager/core/common/password_manager_pref_names.h" 23#include "testing/gmock/include/gmock/gmock.h" 24#include "testing/gtest/include/gtest/gtest.h" 25 26using autofill::PasswordForm; 27using base::ASCIIToUTF16; 28using ::testing::_; 29using ::testing::Eq; 30using ::testing::Mock; 31using ::testing::Return; 32 33namespace autofill { 34class AutofillManager; 35} 36 37namespace password_manager { 38 39namespace { 40 41void RunAllPendingTasks() { 42 base::RunLoop run_loop; 43 base::MessageLoop::current()->PostTask( 44 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); 45 run_loop.Run(); 46} 47 48class TestPasswordManagerClient : public StubPasswordManagerClient { 49 public: 50 explicit TestPasswordManagerClient(PasswordStore* password_store) 51 : password_store_(password_store) { 52 prefs_.registry()->RegisterBooleanPref(prefs::kPasswordManagerEnabled, 53 true); 54 } 55 56 virtual void PromptUserToSavePassword(PasswordFormManager* form_to_save) 57 OVERRIDE {} 58 virtual PrefService* GetPrefs() OVERRIDE { return &prefs_; } 59 virtual PasswordStore* GetPasswordStore() OVERRIDE { return password_store_; } 60 virtual PasswordManagerDriver* GetDriver() OVERRIDE { return &driver_; } 61 virtual void AuthenticateAutofillAndFillForm( 62 scoped_ptr<autofill::PasswordFormFillData> fill_data) OVERRIDE { 63 driver_.FillPasswordForm(*fill_data.get()); 64 } 65 66 MockPasswordManagerDriver* GetMockDriver() { return &driver_; } 67 68 private: 69 TestingPrefServiceSimple prefs_; 70 PasswordStore* password_store_; 71 MockPasswordManagerDriver driver_; 72}; 73 74class TestPasswordManager : public PasswordManager { 75 public: 76 explicit TestPasswordManager(PasswordManagerClient* client) 77 : PasswordManager(client) {} 78 79 virtual void Autofill(const autofill::PasswordForm& form_for_autofill, 80 const autofill::PasswordFormMap& best_matches, 81 const autofill::PasswordForm& preferred_match, 82 bool wait_for_username) const OVERRIDE { 83 best_matches_ = best_matches; 84 } 85 86 const autofill::PasswordFormMap& GetLatestBestMatches() { 87 return best_matches_; 88 } 89 90 private: 91 // Marked mutable to get around constness of Autofill(). 92 mutable autofill::PasswordFormMap best_matches_; 93}; 94 95} // namespace 96 97class PasswordFormManagerTest : public testing::Test { 98 public: 99 PasswordFormManagerTest() {} 100 101 virtual void SetUp() { 102 observed_form_.origin = GURL("http://accounts.google.com/a/LoginAuth"); 103 observed_form_.action = GURL("http://accounts.google.com/a/Login"); 104 observed_form_.username_element = ASCIIToUTF16("Email"); 105 observed_form_.password_element = ASCIIToUTF16("Passwd"); 106 observed_form_.submit_element = ASCIIToUTF16("signIn"); 107 observed_form_.signon_realm = "http://accounts.google.com"; 108 109 saved_match_ = observed_form_; 110 saved_match_.origin = GURL("http://accounts.google.com/a/ServiceLoginAuth"); 111 saved_match_.action = GURL("http://accounts.google.com/a/ServiceLogin"); 112 saved_match_.preferred = true; 113 saved_match_.username_value = ASCIIToUTF16("test@gmail.com"); 114 saved_match_.password_value = ASCIIToUTF16("test1"); 115 saved_match_.other_possible_usernames.push_back( 116 ASCIIToUTF16("test2@gmail.com")); 117 } 118 119 virtual void TearDown() { 120 if (mock_store_) 121 mock_store_->Shutdown(); 122 } 123 124 void InitializeMockStore() { 125 if (!mock_store_) { 126 mock_store_ = new MockPasswordStore(); 127 ASSERT_TRUE(mock_store_); 128 } 129 } 130 131 MockPasswordStore* mock_store() const { return mock_store_.get(); } 132 133 PasswordForm* GetPendingCredentials(PasswordFormManager* p) { 134 return &p->pending_credentials_; 135 } 136 137 void SimulateMatchingPhase(PasswordFormManager* p, bool find_match) { 138 // Roll up the state to mock out the matching phase. 139 p->state_ = PasswordFormManager::POST_MATCHING_PHASE; 140 if (!find_match) 141 return; 142 143 PasswordForm* match = new PasswordForm(saved_match_); 144 // Heap-allocated form is owned by p. 145 p->best_matches_[match->username_value] = match; 146 p->preferred_match_ = match; 147 } 148 149 void SimulateFetchMatchingLoginsFromPasswordStore( 150 PasswordFormManager* manager) { 151 // Just need to update the internal states. 152 manager->state_ = PasswordFormManager::MATCHING_PHASE; 153 } 154 155 void SimulateResponseFromPasswordStore( 156 PasswordFormManager* manager, 157 const std::vector<PasswordForm*>& result) { 158 // Simply call the callback method when request done. This will transfer 159 // the ownership of the objects in |result| to the |manager|. 160 manager->OnGetPasswordStoreResults(result); 161 } 162 163 void SanitizePossibleUsernames(PasswordFormManager* p, PasswordForm* form) { 164 p->SanitizePossibleUsernames(form); 165 } 166 167 bool IgnoredResult(PasswordFormManager* p, PasswordForm* form) { 168 return p->IgnoreResult(*form); 169 } 170 171 PasswordForm* observed_form() { return &observed_form_; } 172 PasswordForm* saved_match() { return &saved_match_; } 173 PasswordForm* CreateSavedMatch(bool blacklisted) { 174 // Owned by the caller of this method. 175 PasswordForm* match = new PasswordForm(saved_match_); 176 match->blacklisted_by_user = blacklisted; 177 return match; 178 } 179 180 private: 181 PasswordForm observed_form_; 182 PasswordForm saved_match_; 183 scoped_refptr<MockPasswordStore> mock_store_; 184}; 185 186TEST_F(PasswordFormManagerTest, TestNewLogin) { 187 scoped_ptr<TestPasswordManagerClient> client( 188 new TestPasswordManagerClient(NULL)); 189 scoped_ptr<MockPasswordManagerDriver> driver; 190 PasswordFormManager* manager = new PasswordFormManager( 191 NULL, client.get(), driver.get(), *observed_form(), false); 192 193 SimulateMatchingPhase(manager, false); 194 // User submits credentials for the observed form. 195 PasswordForm credentials = *observed_form(); 196 credentials.username_value = saved_match()->username_value; 197 credentials.password_value = saved_match()->password_value; 198 credentials.preferred = true; 199 manager->ProvisionallySave( 200 credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 201 202 // Successful login. The PasswordManager would instruct PasswordFormManager 203 // to save, which should know this is a new login. 204 EXPECT_TRUE(manager->IsNewLogin()); 205 // Make sure the credentials that would be submitted on successful login 206 // are going to match the stored entry in the db. 207 EXPECT_EQ(observed_form()->origin.spec(), 208 GetPendingCredentials(manager)->origin.spec()); 209 EXPECT_EQ(observed_form()->signon_realm, 210 GetPendingCredentials(manager)->signon_realm); 211 EXPECT_EQ(observed_form()->action, GetPendingCredentials(manager)->action); 212 EXPECT_TRUE(GetPendingCredentials(manager)->preferred); 213 EXPECT_EQ(saved_match()->password_value, 214 GetPendingCredentials(manager)->password_value); 215 EXPECT_EQ(saved_match()->username_value, 216 GetPendingCredentials(manager)->username_value); 217 218 // Now, suppose the user re-visits the site and wants to save an additional 219 // login for the site with a new username. In this case, the matching phase 220 // will yield the previously saved login. 221 SimulateMatchingPhase(manager, true); 222 // Set up the new login. 223 base::string16 new_user = ASCIIToUTF16("newuser"); 224 base::string16 new_pass = ASCIIToUTF16("newpass"); 225 credentials.username_value = new_user; 226 credentials.password_value = new_pass; 227 manager->ProvisionallySave( 228 credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 229 230 // Again, the PasswordFormManager should know this is still a new login. 231 EXPECT_TRUE(manager->IsNewLogin()); 232 // And make sure everything squares up again. 233 EXPECT_EQ(observed_form()->origin.spec(), 234 GetPendingCredentials(manager)->origin.spec()); 235 EXPECT_EQ(observed_form()->signon_realm, 236 GetPendingCredentials(manager)->signon_realm); 237 EXPECT_TRUE(GetPendingCredentials(manager)->preferred); 238 EXPECT_EQ(new_pass, GetPendingCredentials(manager)->password_value); 239 EXPECT_EQ(new_user, GetPendingCredentials(manager)->username_value); 240 delete manager; 241} 242 243TEST_F(PasswordFormManagerTest, TestUpdatePassword) { 244 // Create a PasswordFormManager with observed_form, as if we just 245 // saw this form and need to find matching logins. 246 scoped_ptr<TestPasswordManagerClient> client( 247 new TestPasswordManagerClient(NULL)); 248 scoped_ptr<MockPasswordManagerDriver> driver; 249 PasswordFormManager* manager = new PasswordFormManager( 250 NULL, client.get(), driver.get(), *observed_form(), false); 251 252 SimulateMatchingPhase(manager, true); 253 254 // User submits credentials for the observed form using a username previously 255 // stored, but a new password. Note that the observed form may have different 256 // origin URL (as it does in this case) than the saved_match, but we want to 257 // make sure the updated password is reflected in saved_match, because that is 258 // what we autofilled. 259 base::string16 new_pass = ASCIIToUTF16("newpassword"); 260 PasswordForm credentials = *observed_form(); 261 credentials.username_value = saved_match()->username_value; 262 credentials.password_value = new_pass; 263 credentials.preferred = true; 264 manager->ProvisionallySave( 265 credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 266 267 // Successful login. The PasswordManager would instruct PasswordFormManager 268 // to save, and since this is an update, it should know not to save as a new 269 // login. 270 EXPECT_FALSE(manager->IsNewLogin()); 271 272 // Make sure the credentials that would be submitted on successful login 273 // are going to match the stored entry in the db. (This verifies correct 274 // behaviour for bug 1074420). 275 EXPECT_EQ(GetPendingCredentials(manager)->origin.spec(), 276 saved_match()->origin.spec()); 277 EXPECT_EQ(GetPendingCredentials(manager)->signon_realm, 278 saved_match()->signon_realm); 279 EXPECT_TRUE(GetPendingCredentials(manager)->preferred); 280 EXPECT_EQ(new_pass, GetPendingCredentials(manager)->password_value); 281 // Done. 282 delete manager; 283} 284 285TEST_F(PasswordFormManagerTest, TestIgnoreResult) { 286 scoped_ptr<TestPasswordManagerClient> client( 287 new TestPasswordManagerClient(NULL)); 288 scoped_ptr<MockPasswordManagerDriver> driver; 289 PasswordFormManager* manager = new PasswordFormManager( 290 NULL, client.get(), driver.get(), *observed_form(), false); 291 292 // Make sure we don't match a PasswordForm if it was originally saved on 293 // an SSL-valid page and we are now on a page with invalid certificate. 294 saved_match()->ssl_valid = true; 295 EXPECT_TRUE(IgnoredResult(manager, saved_match())); 296 297 saved_match()->ssl_valid = false; 298 // Different paths for action / origin are okay. 299 saved_match()->action = GURL("http://www.google.com/b/Login"); 300 saved_match()->origin = GURL("http://www.google.com/foo"); 301 EXPECT_FALSE(IgnoredResult(manager, saved_match())); 302 303 // Done. 304 delete manager; 305} 306 307TEST_F(PasswordFormManagerTest, TestEmptyAction) { 308 scoped_ptr<TestPasswordManagerClient> client( 309 new TestPasswordManagerClient(NULL)); 310 scoped_ptr<MockPasswordManagerDriver> driver; 311 scoped_ptr<PasswordFormManager> manager(new PasswordFormManager( 312 NULL, client.get(), driver.get(), *observed_form(), false)); 313 314 saved_match()->action = GURL(); 315 SimulateMatchingPhase(manager.get(), true); 316 // User logs in with the autofilled username / password from saved_match. 317 PasswordForm login = *observed_form(); 318 login.username_value = saved_match()->username_value; 319 login.password_value = saved_match()->password_value; 320 manager->ProvisionallySave( 321 login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 322 EXPECT_FALSE(manager->IsNewLogin()); 323 // We bless our saved PasswordForm entry with the action URL of the 324 // observed form. 325 EXPECT_EQ(observed_form()->action, 326 GetPendingCredentials(manager.get())->action); 327} 328 329TEST_F(PasswordFormManagerTest, TestUpdateAction) { 330 scoped_ptr<TestPasswordManagerClient> client( 331 new TestPasswordManagerClient(NULL)); 332 scoped_ptr<MockPasswordManagerDriver> driver; 333 scoped_ptr<PasswordFormManager> manager(new PasswordFormManager( 334 NULL, client.get(), driver.get(), *observed_form(), false)); 335 336 SimulateMatchingPhase(manager.get(), true); 337 // User logs in with the autofilled username / password from saved_match. 338 PasswordForm login = *observed_form(); 339 login.username_value = saved_match()->username_value; 340 login.password_value = saved_match()->password_value; 341 342 manager->ProvisionallySave( 343 login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 344 EXPECT_FALSE(manager->IsNewLogin()); 345 // The observed action URL is different from the previously saved one, and 346 // is the same as the one that would be submitted on successful login. 347 EXPECT_NE(observed_form()->action, saved_match()->action); 348 EXPECT_EQ(observed_form()->action, 349 GetPendingCredentials(manager.get())->action); 350} 351 352TEST_F(PasswordFormManagerTest, TestDynamicAction) { 353 scoped_ptr<TestPasswordManagerClient> client( 354 new TestPasswordManagerClient(NULL)); 355 scoped_ptr<MockPasswordManagerDriver> driver; 356 scoped_ptr<PasswordFormManager> manager(new PasswordFormManager( 357 NULL, client.get(), driver.get(), *observed_form(), false)); 358 359 SimulateMatchingPhase(manager.get(), false); 360 PasswordForm login(*observed_form()); 361 // The submitted action URL is different from the one observed on page load. 362 GURL new_action = GURL("http://www.google.com/new_action"); 363 login.action = new_action; 364 365 manager->ProvisionallySave( 366 login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 367 EXPECT_TRUE(manager->IsNewLogin()); 368 // Check that the provisionally saved action URL is the same as the submitted 369 // action URL, not the one observed on page load. 370 EXPECT_EQ(new_action, GetPendingCredentials(manager.get())->action); 371} 372 373TEST_F(PasswordFormManagerTest, TestAlternateUsername) { 374 // Need a MessageLoop for callbacks. 375 base::MessageLoop message_loop; 376 scoped_refptr<TestPasswordStore> password_store = new TestPasswordStore; 377 CHECK(password_store->Init(syncer::SyncableService::StartSyncFlare())); 378 379 TestPasswordManagerClient client(password_store.get()); 380 TestPasswordManager password_manager(&client); 381 scoped_ptr<PasswordFormManager> manager(new PasswordFormManager( 382 &password_manager, &client, client.GetDriver(), *observed_form(), false)); 383 384 password_store->AddLogin(*saved_match()); 385 manager->FetchMatchingLoginsFromPasswordStore(PasswordStore::ALLOW_PROMPT); 386 RunAllPendingTasks(); 387 388 // The saved match has the right username already. 389 PasswordForm login(*observed_form()); 390 login.username_value = saved_match()->username_value; 391 login.password_value = saved_match()->password_value; 392 login.preferred = true; 393 manager->ProvisionallySave( 394 login, PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES); 395 396 EXPECT_FALSE(manager->IsNewLogin()); 397 manager->Save(); 398 RunAllPendingTasks(); 399 400 // Should be only one password stored, and should not have 401 // |other_possible_usernames| set anymore. 402 TestPasswordStore::PasswordMap passwords = password_store->stored_passwords(); 403 EXPECT_EQ(1U, passwords.size()); 404 ASSERT_EQ(1U, passwords[saved_match()->signon_realm].size()); 405 EXPECT_EQ(saved_match()->username_value, 406 passwords[saved_match()->signon_realm][0].username_value); 407 EXPECT_EQ(0U, 408 passwords[saved_match()->signon_realm][0] 409 .other_possible_usernames.size()); 410 411 // This time use an alternate username 412 manager.reset(new PasswordFormManager( 413 &password_manager, &client, client.GetDriver(), *observed_form(), false)); 414 password_store->Clear(); 415 password_store->AddLogin(*saved_match()); 416 manager->FetchMatchingLoginsFromPasswordStore(PasswordStore::ALLOW_PROMPT); 417 RunAllPendingTasks(); 418 419 base::string16 new_username = saved_match()->other_possible_usernames[0]; 420 login.username_value = new_username; 421 manager->ProvisionallySave( 422 login, PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES); 423 424 EXPECT_FALSE(manager->IsNewLogin()); 425 manager->Save(); 426 RunAllPendingTasks(); 427 428 // |other_possible_usernames| should also be empty, but username_value should 429 // be changed to match |new_username| 430 passwords = password_store->stored_passwords(); 431 EXPECT_EQ(1U, passwords.size()); 432 ASSERT_EQ(1U, passwords[saved_match()->signon_realm].size()); 433 EXPECT_EQ(new_username, 434 passwords[saved_match()->signon_realm][0].username_value); 435 EXPECT_EQ(0U, 436 passwords[saved_match()->signon_realm][0] 437 .other_possible_usernames.size()); 438 password_store->Shutdown(); 439} 440 441TEST_F(PasswordFormManagerTest, TestValidForms) { 442 // User submits credentials for the observed form. 443 PasswordForm credentials = *observed_form(); 444 credentials.scheme = PasswordForm::SCHEME_HTML; 445 credentials.username_value = saved_match()->username_value; 446 credentials.password_value = saved_match()->password_value; 447 448 // Form with both username_element and password_element. 449 PasswordFormManager manager1(NULL, NULL, NULL, credentials, false); 450 SimulateMatchingPhase(&manager1, false); 451 EXPECT_TRUE(manager1.HasValidPasswordForm()); 452 453 // Form without a username_element but with a password_element. 454 credentials.username_element.clear(); 455 PasswordFormManager manager2(NULL, NULL, NULL, credentials, false); 456 SimulateMatchingPhase(&manager2, false); 457 EXPECT_FALSE(manager2.HasValidPasswordForm()); 458 459 // Form without a password_element but with a username_element. 460 credentials.username_element = saved_match()->username_element; 461 credentials.password_element.clear(); 462 PasswordFormManager manager3(NULL, NULL, NULL, credentials, false); 463 SimulateMatchingPhase(&manager3, false); 464 EXPECT_FALSE(manager3.HasValidPasswordForm()); 465 466 // Form with neither a password_element nor a username_element. 467 credentials.username_element.clear(); 468 credentials.password_element.clear(); 469 PasswordFormManager manager4(NULL, NULL, NULL, credentials, false); 470 SimulateMatchingPhase(&manager4, false); 471 EXPECT_FALSE(manager4.HasValidPasswordForm()); 472} 473 474TEST_F(PasswordFormManagerTest, TestValidFormsBasic) { 475 // User submits credentials for the observed form. 476 PasswordForm credentials = *observed_form(); 477 credentials.scheme = PasswordForm::SCHEME_BASIC; 478 credentials.username_value = saved_match()->username_value; 479 credentials.password_value = saved_match()->password_value; 480 481 // Form with both username_element and password_element. 482 PasswordFormManager manager1(NULL, NULL, NULL, credentials, false); 483 SimulateMatchingPhase(&manager1, false); 484 EXPECT_TRUE(manager1.HasValidPasswordForm()); 485 486 // Form without a username_element but with a password_element. 487 credentials.username_element.clear(); 488 PasswordFormManager manager2(NULL, NULL, NULL, credentials, false); 489 SimulateMatchingPhase(&manager2, false); 490 EXPECT_TRUE(manager2.HasValidPasswordForm()); 491 492 // Form without a password_element but with a username_element. 493 credentials.username_element = saved_match()->username_element; 494 credentials.password_element.clear(); 495 PasswordFormManager manager3(NULL, NULL, NULL, credentials, false); 496 SimulateMatchingPhase(&manager3, false); 497 EXPECT_TRUE(manager3.HasValidPasswordForm()); 498 499 // Form with neither a password_element nor a username_element. 500 credentials.username_element.clear(); 501 credentials.password_element.clear(); 502 PasswordFormManager manager4(NULL, NULL, NULL, credentials, false); 503 SimulateMatchingPhase(&manager4, false); 504 EXPECT_TRUE(manager4.HasValidPasswordForm()); 505} 506 507TEST_F(PasswordFormManagerTest, TestSendNotBlacklistedMessage) { 508 base::MessageLoop message_loop; 509 510 // A dumb password manager. 511 TestPasswordManagerClient client(NULL); 512 TestPasswordManager password_manager(&client); 513 scoped_ptr<PasswordFormManager> manager(new PasswordFormManager( 514 &password_manager, &client, client.GetDriver(), *observed_form(), false)); 515 516 // First time sign up attempt; No login result is found from password store; 517 // We should send the not blacklisted message. 518 EXPECT_CALL(*client.GetMockDriver(), AllowPasswordGenerationForForm(_)) 519 .Times(1); 520 SimulateFetchMatchingLoginsFromPasswordStore(manager.get()); 521 std::vector<PasswordForm*> result; 522 SimulateResponseFromPasswordStore(manager.get(), result); 523 Mock::VerifyAndClearExpectations(client.GetMockDriver()); 524 525 // Sign up attempt to previously visited sites; Login result is found from 526 // password store, and is not blacklisted; We should send the not blacklisted 527 // message. 528 manager.reset(new PasswordFormManager( 529 &password_manager, &client, client.GetDriver(), *observed_form(), false)); 530 EXPECT_CALL(*client.GetMockDriver(), AllowPasswordGenerationForForm(_)) 531 .Times(1); 532 SimulateFetchMatchingLoginsFromPasswordStore(manager.get()); 533 // We need add heap allocated objects to result. 534 result.push_back(CreateSavedMatch(false)); 535 SimulateResponseFromPasswordStore(manager.get(), result); 536 Mock::VerifyAndClearExpectations(client.GetMockDriver()); 537 538 // Sign up attempt to previously visited sites; Login result is found from 539 // password store, but is blacklisted; We should not send the not blacklisted 540 // message. 541 manager.reset(new PasswordFormManager( 542 &password_manager, &client, client.GetDriver(), *observed_form(), false)); 543 EXPECT_CALL(*client.GetMockDriver(), AllowPasswordGenerationForForm(_)) 544 .Times(0); 545 SimulateFetchMatchingLoginsFromPasswordStore(manager.get()); 546 result.clear(); 547 result.push_back(CreateSavedMatch(true)); 548 SimulateResponseFromPasswordStore(manager.get(), result); 549 Mock::VerifyAndClearExpectations(client.GetMockDriver()); 550} 551 552TEST_F(PasswordFormManagerTest, TestForceInclusionOfGeneratedPasswords) { 553 base::MessageLoop message_loop; 554 555 TestPasswordManagerClient client(NULL); 556 TestPasswordManager password_manager(&client); 557 scoped_ptr<PasswordFormManager> manager(new PasswordFormManager( 558 &password_manager, &client, client.GetDriver(), *observed_form(), false)); 559 560 // Simulate having two matches for this origin, one of which was from a form 561 // with different HTML tags for elements. Because of scoring differences, 562 // only the first form will be sent to Autofill(). 563 std::vector<PasswordForm*> results; 564 results.push_back(CreateSavedMatch(false)); 565 results.push_back(CreateSavedMatch(false)); 566 results[1]->username_value = ASCIIToUTF16("other@gmail.com"); 567 results[1]->password_element = ASCIIToUTF16("signup_password"); 568 results[1]->username_element = ASCIIToUTF16("signup_username"); 569 SimulateFetchMatchingLoginsFromPasswordStore(manager.get()); 570 SimulateResponseFromPasswordStore(manager.get(), results); 571 EXPECT_EQ(1u, password_manager.GetLatestBestMatches().size()); 572 results.clear(); 573 574 // Same thing, except this time the credentials that don't match quite as 575 // well are generated. They should now be sent to Autofill(). 576 manager.reset(new PasswordFormManager( 577 &password_manager, &client, client.GetDriver(), *observed_form(), false)); 578 results.push_back(CreateSavedMatch(false)); 579 results.push_back(CreateSavedMatch(false)); 580 results[1]->username_value = ASCIIToUTF16("other@gmail.com"); 581 results[1]->password_element = ASCIIToUTF16("signup_password"); 582 results[1]->username_element = ASCIIToUTF16("signup_username"); 583 results[1]->type = PasswordForm::TYPE_GENERATED; 584 SimulateFetchMatchingLoginsFromPasswordStore(manager.get()); 585 SimulateResponseFromPasswordStore(manager.get(), results); 586 EXPECT_EQ(2u, password_manager.GetLatestBestMatches().size()); 587} 588 589TEST_F(PasswordFormManagerTest, TestSanitizePossibleUsernames) { 590 scoped_ptr<TestPasswordManagerClient> client( 591 new TestPasswordManagerClient(NULL)); 592 scoped_ptr<MockPasswordManagerDriver> driver; 593 scoped_ptr<PasswordFormManager> manager(new PasswordFormManager( 594 NULL, client.get(), driver.get(), *observed_form(), false)); 595 PasswordForm credentials(*observed_form()); 596 credentials.other_possible_usernames.push_back(ASCIIToUTF16("543-43-1234")); 597 credentials.other_possible_usernames.push_back( 598 ASCIIToUTF16("378282246310005")); 599 credentials.other_possible_usernames.push_back( 600 ASCIIToUTF16("other username")); 601 credentials.username_value = ASCIIToUTF16("test@gmail.com"); 602 603 SanitizePossibleUsernames(manager.get(), &credentials); 604 605 // Possible credit card number and SSN are stripped. 606 std::vector<base::string16> expected; 607 expected.push_back(ASCIIToUTF16("other username")); 608 EXPECT_THAT(credentials.other_possible_usernames, Eq(expected)); 609 610 credentials.other_possible_usernames.clear(); 611 credentials.other_possible_usernames.push_back(ASCIIToUTF16("511-32-9830")); 612 credentials.other_possible_usernames.push_back(ASCIIToUTF16("duplicate")); 613 credentials.other_possible_usernames.push_back(ASCIIToUTF16("duplicate")); 614 credentials.other_possible_usernames.push_back(ASCIIToUTF16("random")); 615 credentials.other_possible_usernames.push_back( 616 ASCIIToUTF16("test@gmail.com")); 617 618 SanitizePossibleUsernames(manager.get(), &credentials); 619 620 // SSN, duplicate in |other_possible_usernames| and duplicate of 621 // |username_value| all removed. 622 expected.clear(); 623 expected.push_back(ASCIIToUTF16("duplicate")); 624 expected.push_back(ASCIIToUTF16("random")); 625 EXPECT_THAT(credentials.other_possible_usernames, Eq(expected)); 626} 627 628TEST_F(PasswordFormManagerTest, TestUpdateIncompleteCredentials) { 629 InitializeMockStore(); 630 631 // We've found this form on a website: 632 PasswordForm encountered_form; 633 encountered_form.origin = GURL("http://accounts.google.com/LoginAuth"); 634 encountered_form.signon_realm = "http://accounts.google.com/"; 635 encountered_form.action = GURL("http://accounts.google.com/Login"); 636 encountered_form.username_element = ASCIIToUTF16("Email"); 637 encountered_form.password_element = ASCIIToUTF16("Passwd"); 638 encountered_form.submit_element = ASCIIToUTF16("signIn"); 639 640 TestPasswordManagerClient client(mock_store()); 641 MockPasswordManagerDriver driver; 642 EXPECT_CALL(driver, IsOffTheRecord()).WillRepeatedly(Return(false)); 643 EXPECT_CALL(driver, AllowPasswordGenerationForForm(_)); 644 645 TestPasswordManager manager(&client); 646 PasswordFormManager form_manager( 647 &manager, &client, &driver, encountered_form, false); 648 649 const PasswordStore::AuthorizationPromptPolicy auth_policy = 650 PasswordStore::DISALLOW_PROMPT; 651 EXPECT_CALL(*mock_store(), 652 GetLogins(encountered_form, auth_policy, &form_manager)); 653 form_manager.FetchMatchingLoginsFromPasswordStore(auth_policy); 654 655 // Password store only has these incomplete credentials. 656 PasswordForm* incomplete_form = new PasswordForm(); 657 incomplete_form->origin = GURL("http://accounts.google.com/LoginAuth"); 658 incomplete_form->signon_realm = "http://accounts.google.com/"; 659 incomplete_form->password_value = ASCIIToUTF16("my_password"); 660 incomplete_form->username_value = ASCIIToUTF16("my_username"); 661 incomplete_form->preferred = true; 662 incomplete_form->ssl_valid = false; 663 incomplete_form->scheme = PasswordForm::SCHEME_HTML; 664 665 // We expect to see this form eventually sent to the Password store. It 666 // has password/username values from the store and 'username_element', 667 // 'password_element', 'submit_element' and 'action' fields copied from 668 // the encountered form. 669 PasswordForm complete_form(*incomplete_form); 670 complete_form.action = encountered_form.action; 671 complete_form.password_element = encountered_form.password_element; 672 complete_form.username_element = encountered_form.username_element; 673 complete_form.submit_element = encountered_form.submit_element; 674 675 // Feed the incomplete credentials to the manager. 676 std::vector<PasswordForm*> results; 677 results.push_back(incomplete_form); // Takes ownership. 678 form_manager.OnRequestDone(results); 679 680 form_manager.ProvisionallySave( 681 complete_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 682 // By now that form has been used once. 683 complete_form.times_used = 1; 684 685 // Check that PasswordStore receives an update request with the complete form. 686 EXPECT_CALL(*mock_store(), UpdateLogin(complete_form)); 687 form_manager.Save(); 688} 689 690TEST_F(PasswordFormManagerTest, TestScoringPublicSuffixMatch) { 691 base::MessageLoop message_loop; 692 693 TestPasswordManagerClient client(NULL); 694 MockPasswordManagerDriver driver; 695 EXPECT_CALL(driver, IsOffTheRecord()).WillRepeatedly(Return(false)); 696 EXPECT_CALL(driver, AllowPasswordGenerationForForm(_)); 697 698 TestPasswordManager password_manager(&client); 699 scoped_ptr<PasswordFormManager> manager(new PasswordFormManager( 700 &password_manager, &client, &driver, *observed_form(), false)); 701 702 // Simulate having two matches for this form, first comes from different 703 // signon realm, but reports the same origin and action as matched form. 704 // Second candidate has the same signon realm as the form, but has a different 705 // origin and action. Public suffix match is the most important criterion so 706 // the second candidate should be selected. 707 std::vector<PasswordForm*> results; 708 results.push_back(CreateSavedMatch(false)); 709 results.push_back(CreateSavedMatch(false)); 710 results[0]->original_signon_realm = "http://accounts2.google.com"; 711 results[1]->origin = GURL("http://accounts.google.com/a/ServiceLoginAuth2"); 712 results[1]->action = GURL("http://accounts.google.com/a/ServiceLogin2"); 713 SimulateFetchMatchingLoginsFromPasswordStore(manager.get()); 714 SimulateResponseFromPasswordStore(manager.get(), results); 715 EXPECT_EQ(1u, password_manager.GetLatestBestMatches().size()); 716 EXPECT_EQ("", password_manager.GetLatestBestMatches().begin() 717 ->second->original_signon_realm); 718} 719 720} // namespace password_manager 721