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 "testing/gtest/include/gtest/gtest.h" 6 7 #include "base/memory/scoped_ptr.h" 8 #include "base/message_loop/message_loop.h" 9 #include "base/strings/string_util.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "chrome/browser/password_manager/password_form_manager.h" 12 #include "chrome/browser/password_manager/password_manager.h" 13 #include "chrome/browser/password_manager/password_manager_delegate.h" 14 #include "chrome/browser/password_manager/password_store.h" 15 #include "chrome/browser/password_manager/password_store_factory.h" 16 #include "chrome/browser/password_manager/test_password_store.h" 17 #include "chrome/browser/profiles/profile_manager.h" 18 #include "chrome/test/base/testing_profile.h" 19 #include "content/public/common/password_form.h" 20 #include "content/public/test/test_utils.h" 21 #include "testing/gmock/include/gmock/gmock.h" 22 23 using content::PasswordForm; 24 25 using ::testing::Eq; 26 27 class TestPasswordManagerDelegate : public PasswordManagerDelegate { 28 public: 29 explicit TestPasswordManagerDelegate(Profile* profile) : profile_(profile) {} 30 31 virtual void FillPasswordForm( 32 const autofill::PasswordFormFillData& form_data) OVERRIDE {} 33 virtual void AddSavePasswordInfoBarIfPermitted( 34 PasswordFormManager* form_to_save) OVERRIDE {} 35 virtual Profile* GetProfile() OVERRIDE { return profile_; } 36 virtual bool DidLastPageLoadEncounterSSLErrors() OVERRIDE { return false; } 37 38 private: 39 Profile* profile_; 40 }; 41 42 class TestPasswordManager : public PasswordManager { 43 public: 44 explicit TestPasswordManager(PasswordManagerDelegate* delegate) 45 : PasswordManager(NULL, delegate) {} 46 47 virtual void Autofill( 48 const content::PasswordForm& form_for_autofill, 49 const content::PasswordFormMap& best_matches, 50 const content::PasswordForm& preferred_match, 51 bool wait_for_username) const OVERRIDE {} 52 }; 53 54 class TestPasswordFormManager : public PasswordFormManager { 55 public: 56 TestPasswordFormManager(Profile* profile, 57 PasswordManager* manager, 58 const content::PasswordForm& observed_form, 59 bool ssl_valid) 60 : PasswordFormManager(profile, manager, NULL, observed_form, ssl_valid), 61 num_sent_messages_(0) {} 62 63 virtual void SendNotBlacklistedToRenderer() OVERRIDE { 64 ++num_sent_messages_; 65 } 66 67 size_t num_sent_messages() { 68 return num_sent_messages_; 69 } 70 71 private: 72 size_t num_sent_messages_; 73 }; 74 75 class PasswordFormManagerTest : public testing::Test { 76 public: 77 PasswordFormManagerTest() { 78 } 79 virtual void SetUp() { 80 observed_form_.origin = GURL("http://accounts.google.com/a/LoginAuth"); 81 observed_form_.action = GURL("http://accounts.google.com/a/Login"); 82 observed_form_.username_element = ASCIIToUTF16("Email"); 83 observed_form_.password_element = ASCIIToUTF16("Passwd"); 84 observed_form_.submit_element = ASCIIToUTF16("signIn"); 85 observed_form_.signon_realm = "http://accounts.google.com"; 86 87 saved_match_ = observed_form_; 88 saved_match_.origin = GURL("http://accounts.google.com/a/ServiceLoginAuth"); 89 saved_match_.action = GURL("http://accounts.google.com/a/ServiceLogin"); 90 saved_match_.preferred = true; 91 saved_match_.username_value = ASCIIToUTF16("test (at) gmail.com"); 92 saved_match_.password_value = ASCIIToUTF16("test1"); 93 saved_match_.other_possible_usernames.push_back( 94 ASCIIToUTF16("test2 (at) gmail.com")); 95 profile_ = new TestingProfile(); 96 } 97 98 virtual void TearDown() { 99 delete profile_; 100 } 101 102 PasswordForm* GetPendingCredentials(PasswordFormManager* p) { 103 return &p->pending_credentials_; 104 } 105 106 void SimulateMatchingPhase(PasswordFormManager* p, bool find_match) { 107 // Roll up the state to mock out the matching phase. 108 p->state_ = PasswordFormManager::POST_MATCHING_PHASE; 109 if (!find_match) 110 return; 111 112 PasswordForm* match = new PasswordForm(saved_match_); 113 // Heap-allocated form is owned by p. 114 p->best_matches_[match->username_value] = match; 115 p->preferred_match_ = match; 116 } 117 118 void SimulateFetchMatchingLoginsFromPasswordStore( 119 PasswordFormManager* manager) { 120 // Just need to update the internal states. 121 manager->state_ = PasswordFormManager::MATCHING_PHASE; 122 } 123 124 void SimulateResponseFromPasswordStore( 125 PasswordFormManager* manager, 126 const std::vector<PasswordForm*>& result) { 127 // Simply call the callback method when request done. This will transfer 128 // the ownership of the objects in |result| to the |manager|. 129 manager->OnGetPasswordStoreResults(result); 130 } 131 132 void SanitizePossibleUsernames(PasswordFormManager* p, PasswordForm* form) { 133 p->SanitizePossibleUsernames(form); 134 } 135 136 bool IgnoredResult(PasswordFormManager* p, PasswordForm* form) { 137 return p->IgnoreResult(*form); 138 } 139 140 Profile* profile() { return profile_; } 141 142 PasswordForm* observed_form() { return &observed_form_; } 143 PasswordForm* saved_match() { return &saved_match_; } 144 PasswordForm* CreateSavedMatch(bool blacklisted) { 145 // Owned by the caller of this method. 146 PasswordForm* match = new PasswordForm(saved_match_); 147 match->blacklisted_by_user = blacklisted; 148 return match; 149 } 150 151 private: 152 PasswordForm observed_form_; 153 PasswordForm saved_match_; 154 Profile* profile_; 155 }; 156 157 TEST_F(PasswordFormManagerTest, TestNewLogin) { 158 PasswordFormManager* manager = new PasswordFormManager( 159 profile(), NULL, NULL, *observed_form(), false); 160 SimulateMatchingPhase(manager, false); 161 // User submits credentials for the observed form. 162 PasswordForm credentials = *observed_form(); 163 credentials.username_value = saved_match()->username_value; 164 credentials.password_value = saved_match()->password_value; 165 credentials.preferred = true; 166 manager->ProvisionallySave( 167 credentials, 168 PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 169 170 // Successful login. The PasswordManager would instruct PasswordFormManager 171 // to save, which should know this is a new login. 172 EXPECT_TRUE(manager->IsNewLogin()); 173 // Make sure the credentials that would be submitted on successful login 174 // are going to match the stored entry in the db. 175 EXPECT_EQ(observed_form()->origin.spec(), 176 GetPendingCredentials(manager)->origin.spec()); 177 EXPECT_EQ(observed_form()->signon_realm, 178 GetPendingCredentials(manager)->signon_realm); 179 EXPECT_EQ(observed_form()->action, 180 GetPendingCredentials(manager)->action); 181 EXPECT_TRUE(GetPendingCredentials(manager)->preferred); 182 EXPECT_EQ(saved_match()->password_value, 183 GetPendingCredentials(manager)->password_value); 184 EXPECT_EQ(saved_match()->username_value, 185 GetPendingCredentials(manager)->username_value); 186 187 // Now, suppose the user re-visits the site and wants to save an additional 188 // login for the site with a new username. In this case, the matching phase 189 // will yield the previously saved login. 190 SimulateMatchingPhase(manager, true); 191 // Set up the new login. 192 string16 new_user = ASCIIToUTF16("newuser"); 193 string16 new_pass = ASCIIToUTF16("newpass"); 194 credentials.username_value = new_user; 195 credentials.password_value = new_pass; 196 manager->ProvisionallySave( 197 credentials, 198 PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 199 200 // Again, the PasswordFormManager should know this is still a new login. 201 EXPECT_TRUE(manager->IsNewLogin()); 202 // And make sure everything squares up again. 203 EXPECT_EQ(observed_form()->origin.spec(), 204 GetPendingCredentials(manager)->origin.spec()); 205 EXPECT_EQ(observed_form()->signon_realm, 206 GetPendingCredentials(manager)->signon_realm); 207 EXPECT_TRUE(GetPendingCredentials(manager)->preferred); 208 EXPECT_EQ(new_pass, 209 GetPendingCredentials(manager)->password_value); 210 EXPECT_EQ(new_user, 211 GetPendingCredentials(manager)->username_value); 212 // Done. 213 delete manager; 214 } 215 216 TEST_F(PasswordFormManagerTest, TestUpdatePassword) { 217 // Create a PasswordFormManager with observed_form, as if we just 218 // saw this form and need to find matching logins. 219 PasswordFormManager* manager = new PasswordFormManager( 220 profile(), NULL, NULL, *observed_form(), false); 221 SimulateMatchingPhase(manager, true); 222 223 // User submits credentials for the observed form using a username previously 224 // stored, but a new password. Note that the observed form may have different 225 // origin URL (as it does in this case) than the saved_match, but we want to 226 // make sure the updated password is reflected in saved_match, because that is 227 // what we autofilled. 228 string16 new_pass = ASCIIToUTF16("newpassword"); 229 PasswordForm credentials = *observed_form(); 230 credentials.username_value = saved_match()->username_value; 231 credentials.password_value = new_pass; 232 credentials.preferred = true; 233 manager->ProvisionallySave( 234 credentials, 235 PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 236 237 // Successful login. The PasswordManager would instruct PasswordFormManager 238 // to save, and since this is an update, it should know not to save as a new 239 // login. 240 EXPECT_FALSE(manager->IsNewLogin()); 241 242 // Make sure the credentials that would be submitted on successful login 243 // are going to match the stored entry in the db. (This verifies correct 244 // behaviour for bug 1074420). 245 EXPECT_EQ(GetPendingCredentials(manager)->origin.spec(), 246 saved_match()->origin.spec()); 247 EXPECT_EQ(GetPendingCredentials(manager)->signon_realm, 248 saved_match()->signon_realm); 249 EXPECT_TRUE(GetPendingCredentials(manager)->preferred); 250 EXPECT_EQ(new_pass, 251 GetPendingCredentials(manager)->password_value); 252 // Done. 253 delete manager; 254 } 255 256 TEST_F(PasswordFormManagerTest, TestIgnoreResult) { 257 PasswordFormManager* manager = new PasswordFormManager( 258 profile(), NULL, NULL, *observed_form(), false); 259 // Make sure we don't match a PasswordForm if it was originally saved on 260 // an SSL-valid page and we are now on a page with invalid certificate. 261 saved_match()->ssl_valid = true; 262 EXPECT_TRUE(IgnoredResult(manager, saved_match())); 263 264 saved_match()->ssl_valid = false; 265 // Different paths for action / origin are okay. 266 saved_match()->action = GURL("http://www.google.com/b/Login"); 267 saved_match()->origin = GURL("http://www.google.com/foo"); 268 EXPECT_FALSE(IgnoredResult(manager, saved_match())); 269 270 // Done. 271 delete manager; 272 } 273 274 TEST_F(PasswordFormManagerTest, TestEmptyAction) { 275 scoped_ptr<PasswordFormManager> manager(new PasswordFormManager( 276 profile(), NULL, NULL, *observed_form(), false)); 277 278 saved_match()->action = GURL(); 279 SimulateMatchingPhase(manager.get(), true); 280 // User logs in with the autofilled username / password from saved_match. 281 PasswordForm login = *observed_form(); 282 login.username_value = saved_match()->username_value; 283 login.password_value = saved_match()->password_value; 284 manager->ProvisionallySave( 285 login, 286 PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 287 EXPECT_FALSE(manager->IsNewLogin()); 288 // We bless our saved PasswordForm entry with the action URL of the 289 // observed form. 290 EXPECT_EQ(observed_form()->action, 291 GetPendingCredentials(manager.get())->action); 292 } 293 294 TEST_F(PasswordFormManagerTest, TestUpdateAction) { 295 scoped_ptr<PasswordFormManager> manager(new PasswordFormManager( 296 profile(), NULL, NULL, *observed_form(), false)); 297 298 SimulateMatchingPhase(manager.get(), true); 299 // User logs in with the autofilled username / password from saved_match. 300 PasswordForm login = *observed_form(); 301 login.username_value = saved_match()->username_value; 302 login.password_value = saved_match()->password_value; 303 304 manager->ProvisionallySave( 305 login, 306 PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 307 EXPECT_FALSE(manager->IsNewLogin()); 308 // The observed action URL is different from the previously saved one, and 309 // is the same as the one that would be submitted on successful login. 310 EXPECT_NE(observed_form()->action, saved_match()->action); 311 EXPECT_EQ(observed_form()->action, 312 GetPendingCredentials(manager.get())->action); 313 } 314 315 TEST_F(PasswordFormManagerTest, TestDynamicAction) { 316 scoped_ptr<PasswordFormManager> manager(new PasswordFormManager( 317 profile(), NULL, NULL, *observed_form(), false)); 318 319 SimulateMatchingPhase(manager.get(), false); 320 PasswordForm login(*observed_form()); 321 // The submitted action URL is different from the one observed on page load. 322 GURL new_action = GURL("http://www.google.com/new_action"); 323 login.action = new_action; 324 325 manager->ProvisionallySave( 326 login, 327 PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); 328 EXPECT_TRUE(manager->IsNewLogin()); 329 // Check that the provisionally saved action URL is the same as the submitted 330 // action URL, not the one observed on page load. 331 EXPECT_EQ(new_action, 332 GetPendingCredentials(manager.get())->action); 333 } 334 335 TEST_F(PasswordFormManagerTest, TestAlternateUsername) { 336 // Need a MessageLoop for callbacks. 337 base::MessageLoop message_loop; 338 PasswordStoreFactory::GetInstance()->SetTestingFactory( 339 profile(), &TestPasswordStore::Create); 340 scoped_refptr<TestPasswordStore> password_store = 341 static_cast<TestPasswordStore*>( 342 PasswordStoreFactory::GetForProfile(profile(), 343 Profile::IMPLICIT_ACCESS).get()); 344 TestPasswordManagerDelegate delegate(profile()); 345 TestPasswordManager password_manager(&delegate); 346 scoped_ptr<TestPasswordFormManager> manager(new TestPasswordFormManager( 347 profile(), &password_manager, *observed_form(), false)); 348 349 password_store->AddLogin(*saved_match()); 350 manager->FetchMatchingLoginsFromPasswordStore(); 351 content::RunAllPendingInMessageLoop(); 352 353 // The saved match has the right username already. 354 PasswordForm login(*observed_form()); 355 login.username_value = saved_match()->username_value; 356 login.password_value = saved_match()->password_value; 357 login.preferred = true; 358 manager->ProvisionallySave( 359 login, 360 PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES); 361 362 EXPECT_FALSE(manager->IsNewLogin()); 363 manager->Save(); 364 content::RunAllPendingInMessageLoop(); 365 366 // Should be only one password stored, and should not have 367 // |other_possible_usernames| set anymore. 368 TestPasswordStore::PasswordMap passwords = password_store->stored_passwords(); 369 EXPECT_EQ(1U, passwords.size()); 370 ASSERT_EQ(1U, passwords[saved_match()->signon_realm].size()); 371 EXPECT_EQ(saved_match()->username_value, 372 passwords[saved_match()->signon_realm][0].username_value); 373 EXPECT_EQ( 374 0U, 375 passwords[saved_match()->signon_realm][0]. 376 other_possible_usernames.size()); 377 378 // This time use an alternate username 379 manager.reset(new TestPasswordFormManager( 380 profile(), &password_manager, *observed_form(), false)); 381 password_store->Clear(); 382 password_store->AddLogin(*saved_match()); 383 manager->FetchMatchingLoginsFromPasswordStore(); 384 content::RunAllPendingInMessageLoop(); 385 386 string16 new_username = saved_match()->other_possible_usernames[0]; 387 login.username_value = new_username; 388 manager->ProvisionallySave( 389 login, 390 PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES); 391 392 EXPECT_FALSE(manager->IsNewLogin()); 393 manager->Save(); 394 content::RunAllPendingInMessageLoop(); 395 396 // |other_possible_usernames| should also be empty, but username_value should 397 // be changed to match |new_username| 398 passwords = password_store->stored_passwords(); 399 EXPECT_EQ(1U, passwords.size()); 400 ASSERT_EQ(1U, passwords[saved_match()->signon_realm].size()); 401 EXPECT_EQ(new_username, 402 passwords[saved_match()->signon_realm][0].username_value); 403 EXPECT_EQ( 404 0U, 405 passwords[saved_match()->signon_realm][0]. 406 other_possible_usernames.size()); 407 } 408 409 TEST_F(PasswordFormManagerTest, TestValidForms) { 410 // User submits credentials for the observed form. 411 PasswordForm credentials = *observed_form(); 412 credentials.scheme = PasswordForm::SCHEME_HTML; 413 credentials.username_value = saved_match()->username_value; 414 credentials.password_value = saved_match()->password_value; 415 416 // Form with both username_element and password_element. 417 PasswordFormManager manager1(profile(), NULL, NULL, credentials, false); 418 SimulateMatchingPhase(&manager1, false); 419 EXPECT_TRUE(manager1.HasValidPasswordForm()); 420 421 // Form without a username_element but with a password_element. 422 credentials.username_element.clear(); 423 PasswordFormManager manager2(profile(), NULL, NULL, credentials, false); 424 SimulateMatchingPhase(&manager2, false); 425 EXPECT_FALSE(manager2.HasValidPasswordForm()); 426 427 // Form without a password_element but with a username_element. 428 credentials.username_element = saved_match()->username_element; 429 credentials.password_element.clear(); 430 PasswordFormManager manager3(profile(), NULL, NULL, credentials, false); 431 SimulateMatchingPhase(&manager3, false); 432 EXPECT_FALSE(manager3.HasValidPasswordForm()); 433 434 // Form with neither a password_element nor a username_element. 435 credentials.username_element.clear(); 436 credentials.password_element.clear(); 437 PasswordFormManager manager4(profile(), NULL, NULL, credentials, false); 438 SimulateMatchingPhase(&manager4, false); 439 EXPECT_FALSE(manager4.HasValidPasswordForm()); 440 } 441 442 TEST_F(PasswordFormManagerTest, TestValidFormsBasic) { 443 // User submits credentials for the observed form. 444 PasswordForm credentials = *observed_form(); 445 credentials.scheme = PasswordForm::SCHEME_BASIC; 446 credentials.username_value = saved_match()->username_value; 447 credentials.password_value = saved_match()->password_value; 448 449 // Form with both username_element and password_element. 450 PasswordFormManager manager1(profile(), NULL, NULL, credentials, false); 451 SimulateMatchingPhase(&manager1, false); 452 EXPECT_TRUE(manager1.HasValidPasswordForm()); 453 454 // Form without a username_element but with a password_element. 455 credentials.username_element.clear(); 456 PasswordFormManager manager2(profile(), NULL, NULL, credentials, false); 457 SimulateMatchingPhase(&manager2, false); 458 EXPECT_TRUE(manager2.HasValidPasswordForm()); 459 460 // Form without a password_element but with a username_element. 461 credentials.username_element = saved_match()->username_element; 462 credentials.password_element.clear(); 463 PasswordFormManager manager3(profile(), NULL, NULL, credentials, false); 464 SimulateMatchingPhase(&manager3, false); 465 EXPECT_TRUE(manager3.HasValidPasswordForm()); 466 467 // Form with neither a password_element nor a username_element. 468 credentials.username_element.clear(); 469 credentials.password_element.clear(); 470 PasswordFormManager manager4(profile(), NULL, NULL, credentials, false); 471 SimulateMatchingPhase(&manager4, false); 472 EXPECT_TRUE(manager4.HasValidPasswordForm()); 473 } 474 475 TEST_F(PasswordFormManagerTest, TestSendNotBlacklistedMessage) { 476 // A dumb password manager. 477 TestPasswordManagerDelegate delegate(profile()); 478 TestPasswordManager password_manager(&delegate); 479 480 // First time sign up attempt; No login result is found from password store; 481 // We should send the not blacklisted message. 482 scoped_ptr<TestPasswordFormManager> manager(new TestPasswordFormManager( 483 profile(), &password_manager, *observed_form(), false)); 484 SimulateFetchMatchingLoginsFromPasswordStore(manager.get()); 485 std::vector<PasswordForm*> result; 486 SimulateResponseFromPasswordStore(manager.get(), result); 487 EXPECT_EQ(1u, manager->num_sent_messages()); 488 489 // Sign up attempt to previously visited sites; Login result is found from 490 // password store, and is not blacklisted; We should send the not blacklisted 491 // message. 492 manager.reset(new TestPasswordFormManager( 493 profile(), &password_manager, *observed_form(), false)); 494 SimulateFetchMatchingLoginsFromPasswordStore(manager.get()); 495 // We need add heap allocated objects to result. 496 result.push_back(CreateSavedMatch(false)); 497 SimulateResponseFromPasswordStore(manager.get(), result); 498 EXPECT_EQ(1u, manager->num_sent_messages()); 499 500 // Sign up attempt to previously visited sites; Login result is found from 501 // password store, but is blacklisted; We should not send the not blacklisted 502 // message. 503 manager.reset(new TestPasswordFormManager( 504 profile(), &password_manager, *observed_form(), false)); 505 SimulateFetchMatchingLoginsFromPasswordStore(manager.get()); 506 result.clear(); 507 result.push_back(CreateSavedMatch(true)); 508 SimulateResponseFromPasswordStore(manager.get(), result); 509 EXPECT_EQ(0u, manager->num_sent_messages()); 510 } 511 512 TEST_F(PasswordFormManagerTest, TestSanitizePossibleUsernames) { 513 scoped_ptr<PasswordFormManager> manager(new PasswordFormManager( 514 profile(), NULL, NULL, *observed_form(), false)); 515 PasswordForm credentials(*observed_form()); 516 credentials.other_possible_usernames.push_back(ASCIIToUTF16("543-43-1234")); 517 credentials.other_possible_usernames.push_back( 518 ASCIIToUTF16("378282246310005")); 519 credentials.other_possible_usernames.push_back( 520 ASCIIToUTF16("other username")); 521 credentials.username_value = ASCIIToUTF16("test (at) gmail.com"); 522 523 SanitizePossibleUsernames(manager.get(), &credentials); 524 525 // Possible credit card number and SSN are stripped. 526 std::vector<string16> expected; 527 expected.push_back(ASCIIToUTF16("other username")); 528 EXPECT_THAT(credentials.other_possible_usernames, Eq(expected)); 529 530 credentials.other_possible_usernames.clear(); 531 credentials.other_possible_usernames.push_back(ASCIIToUTF16("511-32-9830")); 532 credentials.other_possible_usernames.push_back(ASCIIToUTF16("duplicate")); 533 credentials.other_possible_usernames.push_back(ASCIIToUTF16("duplicate")); 534 credentials.other_possible_usernames.push_back(ASCIIToUTF16("random")); 535 credentials.other_possible_usernames.push_back( 536 ASCIIToUTF16("test (at) gmail.com")); 537 538 SanitizePossibleUsernames(manager.get(), &credentials); 539 540 // SSN, duplicate in |other_possible_usernames| and duplicate of 541 // |username_value| all removed. 542 expected.clear(); 543 expected.push_back(ASCIIToUTF16("duplicate")); 544 expected.push_back(ASCIIToUTF16("random")); 545 EXPECT_THAT(credentials.other_possible_usernames, Eq(expected)); 546 } 547