password_form_manager_unittest.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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_store.h" 15#include "components/password_manager/core/browser/password_form_manager.h" 16#include "components/password_manager/core/browser/password_manager.h" 17#include "components/password_manager/core/browser/password_manager_driver.h" 18#include "components/password_manager/core/browser/password_store.h" 19#include "components/password_manager/core/browser/stub_password_manager_client.h" 20#include "components/password_manager/core/browser/stub_password_manager_driver.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 MockPasswordManagerDriver : public StubPasswordManagerDriver { 49 public: 50 MOCK_METHOD0(IsOffTheRecord, bool()); 51 MOCK_METHOD1(AllowPasswordGenerationForForm, 52 void(const autofill::PasswordForm&)); 53}; 54 55class TestPasswordManagerClient : public StubPasswordManagerClient { 56 public: 57 explicit TestPasswordManagerClient(PasswordStore* password_store) 58 : password_store_(password_store) { 59 prefs_.registry()->RegisterBooleanPref(prefs::kPasswordManagerSavingEnabled, 60 true); 61 } 62 63 virtual void PromptUserToSavePassword(PasswordFormManager* form_to_save) 64 OVERRIDE {} 65 virtual PrefService* GetPrefs() OVERRIDE { return &prefs_; } 66 virtual PasswordStore* GetPasswordStore() OVERRIDE { return password_store_; } 67 virtual PasswordManagerDriver* GetDriver() OVERRIDE { return &driver_; } 68 virtual void AuthenticateAutofillAndFillForm( 69 scoped_ptr<autofill::PasswordFormFillData> fill_data) OVERRIDE { 70 driver_.FillPasswordForm(*fill_data.get()); 71 } 72 73 MockPasswordManagerDriver* GetMockDriver() { return &driver_; } 74 75 private: 76 TestingPrefServiceSimple prefs_; 77 PasswordStore* password_store_; 78 MockPasswordManagerDriver driver_; 79}; 80 81class TestPasswordManager : public PasswordManager { 82 public: 83 explicit TestPasswordManager(PasswordManagerClient* client) 84 : PasswordManager(client) {} 85 86 virtual void Autofill(const autofill::PasswordForm& form_for_autofill, 87 const autofill::PasswordFormMap& best_matches, 88 const autofill::PasswordForm& preferred_match, 89 bool wait_for_username) const OVERRIDE { 90 best_matches_ = best_matches; 91 } 92 93 const autofill::PasswordFormMap& GetLatestBestMatches() { 94 return best_matches_; 95 } 96 97 private: 98 // Marked mutable to get around constness of Autofill(). 99 mutable autofill::PasswordFormMap best_matches_; 100}; 101 102} // namespace 103 104class PasswordFormManagerTest : public testing::Test { 105 public: 106 PasswordFormManagerTest() : client_(NULL /*password_store*/) {} 107 108 virtual void SetUp() { 109 observed_form_.origin = GURL("http://accounts.google.com/a/LoginAuth"); 110 observed_form_.action = GURL("http://accounts.google.com/a/Login"); 111 observed_form_.username_element = ASCIIToUTF16("Email"); 112 observed_form_.password_element = ASCIIToUTF16("Passwd"); 113 observed_form_.submit_element = ASCIIToUTF16("signIn"); 114 observed_form_.signon_realm = "http://accounts.google.com"; 115 116 saved_match_ = observed_form_; 117 saved_match_.origin = GURL("http://accounts.google.com/a/ServiceLoginAuth"); 118 saved_match_.action = GURL("http://accounts.google.com/a/ServiceLogin"); 119 saved_match_.preferred = true; 120 saved_match_.username_value = ASCIIToUTF16("test@gmail.com"); 121 saved_match_.password_value = ASCIIToUTF16("test1"); 122 saved_match_.other_possible_usernames.push_back( 123 ASCIIToUTF16("test2@gmail.com")); 124 } 125 126 virtual void TearDown() { 127 if (mock_store_) 128 mock_store_->Shutdown(); 129 } 130 131 void InitializeMockStore() { 132 if (!mock_store_) { 133 mock_store_ = new MockPasswordStore(); 134 ASSERT_TRUE(mock_store_); 135 } 136 } 137 138 MockPasswordStore* mock_store() const { return mock_store_.get(); } 139 140 PasswordForm* GetPendingCredentials(PasswordFormManager* p) { 141 return &p->pending_credentials_; 142 } 143 144 void SimulateMatchingPhase(PasswordFormManager* p, bool find_match) { 145 // Roll up the state to mock out the matching phase. 146 p->state_ = PasswordFormManager::POST_MATCHING_PHASE; 147 if (!find_match) 148 return; 149 150 PasswordForm* match = new PasswordForm(saved_match_); 151 // Heap-allocated form is owned by p. 152 p->best_matches_[match->username_value] = match; 153 p->preferred_match_ = match; 154 } 155 156 void SimulateFetchMatchingLoginsFromPasswordStore( 157 PasswordFormManager* manager) { 158 // Just need to update the internal states. 159 manager->state_ = PasswordFormManager::MATCHING_PHASE; 160 } 161 162 void SimulateResponseFromPasswordStore( 163 PasswordFormManager* manager, 164 const std::vector<PasswordForm*>& result) { 165 // Simply call the callback method when request done. This will transfer 166 // the ownership of the objects in |result| to the |manager|. 167 manager->OnGetPasswordStoreResults(result); 168 } 169 170 void SanitizePossibleUsernames(PasswordFormManager* p, PasswordForm* form) { 171 p->SanitizePossibleUsernames(form); 172 } 173 174 bool IgnoredResult(PasswordFormManager* p, PasswordForm* form) { 175 return p->IgnoreResult(*form); 176 } 177 178 PasswordForm* observed_form() { return &observed_form_; } 179 PasswordForm* saved_match() { return &saved_match_; } 180 PasswordForm* CreateSavedMatch(bool blacklisted) { 181 // Owned by the caller of this method. 182 PasswordForm* match = new PasswordForm(saved_match_); 183 match->blacklisted_by_user = blacklisted; 184 return match; 185 } 186 187 TestPasswordManagerClient* client() { return &client_; } 188 189 private: 190 PasswordForm observed_form_; 191 PasswordForm saved_match_; 192 scoped_refptr<MockPasswordStore> mock_store_; 193 TestPasswordManagerClient client_; 194}; 195 196TEST_F(PasswordFormManagerTest, TestNewLogin) { 197 PasswordFormManager manager(NULL, client(), NULL, *observed_form(), false); 198 SimulateMatchingPhase(&manager, false); 199 200 // User submits credentials for the observed form. 201 PasswordForm credentials = *observed_form(); 202 credentials.username_value = saved_match()->username_value; 203 credentials.password_value = saved_match()->password_value; 204 credentials.preferred = true; 205 manager.ProvisionallySave( 206 credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 207 208 // Successful login. The PasswordManager would instruct PasswordFormManager 209 // to save, which should know this is a new login. 210 EXPECT_TRUE(manager.IsNewLogin()); 211 // Make sure the credentials that would be submitted on successful login 212 // are going to match the stored entry in the db. 213 EXPECT_EQ(observed_form()->origin.spec(), 214 GetPendingCredentials(&manager)->origin.spec()); 215 EXPECT_EQ(observed_form()->signon_realm, 216 GetPendingCredentials(&manager)->signon_realm); 217 EXPECT_EQ(observed_form()->action, GetPendingCredentials(&manager)->action); 218 EXPECT_TRUE(GetPendingCredentials(&manager)->preferred); 219 EXPECT_EQ(saved_match()->password_value, 220 GetPendingCredentials(&manager)->password_value); 221 EXPECT_EQ(saved_match()->username_value, 222 GetPendingCredentials(&manager)->username_value); 223 EXPECT_TRUE(GetPendingCredentials(&manager)->new_password_element.empty()); 224 EXPECT_TRUE(GetPendingCredentials(&manager)->new_password_value.empty()); 225 226 // Now, suppose the user re-visits the site and wants to save an additional 227 // login for the site with a new username. In this case, the matching phase 228 // will yield the previously saved login. 229 SimulateMatchingPhase(&manager, true); 230 // Set up the new login. 231 base::string16 new_user = ASCIIToUTF16("newuser"); 232 base::string16 new_pass = ASCIIToUTF16("newpass"); 233 credentials.username_value = new_user; 234 credentials.password_value = new_pass; 235 manager.ProvisionallySave( 236 credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 237 238 // Again, the PasswordFormManager should know this is still a new login. 239 EXPECT_TRUE(manager.IsNewLogin()); 240 // And make sure everything squares up again. 241 EXPECT_EQ(observed_form()->origin.spec(), 242 GetPendingCredentials(&manager)->origin.spec()); 243 EXPECT_EQ(observed_form()->signon_realm, 244 GetPendingCredentials(&manager)->signon_realm); 245 EXPECT_TRUE(GetPendingCredentials(&manager)->preferred); 246 EXPECT_EQ(new_pass, GetPendingCredentials(&manager)->password_value); 247 EXPECT_EQ(new_user, GetPendingCredentials(&manager)->username_value); 248 EXPECT_TRUE(GetPendingCredentials(&manager)->new_password_element.empty()); 249 EXPECT_TRUE(GetPendingCredentials(&manager)->new_password_value.empty()); 250} 251 252TEST_F(PasswordFormManagerTest, TestNewLoginFromNewPasswordElement) { 253 // Add a new password field to the test form. The PasswordFormManager should 254 // save the password from this field, instead of the current password field. 255 observed_form()->new_password_element = ASCIIToUTF16("NewPasswd"); 256 257 PasswordFormManager manager(NULL, client(), NULL, *observed_form(), false); 258 SimulateMatchingPhase(&manager, false); 259 260 // User enters current and new credentials to the observed form. 261 PasswordForm credentials(*observed_form()); 262 credentials.username_value = saved_match()->username_value; 263 credentials.password_value = saved_match()->password_value; 264 credentials.new_password_value = ASCIIToUTF16("newpassword"); 265 credentials.preferred = true; 266 manager.ProvisionallySave( 267 credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 268 269 // Successful login. The PasswordManager would instruct PasswordFormManager 270 // to save, which should know this is a new login. 271 EXPECT_TRUE(manager.IsNewLogin()); 272 EXPECT_EQ(credentials.origin, GetPendingCredentials(&manager)->origin); 273 EXPECT_EQ(credentials.signon_realm, 274 GetPendingCredentials(&manager)->signon_realm); 275 EXPECT_EQ(credentials.action, GetPendingCredentials(&manager)->action); 276 EXPECT_TRUE(GetPendingCredentials(&manager)->preferred); 277 EXPECT_EQ(credentials.username_value, 278 GetPendingCredentials(&manager)->username_value); 279 280 // By this point, the PasswordFormManager should have promoted the new 281 // password value to be the current password, and should have wiped the 282 // password element names: they are likely going to be different on a login 283 // form, so it is not worth remembering them. 284 EXPECT_EQ(credentials.new_password_value, 285 GetPendingCredentials(&manager)->password_value); 286 EXPECT_TRUE(GetPendingCredentials(&manager)->password_element.empty()); 287 EXPECT_TRUE(GetPendingCredentials(&manager)->new_password_element.empty()); 288 EXPECT_TRUE(GetPendingCredentials(&manager)->new_password_value.empty()); 289} 290 291TEST_F(PasswordFormManagerTest, TestUpdatePassword) { 292 // Create a PasswordFormManager with observed_form, as if we just 293 // saw this form and need to find matching logins. 294 PasswordFormManager manager(NULL, client(), NULL, *observed_form(), false); 295 296 SimulateMatchingPhase(&manager, true); 297 298 // User submits credentials for the observed form using a username previously 299 // stored, but a new password. Note that the observed form may have different 300 // origin URL (as it does in this case) than the saved_match, but we want to 301 // make sure the updated password is reflected in saved_match, because that is 302 // what we autofilled. 303 base::string16 new_pass = ASCIIToUTF16("test2"); 304 PasswordForm credentials = *observed_form(); 305 credentials.username_value = saved_match()->username_value; 306 credentials.password_value = new_pass; 307 credentials.preferred = true; 308 manager.ProvisionallySave( 309 credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 310 311 // Successful login. The PasswordManager would instruct PasswordFormManager 312 // to save, and since this is an update, it should know not to save as a new 313 // login. 314 EXPECT_FALSE(manager.IsNewLogin()); 315 316 // Make sure the credentials that would be submitted on successful login 317 // are going to match the stored entry in the db. (This verifies correct 318 // behaviour for bug 1074420). 319 EXPECT_EQ(GetPendingCredentials(&manager)->origin.spec(), 320 saved_match()->origin.spec()); 321 EXPECT_EQ(GetPendingCredentials(&manager)->signon_realm, 322 saved_match()->signon_realm); 323 EXPECT_TRUE(GetPendingCredentials(&manager)->preferred); 324 EXPECT_EQ(new_pass, GetPendingCredentials(&manager)->password_value); 325} 326 327TEST_F(PasswordFormManagerTest, TestUpdatePasswordFromNewPasswordElement) { 328 // Add a new password field to the test form. The PasswordFormManager should 329 // save the password from this field, instead of the current password field. 330 observed_form()->new_password_element = ASCIIToUTF16("NewPasswd"); 331 332 // Given that |observed_form| was most likely a change password form, it 333 // should not serve as a source for updating meta-information stored with the 334 // old credentials, such as element names, as they are likely going to be 335 // different between change password and login forms. To test this in depth, 336 // forcibly wipe |submit_element|, which should normally trigger updating this 337 // field from |observed_form| in the UpdateLogin() step as a special case. We 338 // will verify in the end that this did not happen. 339 saved_match()->submit_element.clear(); 340 341 InitializeMockStore(); 342 TestPasswordManagerClient client_with_store(mock_store()); 343 PasswordFormManager manager(NULL, 344 &client_with_store, 345 client_with_store.GetDriver(), 346 *observed_form(), 347 false); 348 EXPECT_CALL(*client_with_store.GetMockDriver(), IsOffTheRecord()) 349 .WillRepeatedly(Return(false)); 350 SimulateMatchingPhase(&manager, true); 351 352 // User submits current and new credentials to the observed form. 353 PasswordForm credentials(*observed_form()); 354 credentials.username_value = saved_match()->username_value; 355 credentials.password_value = saved_match()->password_value; 356 credentials.new_password_value = ASCIIToUTF16("test2"); 357 credentials.preferred = true; 358 manager.ProvisionallySave( 359 credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 360 361 // Successful login. The PasswordManager would instruct PasswordFormManager 362 // to save, and since this is an update, it should know not to save as a new 363 // login. 364 EXPECT_FALSE(manager.IsNewLogin()); 365 366 // By now, the PasswordFormManager should have promoted the new password value 367 // already to be the current password, and should no longer maintain any info 368 // about the new password. 369 EXPECT_EQ(credentials.new_password_value, 370 GetPendingCredentials(&manager)->password_value); 371 EXPECT_TRUE(GetPendingCredentials(&manager)->new_password_element.empty()); 372 EXPECT_TRUE(GetPendingCredentials(&manager)->new_password_value.empty()); 373 374 // Trigger saving to exercise some special case handling in UpdateLogin(). 375 PasswordForm new_credentials; 376 EXPECT_CALL(*mock_store(), UpdateLogin(_)) 377 .WillOnce(testing::SaveArg<0>(&new_credentials)); 378 manager.Save(); 379 Mock::VerifyAndClearExpectations(mock_store()); 380 381 // No meta-information should be updated, only the password. 382 EXPECT_EQ(credentials.new_password_value, new_credentials.password_value); 383 EXPECT_EQ(saved_match()->username_element, new_credentials.username_element); 384 EXPECT_EQ(saved_match()->password_element, new_credentials.password_element); 385 EXPECT_EQ(saved_match()->submit_element, new_credentials.submit_element); 386} 387 388TEST_F(PasswordFormManagerTest, TestIgnoreResult) { 389 PasswordFormManager manager(NULL, client(), NULL, *observed_form(), false); 390 391 // Make sure we don't match a PasswordForm if it was originally saved on 392 // an SSL-valid page and we are now on a page with invalid certificate. 393 saved_match()->ssl_valid = true; 394 EXPECT_TRUE(IgnoredResult(&manager, saved_match())); 395 396 saved_match()->ssl_valid = false; 397 // Different paths for action / origin are okay. 398 saved_match()->action = GURL("http://www.google.com/b/Login"); 399 saved_match()->origin = GURL("http://www.google.com/foo"); 400 EXPECT_FALSE(IgnoredResult(&manager, saved_match())); 401} 402 403TEST_F(PasswordFormManagerTest, TestEmptyAction) { 404 PasswordFormManager manager(NULL, client(), NULL, *observed_form(), false); 405 406 saved_match()->action = GURL(); 407 SimulateMatchingPhase(&manager, true); 408 // User logs in with the autofilled username / password from saved_match. 409 PasswordForm login = *observed_form(); 410 login.username_value = saved_match()->username_value; 411 login.password_value = saved_match()->password_value; 412 manager.ProvisionallySave( 413 login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 414 EXPECT_FALSE(manager.IsNewLogin()); 415 // We bless our saved PasswordForm entry with the action URL of the 416 // observed form. 417 EXPECT_EQ(observed_form()->action, GetPendingCredentials(&manager)->action); 418} 419 420TEST_F(PasswordFormManagerTest, TestUpdateAction) { 421 PasswordFormManager manager(NULL, client(), NULL, *observed_form(), false); 422 423 SimulateMatchingPhase(&manager, true); 424 // User logs in with the autofilled username / password from saved_match. 425 PasswordForm login = *observed_form(); 426 login.username_value = saved_match()->username_value; 427 login.password_value = saved_match()->password_value; 428 429 manager.ProvisionallySave( 430 login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 431 EXPECT_FALSE(manager.IsNewLogin()); 432 // The observed action URL is different from the previously saved one, and 433 // is the same as the one that would be submitted on successful login. 434 EXPECT_NE(observed_form()->action, saved_match()->action); 435 EXPECT_EQ(observed_form()->action, GetPendingCredentials(&manager)->action); 436} 437 438TEST_F(PasswordFormManagerTest, TestDynamicAction) { 439 PasswordFormManager manager(NULL, client(), NULL, *observed_form(), false); 440 441 SimulateMatchingPhase(&manager, false); 442 PasswordForm login(*observed_form()); 443 // The submitted action URL is different from the one observed on page load. 444 GURL new_action = GURL("http://www.google.com/new_action"); 445 login.action = new_action; 446 447 manager.ProvisionallySave( 448 login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 449 EXPECT_TRUE(manager.IsNewLogin()); 450 // Check that the provisionally saved action URL is the same as the submitted 451 // action URL, not the one observed on page load. 452 EXPECT_EQ(new_action, GetPendingCredentials(&manager)->action); 453} 454 455TEST_F(PasswordFormManagerTest, TestAlternateUsername) { 456 // Need a MessageLoop for callbacks. 457 base::MessageLoop message_loop; 458 scoped_refptr<TestPasswordStore> password_store = new TestPasswordStore; 459 CHECK(password_store->Init(syncer::SyncableService::StartSyncFlare(), "")); 460 461 TestPasswordManagerClient client_with_store(password_store.get()); 462 TestPasswordManager password_manager(&client_with_store); 463 PasswordFormManager manager(&password_manager, 464 &client_with_store, 465 client_with_store.GetDriver(), 466 *observed_form(), 467 false); 468 EXPECT_CALL(*client_with_store.GetMockDriver(), 469 AllowPasswordGenerationForForm(_)).Times(1); 470 EXPECT_CALL(*client_with_store.GetMockDriver(), IsOffTheRecord()) 471 .WillRepeatedly(Return(false)); 472 473 password_store->AddLogin(*saved_match()); 474 manager.FetchMatchingLoginsFromPasswordStore(PasswordStore::ALLOW_PROMPT); 475 RunAllPendingTasks(); 476 477 // The saved match has the right username already. 478 PasswordForm login(*observed_form()); 479 login.username_value = saved_match()->username_value; 480 login.password_value = saved_match()->password_value; 481 login.preferred = true; 482 manager.ProvisionallySave( 483 login, PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES); 484 485 EXPECT_FALSE(manager.IsNewLogin()); 486 manager.Save(); 487 RunAllPendingTasks(); 488 489 // Should be only one password stored, and should not have 490 // |other_possible_usernames| set anymore. 491 TestPasswordStore::PasswordMap passwords = password_store->stored_passwords(); 492 EXPECT_EQ(1U, passwords.size()); 493 ASSERT_EQ(1U, passwords[saved_match()->signon_realm].size()); 494 EXPECT_EQ(saved_match()->username_value, 495 passwords[saved_match()->signon_realm][0].username_value); 496 EXPECT_EQ(0U, 497 passwords[saved_match()->signon_realm][0] 498 .other_possible_usernames.size()); 499 500 // This time use an alternate username 501 PasswordFormManager manager_alt(&password_manager, 502 &client_with_store, 503 client_with_store.GetDriver(), 504 *observed_form(), 505 false); 506 EXPECT_CALL(*client_with_store.GetMockDriver(), 507 AllowPasswordGenerationForForm(_)).Times(1); 508 password_store->Clear(); 509 password_store->AddLogin(*saved_match()); 510 manager_alt.FetchMatchingLoginsFromPasswordStore(PasswordStore::ALLOW_PROMPT); 511 RunAllPendingTasks(); 512 513 base::string16 new_username = saved_match()->other_possible_usernames[0]; 514 login.username_value = new_username; 515 manager_alt.ProvisionallySave( 516 login, PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES); 517 518 EXPECT_FALSE(manager_alt.IsNewLogin()); 519 manager_alt.Save(); 520 RunAllPendingTasks(); 521 522 // |other_possible_usernames| should also be empty, but username_value should 523 // be changed to match |new_username| 524 passwords = password_store->stored_passwords(); 525 EXPECT_EQ(1U, passwords.size()); 526 ASSERT_EQ(1U, passwords[saved_match()->signon_realm].size()); 527 EXPECT_EQ(new_username, 528 passwords[saved_match()->signon_realm][0].username_value); 529 EXPECT_EQ(0U, 530 passwords[saved_match()->signon_realm][0] 531 .other_possible_usernames.size()); 532 password_store->Shutdown(); 533} 534 535TEST_F(PasswordFormManagerTest, TestValidForms) { 536 // User submits credentials for the observed form. 537 PasswordForm credentials = *observed_form(); 538 credentials.scheme = PasswordForm::SCHEME_HTML; 539 credentials.username_value = saved_match()->username_value; 540 credentials.password_value = saved_match()->password_value; 541 542 // An alternate version of the form that also has a new_password_element. 543 PasswordForm new_credentials(*observed_form()); 544 new_credentials.new_password_element = ASCIIToUTF16("NewPasswd"); 545 new_credentials.new_password_value = ASCIIToUTF16("test1new"); 546 547 // Form with both username_element and password_element. 548 PasswordFormManager manager1(NULL, NULL, NULL, credentials, false); 549 SimulateMatchingPhase(&manager1, false); 550 EXPECT_TRUE(manager1.HasValidPasswordForm()); 551 552 // Form with username_element, password_element, and new_password_element. 553 PasswordFormManager manager2(NULL, NULL, NULL, new_credentials, false); 554 SimulateMatchingPhase(&manager2, false); 555 EXPECT_TRUE(manager2.HasValidPasswordForm()); 556 557 // Form with username_element and only new_password_element. 558 new_credentials.password_element.clear(); 559 PasswordFormManager manager3(NULL, NULL, NULL, new_credentials, false); 560 SimulateMatchingPhase(&manager3, false); 561 EXPECT_TRUE(manager3.HasValidPasswordForm()); 562 563 // Form without a username_element but with a password_element. 564 credentials.username_element.clear(); 565 PasswordFormManager manager4(NULL, NULL, NULL, credentials, false); 566 SimulateMatchingPhase(&manager4, false); 567 EXPECT_FALSE(manager4.HasValidPasswordForm()); 568 569 // Form without a username_element but with a new_password_element. 570 new_credentials.username_element.clear(); 571 PasswordFormManager manager5(NULL, NULL, NULL, new_credentials, false); 572 SimulateMatchingPhase(&manager5, false); 573 EXPECT_FALSE(manager5.HasValidPasswordForm()); 574 575 // Form without a password_element but with a username_element. 576 credentials.username_element = saved_match()->username_element; 577 credentials.password_element.clear(); 578 PasswordFormManager manager6(NULL, NULL, NULL, credentials, false); 579 SimulateMatchingPhase(&manager6, false); 580 EXPECT_FALSE(manager6.HasValidPasswordForm()); 581 582 // Form with neither a password_element nor a username_element. 583 credentials.username_element.clear(); 584 credentials.password_element.clear(); 585 PasswordFormManager manager7(NULL, NULL, NULL, credentials, false); 586 SimulateMatchingPhase(&manager7, false); 587 EXPECT_FALSE(manager7.HasValidPasswordForm()); 588} 589 590TEST_F(PasswordFormManagerTest, TestValidFormsBasic) { 591 // User submits credentials for the observed form. 592 PasswordForm credentials = *observed_form(); 593 credentials.scheme = PasswordForm::SCHEME_BASIC; 594 credentials.username_value = saved_match()->username_value; 595 credentials.password_value = saved_match()->password_value; 596 597 // Form with both username_element and password_element. 598 PasswordFormManager manager1(NULL, NULL, NULL, credentials, false); 599 SimulateMatchingPhase(&manager1, false); 600 EXPECT_TRUE(manager1.HasValidPasswordForm()); 601 602 // Form without a username_element but with a password_element. 603 credentials.username_element.clear(); 604 PasswordFormManager manager2(NULL, NULL, NULL, credentials, false); 605 SimulateMatchingPhase(&manager2, false); 606 EXPECT_TRUE(manager2.HasValidPasswordForm()); 607 608 // Form without a password_element but with a username_element. 609 credentials.username_element = saved_match()->username_element; 610 credentials.password_element.clear(); 611 PasswordFormManager manager3(NULL, NULL, NULL, credentials, false); 612 SimulateMatchingPhase(&manager3, false); 613 EXPECT_TRUE(manager3.HasValidPasswordForm()); 614 615 // Form with neither a password_element nor a username_element. 616 credentials.username_element.clear(); 617 credentials.password_element.clear(); 618 PasswordFormManager manager4(NULL, NULL, NULL, credentials, false); 619 SimulateMatchingPhase(&manager4, false); 620 EXPECT_TRUE(manager4.HasValidPasswordForm()); 621} 622 623TEST_F(PasswordFormManagerTest, TestSendNotBlacklistedMessage) { 624 base::MessageLoop message_loop; 625 626 TestPasswordManager password_manager(client()); 627 PasswordFormManager manager_no_creds(&password_manager, 628 client(), 629 client()->GetDriver(), 630 *observed_form(), 631 false); 632 633 // First time sign-up attempt. Password store does not contain matching 634 // credentials. AllowPasswordGenerationForForm should be called to send the 635 // "not blacklisted" message. 636 EXPECT_CALL(*(client()->GetMockDriver()), AllowPasswordGenerationForForm(_)) 637 .Times(1); 638 SimulateFetchMatchingLoginsFromPasswordStore(&manager_no_creds); 639 std::vector<PasswordForm*> result; 640 SimulateResponseFromPasswordStore(&manager_no_creds, result); 641 Mock::VerifyAndClearExpectations(client()->GetMockDriver()); 642 643 // Signing up on a previously visited site. Credentials are found in the 644 // password store, and are not blacklisted. AllowPasswordGenerationForForm 645 // should be called to send the "not blacklisted" message. 646 PasswordFormManager manager_creds(&password_manager, 647 client(), 648 client()->GetDriver(), 649 *observed_form(), 650 false); 651 EXPECT_CALL(*(client()->GetMockDriver()), AllowPasswordGenerationForForm(_)) 652 .Times(1); 653 EXPECT_CALL(*(client()->GetMockDriver()), IsOffTheRecord()) 654 .WillRepeatedly(Return(false)); 655 SimulateFetchMatchingLoginsFromPasswordStore(&manager_creds); 656 // We need add heap allocated objects to result. 657 result.push_back(CreateSavedMatch(false)); 658 SimulateResponseFromPasswordStore(&manager_creds, result); 659 Mock::VerifyAndClearExpectations(client()->GetMockDriver()); 660 661 // Signing up on a previously visited site. Credentials are found in the 662 // password store, but they are blacklisted. AllowPasswordGenerationForForm 663 // should not be called and no "not blacklisted" message sent. 664 PasswordFormManager manager_blacklisted(&password_manager, 665 client(), 666 client()->GetDriver(), 667 *observed_form(), 668 false); 669 EXPECT_CALL(*(client()->GetMockDriver()), AllowPasswordGenerationForForm(_)) 670 .Times(0); 671 SimulateFetchMatchingLoginsFromPasswordStore(&manager_blacklisted); 672 result.clear(); 673 result.push_back(CreateSavedMatch(true)); 674 SimulateResponseFromPasswordStore(&manager_blacklisted, result); 675 Mock::VerifyAndClearExpectations(client()->GetMockDriver()); 676} 677 678TEST_F(PasswordFormManagerTest, TestForceInclusionOfGeneratedPasswords) { 679 base::MessageLoop message_loop; 680 681 // Simulate having two matches for this origin, one of which was from a form 682 // with different HTML tags for elements. Because of scoring differences, 683 // only the first form will be sent to Autofill(). 684 TestPasswordManager password_manager(client()); 685 PasswordFormManager manager_match(&password_manager, 686 client(), 687 client()->GetDriver(), 688 *observed_form(), 689 false); 690 EXPECT_CALL(*(client()->GetMockDriver()), AllowPasswordGenerationForForm(_)) 691 .Times(1); 692 EXPECT_CALL(*(client()->GetMockDriver()), IsOffTheRecord()) 693 .WillRepeatedly(Return(false)); 694 695 std::vector<PasswordForm*> results; 696 results.push_back(CreateSavedMatch(false)); 697 results.push_back(CreateSavedMatch(false)); 698 results[1]->username_value = ASCIIToUTF16("other@gmail.com"); 699 results[1]->password_element = ASCIIToUTF16("signup_password"); 700 results[1]->username_element = ASCIIToUTF16("signup_username"); 701 SimulateFetchMatchingLoginsFromPasswordStore(&manager_match); 702 SimulateResponseFromPasswordStore(&manager_match, results); 703 EXPECT_EQ(1u, password_manager.GetLatestBestMatches().size()); 704 results.clear(); 705 706 // Same thing, except this time the credentials that don't match quite as 707 // well are generated. They should now be sent to Autofill(). 708 PasswordFormManager manager_no_match(&password_manager, 709 client(), 710 client()->GetDriver(), 711 *observed_form(), 712 false); 713 EXPECT_CALL(*(client()->GetMockDriver()), AllowPasswordGenerationForForm(_)) 714 .Times(1); 715 716 results.push_back(CreateSavedMatch(false)); 717 results.push_back(CreateSavedMatch(false)); 718 results[1]->username_value = ASCIIToUTF16("other@gmail.com"); 719 results[1]->password_element = ASCIIToUTF16("signup_password"); 720 results[1]->username_element = ASCIIToUTF16("signup_username"); 721 results[1]->type = PasswordForm::TYPE_GENERATED; 722 SimulateFetchMatchingLoginsFromPasswordStore(&manager_no_match); 723 SimulateResponseFromPasswordStore(&manager_no_match, results); 724 EXPECT_EQ(2u, password_manager.GetLatestBestMatches().size()); 725} 726 727TEST_F(PasswordFormManagerTest, TestSanitizePossibleUsernames) { 728 PasswordFormManager manager(NULL, client(), NULL, *observed_form(), false); 729 PasswordForm credentials(*observed_form()); 730 credentials.other_possible_usernames.push_back(ASCIIToUTF16("543-43-1234")); 731 credentials.other_possible_usernames.push_back( 732 ASCIIToUTF16("378282246310005")); 733 credentials.other_possible_usernames.push_back( 734 ASCIIToUTF16("other username")); 735 credentials.username_value = ASCIIToUTF16("test@gmail.com"); 736 737 SanitizePossibleUsernames(&manager, &credentials); 738 739 // Possible credit card number and SSN are stripped. 740 std::vector<base::string16> expected; 741 expected.push_back(ASCIIToUTF16("other username")); 742 EXPECT_THAT(credentials.other_possible_usernames, Eq(expected)); 743 744 credentials.other_possible_usernames.clear(); 745 credentials.other_possible_usernames.push_back(ASCIIToUTF16("511-32-9830")); 746 credentials.other_possible_usernames.push_back(ASCIIToUTF16("duplicate")); 747 credentials.other_possible_usernames.push_back(ASCIIToUTF16("duplicate")); 748 credentials.other_possible_usernames.push_back(ASCIIToUTF16("random")); 749 credentials.other_possible_usernames.push_back( 750 ASCIIToUTF16("test@gmail.com")); 751 752 SanitizePossibleUsernames(&manager, &credentials); 753 754 // SSN, duplicate in |other_possible_usernames| and duplicate of 755 // |username_value| all removed. 756 expected.clear(); 757 expected.push_back(ASCIIToUTF16("duplicate")); 758 expected.push_back(ASCIIToUTF16("random")); 759 EXPECT_THAT(credentials.other_possible_usernames, Eq(expected)); 760} 761 762TEST_F(PasswordFormManagerTest, TestUpdateIncompleteCredentials) { 763 InitializeMockStore(); 764 765 // We've found this form on a website: 766 PasswordForm encountered_form; 767 encountered_form.origin = GURL("http://accounts.google.com/LoginAuth"); 768 encountered_form.signon_realm = "http://accounts.google.com/"; 769 encountered_form.action = GURL("http://accounts.google.com/Login"); 770 encountered_form.username_element = ASCIIToUTF16("Email"); 771 encountered_form.password_element = ASCIIToUTF16("Passwd"); 772 encountered_form.submit_element = ASCIIToUTF16("signIn"); 773 774 TestPasswordManagerClient client_with_store(mock_store()); 775 EXPECT_CALL(*(client_with_store.GetMockDriver()), IsOffTheRecord()) 776 .WillRepeatedly(Return(false)); 777 EXPECT_CALL(*(client_with_store.GetMockDriver()), 778 AllowPasswordGenerationForForm(_)); 779 780 TestPasswordManager manager(&client_with_store); 781 PasswordFormManager form_manager(&manager, 782 &client_with_store, 783 client_with_store.GetMockDriver(), 784 encountered_form, 785 false); 786 787 const PasswordStore::AuthorizationPromptPolicy auth_policy = 788 PasswordStore::DISALLOW_PROMPT; 789 EXPECT_CALL(*mock_store(), 790 GetLogins(encountered_form, auth_policy, &form_manager)); 791 form_manager.FetchMatchingLoginsFromPasswordStore(auth_policy); 792 793 // Password store only has these incomplete credentials. 794 PasswordForm* incomplete_form = new PasswordForm(); 795 incomplete_form->origin = GURL("http://accounts.google.com/LoginAuth"); 796 incomplete_form->signon_realm = "http://accounts.google.com/"; 797 incomplete_form->password_value = ASCIIToUTF16("my_password"); 798 incomplete_form->username_value = ASCIIToUTF16("my_username"); 799 incomplete_form->preferred = true; 800 incomplete_form->ssl_valid = false; 801 incomplete_form->scheme = PasswordForm::SCHEME_HTML; 802 803 // We expect to see this form eventually sent to the Password store. It 804 // has password/username values from the store and 'username_element', 805 // 'password_element', 'submit_element' and 'action' fields copied from 806 // the encountered form. 807 PasswordForm complete_form(*incomplete_form); 808 complete_form.action = encountered_form.action; 809 complete_form.password_element = encountered_form.password_element; 810 complete_form.username_element = encountered_form.username_element; 811 complete_form.submit_element = encountered_form.submit_element; 812 813 PasswordForm obsolete_form(*incomplete_form); 814 obsolete_form.action = encountered_form.action; 815 816 // Feed the incomplete credentials to the manager. 817 std::vector<PasswordForm*> results; 818 results.push_back(incomplete_form); // Takes ownership. 819 form_manager.OnRequestDone(results); 820 821 form_manager.ProvisionallySave( 822 complete_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 823 // By now that form has been used once. 824 complete_form.times_used = 1; 825 obsolete_form.times_used = 1; 826 827 // Check that PasswordStore receives an update request with the complete form. 828 EXPECT_CALL(*mock_store(), RemoveLogin(obsolete_form)); 829 EXPECT_CALL(*mock_store(), AddLogin(complete_form)); 830 form_manager.Save(); 831} 832 833TEST_F(PasswordFormManagerTest, TestScoringPublicSuffixMatch) { 834 base::MessageLoop message_loop; 835 836 EXPECT_CALL(*(client()->GetMockDriver()), IsOffTheRecord()) 837 .WillRepeatedly(Return(false)); 838 EXPECT_CALL(*(client()->GetMockDriver()), AllowPasswordGenerationForForm(_)); 839 840 TestPasswordManager password_manager(client()); 841 PasswordFormManager manager(&password_manager, 842 client(), 843 client()->GetMockDriver(), 844 *observed_form(), 845 false); 846 847 // Simulate having two matches for this form, first comes from different 848 // signon realm, but reports the same origin and action as matched form. 849 // Second candidate has the same signon realm as the form, but has a different 850 // origin and action. Public suffix match is the most important criterion so 851 // the second candidate should be selected. 852 std::vector<PasswordForm*> results; 853 results.push_back(CreateSavedMatch(false)); 854 results.push_back(CreateSavedMatch(false)); 855 results[0]->original_signon_realm = "http://accounts2.google.com"; 856 results[1]->origin = GURL("http://accounts.google.com/a/ServiceLoginAuth2"); 857 results[1]->action = GURL("http://accounts.google.com/a/ServiceLogin2"); 858 SimulateFetchMatchingLoginsFromPasswordStore(&manager); 859 SimulateResponseFromPasswordStore(&manager, results); 860 EXPECT_EQ(1u, password_manager.GetLatestBestMatches().size()); 861 EXPECT_EQ("", password_manager.GetLatestBestMatches().begin() 862 ->second->original_signon_realm); 863} 864 865TEST_F(PasswordFormManagerTest, InvalidActionURLsDoNotMatch) { 866 PasswordFormManager manager(NULL, client(), NULL, *observed_form(), false); 867 868 PasswordForm invalid_action_form(*observed_form()); 869 invalid_action_form.action = GURL("http://"); 870 ASSERT_FALSE(invalid_action_form.action.is_valid()); 871 ASSERT_FALSE(invalid_action_form.action.is_empty()); 872 // Non-empty invalid action URLs should not match other actions. 873 // First when the compared form has an invalid URL: 874 EXPECT_EQ(0, 875 manager.DoesManage(invalid_action_form) & 876 PasswordFormManager::RESULT_ACTION_MATCH); 877 // Then when the observed form has an invalid URL: 878 PasswordForm valid_action_form(*observed_form()); 879 PasswordFormManager invalid_manager( 880 NULL, client(), NULL, invalid_action_form, false); 881 EXPECT_EQ(0, 882 invalid_manager.DoesManage(valid_action_form) & 883 PasswordFormManager::RESULT_ACTION_MATCH); 884} 885 886TEST_F(PasswordFormManagerTest, EmptyActionURLsDoNotMatchNonEmpty) { 887 PasswordFormManager manager(NULL, client(), NULL, *observed_form(), false); 888 889 PasswordForm empty_action_form(*observed_form()); 890 empty_action_form.action = GURL(); 891 ASSERT_FALSE(empty_action_form.action.is_valid()); 892 ASSERT_TRUE(empty_action_form.action.is_empty()); 893 // First when the compared form has an empty URL: 894 EXPECT_EQ(0, 895 manager.DoesManage(empty_action_form) & 896 PasswordFormManager::RESULT_ACTION_MATCH); 897 // Then when the observed form has an empty URL: 898 PasswordForm valid_action_form(*observed_form()); 899 PasswordFormManager empty_action_manager( 900 NULL, client(), NULL, empty_action_form, false); 901 EXPECT_EQ(0, 902 empty_action_manager.DoesManage(valid_action_form) & 903 PasswordFormManager::RESULT_ACTION_MATCH); 904} 905 906TEST_F(PasswordFormManagerTest, NonHTMLFormsDoNotMatchHTMLForms) { 907 PasswordFormManager manager(NULL, client(), NULL, *observed_form(), false); 908 909 ASSERT_EQ(PasswordForm::SCHEME_HTML, observed_form()->scheme); 910 PasswordForm non_html_form(*observed_form()); 911 non_html_form.scheme = PasswordForm::SCHEME_DIGEST; 912 EXPECT_EQ(0, 913 manager.DoesManage(non_html_form) & 914 PasswordFormManager::RESULT_MANDATORY_ATTRIBUTES_MATCH); 915 916 // The other way round: observing a non-HTML form, don't match a HTML form. 917 PasswordForm html_form(*observed_form()); 918 PasswordFormManager non_html_manager( 919 NULL, client(), NULL, non_html_form, false); 920 EXPECT_EQ(0, 921 non_html_manager.DoesManage(html_form) & 922 PasswordFormManager::RESULT_MANDATORY_ATTRIBUTES_MATCH); 923} 924 925TEST_F(PasswordFormManagerTest, OriginCheck_HostsMatchExactly) { 926 // Host part of origins must match exactly, not just by prefix. 927 PasswordFormManager manager(NULL, client(), NULL, *observed_form(), false); 928 929 PasswordForm form_longer_host(*observed_form()); 930 form_longer_host.origin = GURL("http://accounts.google.com.au/a/LoginAuth"); 931 // Check that accounts.google.com does not match accounts.google.com.au. 932 EXPECT_EQ(0, 933 manager.DoesManage(form_longer_host) & 934 PasswordFormManager::RESULT_MANDATORY_ATTRIBUTES_MATCH); 935} 936 937TEST_F(PasswordFormManagerTest, OriginCheck_MoreSecureSchemePathsMatchPrefix) { 938 // If the URL scheme of the observed form is HTTP, and the compared form is 939 // HTTPS, then the compared form can extend the path. 940 PasswordFormManager manager(NULL, client(), NULL, *observed_form(), false); 941 942 PasswordForm form_longer_path(*observed_form()); 943 form_longer_path.origin = GURL("https://accounts.google.com/a/LoginAuth/sec"); 944 EXPECT_NE(0, 945 manager.DoesManage(form_longer_path) & 946 PasswordFormManager::RESULT_MANDATORY_ATTRIBUTES_MATCH); 947} 948 949TEST_F(PasswordFormManagerTest, 950 OriginCheck_NotMoreSecureSchemePathsMatchExactly) { 951 // If the origin URL scheme of the compared form is not more secure than that 952 // of the observed form, then the paths must match exactly. 953 PasswordFormManager manager(NULL, client(), NULL, *observed_form(), false); 954 955 PasswordForm form_longer_path(*observed_form()); 956 form_longer_path.origin = GURL("http://accounts.google.com/a/LoginAuth/sec"); 957 // Check that /a/LoginAuth does not match /a/LoginAuth/more. 958 EXPECT_EQ(0, 959 manager.DoesManage(form_longer_path) & 960 PasswordFormManager::RESULT_MANDATORY_ATTRIBUTES_MATCH); 961 962 PasswordForm secure_observed_form(*observed_form()); 963 secure_observed_form.origin = GURL("https://accounts.google.com/a/LoginAuth"); 964 PasswordFormManager secure_manager( 965 NULL, client(), NULL, secure_observed_form, true); 966 // Also for HTTPS in the observed form, and HTTP in the compared form, an 967 // exact path match is expected. 968 EXPECT_EQ(0, 969 secure_manager.DoesManage(form_longer_path) & 970 PasswordFormManager::RESULT_MANDATORY_ATTRIBUTES_MATCH); 971 // Not even upgrade to HTTPS in the compared form should help. 972 form_longer_path.origin = GURL("https://accounts.google.com/a/LoginAuth/sec"); 973 EXPECT_EQ(0, 974 secure_manager.DoesManage(form_longer_path) & 975 PasswordFormManager::RESULT_MANDATORY_ATTRIBUTES_MATCH); 976} 977 978} // namespace password_manager 979