password_manager.cc revision dc0f95d653279beabeb9817299e2902918ba123e
1// Copyright (c) 2011 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 <vector>
8
9#include "base/stl_util-inl.h"
10#include "base/threading/platform_thread.h"
11#include "base/utf_string_conversions.h"
12#include "chrome/browser/metrics/user_metrics.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/prefs/pref_service.h"
16#include "chrome/browser/profiles/profile.h"
17#include "chrome/common/autofill_messages.h"
18#include "chrome/common/pref_names.h"
19#include "chrome/common/render_messages_params.h"
20#include "grit/generated_resources.h"
21
22using webkit_glue::PasswordForm;
23using webkit_glue::PasswordFormMap;
24
25// static
26void PasswordManager::RegisterUserPrefs(PrefService* prefs) {
27  prefs->RegisterBooleanPref(prefs::kPasswordManagerEnabled, true);
28  prefs->RegisterBooleanPref(prefs::kPasswordManagerAllowShowPasswords, true);
29}
30
31// This routine is called when PasswordManagers are constructed.
32//
33// Currently we report metrics only once at startup. We require
34// that this is only ever called from a single thread in order to
35// avoid needing to lock (a static boolean flag is then sufficient to
36// guarantee running only once).
37static void ReportMetrics(bool password_manager_enabled) {
38  static base::PlatformThreadId initial_thread_id =
39      base::PlatformThread::CurrentId();
40  DCHECK(initial_thread_id == base::PlatformThread::CurrentId());
41
42  static bool ran_once = false;
43  if (ran_once)
44    return;
45  ran_once = true;
46
47  if (password_manager_enabled)
48    UserMetrics::RecordAction(UserMetricsAction("PasswordManager_Enabled"));
49  else
50    UserMetrics::RecordAction(UserMetricsAction("PasswordManager_Disabled"));
51}
52
53PasswordManager::PasswordManager(TabContents* tab_contents,
54                                 PasswordManagerDelegate* delegate)
55    : TabContentsObserver(tab_contents),
56      login_managers_deleter_(&pending_login_managers_),
57      delegate_(delegate),
58      observer_(NULL) {
59  DCHECK(delegate_);
60  password_manager_enabled_.Init(prefs::kPasswordManagerEnabled,
61      delegate_->GetProfileForPasswordManager()->GetPrefs(), NULL);
62
63  ReportMetrics(*password_manager_enabled_);
64}
65
66PasswordManager::~PasswordManager() {
67}
68
69void PasswordManager::ProvisionallySavePassword(PasswordForm form) {
70  if (!delegate_->GetProfileForPasswordManager() ||
71      delegate_->GetProfileForPasswordManager()->IsOffTheRecord() ||
72      !*password_manager_enabled_)
73    return;
74
75  // No password to save? Then don't.
76  if (form.password_value.empty())
77    return;
78
79  LoginManagers::iterator iter;
80  PasswordFormManager* manager = NULL;
81  for (iter = pending_login_managers_.begin();
82       iter != pending_login_managers_.end(); iter++) {
83    if ((*iter)->DoesManage(form)) {
84      manager = *iter;
85      break;
86    }
87  }
88  // If we didn't find a manager, this means a form was submitted without
89  // first loading the page containing the form. Don't offer to save
90  // passwords in this case.
91  if (!manager)
92    return;
93
94  // If we found a manager but it didn't finish matching yet, the user has
95  // tried to submit credentials before we had time to even find matching
96  // results for the given form and autofill. If this is the case, we just
97  // give up.
98  if (!manager->HasCompletedMatching())
99    return;
100
101  // Also get out of here if the user told us to 'never remember' passwords for
102  // this form.
103  if (manager->IsBlacklisted())
104    return;
105
106  form.ssl_valid = form.origin.SchemeIsSecure() &&
107      !delegate_->DidLastPageLoadEncounterSSLErrors();
108  form.preferred = true;
109  manager->ProvisionallySave(form);
110  provisional_save_manager_.reset(manager);
111  pending_login_managers_.erase(iter);
112  // We don't care about the rest of the forms on the page now that one
113  // was selected.
114  STLDeleteElements(&pending_login_managers_);
115}
116
117void PasswordManager::DidNavigate() {
118  // As long as this navigation isn't due to a currently pending
119  // password form submit, we're ready to reset and move on.
120  if (!provisional_save_manager_.get() && !pending_login_managers_.empty())
121    STLDeleteElements(&pending_login_managers_);
122}
123
124void PasswordManager::ClearProvisionalSave() {
125  provisional_save_manager_.reset();
126}
127
128void PasswordManager::SetObserver(LoginModelObserver* observer) {
129  observer_ = observer;
130}
131
132void PasswordManager::DidStopLoading() {
133  if (!provisional_save_manager_.get())
134    return;
135
136  DCHECK(!delegate_->GetProfileForPasswordManager()->IsOffTheRecord());
137  DCHECK(!provisional_save_manager_->IsBlacklisted());
138
139  if (!delegate_->GetProfileForPasswordManager())
140    return;
141  // Form is not completely valid - we do not support it.
142  if (!provisional_save_manager_->HasValidPasswordForm())
143    return;
144
145  provisional_save_manager_->SubmitPassed();
146  if (provisional_save_manager_->IsNewLogin()) {
147    delegate_->AddSavePasswordInfoBar(provisional_save_manager_.release());
148  } else {
149    // If the save is not a new username entry, then we just want to save this
150    // data (since the user already has related data saved), so don't prompt.
151    provisional_save_manager_->Save();
152    provisional_save_manager_.reset();
153  }
154}
155
156void PasswordManager::DidNavigateAnyFramePostCommit(
157      const NavigationController::LoadCommittedDetails& details,
158      const ViewHostMsg_FrameNavigate_Params& params) {
159  if (params.password_form.origin.is_valid())
160    ProvisionallySavePassword(params.password_form);
161}
162
163bool PasswordManager::OnMessageReceived(const IPC::Message& message) {
164  bool handled = true;
165  IPC_BEGIN_MESSAGE_MAP(PasswordManager, message)
166    IPC_MESSAGE_HANDLER(AutoFillHostMsg_PasswordFormsFound,
167                        OnPasswordFormsFound)
168    IPC_MESSAGE_HANDLER(AutoFillHostMsg_PasswordFormsVisible,
169                        OnPasswordFormsVisible)
170    IPC_MESSAGE_UNHANDLED(handled = false)
171  IPC_END_MESSAGE_MAP()
172  return handled;
173}
174
175void PasswordManager::OnPasswordFormsFound(
176    const std::vector<PasswordForm>& forms) {
177  if (!delegate_->GetProfileForPasswordManager())
178    return;
179  if (!*password_manager_enabled_)
180    return;
181
182  // Ask the SSLManager for current security.
183  bool had_ssl_error = delegate_->DidLastPageLoadEncounterSSLErrors();
184
185  std::vector<PasswordForm>::const_iterator iter;
186  for (iter = forms.begin(); iter != forms.end(); iter++) {
187    bool ssl_valid = iter->origin.SchemeIsSecure() && !had_ssl_error;
188    PasswordFormManager* manager =
189        new PasswordFormManager(delegate_->GetProfileForPasswordManager(),
190                                this, *iter, ssl_valid);
191    pending_login_managers_.push_back(manager);
192    manager->FetchMatchingLoginsFromPasswordStore();
193  }
194}
195
196void PasswordManager::OnPasswordFormsVisible(
197    const std::vector<PasswordForm>& visible_forms) {
198  if (!provisional_save_manager_.get())
199    return;
200  std::vector<PasswordForm>::const_iterator iter;
201  for (iter = visible_forms.begin(); iter != visible_forms.end(); iter++) {
202    if (provisional_save_manager_->DoesManage(*iter)) {
203      // The form trying to be saved has immediately re-appeared. Assume login
204      // failure and abort this save, by clearing provisional_save_manager_.
205      // Don't delete the login managers since the user may try again
206      // and we want to be able to save in that case.
207      provisional_save_manager_->SubmitFailed();
208      ClearProvisionalSave();
209      break;
210    }
211  }
212}
213
214void PasswordManager::Autofill(
215    const PasswordForm& form_for_autofill,
216    const PasswordFormMap& best_matches,
217    const PasswordForm* const preferred_match,
218    bool wait_for_username) const {
219  DCHECK(preferred_match);
220  switch (form_for_autofill.scheme) {
221    case PasswordForm::SCHEME_HTML: {
222      // Note the check above is required because the observer_ for a non-HTML
223      // schemed password form may have been freed, so we need to distinguish.
224      webkit_glue::PasswordFormFillData fill_data;
225      webkit_glue::PasswordFormDomManager::InitFillData(form_for_autofill,
226                                                        best_matches,
227                                                        preferred_match,
228                                                        wait_for_username,
229                                                        &fill_data);
230      delegate_->FillPasswordForm(fill_data);
231      return;
232    }
233    default:
234      if (observer_) {
235        observer_->OnAutofillDataAvailable(
236            UTF16ToWideHack(preferred_match->username_value),
237            UTF16ToWideHack(preferred_match->password_value));
238      }
239  }
240}
241