password_manager.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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 "chrome/browser/password_manager/password_manager.h"
6
7#include "base/metrics/field_trial.h"
8#include "base/metrics/histogram.h"
9#include "base/prefs/pref_service.h"
10#include "base/strings/string_util.h"
11#include "base/strings/utf_string_conversions.h"
12#include "base/threading/platform_thread.h"
13#include "chrome/browser/password_manager/password_form_manager.h"
14#include "chrome/browser/password_manager/password_manager_delegate.h"
15#include "chrome/browser/profiles/profile.h"
16#include "chrome/common/chrome_version_info.h"
17#include "chrome/common/pref_names.h"
18#include "components/autofill/common/autofill_messages.h"
19#include "components/user_prefs/pref_registry_syncable.h"
20#include "content/public/browser/navigation_details.h"
21#include "content/public/browser/user_metrics.h"
22#include "content/public/browser/web_contents.h"
23#include "content/public/common/frame_navigate_params.h"
24#include "grit/generated_resources.h"
25
26using content::UserMetricsAction;
27using content::WebContents;
28using content::PasswordForm;
29using content::PasswordFormMap;
30
31DEFINE_WEB_CONTENTS_USER_DATA_KEY(PasswordManager);
32
33namespace {
34
35const char kSpdyProxyRealm[] = "/SpdyProxy";
36const char kOtherPossibleUsernamesExperiment[] =
37    "PasswordManagerOtherPossibleUsernames";
38
39// This routine is called when PasswordManagers are constructed.
40//
41// Currently we report metrics only once at startup. We require
42// that this is only ever called from a single thread in order to
43// avoid needing to lock (a static boolean flag is then sufficient to
44// guarantee running only once).
45void ReportMetrics(bool password_manager_enabled) {
46  static base::PlatformThreadId initial_thread_id =
47      base::PlatformThread::CurrentId();
48  DCHECK(initial_thread_id == base::PlatformThread::CurrentId());
49
50  static bool ran_once = false;
51  if (ran_once)
52    return;
53  ran_once = true;
54
55  // TODO(isherman): This does not actually measure a user action.  It should be
56  // a boolean histogram.
57  if (password_manager_enabled)
58    content::RecordAction(UserMetricsAction("PasswordManager_Enabled"));
59  else
60    content::RecordAction(UserMetricsAction("PasswordManager_Disabled"));
61}
62
63}  // namespace
64
65// static
66void PasswordManager::RegisterUserPrefs(
67    user_prefs::PrefRegistrySyncable* registry) {
68  registry->RegisterBooleanPref(
69      prefs::kPasswordManagerEnabled,
70      true,
71      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
72  registry->RegisterBooleanPref(
73      prefs::kPasswordManagerAllowShowPasswords,
74      true,
75      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
76}
77
78// static
79void PasswordManager::CreateForWebContentsAndDelegate(
80    content::WebContents* contents,
81    PasswordManagerDelegate* delegate) {
82  if (FromWebContents(contents)) {
83    DCHECK_EQ(delegate, FromWebContents(contents)->delegate_);
84    return;
85  }
86
87  contents->SetUserData(UserDataKey(),
88                        new PasswordManager(contents, delegate));
89}
90
91PasswordManager::PasswordManager(WebContents* web_contents,
92                                 PasswordManagerDelegate* delegate)
93    : content::WebContentsObserver(web_contents),
94      delegate_(delegate),
95      observer_(NULL) {
96  DCHECK(delegate_);
97  password_manager_enabled_.Init(prefs::kPasswordManagerEnabled,
98                                 delegate_->GetProfile()->GetPrefs());
99
100  ReportMetrics(*password_manager_enabled_);
101}
102
103PasswordManager::~PasswordManager() {
104  if (observer_)
105    observer_->OnLoginModelDestroying();
106}
107
108void PasswordManager::SetFormHasGeneratedPassword(const PasswordForm& form) {
109  for (ScopedVector<PasswordFormManager>::iterator iter =
110           pending_login_managers_.begin();
111       iter != pending_login_managers_.end(); ++iter) {
112    if ((*iter)->DoesManage(
113        form, PasswordFormManager::ACTION_MATCH_REQUIRED)) {
114      (*iter)->SetHasGeneratedPassword();
115      return;
116    }
117  }
118  // If there is no corresponding PasswordFormManager, we create one. This is
119  // not the common case, and should only happen when there is a bug in our
120  // ability to detect forms.
121  bool ssl_valid = (form.origin.SchemeIsSecure() &&
122                    !delegate_->DidLastPageLoadEncounterSSLErrors());
123  PasswordFormManager* manager =
124      new PasswordFormManager(delegate_->GetProfile(),
125                              this,
126                              web_contents(),
127                              form,
128                              ssl_valid);
129  pending_login_managers_.push_back(manager);
130  manager->SetHasGeneratedPassword();
131  // TODO(gcasto): Add UMA stats to track this.
132}
133
134bool PasswordManager::IsSavingEnabled() const {
135  return *password_manager_enabled_ &&
136         !delegate_->GetProfile()->IsOffTheRecord();
137}
138
139void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) {
140  if (!IsSavingEnabled())
141    return;
142
143  // No password to save? Then don't.
144  if (form.password_value.empty())
145    return;
146
147  scoped_ptr<PasswordFormManager> manager;
148  ScopedVector<PasswordFormManager>::iterator matched_manager_it =
149      pending_login_managers_.end();
150  for (ScopedVector<PasswordFormManager>::iterator iter =
151           pending_login_managers_.begin();
152       iter != pending_login_managers_.end(); ++iter) {
153    // If we find a manager that exactly matches the submitted form including
154    // the action URL, exit the loop.
155    if ((*iter)->DoesManage(
156        form, PasswordFormManager::ACTION_MATCH_REQUIRED)) {
157      matched_manager_it = iter;
158      break;
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    } else if ((*iter)->DoesManage(
163        form, PasswordFormManager::ACTION_MATCH_NOT_REQUIRED)) {
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    return;
177  }
178
179  // If we found a manager but it didn't finish matching yet, the user has
180  // tried to submit credentials before we had time to even find matching
181  // results for the given form and autofill. If this is the case, we just
182  // give up.
183  if (!manager->HasCompletedMatching())
184    return;
185
186  // Also get out of here if the user told us to 'never remember' passwords for
187  // this form.
188  if (manager->IsBlacklisted())
189    return;
190
191  // Bail if we're missing any of the necessary form components.
192  if (!manager->HasValidPasswordForm())
193    return;
194
195  // Always save generated passwords, as the user expresses explicit intent for
196  // Chrome to manage such passwords. For other passwords, respect the
197  // autocomplete attribute.
198  if (!manager->HasGeneratedPassword() && !form.password_autocomplete_set)
199    return;
200
201  PasswordForm provisionally_saved_form(form);
202  provisionally_saved_form.ssl_valid = form.origin.SchemeIsSecure() &&
203      !delegate_->DidLastPageLoadEncounterSSLErrors();
204  provisionally_saved_form.preferred = true;
205  PasswordFormManager::OtherPossibleUsernamesAction action =
206      PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES;
207  if (OtherPossibleUsernamesEnabled())
208    action = PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES;
209  manager->ProvisionallySave(provisionally_saved_form, action);
210  provisional_save_manager_.swap(manager);
211}
212
213void PasswordManager::SetObserver(LoginModelObserver* observer) {
214  observer_ = observer;
215}
216
217void PasswordManager::DidNavigateAnyFrame(
218      const content::LoadCommittedDetails& details,
219      const content::FrameNavigateParams& params) {
220  bool password_form_submitted = params.password_form.origin.is_valid();
221
222  // Try to save the password if one was submitted.
223  if (password_form_submitted)
224    ProvisionallySavePassword(params.password_form);
225
226  // Clear data after submission or main frame navigation. We don't want
227  // to clear data after subframe navigation as there might be password
228  // forms on other frames that could be submitted.
229  if (password_form_submitted || details.is_main_frame)
230    pending_login_managers_.clear();
231}
232
233bool PasswordManager::OnMessageReceived(const IPC::Message& message) {
234  bool handled = true;
235  IPC_BEGIN_MESSAGE_MAP(PasswordManager, message)
236    IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsParsed,
237                        OnPasswordFormsParsed)
238    IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsRendered,
239                        OnPasswordFormsRendered)
240    IPC_MESSAGE_UNHANDLED(handled = false)
241  IPC_END_MESSAGE_MAP()
242  return handled;
243}
244
245void PasswordManager::OnPasswordFormsParsed(
246    const std::vector<PasswordForm>& forms) {
247  // Ask the SSLManager for current security.
248  bool had_ssl_error = delegate_->DidLastPageLoadEncounterSSLErrors();
249
250  for (std::vector<PasswordForm>::const_iterator iter = forms.begin();
251       iter != forms.end(); ++iter) {
252    // Don't involve the password manager if this form corresponds to
253    // SpdyProxy authentication, as indicated by the realm.
254    if (EndsWith(iter->signon_realm, kSpdyProxyRealm, true))
255      continue;
256
257    bool ssl_valid = iter->origin.SchemeIsSecure() && !had_ssl_error;
258    PasswordFormManager* manager =
259        new PasswordFormManager(delegate_->GetProfile(),
260                                this,
261                                web_contents(),
262                                *iter,
263                                ssl_valid);
264    pending_login_managers_.push_back(manager);
265    manager->FetchMatchingLoginsFromPasswordStore();
266  }
267}
268
269void PasswordManager::OnPasswordFormsRendered(
270    const std::vector<PasswordForm>& visible_forms) {
271  if (!provisional_save_manager_.get())
272    return;
273
274  DCHECK(IsSavingEnabled());
275
276  // First, check for a failed login attempt.
277  for (std::vector<PasswordForm>::const_iterator iter = visible_forms.begin();
278       iter != visible_forms.end(); ++iter) {
279    if (provisional_save_manager_->DoesManage(
280        *iter, PasswordFormManager::ACTION_MATCH_REQUIRED)) {
281      // The form trying to be saved has immediately re-appeared. Assume login
282      // failure and abort this save, by clearing provisional_save_manager_.
283      provisional_save_manager_->SubmitFailed();
284      provisional_save_manager_.reset();
285      return;
286    }
287  }
288
289  if (!provisional_save_manager_->HasValidPasswordForm()) {
290    // Form is not completely valid - we do not support it.
291    NOTREACHED();
292    provisional_save_manager_.reset();
293    return;
294  }
295
296  // Looks like a successful login attempt. Either show an infobar or
297  // automatically save the login data. We prompt when the user hasn't already
298  // given consent, either through previously accepting the infobar or by having
299  // the browser generate the password.
300  provisional_save_manager_->SubmitPassed();
301  if (provisional_save_manager_->HasGeneratedPassword())
302    UMA_HISTOGRAM_COUNTS("PasswordGeneration.Submitted", 1);
303  if (provisional_save_manager_->IsNewLogin() &&
304      !provisional_save_manager_->HasGeneratedPassword()) {
305    delegate_->AddSavePasswordInfoBarIfPermitted(
306        provisional_save_manager_.release());
307  } else {
308    provisional_save_manager_->Save();
309    provisional_save_manager_.reset();
310  }
311}
312
313void PasswordManager::PossiblyInitializeUsernamesExperiment(
314    const PasswordFormMap& best_matches) const {
315  if (base::FieldTrialList::Find(kOtherPossibleUsernamesExperiment))
316    return;
317
318  bool other_possible_usernames_exist = false;
319  for (content::PasswordFormMap::const_iterator it = best_matches.begin();
320       it != best_matches.end(); ++it) {
321    if (!it->second->other_possible_usernames.empty()) {
322      other_possible_usernames_exist = true;
323      break;
324    }
325  }
326
327  if (!other_possible_usernames_exist)
328    return;
329
330  const base::FieldTrial::Probability kDivisor = 100;
331  scoped_refptr<base::FieldTrial> trial(
332      base::FieldTrialList::FactoryGetFieldTrial(
333          kOtherPossibleUsernamesExperiment,
334          kDivisor, "Disabled", 2013, 12, 31, NULL));
335  trial->UseOneTimeRandomization();
336  base::FieldTrial::Probability enabled_probability = 0;
337
338  switch (chrome::VersionInfo::GetChannel()) {
339    case chrome::VersionInfo::CHANNEL_DEV:
340    case chrome::VersionInfo::CHANNEL_BETA:
341      enabled_probability = 50;
342      break;
343    default:
344      break;
345  }
346
347  trial->AppendGroup("Enabled", enabled_probability);
348}
349
350bool PasswordManager::OtherPossibleUsernamesEnabled() const {
351  return base::FieldTrialList::FindFullName(
352      kOtherPossibleUsernamesExperiment) == "Enabled";
353}
354
355void PasswordManager::Autofill(
356    const PasswordForm& form_for_autofill,
357    const PasswordFormMap& best_matches,
358    const PasswordForm& preferred_match,
359    bool wait_for_username) const {
360  PossiblyInitializeUsernamesExperiment(best_matches);
361  switch (form_for_autofill.scheme) {
362    case PasswordForm::SCHEME_HTML: {
363      // Note the check above is required because the observer_ for a non-HTML
364      // schemed password form may have been freed, so we need to distinguish.
365      autofill::PasswordFormFillData fill_data;
366      InitPasswordFormFillData(form_for_autofill,
367                               best_matches,
368                               &preferred_match,
369                               wait_for_username,
370                               OtherPossibleUsernamesEnabled(),
371                               &fill_data);
372      delegate_->FillPasswordForm(fill_data);
373      return;
374    }
375    default:
376      if (observer_) {
377        observer_->OnAutofillDataAvailable(preferred_match.username_value,
378                                           preferred_match.password_value);
379      }
380  }
381}
382