password_manager.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
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_manager.h"
6
7#include "base/command_line.h"
8#include "base/metrics/field_trial.h"
9#include "base/metrics/histogram.h"
10#include "base/prefs/pref_service.h"
11#include "base/strings/string_util.h"
12#include "base/strings/utf_string_conversions.h"
13#include "base/threading/platform_thread.h"
14#include "components/autofill/core/common/password_autofill_util.h"
15#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
16#include "components/password_manager/core/browser/password_autofill_manager.h"
17#include "components/password_manager/core/browser/password_form_manager.h"
18#include "components/password_manager/core/browser/password_manager_client.h"
19#include "components/password_manager/core/browser/password_manager_driver.h"
20#include "components/password_manager/core/browser/password_manager_metrics_util.h"
21#include "components/password_manager/core/common/password_manager_pref_names.h"
22#include "components/pref_registry/pref_registry_syncable.h"
23
24using autofill::PasswordForm;
25using autofill::PasswordFormMap;
26
27namespace password_manager {
28
29namespace {
30
31const char kSpdyProxyRealm[] = "/SpdyProxy";
32
33// Shorten the name to spare line breaks. The code provides enough context
34// already.
35typedef autofill::SavePasswordProgressLogger Logger;
36
37// This routine is called when PasswordManagers are constructed.
38//
39// Currently we report metrics only once at startup. We require
40// that this is only ever called from a single thread in order to
41// avoid needing to lock (a static boolean flag is then sufficient to
42// guarantee running only once).
43void ReportMetrics(bool password_manager_enabled) {
44  static base::PlatformThreadId initial_thread_id =
45      base::PlatformThread::CurrentId();
46  DCHECK(initial_thread_id == base::PlatformThread::CurrentId());
47
48  static bool ran_once = false;
49  if (ran_once)
50    return;
51  ran_once = true;
52
53  UMA_HISTOGRAM_BOOLEAN("PasswordManager.Enabled", password_manager_enabled);
54}
55
56}  // namespace
57
58const char PasswordManager::kOtherPossibleUsernamesExperiment[] =
59    "PasswordManagerOtherPossibleUsernames";
60
61// static
62void PasswordManager::RegisterProfilePrefs(
63    user_prefs::PrefRegistrySyncable* registry) {
64  registry->RegisterBooleanPref(
65      prefs::kPasswordManagerEnabled,
66      true,
67      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
68  registry->RegisterBooleanPref(
69      prefs::kPasswordManagerAllowShowPasswords,
70      true,
71      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
72  registry->RegisterListPref(prefs::kPasswordManagerGroupsForDomains,
73                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
74}
75
76PasswordManager::PasswordManager(PasswordManagerClient* client)
77    : client_(client), driver_(client->GetDriver()) {
78  DCHECK(client_);
79  DCHECK(driver_);
80  password_manager_enabled_.Init(prefs::kPasswordManagerEnabled,
81                                 client_->GetPrefs());
82
83  ReportMetrics(*password_manager_enabled_);
84}
85
86PasswordManager::~PasswordManager() {
87  FOR_EACH_OBSERVER(LoginModelObserver, observers_, OnLoginModelDestroying());
88}
89
90void PasswordManager::SetFormHasGeneratedPassword(const PasswordForm& form) {
91  DCHECK(IsSavingEnabledForCurrentPage());
92
93  for (ScopedVector<PasswordFormManager>::iterator iter =
94           pending_login_managers_.begin();
95       iter != pending_login_managers_.end();
96       ++iter) {
97    if ((*iter)->DoesManage(form, PasswordFormManager::ACTION_MATCH_REQUIRED)) {
98      (*iter)->SetHasGeneratedPassword();
99      return;
100    }
101  }
102  // If there is no corresponding PasswordFormManager, we create one. This is
103  // not the common case, and should only happen when there is a bug in our
104  // ability to detect forms.
105  bool ssl_valid = form.origin.SchemeIsSecure();
106  PasswordFormManager* manager =
107      new PasswordFormManager(this, client_, driver_, form, ssl_valid);
108  pending_login_managers_.push_back(manager);
109  manager->SetHasGeneratedPassword();
110  // TODO(gcasto): Add UMA stats to track this.
111}
112
113bool PasswordManager::IsSavingEnabledForCurrentPage() const {
114  return *password_manager_enabled_ && !driver_->IsOffTheRecord() &&
115         !driver_->DidLastPageLoadEncounterSSLErrors();
116}
117
118void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) {
119  bool is_saving_enabled = IsSavingEnabledForCurrentPage();
120
121  scoped_ptr<BrowserSavePasswordProgressLogger> logger;
122  if (client_->IsLoggingActive()) {
123    logger.reset(new BrowserSavePasswordProgressLogger(client_));
124    logger->LogMessage(Logger::STRING_PROVISIONALLY_SAVE_PASSWORD_METHOD);
125    logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVE_PASSWORD_FORM,
126                            form);
127    logger->LogBoolean(Logger::STRING_IS_SAVING_ENABLED, is_saving_enabled);
128    logger->LogBoolean(Logger::STRING_SSL_ERRORS_PRESENT,
129                       driver_->DidLastPageLoadEncounterSSLErrors());
130  }
131
132  if (!is_saving_enabled) {
133    RecordFailure(SAVING_DISABLED, form.origin.host(), logger.get());
134    return;
135  }
136
137  // No password to save? Then don't.
138  if (form.password_value.empty()) {
139    RecordFailure(EMPTY_PASSWORD, form.origin.host(), logger.get());
140    return;
141  }
142
143  scoped_ptr<PasswordFormManager> manager;
144  ScopedVector<PasswordFormManager>::iterator matched_manager_it =
145      pending_login_managers_.end();
146  for (ScopedVector<PasswordFormManager>::iterator iter =
147           pending_login_managers_.begin();
148       iter != pending_login_managers_.end();
149       ++iter) {
150    if ((*iter)->DoesManage(form, PasswordFormManager::ACTION_MATCH_REQUIRED)) {
151      // If we find a manager that exactly matches the submitted form including
152      // the action URL, exit the loop.
153      if (logger)
154        logger->LogMessage(Logger::STRING_EXACT_MATCH);
155      matched_manager_it = iter;
156      break;
157    } else if ((*iter)->DoesManage(
158                   form, PasswordFormManager::ACTION_MATCH_NOT_REQUIRED)) {
159      // If the current manager matches the submitted form excluding the action
160      // URL, remember it as a candidate and continue searching for an exact
161      // match.
162      if (logger)
163        logger->LogMessage(Logger::STRING_MATCH_WITHOUT_ACTION);
164      matched_manager_it = iter;
165    }
166  }
167  // If we didn't find a manager, this means a form was submitted without
168  // first loading the page containing the form. Don't offer to save
169  // passwords in this case.
170  if (matched_manager_it != pending_login_managers_.end()) {
171    // Transfer ownership of the manager from |pending_login_managers_| to
172    // |manager|.
173    manager.reset(*matched_manager_it);
174    pending_login_managers_.weak_erase(matched_manager_it);
175  } else {
176    RecordFailure(NO_MATCHING_FORM, form.origin.host(), logger.get());
177    return;
178  }
179
180  // If we found a manager but it didn't finish matching yet, the user has
181  // tried to submit credentials before we had time to even find matching
182  // results for the given form and autofill. If this is the case, we just
183  // give up.
184  if (!manager->HasCompletedMatching()) {
185    RecordFailure(MATCHING_NOT_COMPLETE, form.origin.host(), logger.get());
186    return;
187  }
188
189  // Also get out of here if the user told us to 'never remember' passwords for
190  // this form.
191  if (manager->IsBlacklisted()) {
192    RecordFailure(FORM_BLACKLISTED, form.origin.host(), logger.get());
193    return;
194  }
195
196  // Bail if we're missing any of the necessary form components.
197  if (!manager->HasValidPasswordForm()) {
198    RecordFailure(INVALID_FORM, form.origin.host(), logger.get());
199    return;
200  }
201
202  // Always save generated passwords, as the user expresses explicit intent for
203  // Chrome to manage such passwords. For other passwords, respect the
204  // autocomplete attribute if autocomplete='off' is not ignored.
205  if (!autofill::ShouldIgnoreAutocompleteOffForPasswordFields() &&
206      !manager->HasGeneratedPassword() && !form.password_autocomplete_set) {
207    RecordFailure(AUTOCOMPLETE_OFF, form.origin.host(), logger.get());
208    return;
209  }
210
211  PasswordForm provisionally_saved_form(form);
212  provisionally_saved_form.ssl_valid =
213      form.origin.SchemeIsSecure() &&
214      !driver_->DidLastPageLoadEncounterSSLErrors();
215  provisionally_saved_form.preferred = true;
216  if (logger) {
217    logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVED_FORM,
218                            provisionally_saved_form);
219  }
220  PasswordFormManager::OtherPossibleUsernamesAction action =
221      PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES;
222  if (OtherPossibleUsernamesEnabled())
223    action = PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES;
224  if (logger) {
225    logger->LogBoolean(
226        Logger::STRING_IGNORE_POSSIBLE_USERNAMES,
227        action == PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
228  }
229  manager->ProvisionallySave(provisionally_saved_form, action);
230  provisional_save_manager_.swap(manager);
231}
232
233void PasswordManager::RecordFailure(ProvisionalSaveFailure failure,
234                                    const std::string& form_origin,
235                                    BrowserSavePasswordProgressLogger* logger) {
236  UMA_HISTOGRAM_ENUMERATION(
237      "PasswordManager.ProvisionalSaveFailure", failure, MAX_FAILURE_VALUE);
238
239  std::string group_name = metrics_util::GroupIdToString(
240      metrics_util::MonitoredDomainGroupId(form_origin, client_->GetPrefs()));
241  if (!group_name.empty()) {
242    metrics_util::LogUMAHistogramEnumeration(
243        "PasswordManager.ProvisionalSaveFailure_" + group_name,
244        failure,
245        MAX_FAILURE_VALUE);
246  }
247
248  if (logger) {
249    switch (failure) {
250      case SAVING_DISABLED:
251        logger->LogMessage(Logger::STRING_SAVING_DISABLED);
252        break;
253      case EMPTY_PASSWORD:
254        logger->LogMessage(Logger::STRING_EMPTY_PASSWORD);
255        break;
256      case MATCHING_NOT_COMPLETE:
257        logger->LogMessage(Logger::STRING_NO_FORM_MANAGER);
258        break;
259      case NO_MATCHING_FORM:
260        logger->LogMessage(Logger::STRING_NO_MATCHING_FORM);
261        break;
262      case FORM_BLACKLISTED:
263        logger->LogMessage(Logger::STRING_FORM_BLACKLISTED);
264        break;
265      case INVALID_FORM:
266        logger->LogMessage(Logger::STRING_INVALID_FORM);
267        break;
268      case AUTOCOMPLETE_OFF:
269        logger->LogMessage(Logger::STRING_AUTOCOMPLETE_OFF);
270        break;
271      case MAX_FAILURE_VALUE:
272        NOTREACHED();
273        return;
274    }
275    logger->LogMessage(Logger::STRING_DECISION_DROP);
276  }
277}
278
279void PasswordManager::AddSubmissionCallback(
280    const PasswordSubmittedCallback& callback) {
281  submission_callbacks_.push_back(callback);
282}
283
284void PasswordManager::AddObserver(LoginModelObserver* observer) {
285  observers_.AddObserver(observer);
286}
287
288void PasswordManager::RemoveObserver(LoginModelObserver* observer) {
289  observers_.RemoveObserver(observer);
290}
291
292void PasswordManager::DidNavigateMainFrame(bool is_in_page) {
293  // Clear data after main frame navigation if the navigation was to a
294  // different page.
295  if (!is_in_page) {
296    pending_login_managers_.clear();
297    driver_->GetPasswordAutofillManager()->Reset();
298  }
299}
300
301void PasswordManager::OnPasswordFormSubmitted(
302    const PasswordForm& password_form) {
303  ProvisionallySavePassword(password_form);
304  for (size_t i = 0; i < submission_callbacks_.size(); ++i) {
305    submission_callbacks_[i].Run(password_form);
306  }
307
308  pending_login_managers_.clear();
309}
310
311void PasswordManager::OnPasswordFormsParsed(
312    const std::vector<PasswordForm>& forms) {
313  CreatePendingLoginManagers(forms);
314}
315
316void PasswordManager::CreatePendingLoginManagers(
317    const std::vector<PasswordForm>& forms) {
318  // Don't try to autofill or save passwords in the presence of SSL errors.
319  if (driver_->DidLastPageLoadEncounterSSLErrors())
320    return;
321
322  // Copy the weak pointers to the currently known login managers for comparison
323  // against the newly added.
324  std::vector<PasswordFormManager*> old_login_managers(
325      pending_login_managers_.get());
326  for (std::vector<PasswordForm>::const_iterator iter = forms.begin();
327       iter != forms.end();
328       ++iter) {
329    // Don't involve the password manager if this form corresponds to
330    // SpdyProxy authentication, as indicated by the realm.
331    if (EndsWith(iter->signon_realm, kSpdyProxyRealm, true))
332      continue;
333    bool old_manager_found = false;
334    for (std::vector<PasswordFormManager*>::const_iterator old_manager =
335             old_login_managers.begin();
336         !old_manager_found && old_manager != old_login_managers.end();
337         ++old_manager) {
338      old_manager_found |= (*old_manager)->DoesManage(
339          *iter, PasswordFormManager::ACTION_MATCH_REQUIRED);
340    }
341    if (old_manager_found)
342      continue;  // The current form is already managed.
343
344    bool ssl_valid = iter->origin.SchemeIsSecure();
345    PasswordFormManager* manager =
346        new PasswordFormManager(this, client_, driver_, *iter, ssl_valid);
347    pending_login_managers_.push_back(manager);
348
349    // Avoid prompting the user for access to a password if they don't have
350    // password saving enabled.
351    PasswordStore::AuthorizationPromptPolicy prompt_policy =
352        *password_manager_enabled_ ? PasswordStore::ALLOW_PROMPT
353                                   : PasswordStore::DISALLOW_PROMPT;
354
355    manager->FetchMatchingLoginsFromPasswordStore(prompt_policy);
356  }
357}
358
359bool PasswordManager::ShouldPromptUserToSavePassword() const {
360  return !client_->IsAutomaticPasswordSavingEnabled() &&
361         provisional_save_manager_->IsNewLogin() &&
362         !provisional_save_manager_->HasGeneratedPassword() &&
363         !provisional_save_manager_->IsPendingCredentialsPublicSuffixMatch();
364}
365
366void PasswordManager::OnPasswordFormsRendered(
367    const std::vector<PasswordForm>& visible_forms) {
368  CreatePendingLoginManagers(visible_forms);
369
370  scoped_ptr<BrowserSavePasswordProgressLogger> logger;
371  if (client_->IsLoggingActive()) {
372    logger.reset(new BrowserSavePasswordProgressLogger(client_));
373    logger->LogMessage(Logger::STRING_ON_PASSWORD_FORMS_RENDERED_METHOD);
374  }
375
376  if (!provisional_save_manager_.get()) {
377    if (logger) {
378      logger->LogMessage(Logger::STRING_NO_PROVISIONAL_SAVE_MANAGER);
379      logger->LogMessage(Logger::STRING_DECISION_DROP);
380    }
381    return;
382  }
383
384  DCHECK(IsSavingEnabledForCurrentPage());
385
386  if (logger) {
387    logger->LogNumber(Logger::STRING_NUMBER_OF_VISIBLE_FORMS,
388                      visible_forms.size());
389  }
390
391  // If we see the login form again, then the login failed.
392  for (size_t i = 0; i < visible_forms.size(); ++i) {
393    // TODO(vabr): The similarity check is just action equality for now. If it
394    // becomes more complex, it may make sense to consider modifying and using
395    // PasswordFormManager::DoesManage for it.
396    if (visible_forms[i].action.is_valid() &&
397        provisional_save_manager_->pending_credentials().action ==
398            visible_forms[i].action) {
399      if (logger) {
400        logger->LogPasswordForm(Logger::STRING_PASSWORD_FORM_REAPPEARED,
401                                visible_forms[i]);
402        logger->LogMessage(Logger::STRING_DECISION_DROP);
403      }
404      provisional_save_manager_->SubmitFailed();
405      provisional_save_manager_.reset();
406      return;
407    }
408  }
409
410  // Looks like a successful login attempt. Either show an infobar or
411  // automatically save the login data. We prompt when the user hasn't already
412  // given consent, either through previously accepting the infobar or by having
413  // the browser generate the password.
414  provisional_save_manager_->SubmitPassed();
415
416  if (ShouldPromptUserToSavePassword()) {
417    if (logger)
418      logger->LogMessage(Logger::STRING_DECISION_ASK);
419    client_->PromptUserToSavePassword(provisional_save_manager_.release());
420  } else {
421    if (logger)
422      logger->LogMessage(Logger::STRING_DECISION_SAVE);
423    provisional_save_manager_->Save();
424    provisional_save_manager_.reset();
425  }
426}
427
428void PasswordManager::PossiblyInitializeUsernamesExperiment(
429    const PasswordFormMap& best_matches) const {
430  if (base::FieldTrialList::Find(kOtherPossibleUsernamesExperiment))
431    return;
432
433  bool other_possible_usernames_exist = false;
434  for (autofill::PasswordFormMap::const_iterator it = best_matches.begin();
435       it != best_matches.end();
436       ++it) {
437    if (!it->second->other_possible_usernames.empty()) {
438      other_possible_usernames_exist = true;
439      break;
440    }
441  }
442
443  if (!other_possible_usernames_exist)
444    return;
445
446  const base::FieldTrial::Probability kDivisor = 100;
447  scoped_refptr<base::FieldTrial> trial(
448      base::FieldTrialList::FactoryGetFieldTrial(
449          kOtherPossibleUsernamesExperiment,
450          kDivisor,
451          "Disabled",
452          2013, 12, 31,
453          base::FieldTrial::ONE_TIME_RANDOMIZED,
454          NULL));
455  base::FieldTrial::Probability enabled_probability =
456      client_->GetProbabilityForExperiment(kOtherPossibleUsernamesExperiment);
457  trial->AppendGroup("Enabled", enabled_probability);
458}
459
460bool PasswordManager::OtherPossibleUsernamesEnabled() const {
461  return base::FieldTrialList::FindFullName(
462             kOtherPossibleUsernamesExperiment) == "Enabled";
463}
464
465void PasswordManager::Autofill(const PasswordForm& form_for_autofill,
466                               const PasswordFormMap& best_matches,
467                               const PasswordForm& preferred_match,
468                               bool wait_for_username) const {
469  PossiblyInitializeUsernamesExperiment(best_matches);
470
471  // TODO(tedchoc): Switch to only requesting authentication if the user is
472  //                acting on the autofilled forms (crbug.com/342594) instead
473  //                of on page load.
474  bool authentication_required = preferred_match.use_additional_authentication;
475  for (autofill::PasswordFormMap::const_iterator it = best_matches.begin();
476       !authentication_required && it != best_matches.end();
477       ++it) {
478    if (it->second->use_additional_authentication)
479      authentication_required = true;
480  }
481
482  switch (form_for_autofill.scheme) {
483    case PasswordForm::SCHEME_HTML: {
484      // Note the check above is required because the observers_ for a non-HTML
485      // schemed password form may have been freed, so we need to distinguish.
486      scoped_ptr<autofill::PasswordFormFillData> fill_data(
487          new autofill::PasswordFormFillData());
488      InitPasswordFormFillData(form_for_autofill,
489                               best_matches,
490                               &preferred_match,
491                               wait_for_username,
492                               OtherPossibleUsernamesEnabled(),
493                               fill_data.get());
494      if (authentication_required)
495        client_->AuthenticateAutofillAndFillForm(fill_data.Pass());
496      else
497        driver_->FillPasswordForm(*fill_data.get());
498      break;
499    }
500    default:
501      FOR_EACH_OBSERVER(
502          LoginModelObserver,
503          observers_,
504          OnAutofillDataAvailable(preferred_match.username_value,
505                                  preferred_match.password_value));
506      break;
507  }
508
509  client_->PasswordWasAutofilled(best_matches);
510}
511
512}  // namespace password_manager
513