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 "components/password_manager/core/browser/password_form_manager.h" 6 7 #include <algorithm> 8 #include <set> 9 10 #include "base/metrics/histogram.h" 11 #include "base/metrics/user_metrics.h" 12 #include "base/strings/string_split.h" 13 #include "base/strings/string_util.h" 14 #include "base/strings/utf_string_conversions.h" 15 #include "components/autofill/core/browser/autofill_manager.h" 16 #include "components/autofill/core/browser/form_structure.h" 17 #include "components/autofill/core/browser/validation.h" 18 #include "components/autofill/core/common/password_form.h" 19 #include "components/password_manager/core/browser/password_manager.h" 20 #include "components/password_manager/core/browser/password_manager_client.h" 21 #include "components/password_manager/core/browser/password_manager_driver.h" 22 #include "components/password_manager/core/browser/password_store.h" 23 24 using autofill::FormStructure; 25 using autofill::PasswordForm; 26 using autofill::PasswordFormMap; 27 using base::Time; 28 29 namespace password_manager { 30 31 namespace { 32 33 enum PasswordGenerationSubmissionEvent { 34 // Generated password was submitted and saved. 35 PASSWORD_SUBMITTED, 36 37 // Generated password submission failed. These passwords aren't saved. 38 PASSWORD_SUBMISSION_FAILED, 39 40 // Generated password was not submitted before navigation. Currently these 41 // passwords are not saved. 42 PASSWORD_NOT_SUBMITTED, 43 44 // Generated password was overridden by a non-generated one. This generally 45 // signals that the user was unhappy with the generated password for some 46 // reason. 47 PASSWORD_OVERRIDDEN, 48 49 // Number of enum entries, used for UMA histogram reporting macros. 50 SUBMISSION_EVENT_ENUM_COUNT 51 }; 52 53 void LogPasswordGenerationSubmissionEvent( 54 PasswordGenerationSubmissionEvent event) { 55 UMA_HISTOGRAM_ENUMERATION("PasswordGeneration.SubmissionEvent", 56 event, SUBMISSION_EVENT_ENUM_COUNT); 57 } 58 59 PasswordForm CopyAndModifySSLValidity(const PasswordForm& orig, 60 bool ssl_valid) { 61 PasswordForm result(orig); 62 result.ssl_valid = ssl_valid; 63 return result; 64 } 65 66 } // namespace 67 68 PasswordFormManager::PasswordFormManager(PasswordManager* password_manager, 69 PasswordManagerClient* client, 70 PasswordManagerDriver* driver, 71 const PasswordForm& observed_form, 72 bool ssl_valid) 73 : best_matches_deleter_(&best_matches_), 74 observed_form_(CopyAndModifySSLValidity(observed_form, ssl_valid)), 75 is_new_login_(true), 76 has_generated_password_(false), 77 password_manager_(password_manager), 78 preferred_match_(NULL), 79 state_(PRE_MATCHING_PHASE), 80 client_(client), 81 driver_(driver), 82 manager_action_(kManagerActionNone), 83 user_action_(kUserActionNone), 84 submit_result_(kSubmitResultNotSubmitted) { 85 if (observed_form_.origin.is_valid()) 86 base::SplitString(observed_form_.origin.path(), '/', &form_path_tokens_); 87 } 88 89 PasswordFormManager::~PasswordFormManager() { 90 UMA_HISTOGRAM_ENUMERATION( 91 "PasswordManager.ActionsTakenV3", GetActionsTaken(), kMaxNumActionsTaken); 92 if (has_generated_password_ && submit_result_ == kSubmitResultNotSubmitted) 93 LogPasswordGenerationSubmissionEvent(PASSWORD_NOT_SUBMITTED); 94 } 95 96 int PasswordFormManager::GetActionsTaken() { 97 return user_action_ + kUserActionMax * (manager_action_ + 98 kManagerActionMax * submit_result_); 99 } 100 101 // TODO(timsteele): use a hash of some sort in the future? 102 PasswordFormManager::MatchResultMask PasswordFormManager::DoesManage( 103 const PasswordForm& form) const { 104 // Non-HTML form case. 105 if (observed_form_.scheme != PasswordForm::SCHEME_HTML || 106 form.scheme != PasswordForm::SCHEME_HTML) { 107 const bool forms_match = observed_form_.signon_realm == form.signon_realm && 108 observed_form_.scheme == form.scheme; 109 return forms_match ? RESULT_COMPLETE_MATCH : RESULT_NO_MATCH; 110 } 111 112 // HTML form case. 113 MatchResultMask result = RESULT_NO_MATCH; 114 115 // Easiest case of matching origins. 116 bool origins_match = form.origin == observed_form_.origin; 117 // If this is a replay of the same form in the case a user entered an invalid 118 // password, the origin of the new form may equal the action of the "first" 119 // form instead. 120 origins_match = origins_match || (form.origin == observed_form_.action); 121 // Otherwise, if action hosts are the same, the old URL scheme is HTTP while 122 // the new one is HTTPS, and the new path equals to or extends the old path, 123 // we also consider the actions a match. This is to accommodate cases where 124 // the original login form is on an HTTP page, but a failed login attempt 125 // redirects to HTTPS (as in http://example.org -> https://example.org/auth). 126 if (!origins_match && !observed_form_.origin.SchemeIsSecure() && 127 form.origin.SchemeIsSecure()) { 128 const std::string& old_path = observed_form_.origin.path(); 129 const std::string& new_path = form.origin.path(); 130 origins_match = 131 observed_form_.origin.host() == form.origin.host() && 132 observed_form_.origin.port() == form.origin.port() && 133 StartsWithASCII(new_path, old_path, /*case_sensitive=*/true); 134 } 135 136 if (form.username_element == observed_form_.username_element && 137 form.password_element == observed_form_.password_element && 138 origins_match) { 139 result |= RESULT_MANDATORY_ATTRIBUTES_MATCH; 140 } 141 142 // Note: although saved password forms might actually have an empty action 143 // URL if they were imported (see bug 1107719), the |form| we see here comes 144 // never from the password store, and should have an exactly matching action. 145 if (form.action == observed_form_.action) 146 result |= RESULT_ACTION_MATCH; 147 148 return result; 149 } 150 151 bool PasswordFormManager::IsBlacklisted() { 152 DCHECK_EQ(state_, POST_MATCHING_PHASE); 153 if (preferred_match_ && preferred_match_->blacklisted_by_user) 154 return true; 155 return false; 156 } 157 158 void PasswordFormManager::PermanentlyBlacklist() { 159 DCHECK_EQ(state_, POST_MATCHING_PHASE); 160 161 // Configure the form about to be saved for blacklist status. 162 pending_credentials_.preferred = true; 163 pending_credentials_.blacklisted_by_user = true; 164 pending_credentials_.username_value.clear(); 165 pending_credentials_.password_value.clear(); 166 167 // Retroactively forget existing matches for this form, so we NEVER prompt or 168 // autofill it again. 169 int num_passwords_deleted = 0; 170 if (!best_matches_.empty()) { 171 PasswordFormMap::const_iterator iter; 172 PasswordStore* password_store = client_->GetPasswordStore(); 173 if (!password_store) { 174 NOTREACHED(); 175 return; 176 } 177 for (iter = best_matches_.begin(); iter != best_matches_.end(); ++iter) { 178 // We want to remove existing matches for this form so that the exact 179 // origin match with |blackisted_by_user == true| is the only result that 180 // shows up in the future for this origin URL. However, we don't want to 181 // delete logins that were actually saved on a different page (hence with 182 // different origin URL) and just happened to match this form because of 183 // the scoring algorithm. See bug 1204493. 184 if (iter->second->origin == observed_form_.origin) { 185 password_store->RemoveLogin(*iter->second); 186 ++num_passwords_deleted; 187 } 188 } 189 } 190 191 UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedWhenBlacklisting", 192 num_passwords_deleted); 193 194 // Save the pending_credentials_ entry marked as blacklisted. 195 SaveAsNewLogin(false); 196 } 197 198 void PasswordFormManager::SetUseAdditionalPasswordAuthentication( 199 bool use_additional_authentication) { 200 pending_credentials_.use_additional_authentication = 201 use_additional_authentication; 202 } 203 204 bool PasswordFormManager::IsNewLogin() { 205 DCHECK_EQ(state_, POST_MATCHING_PHASE); 206 return is_new_login_; 207 } 208 209 bool PasswordFormManager::IsPendingCredentialsPublicSuffixMatch() { 210 return pending_credentials_.IsPublicSuffixMatch(); 211 } 212 213 void PasswordFormManager::SetHasGeneratedPassword() { 214 has_generated_password_ = true; 215 } 216 217 bool PasswordFormManager::HasGeneratedPassword() { 218 // This check is permissive, as the user may have generated a password and 219 // then edited it in the form itself. However, even in this case the user 220 // has already given consent, so we treat these cases the same. 221 return has_generated_password_; 222 } 223 224 bool PasswordFormManager::HasValidPasswordForm() { 225 DCHECK_EQ(state_, POST_MATCHING_PHASE); 226 // Non-HTML password forms (primarily HTTP and FTP autentication) 227 // do not contain username_element and password_element values. 228 if (observed_form_.scheme != PasswordForm::SCHEME_HTML) 229 return true; 230 return !observed_form_.password_element.empty() || 231 !observed_form_.new_password_element.empty(); 232 } 233 234 void PasswordFormManager::ProvisionallySave( 235 const PasswordForm& credentials, 236 OtherPossibleUsernamesAction action) { 237 DCHECK_EQ(state_, POST_MATCHING_PHASE); 238 DCHECK_NE(RESULT_NO_MATCH, DoesManage(credentials)); 239 240 // If this was a sign-up or change password form, we want to persist the new 241 // password; if this was a login form, then the current password (which might 242 // still be "new" in the sense that we see these credentials for the first 243 // time, or that the user manually entered his actual password to overwrite an 244 // obsolete password we had in the store). 245 base::string16 password_to_save(credentials.new_password_element.empty() ? 246 credentials.password_value : credentials.new_password_value); 247 248 // Make sure the important fields stay the same as the initially observed or 249 // autofilled ones, as they may have changed if the user experienced a login 250 // failure. 251 // Look for these credentials in the list containing auto-fill entries. 252 PasswordFormMap::const_iterator it = 253 best_matches_.find(credentials.username_value); 254 if (it != best_matches_.end()) { 255 // The user signed in with a login we autofilled. 256 pending_credentials_ = *it->second; 257 bool password_changed = 258 pending_credentials_.password_value != password_to_save; 259 if (IsPendingCredentialsPublicSuffixMatch()) { 260 // If the autofilled credentials were only a PSL match, store a copy with 261 // the current origin and signon realm. This ensures that on the next 262 // visit, a precise match is found. 263 is_new_login_ = true; 264 user_action_ = password_changed ? kUserActionChoosePslMatch 265 : kUserActionOverridePassword; 266 // Normally, the copy of the PSL matched credentials, adapted for the 267 // current domain, is saved automatically without asking the user, because 268 // the copy likely represents the same account, i.e., the one for which 269 // the user already agreed to store a password. 270 // 271 // However, if the user changes the suggested password, it might indicate 272 // that the autofilled credentials and |credentials| actually correspond 273 // to two different accounts (see http://crbug.com/385619). In that case 274 // the user should be asked again before saving the password. This is 275 // ensured by clearing |original_signon_realm| on |pending_credentials_|, 276 // which unmarks it as a PSL match. 277 // 278 // There is still the edge case when the autofilled credentials represent 279 // the same account as |credentials| but the stored password was out of 280 // date. In that case, the user just had to manually enter the new 281 // password, which is now in |credentials|. The best thing would be to 282 // save automatically, and also update the original credentials. However, 283 // we have no way to tell if this is the case. This will likely happen 284 // infrequently, and the inconvenience put on the user by asking them is 285 // not significant, so we are fine with asking here again. 286 if (password_changed) { 287 pending_credentials_.original_signon_realm.clear(); 288 DCHECK(!IsPendingCredentialsPublicSuffixMatch()); 289 } 290 } else { // Not a PSL match. 291 is_new_login_ = false; 292 if (password_changed) 293 user_action_ = kUserActionOverridePassword; 294 } 295 } else if (action == ALLOW_OTHER_POSSIBLE_USERNAMES && 296 UpdatePendingCredentialsIfOtherPossibleUsername( 297 credentials.username_value)) { 298 // |pending_credentials_| is now set. Note we don't update 299 // |pending_credentials_.username_value| to |credentials.username_value| 300 // yet because we need to keep the original username to modify the stored 301 // credential. 302 selected_username_ = credentials.username_value; 303 is_new_login_ = false; 304 } else { 305 // User typed in a new, unknown username. 306 user_action_ = kUserActionOverrideUsernameAndPassword; 307 pending_credentials_ = observed_form_; 308 pending_credentials_.username_value = credentials.username_value; 309 pending_credentials_.other_possible_usernames = 310 credentials.other_possible_usernames; 311 312 // The password value will be filled in later, remove any garbage for now. 313 pending_credentials_.password_value.clear(); 314 pending_credentials_.new_password_value.clear(); 315 316 // If this was a sign-up or change password form, the names of the elements 317 // are likely different than those on a login form, so do not bother saving 318 // them. We will fill them with meaningful values in UpdateLogin() when the 319 // user goes onto a real login form for the first time. 320 if (!credentials.new_password_element.empty()) { 321 pending_credentials_.password_element.clear(); 322 pending_credentials_.new_password_element.clear(); 323 } 324 } 325 326 pending_credentials_.action = credentials.action; 327 // If the user selected credentials we autofilled from a PasswordForm 328 // that contained no action URL (IE6/7 imported passwords, for example), 329 // bless it with the action URL from the observed form. See bug 1107719. 330 if (pending_credentials_.action.is_empty()) 331 pending_credentials_.action = observed_form_.action; 332 333 pending_credentials_.password_value = password_to_save; 334 pending_credentials_.preferred = credentials.preferred; 335 336 if (user_action_ == kUserActionOverridePassword && 337 pending_credentials_.type == PasswordForm::TYPE_GENERATED && 338 !has_generated_password_) { 339 LogPasswordGenerationSubmissionEvent(PASSWORD_OVERRIDDEN); 340 } 341 342 if (has_generated_password_) 343 pending_credentials_.type = PasswordForm::TYPE_GENERATED; 344 } 345 346 void PasswordFormManager::Save() { 347 DCHECK_EQ(state_, POST_MATCHING_PHASE); 348 DCHECK(!driver_->IsOffTheRecord()); 349 350 if (IsNewLogin()) 351 SaveAsNewLogin(true); 352 else 353 UpdateLogin(); 354 } 355 356 void PasswordFormManager::FetchMatchingLoginsFromPasswordStore( 357 PasswordStore::AuthorizationPromptPolicy prompt_policy) { 358 DCHECK_EQ(state_, PRE_MATCHING_PHASE); 359 state_ = MATCHING_PHASE; 360 PasswordStore* password_store = client_->GetPasswordStore(); 361 if (!password_store) { 362 NOTREACHED(); 363 return; 364 } 365 password_store->GetLogins(observed_form_, prompt_policy, this); 366 } 367 368 bool PasswordFormManager::HasCompletedMatching() { 369 return state_ == POST_MATCHING_PHASE; 370 } 371 372 void PasswordFormManager::OnRequestDone( 373 const std::vector<PasswordForm*>& logins_result) { 374 // Note that the result gets deleted after this call completes, but we own 375 // the PasswordForm objects pointed to by the result vector, thus we keep 376 // copies to a minimum here. 377 378 int best_score = 0; 379 // These credentials will be in the final result regardless of score. 380 std::vector<PasswordForm> credentials_to_keep; 381 for (size_t i = 0; i < logins_result.size(); i++) { 382 if (ShouldIgnoreResult(*logins_result[i])) { 383 delete logins_result[i]; 384 continue; 385 } 386 // Score and update best matches. 387 int current_score = ScoreResult(*logins_result[i]); 388 // This check is here so we can append empty path matches in the event 389 // they don't score as high as others and aren't added to best_matches_. 390 // This is most commonly imported firefox logins. We skip blacklisted 391 // ones because clearly we don't want to autofill them, and secondly 392 // because they only mean something when we have no other matches already 393 // saved in Chrome - in which case they'll make it through the regular 394 // scoring flow below by design. Note signon_realm == origin implies empty 395 // path logins_result, since signon_realm is a prefix of origin for HTML 396 // password forms. 397 // TODO(timsteele): Bug 1269400. We probably should do something more 398 // elegant for any shorter-path match instead of explicitly handling empty 399 // path matches. 400 if ((observed_form_.scheme == PasswordForm::SCHEME_HTML) && 401 (observed_form_.signon_realm == logins_result[i]->origin.spec()) && 402 (current_score > 0) && (!logins_result[i]->blacklisted_by_user)) { 403 credentials_to_keep.push_back(*logins_result[i]); 404 } 405 406 // Always keep generated passwords as part of the result set. If a user 407 // generates a password on a signup form, it should show on a login form 408 // even if they have a previous login saved. 409 // TODO(gcasto): We don't want to cut credentials that were saved on signup 410 // forms even if they weren't generated, but currently it's hard to 411 // distinguish between those forms and two different login forms on the 412 // same domain. Filed http://crbug.com/294468 to look into this. 413 if (logins_result[i]->type == PasswordForm::TYPE_GENERATED) 414 credentials_to_keep.push_back(*logins_result[i]); 415 416 if (current_score < best_score) { 417 delete logins_result[i]; 418 continue; 419 } 420 if (current_score == best_score) { 421 PasswordForm* old_form = best_matches_[logins_result[i]->username_value]; 422 if (old_form) { 423 if (preferred_match_ == old_form) 424 preferred_match_ = NULL; 425 delete old_form; 426 } 427 best_matches_[logins_result[i]->username_value] = logins_result[i]; 428 } else if (current_score > best_score) { 429 best_score = current_score; 430 // This new login has a better score than all those up to this point 431 // Note 'this' owns all the PasswordForms in best_matches_. 432 STLDeleteValues(&best_matches_); 433 preferred_match_ = NULL; // Don't delete, its owned by best_matches_. 434 best_matches_[logins_result[i]->username_value] = logins_result[i]; 435 } 436 preferred_match_ = logins_result[i]->preferred ? logins_result[i] 437 : preferred_match_; 438 } 439 // We're done matching now. 440 state_ = POST_MATCHING_PHASE; 441 442 client_->AutofillResultsComputed(); 443 444 // TODO(gcasto): Change this to check that best_matches_ is empty. This should 445 // be equivalent for the moment, but it's less clear and may not be 446 // equivalent in the future. 447 if (best_score <= 0) { 448 // If no saved forms can be used, then it isn't blacklisted and generation 449 // should be allowed. 450 driver_->AllowPasswordGenerationForForm(observed_form_); 451 return; 452 } 453 454 for (std::vector<PasswordForm>::const_iterator it = 455 credentials_to_keep.begin(); 456 it != credentials_to_keep.end(); ++it) { 457 // If we don't already have a result with the same username, add the 458 // lower-scored match (if it had equal score it would already be in 459 // best_matches_). 460 if (best_matches_.find(it->username_value) == best_matches_.end()) 461 best_matches_[it->username_value] = new PasswordForm(*it); 462 } 463 464 UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsNotShown", 465 logins_result.size() - best_matches_.size()); 466 467 // It is possible we have at least one match but have no preferred_match_, 468 // because a user may have chosen to 'Forget' the preferred match. So we 469 // just pick the first one and whichever the user selects for submit will 470 // be saved as preferred. 471 DCHECK(!best_matches_.empty()); 472 if (!preferred_match_) 473 preferred_match_ = best_matches_.begin()->second; 474 475 // Check to see if the user told us to ignore this site in the past. 476 if (preferred_match_->blacklisted_by_user) { 477 client_->PasswordAutofillWasBlocked(best_matches_); 478 manager_action_ = kManagerActionBlacklisted; 479 return; 480 } 481 482 // If not blacklisted, inform the driver that password generation is allowed 483 // for |observed_form_|. 484 driver_->AllowPasswordGenerationForForm(observed_form_); 485 486 // Proceed to autofill. 487 // Note that we provide the choices but don't actually prefill a value if: 488 // (1) we are in Incognito mode, (2) the ACTION paths don't match, 489 // or (3) if it matched using public suffix domain matching. 490 bool wait_for_username = 491 driver_->IsOffTheRecord() || 492 observed_form_.action.GetWithEmptyPath() != 493 preferred_match_->action.GetWithEmptyPath() || 494 preferred_match_->IsPublicSuffixMatch(); 495 if (wait_for_username) 496 manager_action_ = kManagerActionNone; 497 else 498 manager_action_ = kManagerActionAutofilled; 499 password_manager_->Autofill(observed_form_, best_matches_, 500 *preferred_match_, wait_for_username); 501 } 502 503 void PasswordFormManager::OnGetPasswordStoreResults( 504 const std::vector<autofill::PasswordForm*>& results) { 505 DCHECK_EQ(state_, MATCHING_PHASE); 506 507 if (results.empty()) { 508 state_ = POST_MATCHING_PHASE; 509 // No result means that we visit this site the first time so we don't need 510 // to check whether this site is blacklisted or not. Just send a message 511 // to allow password generation. 512 driver_->AllowPasswordGenerationForForm(observed_form_); 513 return; 514 } 515 OnRequestDone(results); 516 } 517 518 bool PasswordFormManager::ShouldIgnoreResult(const PasswordForm& form) const { 519 // Do not autofill on sign-up or change password forms (until we have some 520 // working change password functionality). 521 if (!observed_form_.new_password_element.empty()) 522 return true; 523 // Don't match an invalid SSL form with one saved under secure circumstances. 524 if (form.ssl_valid && !observed_form_.ssl_valid) 525 return true; 526 527 if (client_->ShouldFilterAutofillResult(form)) 528 return true; 529 530 return false; 531 } 532 533 void PasswordFormManager::SaveAsNewLogin(bool reset_preferred_login) { 534 DCHECK_EQ(state_, POST_MATCHING_PHASE); 535 DCHECK(IsNewLogin()); 536 // The new_form is being used to sign in, so it is preferred. 537 DCHECK(pending_credentials_.preferred); 538 // new_form contains the same basic data as observed_form_ (because its the 539 // same form), but with the newly added credentials. 540 541 DCHECK(!driver_->IsOffTheRecord()); 542 543 PasswordStore* password_store = client_->GetPasswordStore(); 544 if (!password_store) { 545 NOTREACHED(); 546 return; 547 } 548 549 // Upload credentials the first time they are saved. This data is used 550 // by password generation to help determine account creation sites. 551 // Blacklisted credentials will never be used, so don't upload a vote for 552 // them. 553 if (!pending_credentials_.blacklisted_by_user) 554 UploadPasswordForm(pending_credentials_.form_data, autofill::PASSWORD); 555 556 pending_credentials_.date_created = Time::Now(); 557 SanitizePossibleUsernames(&pending_credentials_); 558 password_store->AddLogin(pending_credentials_); 559 560 if (reset_preferred_login) { 561 UpdatePreferredLoginState(password_store); 562 } 563 } 564 565 void PasswordFormManager::SanitizePossibleUsernames(PasswordForm* form) { 566 // Remove any possible usernames that could be credit cards or SSN for privacy 567 // reasons. Also remove duplicates, both in other_possible_usernames and 568 // between other_possible_usernames and username_value. 569 std::set<base::string16> set; 570 for (std::vector<base::string16>::iterator it = 571 form->other_possible_usernames.begin(); 572 it != form->other_possible_usernames.end(); ++it) { 573 if (!autofill::IsValidCreditCardNumber(*it) && !autofill::IsSSN(*it)) 574 set.insert(*it); 575 } 576 set.erase(form->username_value); 577 std::vector<base::string16> temp(set.begin(), set.end()); 578 form->other_possible_usernames.swap(temp); 579 } 580 581 void PasswordFormManager::UpdatePreferredLoginState( 582 PasswordStore* password_store) { 583 DCHECK(password_store); 584 PasswordFormMap::iterator iter; 585 for (iter = best_matches_.begin(); iter != best_matches_.end(); iter++) { 586 if (iter->second->username_value != pending_credentials_.username_value && 587 iter->second->preferred) { 588 // This wasn't the selected login but it used to be preferred. 589 iter->second->preferred = false; 590 if (user_action_ == kUserActionNone) 591 user_action_ = kUserActionChoose; 592 password_store->UpdateLogin(*iter->second); 593 } 594 } 595 } 596 597 void PasswordFormManager::UpdateLogin() { 598 DCHECK_EQ(state_, POST_MATCHING_PHASE); 599 DCHECK(preferred_match_); 600 // If we're doing an Update, we either autofilled correctly and need to 601 // update the stats, or the user typed in a new password for autofilled 602 // username, or the user selected one of the non-preferred matches, 603 // thus requiring a swap of preferred bits. 604 DCHECK(!IsNewLogin() && pending_credentials_.preferred); 605 DCHECK(!driver_->IsOffTheRecord()); 606 607 PasswordStore* password_store = client_->GetPasswordStore(); 608 if (!password_store) { 609 NOTREACHED(); 610 return; 611 } 612 613 // Update metadata. 614 ++pending_credentials_.times_used; 615 616 if (client_->IsSyncAccountCredential( 617 base::UTF16ToUTF8(pending_credentials_.username_value), 618 pending_credentials_.signon_realm)) { 619 base::RecordAction( 620 base::UserMetricsAction("PasswordManager_SyncCredentialUsed")); 621 } 622 623 // Check to see if this form is a candidate for password generation. 624 CheckForAccountCreationForm(pending_credentials_, observed_form_); 625 626 UpdatePreferredLoginState(password_store); 627 628 // Remove alternate usernames. At this point we assume that we have found 629 // the right username. 630 pending_credentials_.other_possible_usernames.clear(); 631 632 // Update the new preferred login. 633 if (!selected_username_.empty()) { 634 // An other possible username is selected. We set this selected username 635 // as the real username. The PasswordStore API isn't designed to update 636 // username, so we delete the old credentials and add a new one instead. 637 password_store->RemoveLogin(pending_credentials_); 638 pending_credentials_.username_value = selected_username_; 639 password_store->AddLogin(pending_credentials_); 640 } else if ((observed_form_.scheme == PasswordForm::SCHEME_HTML) && 641 (observed_form_.origin.spec().length() > 642 observed_form_.signon_realm.length()) && 643 (observed_form_.signon_realm == 644 pending_credentials_.origin.spec())) { 645 // Note origin.spec().length > signon_realm.length implies the origin has a 646 // path, since signon_realm is a prefix of origin for HTML password forms. 647 // 648 // The user logged in successfully with one of our autofilled logins on a 649 // page with non-empty path, but the autofilled entry was initially saved/ 650 // imported with an empty path. Rather than just mark this entry preferred, 651 // we create a more specific copy for this exact page and leave the "master" 652 // unchanged. This is to prevent the case where that master login is used 653 // on several sites (e.g site.com/a and site.com/b) but the user actually 654 // has a different preference on each site. For example, on /a, he wants the 655 // general empty-path login so it is flagged as preferred, but on /b he logs 656 // in with a different saved entry - we don't want to remove the preferred 657 // status of the former because upon return to /a it won't be the default- 658 // fill match. 659 // TODO(timsteele): Bug 1188626 - expire the master copies. 660 PasswordForm copy(pending_credentials_); 661 copy.origin = observed_form_.origin; 662 copy.action = observed_form_.action; 663 password_store->AddLogin(copy); 664 } else if (observed_form_.new_password_element.empty() && 665 (pending_credentials_.password_element.empty() || 666 pending_credentials_.username_element.empty() || 667 pending_credentials_.submit_element.empty())) { 668 // If |observed_form_| was a sign-up or change password form, there is no 669 // point in trying to update element names: they are likely going to be 670 // different than those on a login form. 671 // Otherwise, given that |password_element| and |username_element| can't be 672 // updated because they are part of Sync and PasswordStore primary key, we 673 // must delete the old credentials altogether and then add the new ones. 674 password_store->RemoveLogin(pending_credentials_); 675 pending_credentials_.password_element = observed_form_.password_element; 676 pending_credentials_.username_element = observed_form_.username_element; 677 pending_credentials_.submit_element = observed_form_.submit_element; 678 password_store->AddLogin(pending_credentials_); 679 } else { 680 password_store->UpdateLogin(pending_credentials_); 681 } 682 } 683 684 bool PasswordFormManager::UpdatePendingCredentialsIfOtherPossibleUsername( 685 const base::string16& username) { 686 for (PasswordFormMap::const_iterator it = best_matches_.begin(); 687 it != best_matches_.end(); ++it) { 688 for (size_t i = 0; i < it->second->other_possible_usernames.size(); ++i) { 689 if (it->second->other_possible_usernames[i] == username) { 690 pending_credentials_ = *it->second; 691 return true; 692 } 693 } 694 } 695 return false; 696 } 697 698 void PasswordFormManager::CheckForAccountCreationForm( 699 const PasswordForm& pending, const PasswordForm& observed) { 700 // We check to see if the saved form_data is the same as the observed 701 // form_data, which should never be true for passwords saved on account 702 // creation forms. This check is only made the first time a password is used 703 // to cut down on false positives. Specifically a site may have multiple login 704 // forms with different markup, which might look similar to a signup form. 705 if (pending.times_used == 1) { 706 FormStructure pending_structure(pending.form_data); 707 FormStructure observed_structure(observed.form_data); 708 // Ignore |pending_structure| if its FormData has no fields. This is to 709 // weed out those credentials that were saved before FormData was added 710 // to PasswordForm. Even without this check, these FormStructure's won't 711 // be uploaded, but it makes it hard to see if we are encountering 712 // unexpected errors. 713 if (!pending.form_data.fields.empty() && 714 pending_structure.FormSignature() != 715 observed_structure.FormSignature()) { 716 UploadPasswordForm(pending.form_data, 717 autofill::ACCOUNT_CREATION_PASSWORD); 718 } 719 } 720 } 721 722 void PasswordFormManager::UploadPasswordForm( 723 const autofill::FormData& form_data, 724 const autofill::ServerFieldType& password_type) { 725 autofill::AutofillManager* autofill_manager = 726 driver_->GetAutofillManager(); 727 if (!autofill_manager) 728 return; 729 730 // Note that this doesn't guarantee that the upload succeeded, only that 731 // |form_data| is considered uploadable. 732 bool success = 733 autofill_manager->UploadPasswordForm(form_data, password_type); 734 UMA_HISTOGRAM_BOOLEAN("PasswordGeneration.UploadStarted", success); 735 } 736 737 int PasswordFormManager::ScoreResult(const PasswordForm& candidate) const { 738 DCHECK_EQ(state_, MATCHING_PHASE); 739 // For scoring of candidate login data: 740 // The most important element that should match is the signon_realm followed 741 // by the origin, the action, the password name, the submit button name, and 742 // finally the username input field name. 743 // If public suffix origin match was not used, it gives an addition of 744 // 128 (1 << 7). 745 // Exact origin match gives an addition of 64 (1 << 6) + # of matching url 746 // dirs. 747 // Partial match gives an addition of 32 (1 << 5) + # matching url dirs 748 // That way, a partial match cannot trump an exact match even if 749 // the partial one matches all other attributes (action, elements) (and 750 // regardless of the matching depth in the URL path). 751 int score = 0; 752 if (!candidate.IsPublicSuffixMatch()) { 753 score += 1 << 7; 754 } 755 if (candidate.origin == observed_form_.origin) { 756 // This check is here for the most common case which 757 // is we have a single match in the db for the given host, 758 // so we don't generally need to walk the entire URL path (the else 759 // clause). 760 score += (1 << 6) + static_cast<int>(form_path_tokens_.size()); 761 } else { 762 // Walk the origin URL paths one directory at a time to see how 763 // deep the two match. 764 std::vector<std::string> candidate_path_tokens; 765 base::SplitString(candidate.origin.path(), '/', &candidate_path_tokens); 766 size_t depth = 0; 767 size_t max_dirs = std::min(form_path_tokens_.size(), 768 candidate_path_tokens.size()); 769 while ((depth < max_dirs) && (form_path_tokens_[depth] == 770 candidate_path_tokens[depth])) { 771 depth++; 772 score++; 773 } 774 // do we have a partial match? 775 score += (depth > 0) ? 1 << 5 : 0; 776 } 777 if (observed_form_.scheme == PasswordForm::SCHEME_HTML) { 778 if (candidate.action == observed_form_.action) 779 score += 1 << 3; 780 if (candidate.password_element == observed_form_.password_element) 781 score += 1 << 2; 782 if (candidate.submit_element == observed_form_.submit_element) 783 score += 1 << 1; 784 if (candidate.username_element == observed_form_.username_element) 785 score += 1 << 0; 786 } 787 788 return score; 789 } 790 791 void PasswordFormManager::SubmitPassed() { 792 submit_result_ = kSubmitResultPassed; 793 if (has_generated_password_) 794 LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMITTED); 795 } 796 797 void PasswordFormManager::SubmitFailed() { 798 submit_result_ = kSubmitResultFailed; 799 if (has_generated_password_) 800 LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMISSION_FAILED); 801 } 802 803 } // namespace password_manager 804