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 "content/common/view_messages.h"
20 #include "grit/generated_resources.h"
21
22 using webkit_glue::PasswordForm;
23 using webkit_glue::PasswordFormMap;
24
25 // static
RegisterUserPrefs(PrefService * prefs)26 void 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).
ReportMetrics(bool password_manager_enabled)37 static 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
PasswordManager(TabContents * tab_contents,PasswordManagerDelegate * delegate)53 PasswordManager::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
~PasswordManager()66 PasswordManager::~PasswordManager() {
67 }
68
ProvisionallySavePassword(PasswordForm form)69 void 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
DidNavigate()117 void 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
ClearProvisionalSave()124 void PasswordManager::ClearProvisionalSave() {
125 provisional_save_manager_.reset();
126 }
127
SetObserver(LoginModelObserver * observer)128 void PasswordManager::SetObserver(LoginModelObserver* observer) {
129 observer_ = observer;
130 }
131
DidStopLoading()132 void 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
DidNavigateAnyFramePostCommit(const NavigationController::LoadCommittedDetails & details,const ViewHostMsg_FrameNavigate_Params & params)156 void 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
OnMessageReceived(const IPC::Message & message)163 bool 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
OnPasswordFormsFound(const std::vector<PasswordForm> & forms)175 void 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
OnPasswordFormsVisible(const std::vector<PasswordForm> & visible_forms)196 void 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
Autofill(const PasswordForm & form_for_autofill,const PasswordFormMap & best_matches,const PasswordForm * const preferred_match,bool wait_for_username) const214 void 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