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

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: Created 5 years, 11 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
« no previous file with comments | « components/password_manager/core/browser/password_form_manager.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/command_line.h"
10 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
11 #include "base/metrics/user_metrics.h" 12 #include "base/metrics/user_metrics.h"
12 #include "base/strings/string_split.h" 13 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h" 14 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
15 #include "components/autofill/core/browser/autofill_manager.h" 16 #include "components/autofill/core/browser/autofill_manager.h"
16 #include "components/autofill/core/browser/form_structure.h" 17 #include "components/autofill/core/browser/form_structure.h"
17 #include "components/autofill/core/browser/validation.h" 18 #include "components/autofill/core/browser/validation.h"
19 #include "components/autofill/core/common/autofill_switches.h"
18 #include "components/autofill/core/common/password_form.h" 20 #include "components/autofill/core/common/password_form.h"
19 #include "components/password_manager/core/browser/browser_save_password_progres s_logger.h" 21 #include "components/password_manager/core/browser/browser_save_password_progres s_logger.h"
20 #include "components/password_manager/core/browser/password_manager.h" 22 #include "components/password_manager/core/browser/password_manager.h"
21 #include "components/password_manager/core/browser/password_manager_client.h" 23 #include "components/password_manager/core/browser/password_manager_client.h"
22 #include "components/password_manager/core/browser/password_manager_driver.h" 24 #include "components/password_manager/core/browser/password_manager_driver.h"
23 #include "components/password_manager/core/browser/password_store.h" 25 #include "components/password_manager/core/browser/password_store.h"
26 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
24 27
25 using autofill::FormStructure; 28 using autofill::FormStructure;
26 using autofill::PasswordForm; 29 using autofill::PasswordForm;
27 using autofill::PasswordFormMap; 30 using autofill::PasswordFormMap;
28 using base::Time; 31 using base::Time;
29 32
30 // Shorten the name to spare line breaks. The code provides enough context 33 // Shorten the name to spare line breaks. The code provides enough context
31 // already. 34 // already.
32 typedef autofill::SavePasswordProgressLogger Logger; 35 typedef autofill::SavePasswordProgressLogger Logger;
33 36
(...skipping 27 matching lines...) Expand all
61 event, SUBMISSION_EVENT_ENUM_COUNT); 64 event, SUBMISSION_EVENT_ENUM_COUNT);
62 } 65 }
63 66
64 PasswordForm CopyAndModifySSLValidity(const PasswordForm& orig, 67 PasswordForm CopyAndModifySSLValidity(const PasswordForm& orig,
65 bool ssl_valid) { 68 bool ssl_valid) {
66 PasswordForm result(orig); 69 PasswordForm result(orig);
67 result.ssl_valid = ssl_valid; 70 result.ssl_valid = ssl_valid;
68 return result; 71 return result;
69 } 72 }
70 73
74 bool IsChangePasswordForm(const PasswordForm& candidate) {
75 return !candidate.new_password_element.empty() &&
76 !candidate.password_element.empty();
77 }
78
71 } // namespace 79 } // namespace
72 80
73 PasswordFormManager::PasswordFormManager( 81 PasswordFormManager::PasswordFormManager(
74 PasswordManager* password_manager, 82 PasswordManager* password_manager,
75 PasswordManagerClient* client, 83 PasswordManagerClient* client,
76 const base::WeakPtr<PasswordManagerDriver>& driver, 84 const base::WeakPtr<PasswordManagerDriver>& driver,
77 const PasswordForm& observed_form, 85 const PasswordForm& observed_form,
78 bool ssl_valid) 86 bool ssl_valid)
79 : best_matches_deleter_(&best_matches_), 87 : best_matches_deleter_(&best_matches_),
80 observed_form_(CopyAndModifySSLValidity(observed_form, ssl_valid)), 88 observed_form_(CopyAndModifySSLValidity(observed_form, ssl_valid)),
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 } else if (action == ALLOW_OTHER_POSSIBLE_USERNAMES && 315 } else if (action == ALLOW_OTHER_POSSIBLE_USERNAMES &&
308 UpdatePendingCredentialsIfOtherPossibleUsername( 316 UpdatePendingCredentialsIfOtherPossibleUsername(
309 credentials.username_value)) { 317 credentials.username_value)) {
310 // |pending_credentials_| is now set. Note we don't update 318 // |pending_credentials_| is now set. Note we don't update
311 // |pending_credentials_.username_value| to |credentials.username_value| 319 // |pending_credentials_.username_value| to |credentials.username_value|
312 // yet because we need to keep the original username to modify the stored 320 // yet because we need to keep the original username to modify the stored
313 // credential. 321 // credential.
314 selected_username_ = credentials.username_value; 322 selected_username_ = credentials.username_value;
315 is_new_login_ = false; 323 is_new_login_ = false;
316 } else { 324 } else {
317 // User typed in a new, unknown username. 325 // Check whether its a change-password form with missing username or its
318 user_action_ = kUserActionOverrideUsernameAndPassword; 326 // obscured. E.g. numeric indicator of the password strength please refer
319 pending_credentials_ = observed_form_; 327 // http://crbug.com/448351.
320 pending_credentials_.username_value = credentials.username_value; 328 PasswordForm matching_form;
321 pending_credentials_.other_possible_usernames = 329 if (IsChangePasswordForm(credentials) &&
322 credentials.other_possible_usernames; 330 HasMatchingCredentialsInStore(credentials, &matching_form)) {
331 is_new_login_ = false;
332 pending_credentials_ = matching_form;
333 selected_username_ = matching_form.username_value;
334 user_action_ = kUserActionOverridePassword;
335 } else {
336 // User typed in a new, unknown username.
337 user_action_ = kUserActionOverrideUsernameAndPassword;
338 pending_credentials_ = observed_form_;
339 pending_credentials_.username_value = credentials.username_value;
340 pending_credentials_.other_possible_usernames =
341 credentials.other_possible_usernames;
323 342
324 // The password value will be filled in later, remove any garbage for now. 343 // The password value will be filled in later, remove any garbage for now.
325 pending_credentials_.password_value.clear(); 344 pending_credentials_.password_value.clear();
326 pending_credentials_.new_password_value.clear(); 345 pending_credentials_.new_password_value.clear();
327 346
328 // If this was a sign-up or change password form, the names of the elements 347 // If this was a sign-up or change password form, the names of the
329 // are likely different than those on a login form, so do not bother saving 348 // elements are likely different than those on a login form, so do not
330 // them. We will fill them with meaningful values in UpdateLogin() when the 349 // bother saving them. We will fill them with meaningful values in
331 // user goes onto a real login form for the first time. 350 // UpdateLogin() when the user goes onto a real login form for the first
332 if (!credentials.new_password_element.empty()) { 351 // time.
333 pending_credentials_.password_element.clear(); 352 if (!credentials.new_password_element.empty()) {
334 pending_credentials_.new_password_element.clear(); 353 pending_credentials_.password_element.clear();
354 pending_credentials_.new_password_element.clear();
355 }
335 } 356 }
336 } 357 }
337 358
338 pending_credentials_.action = credentials.action; 359 pending_credentials_.action = credentials.action;
339 // If the user selected credentials we autofilled from a PasswordForm 360 // If the user selected credentials we autofilled from a PasswordForm
340 // that contained no action URL (IE6/7 imported passwords, for example), 361 // that contained no action URL (IE6/7 imported passwords, for example),
341 // bless it with the action URL from the observed form. See bug 1107719. 362 // bless it with the action URL from the observed form. See bug 1107719.
342 if (pending_credentials_.action.is_empty()) 363 if (pending_credentials_.action.is_empty())
343 pending_credentials_.action = observed_form_.action; 364 pending_credentials_.action = observed_form_.action;
344 365
(...skipping 26 matching lines...) Expand all
371 state_ = MATCHING_PHASE; 392 state_ = MATCHING_PHASE;
372 393
373 scoped_ptr<BrowserSavePasswordProgressLogger> logger; 394 scoped_ptr<BrowserSavePasswordProgressLogger> logger;
374 if (client_->IsLoggingActive()) { 395 if (client_->IsLoggingActive()) {
375 logger.reset(new BrowserSavePasswordProgressLogger(client_)); 396 logger.reset(new BrowserSavePasswordProgressLogger(client_));
376 logger->LogMessage(Logger::STRING_FETCH_LOGINS_METHOD); 397 logger->LogMessage(Logger::STRING_FETCH_LOGINS_METHOD);
377 } 398 }
378 399
379 // Do not autofill on sign-up or change password forms (until we have some 400 // Do not autofill on sign-up or change password forms (until we have some
380 // working change password functionality). 401 // working change password functionality).
381 if (!observed_form_.new_password_element.empty()) { 402 if (!observed_form_.new_password_element.empty() &&
403 !base::CommandLine::ForCurrentProcess()->HasSwitch(
404 autofill::switches::kEnablePasswordSaveOnInPageNavigation)) {
382 if (logger) 405 if (logger)
383 logger->LogMessage(Logger::STRING_FORM_NOT_AUTOFILLED); 406 logger->LogMessage(Logger::STRING_FORM_NOT_AUTOFILLED);
384 client_->AutofillResultsComputed(); 407 client_->AutofillResultsComputed();
385 // There is no point in looking for the credentials in the store when they 408 // There is no point in looking for the credentials in the store when they
386 // won't be autofilled, so pretend there were none. 409 // won't be autofilled, so pretend there were none.
387 std::vector<autofill::PasswordForm*> dummy_results; 410 std::vector<autofill::PasswordForm*> dummy_results;
388 OnGetPasswordStoreResults(dummy_results); 411 OnGetPasswordStoreResults(dummy_results);
389 return; 412 return;
390 } 413 }
391 414
392 PasswordStore* password_store = client_->GetPasswordStore(); 415 PasswordStore* password_store = client_->GetPasswordStore();
393 if (!password_store) { 416 if (!password_store) {
394 if (logger) 417 if (logger)
395 logger->LogMessage(Logger::STRING_NO_STORE); 418 logger->LogMessage(Logger::STRING_NO_STORE);
396 NOTREACHED(); 419 NOTREACHED();
397 return; 420 return;
398 } 421 }
399 password_store->GetLogins(observed_form_, prompt_policy, this); 422 password_store->GetLogins(observed_form_, prompt_policy, this);
400 } 423 }
401 424
402 bool PasswordFormManager::HasCompletedMatching() const { 425 bool PasswordFormManager::HasCompletedMatching() const {
403 return state_ == POST_MATCHING_PHASE; 426 return state_ == POST_MATCHING_PHASE;
404 } 427 }
405 428
406 bool PasswordFormManager::IsIgnorableChangePasswordForm() const { 429 bool PasswordFormManager::IsIgnorableChangePasswordForm() const {
407 bool is_change_password_form = !observed_form_.new_password_element.empty() && 430 bool is_username_certainly_correct =
408 !observed_form_.password_element.empty(); 431 observed_form_.username_marked_by_site ||
409 bool is_username_certainly_correct = observed_form_.username_marked_by_site; 432 HasMatchingCredentialsInStore(observed_form_, nullptr);
410 return is_change_password_form && !is_username_certainly_correct; 433 return IsChangePasswordForm(observed_form_) && !is_username_certainly_correct;
411 } 434 }
412 435
413 void PasswordFormManager::OnRequestDone( 436 void PasswordFormManager::OnRequestDone(
414 const std::vector<PasswordForm*>& logins_result) { 437 const std::vector<PasswordForm*>& logins_result) {
415 // Note that the result gets deleted after this call completes, but we own 438 // 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 439 // the PasswordForm objects pointed to by the result vector, thus we keep
417 // copies to a minimum here. 440 // copies to a minimum here.
418 441
419 scoped_ptr<BrowserSavePasswordProgressLogger> logger; 442 scoped_ptr<BrowserSavePasswordProgressLogger> logger;
420 if (client_->IsLoggingActive()) { 443 if (client_->IsLoggingActive()) {
(...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after
861 if (has_generated_password_) 884 if (has_generated_password_)
862 LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMITTED); 885 LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMITTED);
863 } 886 }
864 887
865 void PasswordFormManager::SubmitFailed() { 888 void PasswordFormManager::SubmitFailed() {
866 submit_result_ = kSubmitResultFailed; 889 submit_result_ = kSubmitResultFailed;
867 if (has_generated_password_) 890 if (has_generated_password_)
868 LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMISSION_FAILED); 891 LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMISSION_FAILED);
869 } 892 }
870 893
894 bool PasswordFormManager::HasMatchingCredentialsInStore(
895 const autofill::PasswordForm& candidate,
896 autofill::PasswordForm* matching_form) const {
897 bool match_found = false;
898 for (PasswordFormMap::const_iterator iter = best_matches_.begin();
vabr (Chromium) 2015/01/28 13:25:32 nit: You can use for (const auto& match : best_mat
Pritam Nikam 2015/01/29 14:14:35 Done.
899 iter != best_matches_.end(); ++iter) {
900 if (net::registry_controlled_domains::SameDomainOrHost(
vabr (Chromium) 2015/01/28 13:25:32 This is too permissive, we cannot just update pass
Pritam Nikam 2015/01/29 14:14:35 Done.
901 iter->second->origin, candidate.origin,
902 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES) &&
903 (iter->second->password_value == candidate.password_value)) {
904 if (matching_form != nullptr)
vabr (Chromium) 2015/01/28 13:25:32 nit: Just write: if (matching_form)
Pritam Nikam 2015/01/29 14:14:35 Done.
905 *matching_form = *(iter->second);
906 match_found = true;
907 break;
908 }
909 }
910
911 return match_found;
912 }
913
871 } // namespace password_manager 914 } // namespace password_manager
OLDNEW
« no previous file with comments | « components/password_manager/core/browser/password_form_manager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698