NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / password_manager / password_manager.cc
blob5ea66ab54b402ac10645f566595bee7eab18bda8
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.
5 #include "chrome/browser/password_manager/password_manager.h"
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 "chrome/browser/password_manager/password_form_manager.h"
15 #include "chrome/browser/password_manager/password_manager_client.h"
16 #include "chrome/browser/password_manager/password_manager_driver.h"
17 #include "chrome/common/pref_names.h"
18 #include "components/autofill/core/common/password_autofill_util.h"
19 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
20 #include "components/password_manager/core/common/password_manager_pref_names.h"
21 #include "components/user_prefs/pref_registry_syncable.h"
22 #include "grit/generated_resources.h"
24 using autofill::PasswordForm;
25 using autofill::PasswordFormMap;
27 namespace {
29 const char kSpdyProxyRealm[] = "/SpdyProxy";
31 // This routine is called when PasswordManagers are constructed.
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).
37 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());
42 static bool ran_once = false;
43 if (ran_once)
44 return;
45 ran_once = true;
47 UMA_HISTOGRAM_BOOLEAN("PasswordManager.Enabled", password_manager_enabled);
50 } // namespace
52 const char PasswordManager::kOtherPossibleUsernamesExperiment[] =
53 "PasswordManagerOtherPossibleUsernames";
55 // static
56 void PasswordManager::RegisterProfilePrefs(
57 user_prefs::PrefRegistrySyncable* registry) {
58 registry->RegisterBooleanPref(
59 prefs::kPasswordManagerEnabled,
60 true,
61 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
62 registry->RegisterBooleanPref(
63 prefs::kPasswordManagerAllowShowPasswords,
64 true,
65 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
66 registry->RegisterListPref(prefs::kPasswordManagerGroupsForDomains,
67 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
70 PasswordManager::PasswordManager(PasswordManagerClient* client)
71 : client_(client), driver_(client->GetDriver()) {
72 DCHECK(client_);
73 DCHECK(driver_);
74 password_manager_enabled_.Init(prefs::kPasswordManagerEnabled,
75 client_->GetPrefs());
77 ReportMetrics(*password_manager_enabled_);
80 PasswordManager::~PasswordManager() {
81 FOR_EACH_OBSERVER(LoginModelObserver, observers_, OnLoginModelDestroying());
84 void PasswordManager::SetFormHasGeneratedPassword(const PasswordForm& form) {
85 for (ScopedVector<PasswordFormManager>::iterator iter =
86 pending_login_managers_.begin();
87 iter != pending_login_managers_.end(); ++iter) {
88 if ((*iter)->DoesManage(
89 form, PasswordFormManager::ACTION_MATCH_REQUIRED)) {
90 (*iter)->SetHasGeneratedPassword();
91 return;
94 // If there is no corresponding PasswordFormManager, we create one. This is
95 // not the common case, and should only happen when there is a bug in our
96 // ability to detect forms.
97 bool ssl_valid = (form.origin.SchemeIsSecure() &&
98 !driver_->DidLastPageLoadEncounterSSLErrors());
99 PasswordFormManager* manager = new PasswordFormManager(
100 this, client_, driver_, form, ssl_valid);
101 pending_login_managers_.push_back(manager);
102 manager->SetHasGeneratedPassword();
103 // TODO(gcasto): Add UMA stats to track this.
106 bool PasswordManager::IsSavingEnabled() const {
107 return *password_manager_enabled_ && !driver_->IsOffTheRecord();
110 void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) {
111 if (!IsSavingEnabled()) {
112 RecordFailure(SAVING_DISABLED, form.origin.host());
113 return;
116 // No password to save? Then don't.
117 if (form.password_value.empty()) {
118 RecordFailure(EMPTY_PASSWORD, form.origin.host());
119 return;
122 scoped_ptr<PasswordFormManager> manager;
123 ScopedVector<PasswordFormManager>::iterator matched_manager_it =
124 pending_login_managers_.end();
125 for (ScopedVector<PasswordFormManager>::iterator iter =
126 pending_login_managers_.begin();
127 iter != pending_login_managers_.end(); ++iter) {
128 // If we find a manager that exactly matches the submitted form including
129 // the action URL, exit the loop.
130 if ((*iter)->DoesManage(
131 form, PasswordFormManager::ACTION_MATCH_REQUIRED)) {
132 matched_manager_it = iter;
133 break;
134 // If the current manager matches the submitted form excluding the action
135 // URL, remember it as a candidate and continue searching for an exact
136 // match.
137 } else if ((*iter)->DoesManage(
138 form, PasswordFormManager::ACTION_MATCH_NOT_REQUIRED)) {
139 matched_manager_it = iter;
142 // If we didn't find a manager, this means a form was submitted without
143 // first loading the page containing the form. Don't offer to save
144 // passwords in this case.
145 if (matched_manager_it != pending_login_managers_.end()) {
146 // Transfer ownership of the manager from |pending_login_managers_| to
147 // |manager|.
148 manager.reset(*matched_manager_it);
149 pending_login_managers_.weak_erase(matched_manager_it);
150 } else {
151 RecordFailure(NO_MATCHING_FORM, form.origin.host());
152 return;
155 // If we found a manager but it didn't finish matching yet, the user has
156 // tried to submit credentials before we had time to even find matching
157 // results for the given form and autofill. If this is the case, we just
158 // give up.
159 if (!manager->HasCompletedMatching()) {
160 RecordFailure(MATCHING_NOT_COMPLETE, form.origin.host());
161 return;
164 // Also get out of here if the user told us to 'never remember' passwords for
165 // this form.
166 if (manager->IsBlacklisted()) {
167 RecordFailure(FORM_BLACKLISTED, form.origin.host());
168 return;
171 // Bail if we're missing any of the necessary form components.
172 if (!manager->HasValidPasswordForm()) {
173 RecordFailure(INVALID_FORM, form.origin.host());
174 return;
177 // Always save generated passwords, as the user expresses explicit intent for
178 // Chrome to manage such passwords. For other passwords, respect the
179 // autocomplete attribute if autocomplete='off' is not ignored.
180 if (!autofill::ShouldIgnoreAutocompleteOffForPasswordFields() &&
181 !manager->HasGeneratedPassword() &&
182 !form.password_autocomplete_set) {
183 RecordFailure(AUTOCOMPLETE_OFF, form.origin.host());
184 return;
187 PasswordForm provisionally_saved_form(form);
188 provisionally_saved_form.ssl_valid =
189 form.origin.SchemeIsSecure() &&
190 !driver_->DidLastPageLoadEncounterSSLErrors();
191 provisionally_saved_form.preferred = true;
192 PasswordFormManager::OtherPossibleUsernamesAction action =
193 PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES;
194 if (OtherPossibleUsernamesEnabled())
195 action = PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES;
196 manager->ProvisionallySave(provisionally_saved_form, action);
197 provisional_save_manager_.swap(manager);
200 void PasswordManager::RecordFailure(ProvisionalSaveFailure failure,
201 const std::string& form_origin) {
202 UMA_HISTOGRAM_ENUMERATION("PasswordManager.ProvisionalSaveFailure",
203 failure, MAX_FAILURE_VALUE);
205 std::string group_name = password_manager_metrics_util::GroupIdToString(
206 password_manager_metrics_util::MonitoredDomainGroupId(
207 form_origin, client_->GetPrefs()));
208 if (!group_name.empty()) {
209 password_manager_metrics_util::LogUMAHistogramEnumeration(
210 "PasswordManager.ProvisionalSaveFailure_" + group_name, failure,
211 MAX_FAILURE_VALUE);
215 void PasswordManager::AddSubmissionCallback(
216 const PasswordSubmittedCallback& callback) {
217 submission_callbacks_.push_back(callback);
220 void PasswordManager::AddObserver(LoginModelObserver* observer) {
221 observers_.AddObserver(observer);
224 void PasswordManager::RemoveObserver(LoginModelObserver* observer) {
225 observers_.RemoveObserver(observer);
228 void PasswordManager::DidNavigateMainFrame(bool is_in_page) {
229 // Clear data after main frame navigation if the navigation was to a
230 // different page.
231 if (!is_in_page)
232 pending_login_managers_.clear();
235 void PasswordManager::OnPasswordFormSubmitted(
236 const PasswordForm& password_form) {
237 ProvisionallySavePassword(password_form);
238 for (size_t i = 0; i < submission_callbacks_.size(); ++i) {
239 submission_callbacks_[i].Run(password_form);
242 pending_login_managers_.clear();
245 void PasswordManager::OnPasswordFormsParsed(
246 const std::vector<PasswordForm>& forms) {
247 // Ask the SSLManager for current security.
248 bool had_ssl_error = driver_->DidLastPageLoadEncounterSSLErrors();
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;
257 bool ssl_valid = iter->origin.SchemeIsSecure() && !had_ssl_error;
258 PasswordFormManager* manager = new PasswordFormManager(
259 this, client_, driver_, *iter, ssl_valid);
260 pending_login_managers_.push_back(manager);
262 // Avoid prompting the user for access to a password if they don't have
263 // password saving enabled.
264 PasswordStore::AuthorizationPromptPolicy prompt_policy =
265 *password_manager_enabled_ ? PasswordStore::ALLOW_PROMPT
266 : PasswordStore::DISALLOW_PROMPT;
268 manager->FetchMatchingLoginsFromPasswordStore(prompt_policy);
272 bool PasswordManager::ShouldPromptUserToSavePassword() const {
273 return provisional_save_manager_->IsNewLogin() &&
274 !provisional_save_manager_->HasGeneratedPassword() &&
275 !provisional_save_manager_->IsPendingCredentialsPublicSuffixMatch();
278 void PasswordManager::OnPasswordFormsRendered(
279 const std::vector<PasswordForm>& visible_forms) {
280 if (!provisional_save_manager_.get())
281 return;
283 DCHECK(IsSavingEnabled());
285 // If we see the login form again, then the login failed.
286 for (size_t i = 0; i < visible_forms.size(); ++i) {
287 // TODO(vabr): The similarity check is just action equality for now. If it
288 // becomes more complex, it may make sense to consider modifying and using
289 // PasswordFormManager::DoesManage for it.
290 if (visible_forms[i].action.is_valid() &&
291 provisional_save_manager_->pending_credentials().action ==
292 visible_forms[i].action) {
293 provisional_save_manager_->SubmitFailed();
294 provisional_save_manager_.reset();
295 return;
299 // Looks like a successful login attempt. Either show an infobar or
300 // automatically save the login data. We prompt when the user hasn't already
301 // given consent, either through previously accepting the infobar or by having
302 // the browser generate the password.
303 provisional_save_manager_->SubmitPassed();
304 if (provisional_save_manager_->HasGeneratedPassword())
305 UMA_HISTOGRAM_COUNTS("PasswordGeneration.Submitted", 1);
307 if (ShouldPromptUserToSavePassword()) {
308 client_->PromptUserToSavePassword(provisional_save_manager_.release());
309 } else {
310 provisional_save_manager_->Save();
311 provisional_save_manager_.reset();
315 void PasswordManager::PossiblyInitializeUsernamesExperiment(
316 const PasswordFormMap& best_matches) const {
317 if (base::FieldTrialList::Find(kOtherPossibleUsernamesExperiment))
318 return;
320 bool other_possible_usernames_exist = false;
321 for (autofill::PasswordFormMap::const_iterator it = best_matches.begin();
322 it != best_matches.end(); ++it) {
323 if (!it->second->other_possible_usernames.empty()) {
324 other_possible_usernames_exist = true;
325 break;
329 if (!other_possible_usernames_exist)
330 return;
332 const base::FieldTrial::Probability kDivisor = 100;
333 scoped_refptr<base::FieldTrial> trial(
334 base::FieldTrialList::FactoryGetFieldTrial(
335 kOtherPossibleUsernamesExperiment,
336 kDivisor,
337 "Disabled",
338 2013, 12, 31,
339 base::FieldTrial::ONE_TIME_RANDOMIZED,
340 NULL));
341 base::FieldTrial::Probability enabled_probability =
342 client_->GetProbabilityForExperiment(kOtherPossibleUsernamesExperiment);
343 trial->AppendGroup("Enabled", enabled_probability);
346 bool PasswordManager::OtherPossibleUsernamesEnabled() const {
347 return base::FieldTrialList::FindFullName(
348 kOtherPossibleUsernamesExperiment) == "Enabled";
351 void PasswordManager::Autofill(
352 const PasswordForm& form_for_autofill,
353 const PasswordFormMap& best_matches,
354 const PasswordForm& preferred_match,
355 bool wait_for_username) const {
356 PossiblyInitializeUsernamesExperiment(best_matches);
358 // TODO(tedchoc): Switch to only requesting authentication if the user is
359 // acting on the autofilled forms (crbug.com/342594) instead
360 // of on page load.
361 bool authentication_required = preferred_match.use_additional_authentication;
362 for (autofill::PasswordFormMap::const_iterator it = best_matches.begin();
363 !authentication_required && it != best_matches.end(); ++it) {
364 if (it->second->use_additional_authentication)
365 authentication_required = true;
368 switch (form_for_autofill.scheme) {
369 case PasswordForm::SCHEME_HTML: {
370 // Note the check above is required because the observers_ for a non-HTML
371 // schemed password form may have been freed, so we need to distinguish.
372 scoped_ptr<autofill::PasswordFormFillData> fill_data(
373 new autofill::PasswordFormFillData());
374 InitPasswordFormFillData(form_for_autofill,
375 best_matches,
376 &preferred_match,
377 wait_for_username,
378 OtherPossibleUsernamesEnabled(),
379 fill_data.get());
380 if (authentication_required)
381 client_->AuthenticateAutofillAndFillForm(fill_data.Pass());
382 else
383 driver_->FillPasswordForm(*fill_data.get());
384 break;
386 default:
387 FOR_EACH_OBSERVER(
388 LoginModelObserver,
389 observers_,
390 OnAutofillDataAvailable(preferred_match.username_value,
391 preferred_match.password_value));
392 break;
395 client_->PasswordWasAutofilled(best_matches);