Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(265)

Side by Side Diff: components/password_manager/core/browser/password_form_manager.cc

Issue 870513002: [PasswordManager] Improve detection of ignorable change password forms. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed breakage. Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/password_manager/core/browser/password_form_manager.h" 5 #include "components/password_manager/core/browser/password_form_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <set> 8 #include <set>
9 9
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 bool PasswordFormManager::HasValidPasswordForm() const { 225 bool PasswordFormManager::HasValidPasswordForm() const {
226 DCHECK_EQ(state_, POST_MATCHING_PHASE); 226 DCHECK_EQ(state_, POST_MATCHING_PHASE);
227 // Non-HTML password forms (primarily HTTP and FTP autentication) 227 // Non-HTML password forms (primarily HTTP and FTP autentication)
228 // do not contain username_element and password_element values. 228 // do not contain username_element and password_element values.
229 if (observed_form_.scheme != PasswordForm::SCHEME_HTML) 229 if (observed_form_.scheme != PasswordForm::SCHEME_HTML)
230 return true; 230 return true;
231 return !observed_form_.password_element.empty() || 231 return !observed_form_.password_element.empty() ||
232 !observed_form_.new_password_element.empty(); 232 !observed_form_.new_password_element.empty();
233 } 233 }
234 234
235 void PasswordFormManager::ProvisionallySave( 235 bool PasswordFormManager::ProvisionallySave(
236 const PasswordForm& credentials, 236 const PasswordForm& credentials,
237 OtherPossibleUsernamesAction action) { 237 OtherPossibleUsernamesAction action) {
238 DCHECK_EQ(state_, POST_MATCHING_PHASE); 238 DCHECK_EQ(state_, POST_MATCHING_PHASE);
239 DCHECK_NE(RESULT_NO_MATCH, DoesManage(credentials)); 239 DCHECK_NE(RESULT_NO_MATCH, DoesManage(credentials));
240 240
241 // If this was a sign-up or change password form, we want to persist the new 241 // If this was a sign-up or change password form, we want to persist the new
242 // password; if this was a login form, then the current password (which might 242 // password; if this was a login form, then the current password (which might
243 // still be "new" in the sense that we see these credentials for the first 243 // still be "new" in the sense that we see these credentials for the first
244 // time, or that the user manually entered his actual password to overwrite an 244 // time, or that the user manually entered his actual password to overwrite an
245 // obsolete password we had in the store). 245 // obsolete password we had in the store).
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 // infrequently, and the inconvenience put on the user by asking them is 296 // infrequently, and the inconvenience put on the user by asking them is
297 // not significant, so we are fine with asking here again. 297 // not significant, so we are fine with asking here again.
298 if (password_changed) { 298 if (password_changed) {
299 pending_credentials_.original_signon_realm.clear(); 299 pending_credentials_.original_signon_realm.clear();
300 DCHECK(!IsPendingCredentialsPublicSuffixMatch()); 300 DCHECK(!IsPendingCredentialsPublicSuffixMatch());
301 } 301 }
302 } else { // Not a PSL match. 302 } else { // Not a PSL match.
303 is_new_login_ = false; 303 is_new_login_ = false;
304 if (password_changed) 304 if (password_changed)
305 user_action_ = kUserActionOverridePassword; 305 user_action_ = kUserActionOverridePassword;
306
307 // For ignorable change-password form, bail out early if usernames are
vabr (Chromium) 2015/02/06 16:27:07 Why should change password forms not be ignored in
Pritam Nikam 2015/02/09 15:48:17 Done.
308 // matching but passwords are not matching.
309 if (IsIgnorableChangePasswordForm() &&
310 pending_credentials_.password_value != credentials.password_value) {
311 return false;
312 }
306 } 313 }
307 } else if (action == ALLOW_OTHER_POSSIBLE_USERNAMES && 314 } else if (action == ALLOW_OTHER_POSSIBLE_USERNAMES &&
308 UpdatePendingCredentialsIfOtherPossibleUsername( 315 UpdatePendingCredentialsIfOtherPossibleUsername(
309 credentials.username_value)) { 316 credentials.username_value)) {
310 // |pending_credentials_| is now set. Note we don't update 317 // |pending_credentials_| is now set. Note we don't update
311 // |pending_credentials_.username_value| to |credentials.username_value| 318 // |pending_credentials_.username_value| to |credentials.username_value|
312 // yet because we need to keep the original username to modify the stored 319 // yet because we need to keep the original username to modify the stored
313 // credential. 320 // credential.
314 selected_username_ = credentials.username_value; 321 selected_username_ = credentials.username_value;
315 is_new_login_ = false; 322 is_new_login_ = false;
316 } else { 323 } else {
317 // User typed in a new, unknown username. 324 // User typed in a new, unknown username.
325 // For ignorable change-password form, bail out early if usernames are not
326 // matching.
327 if (IsIgnorableChangePasswordForm())
328 return false;
329
318 user_action_ = kUserActionOverrideUsernameAndPassword; 330 user_action_ = kUserActionOverrideUsernameAndPassword;
319 pending_credentials_ = observed_form_; 331 pending_credentials_ = observed_form_;
320 pending_credentials_.username_value = credentials.username_value; 332 pending_credentials_.username_value = credentials.username_value;
321 pending_credentials_.other_possible_usernames = 333 pending_credentials_.other_possible_usernames =
322 credentials.other_possible_usernames; 334 credentials.other_possible_usernames;
323 335
324 // The password value will be filled in later, remove any garbage for now. 336 // The password value will be filled in later, remove any garbage for now.
325 pending_credentials_.password_value.clear(); 337 pending_credentials_.password_value.clear();
326 pending_credentials_.new_password_value.clear(); 338 pending_credentials_.new_password_value.clear();
327 339
(...skipping 18 matching lines...) Expand all
346 pending_credentials_.preferred = credentials.preferred; 358 pending_credentials_.preferred = credentials.preferred;
347 359
348 if (user_action_ == kUserActionOverridePassword && 360 if (user_action_ == kUserActionOverridePassword &&
349 pending_credentials_.type == PasswordForm::TYPE_GENERATED && 361 pending_credentials_.type == PasswordForm::TYPE_GENERATED &&
350 !has_generated_password_) { 362 !has_generated_password_) {
351 LogPasswordGenerationSubmissionEvent(PASSWORD_OVERRIDDEN); 363 LogPasswordGenerationSubmissionEvent(PASSWORD_OVERRIDDEN);
352 } 364 }
353 365
354 if (has_generated_password_) 366 if (has_generated_password_)
355 pending_credentials_.type = PasswordForm::TYPE_GENERATED; 367 pending_credentials_.type = PasswordForm::TYPE_GENERATED;
368
369 return true;
356 } 370 }
357 371
358 void PasswordFormManager::Save() { 372 void PasswordFormManager::Save() {
359 DCHECK_EQ(state_, POST_MATCHING_PHASE); 373 DCHECK_EQ(state_, POST_MATCHING_PHASE);
360 DCHECK(!client_->IsOffTheRecord()); 374 DCHECK(!client_->IsOffTheRecord());
361 375
362 if (IsNewLogin()) 376 if (IsNewLogin())
363 SaveAsNewLogin(true); 377 SaveAsNewLogin(true);
364 else 378 else
365 UpdateLogin(); 379 UpdateLogin();
366 } 380 }
367 381
368 void PasswordFormManager::FetchMatchingLoginsFromPasswordStore( 382 void PasswordFormManager::FetchMatchingLoginsFromPasswordStore(
369 PasswordStore::AuthorizationPromptPolicy prompt_policy) { 383 PasswordStore::AuthorizationPromptPolicy prompt_policy) {
370 DCHECK_EQ(state_, PRE_MATCHING_PHASE); 384 DCHECK_EQ(state_, PRE_MATCHING_PHASE);
371 state_ = MATCHING_PHASE; 385 state_ = MATCHING_PHASE;
372 386
373 scoped_ptr<BrowserSavePasswordProgressLogger> logger; 387 scoped_ptr<BrowserSavePasswordProgressLogger> logger;
374 if (client_->IsLoggingActive()) { 388 if (client_->IsLoggingActive()) {
375 logger.reset(new BrowserSavePasswordProgressLogger(client_)); 389 logger.reset(new BrowserSavePasswordProgressLogger(client_));
376 logger->LogMessage(Logger::STRING_FETCH_LOGINS_METHOD); 390 logger->LogMessage(Logger::STRING_FETCH_LOGINS_METHOD);
377 } 391 }
378 392
379 // Do not autofill on sign-up or change password forms (until we have some
vabr (Chromium) 2015/02/06 16:27:07 The goal of http://crbug.com/448351 is not at all
Pritam Nikam 2015/02/09 15:48:17 In my opinion, this is needed to fetch stored form
380 // working change password functionality).
381 if (!observed_form_.new_password_element.empty()) {
382 if (logger)
383 logger->LogMessage(Logger::STRING_FORM_NOT_AUTOFILLED);
384 client_->AutofillResultsComputed();
385 // There is no point in looking for the credentials in the store when they
386 // won't be autofilled, so pretend there were none.
387 std::vector<autofill::PasswordForm*> dummy_results;
388 OnGetPasswordStoreResults(dummy_results);
389 return;
390 }
391
392 PasswordStore* password_store = client_->GetPasswordStore(); 393 PasswordStore* password_store = client_->GetPasswordStore();
393 if (!password_store) { 394 if (!password_store) {
394 if (logger) 395 if (logger)
395 logger->LogMessage(Logger::STRING_NO_STORE); 396 logger->LogMessage(Logger::STRING_NO_STORE);
396 NOTREACHED(); 397 NOTREACHED();
397 return; 398 return;
398 } 399 }
399 password_store->GetLogins(observed_form_, prompt_policy, this); 400 password_store->GetLogins(observed_form_, prompt_policy, this);
400 } 401 }
401 402
402 bool PasswordFormManager::HasCompletedMatching() const { 403 bool PasswordFormManager::HasCompletedMatching() const {
403 return state_ == POST_MATCHING_PHASE; 404 return state_ == POST_MATCHING_PHASE;
404 } 405 }
405 406
406 bool PasswordFormManager::IsIgnorableChangePasswordForm() const {
407 bool is_change_password_form = !observed_form_.new_password_element.empty() &&
408 !observed_form_.password_element.empty();
409 bool is_username_certainly_correct = observed_form_.username_marked_by_site;
410 return is_change_password_form && !is_username_certainly_correct;
411 }
412
413 void PasswordFormManager::OnRequestDone( 407 void PasswordFormManager::OnRequestDone(
414 const std::vector<PasswordForm*>& logins_result) { 408 const std::vector<PasswordForm*>& logins_result) {
415 // Note that the result gets deleted after this call completes, but we own 409 // Note that the result gets deleted after this call completes, but we own
416 // the PasswordForm objects pointed to by the result vector, thus we keep 410 // the PasswordForm objects pointed to by the result vector, thus we keep
417 // copies to a minimum here. 411 // copies to a minimum here.
418 412
419 scoped_ptr<BrowserSavePasswordProgressLogger> logger; 413 scoped_ptr<BrowserSavePasswordProgressLogger> logger;
420 if (client_->IsLoggingActive()) { 414 if (client_->IsLoggingActive()) {
421 logger.reset(new BrowserSavePasswordProgressLogger(client_)); 415 logger.reset(new BrowserSavePasswordProgressLogger(client_));
422 logger->LogMessage(Logger::STRING_ON_REQUEST_DONE_METHOD); 416 logger->LogMessage(Logger::STRING_ON_REQUEST_DONE_METHOD);
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 // (1) we are in Incognito mode, (2) the ACTION paths don't match, 538 // (1) we are in Incognito mode, (2) the ACTION paths don't match,
545 // or (3) if it matched using public suffix domain matching. 539 // or (3) if it matched using public suffix domain matching.
546 bool wait_for_username = client_->IsOffTheRecord() || 540 bool wait_for_username = client_->IsOffTheRecord() ||
547 observed_form_.action.GetWithEmptyPath() != 541 observed_form_.action.GetWithEmptyPath() !=
548 preferred_match_->action.GetWithEmptyPath() || 542 preferred_match_->action.GetWithEmptyPath() ||
549 preferred_match_->IsPublicSuffixMatch(); 543 preferred_match_->IsPublicSuffixMatch();
550 if (wait_for_username) 544 if (wait_for_username)
551 manager_action_ = kManagerActionNone; 545 manager_action_ = kManagerActionNone;
552 else 546 else
553 manager_action_ = kManagerActionAutofilled; 547 manager_action_ = kManagerActionAutofilled;
554 password_manager_->Autofill(driver.get(), observed_form_, best_matches_, 548
555 *preferred_match_, wait_for_username); 549 // Do not autofill on sign-up or change password forms (until we have some
550 // working change password functionality).
551 if (observed_form_.new_password_element.empty()) {
vabr (Chromium) 2015/02/06 16:27:07 What's the advantage of moving the check to so lat
Pritam Nikam 2015/02/09 15:48:17 We can skip autofilling for all change-password fo
552 password_manager_->Autofill(driver.get(), observed_form_, best_matches_,
553 *preferred_match_, wait_for_username);
554 }
556 } 555 }
557 556
558 void PasswordFormManager::OnGetPasswordStoreResults( 557 void PasswordFormManager::OnGetPasswordStoreResults(
559 const std::vector<autofill::PasswordForm*>& results) { 558 const std::vector<autofill::PasswordForm*>& results) {
560 DCHECK_EQ(state_, MATCHING_PHASE); 559 DCHECK_EQ(state_, MATCHING_PHASE);
561 560
562 scoped_ptr<BrowserSavePasswordProgressLogger> logger; 561 scoped_ptr<BrowserSavePasswordProgressLogger> logger;
563 if (client_->IsLoggingActive()) { 562 if (client_->IsLoggingActive()) {
564 logger.reset(new BrowserSavePasswordProgressLogger(client_)); 563 logger.reset(new BrowserSavePasswordProgressLogger(client_));
565 logger->LogMessage(Logger::STRING_ON_GET_STORE_RESULTS_METHOD); 564 logger->LogMessage(Logger::STRING_ON_GET_STORE_RESULTS_METHOD);
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
861 if (has_generated_password_) 860 if (has_generated_password_)
862 LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMITTED); 861 LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMITTED);
863 } 862 }
864 863
865 void PasswordFormManager::SubmitFailed() { 864 void PasswordFormManager::SubmitFailed() {
866 submit_result_ = kSubmitResultFailed; 865 submit_result_ = kSubmitResultFailed;
867 if (has_generated_password_) 866 if (has_generated_password_)
868 LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMISSION_FAILED); 867 LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMISSION_FAILED);
869 } 868 }
870 869
870 bool PasswordFormManager::IsIgnorableChangePasswordForm() const {
871 bool is_change_password_form = !observed_form_.new_password_element.empty() &&
872 !observed_form_.password_element.empty();
873 bool is_username_certainly_correct = observed_form_.username_marked_by_site;
874 return is_change_password_form && !is_username_certainly_correct;
875 }
876
871 } // namespace password_manager 877 } // namespace password_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698