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 "components/password_manager/core/browser/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 "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/password_manager/core/common/password_manager_switches.h"
23 #include "components/pref_registry/pref_registry_syncable.h"
25 using autofill::PasswordForm;
26 using autofill::PasswordFormMap;
28 namespace password_manager {
32 const char kSpdyProxyRealm[] = "/SpdyProxy";
34 // Shorten the name to spare line breaks. The code provides enough context
36 typedef autofill::SavePasswordProgressLogger Logger;
38 // This routine is called when PasswordManagers are constructed.
40 // Currently we report metrics only once at startup. We require
41 // that this is only ever called from a single thread in order to
42 // avoid needing to lock (a static boolean flag is then sufficient to
43 // guarantee running only once).
44 void ReportMetrics(bool password_manager_enabled) {
45 static base::PlatformThreadId initial_thread_id =
46 base::PlatformThread::CurrentId();
47 DCHECK(initial_thread_id == base::PlatformThread::CurrentId());
49 static bool ran_once = false;
54 UMA_HISTOGRAM_BOOLEAN("PasswordManager.Enabled", password_manager_enabled);
57 bool ShouldDropSyncCredential() {
58 std::string group_name =
59 base::FieldTrialList::FindFullName("PasswordManagerDropSyncCredential");
61 CommandLine* command_line = CommandLine::ForCurrentProcess();
62 if (command_line->HasSwitch(switches::kEnableDropSyncCredential))
65 if (command_line->HasSwitch(switches::kDisableDropSyncCredential))
68 // Default to not saving.
69 return group_name != "Disabled";
74 const char PasswordManager::kOtherPossibleUsernamesExperiment[] =
75 "PasswordManagerOtherPossibleUsernames";
78 void PasswordManager::RegisterProfilePrefs(
79 user_prefs::PrefRegistrySyncable* registry) {
80 registry->RegisterBooleanPref(
81 prefs::kPasswordManagerSavingEnabled,
83 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
84 registry->RegisterBooleanPref(
85 prefs::kPasswordManagerAllowShowPasswords,
87 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
88 registry->RegisterListPref(prefs::kPasswordManagerGroupsForDomains,
89 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
92 PasswordManager::PasswordManager(PasswordManagerClient* client)
93 : client_(client), driver_(client->GetDriver()) {
96 saving_passwords_enabled_.Init(prefs::kPasswordManagerSavingEnabled,
99 ReportMetrics(*saving_passwords_enabled_);
102 PasswordManager::~PasswordManager() {
103 FOR_EACH_OBSERVER(LoginModelObserver, observers_, OnLoginModelDestroying());
106 void PasswordManager::SetFormHasGeneratedPassword(const PasswordForm& form) {
107 DCHECK(IsSavingEnabledForCurrentPage());
109 for (ScopedVector<PasswordFormManager>::iterator iter =
110 pending_login_managers_.begin();
111 iter != pending_login_managers_.end();
113 if ((*iter)->DoesManage(form) ==
114 PasswordFormManager::RESULT_COMPLETE_MATCH) {
115 (*iter)->SetHasGeneratedPassword();
119 // If there is no corresponding PasswordFormManager, we create one. This is
120 // not the common case, and should only happen when there is a bug in our
121 // ability to detect forms.
122 bool ssl_valid = form.origin.SchemeIsSecure();
123 PasswordFormManager* manager =
124 new PasswordFormManager(this, client_, driver_, form, ssl_valid);
125 pending_login_managers_.push_back(manager);
126 manager->SetHasGeneratedPassword();
127 // TODO(gcasto): Add UMA stats to track this.
130 bool PasswordManager::IsEnabledForCurrentPage() const {
131 return !driver_->DidLastPageLoadEncounterSSLErrors() &&
132 client_->IsPasswordManagerEnabledForCurrentPage();
135 bool PasswordManager::IsSavingEnabledForCurrentPage() const {
136 return *saving_passwords_enabled_ && !driver_->IsOffTheRecord() &&
137 IsEnabledForCurrentPage();
140 void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) {
141 bool is_saving_enabled = IsSavingEnabledForCurrentPage();
143 scoped_ptr<BrowserSavePasswordProgressLogger> logger;
144 if (client_->IsLoggingActive()) {
145 logger.reset(new BrowserSavePasswordProgressLogger(client_));
146 logger->LogMessage(Logger::STRING_PROVISIONALLY_SAVE_PASSWORD_METHOD);
147 logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVE_PASSWORD_FORM,
149 logger->LogBoolean(Logger::STRING_IS_SAVING_ENABLED, is_saving_enabled);
150 logger->LogBoolean(Logger::STRING_SSL_ERRORS_PRESENT,
151 driver_->DidLastPageLoadEncounterSSLErrors());
154 if (!is_saving_enabled) {
155 RecordFailure(SAVING_DISABLED, form.origin.host(), logger.get());
159 // No password to save? Then don't.
160 if (form.password_value.empty() && form.new_password_value.empty()) {
161 RecordFailure(EMPTY_PASSWORD, form.origin.host(), logger.get());
165 scoped_ptr<PasswordFormManager> manager;
166 ScopedVector<PasswordFormManager>::iterator matched_manager_it =
167 pending_login_managers_.end();
168 // Below, "matching" is in DoesManage-sense and "not ready" in
169 // !HasCompletedMatching sense. We keep track of such PasswordFormManager
170 // instances for UMA.
171 bool has_found_matching_managers_which_were_not_ready = false;
172 for (ScopedVector<PasswordFormManager>::iterator iter =
173 pending_login_managers_.begin();
174 iter != pending_login_managers_.end();
176 PasswordFormManager::MatchResultMask result = (*iter)->DoesManage(form);
178 if (!(*iter)->HasCompletedMatching()) {
179 if (result != PasswordFormManager::RESULT_NO_MATCH)
180 has_found_matching_managers_which_were_not_ready = true;
184 if (result == PasswordFormManager::RESULT_COMPLETE_MATCH) {
185 // If we find a manager that exactly matches the submitted form including
186 // the action URL, exit the loop.
188 logger->LogMessage(Logger::STRING_EXACT_MATCH);
189 matched_manager_it = iter;
191 } else if (result == (PasswordFormManager::RESULT_COMPLETE_MATCH &
192 ~PasswordFormManager::RESULT_ACTION_MATCH)) {
193 // If the current manager matches the submitted form excluding the action
194 // URL, remember it as a candidate and continue searching for an exact
195 // match. See http://crbug.com/27246 for an example where actions can
198 logger->LogMessage(Logger::STRING_MATCH_WITHOUT_ACTION);
199 matched_manager_it = iter;
202 // If we didn't find a manager, this means a form was submitted without
203 // first loading the page containing the form. Don't offer to save
204 // passwords in this case.
205 if (matched_manager_it != pending_login_managers_.end()) {
206 // Transfer ownership of the manager from |pending_login_managers_| to
208 manager.reset(*matched_manager_it);
209 pending_login_managers_.weak_erase(matched_manager_it);
210 } else if (has_found_matching_managers_which_were_not_ready) {
211 // We found some managers, but none finished matching yet. The user has
212 // tried to submit credentials before we had time to even find matching
213 // results for the given form and autofill. If this is the case, we just
215 RecordFailure(MATCHING_NOT_COMPLETE, form.origin.host(), logger.get());
218 RecordFailure(NO_MATCHING_FORM, form.origin.host(), logger.get());
222 // Also get out of here if the user told us to 'never remember' passwords for
224 if (manager->IsBlacklisted()) {
225 RecordFailure(FORM_BLACKLISTED, form.origin.host(), logger.get());
229 // Bail if we're missing any of the necessary form components.
230 if (!manager->HasValidPasswordForm()) {
231 RecordFailure(INVALID_FORM, form.origin.host(), logger.get());
235 // Don't save credentials for the syncing account. See crbug.com/365832 for
237 if (ShouldDropSyncCredential() &&
238 client_->IsSyncAccountCredential(
239 base::UTF16ToUTF8(form.username_value), form.signon_realm)) {
240 RecordFailure(SYNC_CREDENTIAL, form.origin.host(), logger.get());
244 // Always save generated passwords, as the user expresses explicit intent for
245 // Chrome to manage such passwords. For other passwords, respect the
246 // autocomplete attribute if autocomplete='off' is not ignored.
247 if (!autofill::ShouldIgnoreAutocompleteOffForPasswordFields() &&
248 !manager->HasGeneratedPassword() && !form.password_autocomplete_set) {
249 RecordFailure(AUTOCOMPLETE_OFF, form.origin.host(), logger.get());
253 PasswordForm provisionally_saved_form(form);
254 provisionally_saved_form.ssl_valid =
255 form.origin.SchemeIsSecure() &&
256 !driver_->DidLastPageLoadEncounterSSLErrors();
257 provisionally_saved_form.preferred = true;
259 logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVED_FORM,
260 provisionally_saved_form);
262 PasswordFormManager::OtherPossibleUsernamesAction action =
263 PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES;
264 if (OtherPossibleUsernamesEnabled())
265 action = PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES;
268 Logger::STRING_IGNORE_POSSIBLE_USERNAMES,
269 action == PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
271 manager->ProvisionallySave(provisionally_saved_form, action);
272 provisional_save_manager_.swap(manager);
275 void PasswordManager::RecordFailure(ProvisionalSaveFailure failure,
276 const std::string& form_origin,
277 BrowserSavePasswordProgressLogger* logger) {
278 UMA_HISTOGRAM_ENUMERATION(
279 "PasswordManager.ProvisionalSaveFailure", failure, MAX_FAILURE_VALUE);
281 std::string group_name = metrics_util::GroupIdToString(
282 metrics_util::MonitoredDomainGroupId(form_origin, client_->GetPrefs()));
283 if (!group_name.empty()) {
284 metrics_util::LogUMAHistogramEnumeration(
285 "PasswordManager.ProvisionalSaveFailure_" + group_name,
292 case SAVING_DISABLED:
293 logger->LogMessage(Logger::STRING_SAVING_DISABLED);
296 logger->LogMessage(Logger::STRING_EMPTY_PASSWORD);
298 case MATCHING_NOT_COMPLETE:
299 logger->LogMessage(Logger::STRING_MATCHING_NOT_COMPLETE);
301 case NO_MATCHING_FORM:
302 logger->LogMessage(Logger::STRING_NO_MATCHING_FORM);
304 case FORM_BLACKLISTED:
305 logger->LogMessage(Logger::STRING_FORM_BLACKLISTED);
308 logger->LogMessage(Logger::STRING_INVALID_FORM);
310 case AUTOCOMPLETE_OFF:
311 logger->LogMessage(Logger::STRING_AUTOCOMPLETE_OFF);
313 case SYNC_CREDENTIAL:
314 logger->LogMessage(Logger::STRING_SYNC_CREDENTIAL);
316 case MAX_FAILURE_VALUE:
320 logger->LogMessage(Logger::STRING_DECISION_DROP);
324 void PasswordManager::AddSubmissionCallback(
325 const PasswordSubmittedCallback& callback) {
326 submission_callbacks_.push_back(callback);
329 void PasswordManager::AddObserver(LoginModelObserver* observer) {
330 observers_.AddObserver(observer);
333 void PasswordManager::RemoveObserver(LoginModelObserver* observer) {
334 observers_.RemoveObserver(observer);
337 void PasswordManager::DidNavigateMainFrame(bool is_in_page) {
338 // Clear data after main frame navigation if the navigation was to a
341 pending_login_managers_.clear();
342 driver_->GetPasswordAutofillManager()->Reset();
346 void PasswordManager::OnPasswordFormSubmitted(
347 const PasswordForm& password_form) {
348 ProvisionallySavePassword(password_form);
349 for (size_t i = 0; i < submission_callbacks_.size(); ++i) {
350 submission_callbacks_[i].Run(password_form);
353 pending_login_managers_.clear();
356 void PasswordManager::OnPasswordFormsParsed(
357 const std::vector<PasswordForm>& forms) {
358 CreatePendingLoginManagers(forms);
361 void PasswordManager::CreatePendingLoginManagers(
362 const std::vector<PasswordForm>& forms) {
363 if (!IsEnabledForCurrentPage())
366 // Copy the weak pointers to the currently known login managers for comparison
367 // against the newly added.
368 std::vector<PasswordFormManager*> old_login_managers(
369 pending_login_managers_.get());
370 for (std::vector<PasswordForm>::const_iterator iter = forms.begin();
373 // Don't involve the password manager if this form corresponds to
374 // SpdyProxy authentication, as indicated by the realm.
375 if (EndsWith(iter->signon_realm, kSpdyProxyRealm, true))
377 bool old_manager_found = false;
378 for (std::vector<PasswordFormManager*>::const_iterator old_manager =
379 old_login_managers.begin();
380 !old_manager_found && old_manager != old_login_managers.end();
382 old_manager_found = (*old_manager)->DoesManage(*iter) ==
383 PasswordFormManager::RESULT_COMPLETE_MATCH;
385 if (old_manager_found)
386 continue; // The current form is already managed.
388 bool ssl_valid = iter->origin.SchemeIsSecure();
389 PasswordFormManager* manager =
390 new PasswordFormManager(this, client_, driver_, *iter, ssl_valid);
391 pending_login_managers_.push_back(manager);
393 PasswordStore::AuthorizationPromptPolicy prompt_policy =
394 client_->GetAuthorizationPromptPolicy(*iter);
396 manager->FetchMatchingLoginsFromPasswordStore(prompt_policy);
400 bool PasswordManager::ShouldPromptUserToSavePassword() const {
401 return !client_->IsAutomaticPasswordSavingEnabled() &&
402 provisional_save_manager_->IsNewLogin() &&
403 !provisional_save_manager_->HasGeneratedPassword() &&
404 !provisional_save_manager_->IsPendingCredentialsPublicSuffixMatch();
407 void PasswordManager::OnPasswordFormsRendered(
408 const std::vector<PasswordForm>& visible_forms,
409 bool did_stop_loading) {
410 CreatePendingLoginManagers(visible_forms);
411 scoped_ptr<BrowserSavePasswordProgressLogger> logger;
412 if (client_->IsLoggingActive()) {
413 logger.reset(new BrowserSavePasswordProgressLogger(client_));
414 logger->LogMessage(Logger::STRING_ON_PASSWORD_FORMS_RENDERED_METHOD);
417 if (!provisional_save_manager_.get()) {
419 logger->LogMessage(Logger::STRING_NO_PROVISIONAL_SAVE_MANAGER);
420 logger->LogMessage(Logger::STRING_DECISION_DROP);
425 DCHECK(IsSavingEnabledForCurrentPage());
428 logger->LogNumber(Logger::STRING_NUMBER_OF_VISIBLE_FORMS,
429 visible_forms.size());
432 // Record all visible forms from the frame.
433 all_visible_forms_.insert(all_visible_forms_.end(),
434 visible_forms.begin(),
435 visible_forms.end());
437 // If we see the login form again, then the login failed.
438 if (did_stop_loading) {
439 for (size_t i = 0; i < all_visible_forms_.size(); ++i) {
440 // TODO(vabr): The similarity check is just action equality for now. If it
441 // becomes more complex, it may make sense to consider modifying and using
442 // PasswordFormManager::DoesManage for it.
443 if (all_visible_forms_[i].action.is_valid() &&
444 provisional_save_manager_->pending_credentials().action ==
445 all_visible_forms_[i].action) {
447 logger->LogPasswordForm(Logger::STRING_PASSWORD_FORM_REAPPEARED,
449 logger->LogMessage(Logger::STRING_DECISION_DROP);
451 provisional_save_manager_->SubmitFailed();
452 provisional_save_manager_.reset();
453 // Clear all_visible_forms_ once we found the match.
454 all_visible_forms_.clear();
459 // Clear all_visible_forms_ after checking all the visible forms.
460 all_visible_forms_.clear();
462 // Looks like a successful login attempt. Either show an infobar or
463 // automatically save the login data. We prompt when the user hasn't
464 // already given consent, either through previously accepting the infobar
465 // or by having the browser generate the password.
466 provisional_save_manager_->SubmitPassed();
468 if (ShouldPromptUserToSavePassword()) {
470 logger->LogMessage(Logger::STRING_DECISION_ASK);
471 client_->PromptUserToSavePassword(provisional_save_manager_.Pass());
474 logger->LogMessage(Logger::STRING_DECISION_SAVE);
475 provisional_save_manager_->Save();
477 if (provisional_save_manager_->HasGeneratedPassword()) {
478 client_->AutomaticPasswordSave(provisional_save_manager_.Pass());
480 provisional_save_manager_.reset();
486 void PasswordManager::PossiblyInitializeUsernamesExperiment(
487 const PasswordFormMap& best_matches) const {
488 if (base::FieldTrialList::Find(kOtherPossibleUsernamesExperiment))
491 bool other_possible_usernames_exist = false;
492 for (autofill::PasswordFormMap::const_iterator it = best_matches.begin();
493 it != best_matches.end();
495 if (!it->second->other_possible_usernames.empty()) {
496 other_possible_usernames_exist = true;
501 if (!other_possible_usernames_exist)
504 const base::FieldTrial::Probability kDivisor = 100;
505 scoped_refptr<base::FieldTrial> trial(
506 base::FieldTrialList::FactoryGetFieldTrial(
507 kOtherPossibleUsernamesExperiment,
511 base::FieldTrial::ONE_TIME_RANDOMIZED,
513 base::FieldTrial::Probability enabled_probability =
514 client_->GetProbabilityForExperiment(kOtherPossibleUsernamesExperiment);
515 trial->AppendGroup("Enabled", enabled_probability);
518 bool PasswordManager::OtherPossibleUsernamesEnabled() const {
519 return base::FieldTrialList::FindFullName(
520 kOtherPossibleUsernamesExperiment) == "Enabled";
523 void PasswordManager::Autofill(const PasswordForm& form_for_autofill,
524 const PasswordFormMap& best_matches,
525 const PasswordForm& preferred_match,
526 bool wait_for_username) const {
527 PossiblyInitializeUsernamesExperiment(best_matches);
529 // TODO(tedchoc): Switch to only requesting authentication if the user is
530 // acting on the autofilled forms (crbug.com/342594) instead
532 bool authentication_required = preferred_match.use_additional_authentication;
533 for (autofill::PasswordFormMap::const_iterator it = best_matches.begin();
534 !authentication_required && it != best_matches.end();
536 if (it->second->use_additional_authentication)
537 authentication_required = true;
540 switch (form_for_autofill.scheme) {
541 case PasswordForm::SCHEME_HTML: {
542 // Note the check above is required because the observers_ for a non-HTML
543 // schemed password form may have been freed, so we need to distinguish.
544 scoped_ptr<autofill::PasswordFormFillData> fill_data(
545 new autofill::PasswordFormFillData());
546 InitPasswordFormFillData(form_for_autofill,
550 OtherPossibleUsernamesEnabled(),
552 if (authentication_required)
553 client_->AuthenticateAutofillAndFillForm(fill_data.Pass());
555 driver_->FillPasswordForm(*fill_data.get());
562 OnAutofillDataAvailable(preferred_match.username_value,
563 preferred_match.password_value));
567 client_->PasswordWasAutofilled(best_matches);
570 } // namespace password_manager