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/password_manager/core/browser/browser_save_password_progress_logger.h"
15 #include "components/password_manager/core/browser/password_autofill_manager.h"
16 #include "components/password_manager/core/browser/password_form_manager.h"
17 #include "components/password_manager/core/browser/password_manager_client.h"
18 #include "components/password_manager/core/browser/password_manager_driver.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/password_manager/core/common/password_manager_switches.h"
22 #include "components/pref_registry/pref_registry_syncable.h"
25 #include "base/prefs/pref_registry_simple.h"
28 using autofill::PasswordForm;
29 using autofill::PasswordFormMap;
31 namespace password_manager {
35 const char kSpdyProxyRealm[] = "/SpdyProxy";
37 // Shorten the name to spare line breaks. The code provides enough context
39 typedef autofill::SavePasswordProgressLogger Logger;
41 // This routine is called when PasswordManagers are constructed.
43 // Currently we report metrics only once at startup. We require
44 // that this is only ever called from a single thread in order to
45 // avoid needing to lock (a static boolean flag is then sufficient to
46 // guarantee running only once).
47 void ReportMetrics(bool password_manager_enabled,
48 PasswordManagerClient* client) {
49 static base::PlatformThreadId initial_thread_id =
50 base::PlatformThread::CurrentId();
51 DCHECK(initial_thread_id == base::PlatformThread::CurrentId());
53 static bool ran_once = false;
58 PasswordStore* store = client->GetPasswordStore();
59 // May be NULL in tests.
62 client->GetSyncUsername(),
63 client->IsPasswordSyncEnabled(
64 password_manager::ONLY_CUSTOM_PASSPHRASE));
66 UMA_HISTOGRAM_BOOLEAN("PasswordManager.Enabled", password_manager_enabled);
69 bool ShouldDropSyncCredential() {
70 std::string group_name =
71 base::FieldTrialList::FindFullName("PasswordManagerDropSyncCredential");
73 CommandLine* command_line = CommandLine::ForCurrentProcess();
74 if (command_line->HasSwitch(switches::kEnableDropSyncCredential))
77 if (command_line->HasSwitch(switches::kDisableDropSyncCredential))
80 // Default to not saving.
81 return group_name != "Disabled";
84 bool URLsEqualUpToScheme(const GURL& a, const GURL& b) {
85 return (a.GetContent() == b.GetContent());
88 bool URLsEqualUpToHttpHttpsSubstitution(const GURL& a, const GURL& b) {
92 // The first-time and retry login forms action URLs sometimes differ in
93 // switching from HTTP to HTTPS, see http://crbug.com/400769.
94 if (a.SchemeIsHTTPOrHTTPS() && b.SchemeIsHTTPOrHTTPS())
95 return URLsEqualUpToScheme(a, b);
102 const char PasswordManager::kOtherPossibleUsernamesExperiment[] =
103 "PasswordManagerOtherPossibleUsernames";
106 void PasswordManager::RegisterProfilePrefs(
107 user_prefs::PrefRegistrySyncable* registry) {
108 registry->RegisterBooleanPref(
109 prefs::kPasswordManagerSavingEnabled,
111 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
112 registry->RegisterBooleanPref(
113 prefs::kPasswordManagerAllowShowPasswords,
115 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
116 registry->RegisterListPref(prefs::kPasswordManagerGroupsForDomains,
117 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
122 void PasswordManager::RegisterLocalPrefs(PrefRegistrySimple* registry) {
123 registry->RegisterInt64Pref(prefs::kOsPasswordLastChanged, 0);
124 registry->RegisterBooleanPref(prefs::kOsPasswordBlank, false);
128 PasswordManager::PasswordManager(PasswordManagerClient* client)
129 : client_(client), driver_(client->GetDriver()) {
132 saving_passwords_enabled_.Init(prefs::kPasswordManagerSavingEnabled,
133 client_->GetPrefs());
135 ReportMetrics(*saving_passwords_enabled_, client_);
138 PasswordManager::~PasswordManager() {
139 FOR_EACH_OBSERVER(LoginModelObserver, observers_, OnLoginModelDestroying());
142 void PasswordManager::SetFormHasGeneratedPassword(const PasswordForm& form) {
143 DCHECK(IsSavingEnabledForCurrentPage());
145 for (ScopedVector<PasswordFormManager>::iterator iter =
146 pending_login_managers_.begin();
147 iter != pending_login_managers_.end();
149 if ((*iter)->DoesManage(form) ==
150 PasswordFormManager::RESULT_COMPLETE_MATCH) {
151 (*iter)->SetHasGeneratedPassword();
155 // If there is no corresponding PasswordFormManager, we create one. This is
156 // not the common case, and should only happen when there is a bug in our
157 // ability to detect forms.
158 bool ssl_valid = form.origin.SchemeIsSecure();
159 PasswordFormManager* manager =
160 new PasswordFormManager(this, client_, driver_, form, ssl_valid);
161 pending_login_managers_.push_back(manager);
162 manager->SetHasGeneratedPassword();
163 // TODO(gcasto): Add UMA stats to track this.
166 bool PasswordManager::IsEnabledForCurrentPage() const {
167 return !driver_->DidLastPageLoadEncounterSSLErrors() &&
168 client_->IsPasswordManagerEnabledForCurrentPage();
171 bool PasswordManager::IsSavingEnabledForCurrentPage() const {
172 return *saving_passwords_enabled_ && !driver_->IsOffTheRecord() &&
173 IsEnabledForCurrentPage();
176 void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) {
177 bool is_saving_enabled = IsSavingEnabledForCurrentPage();
179 scoped_ptr<BrowserSavePasswordProgressLogger> logger;
180 if (client_->IsLoggingActive()) {
181 logger.reset(new BrowserSavePasswordProgressLogger(client_));
182 logger->LogMessage(Logger::STRING_PROVISIONALLY_SAVE_PASSWORD_METHOD);
183 logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVE_PASSWORD_FORM,
185 logger->LogBoolean(Logger::STRING_IS_SAVING_ENABLED, is_saving_enabled);
186 logger->LogBoolean(Logger::STRING_SSL_ERRORS_PRESENT,
187 driver_->DidLastPageLoadEncounterSSLErrors());
190 if (!is_saving_enabled) {
191 RecordFailure(SAVING_DISABLED, form.origin.host(), logger.get());
195 // No password to save? Then don't.
196 if ((form.new_password_element.empty() && form.password_value.empty()) ||
197 (!form.new_password_element.empty() && form.new_password_value.empty())) {
198 RecordFailure(EMPTY_PASSWORD, form.origin.host(), logger.get());
202 scoped_ptr<PasswordFormManager> manager;
203 ScopedVector<PasswordFormManager>::iterator matched_manager_it =
204 pending_login_managers_.end();
205 // Below, "matching" is in DoesManage-sense and "not ready" in
206 // !HasCompletedMatching sense. We keep track of such PasswordFormManager
207 // instances for UMA.
208 bool has_found_matching_managers_which_were_not_ready = false;
209 for (ScopedVector<PasswordFormManager>::iterator iter =
210 pending_login_managers_.begin();
211 iter != pending_login_managers_.end();
213 PasswordFormManager::MatchResultMask result = (*iter)->DoesManage(form);
215 if (!(*iter)->HasCompletedMatching()) {
216 if (result != PasswordFormManager::RESULT_NO_MATCH)
217 has_found_matching_managers_which_were_not_ready = true;
221 if (result == PasswordFormManager::RESULT_COMPLETE_MATCH) {
222 // If we find a manager that exactly matches the submitted form including
223 // the action URL, exit the loop.
225 logger->LogMessage(Logger::STRING_EXACT_MATCH);
226 matched_manager_it = iter;
228 } else if (result == (PasswordFormManager::RESULT_COMPLETE_MATCH &
229 ~PasswordFormManager::RESULT_ACTION_MATCH)) {
230 // If the current manager matches the submitted form excluding the action
231 // URL, remember it as a candidate and continue searching for an exact
232 // match. See http://crbug.com/27246 for an example where actions can
235 logger->LogMessage(Logger::STRING_MATCH_WITHOUT_ACTION);
236 matched_manager_it = iter;
239 // If we didn't find a manager, this means a form was submitted without
240 // first loading the page containing the form. Don't offer to save
241 // passwords in this case.
242 if (matched_manager_it != pending_login_managers_.end()) {
243 // Transfer ownership of the manager from |pending_login_managers_| to
245 manager.reset(*matched_manager_it);
246 pending_login_managers_.weak_erase(matched_manager_it);
247 } else if (has_found_matching_managers_which_were_not_ready) {
248 // We found some managers, but none finished matching yet. The user has
249 // tried to submit credentials before we had time to even find matching
250 // results for the given form and autofill. If this is the case, we just
252 RecordFailure(MATCHING_NOT_COMPLETE, form.origin.host(), logger.get());
255 RecordFailure(NO_MATCHING_FORM, form.origin.host(), logger.get());
259 // Also get out of here if the user told us to 'never remember' passwords for
261 if (manager->IsBlacklisted()) {
262 RecordFailure(FORM_BLACKLISTED, form.origin.host(), logger.get());
266 // Bail if we're missing any of the necessary form components.
267 if (!manager->HasValidPasswordForm()) {
268 RecordFailure(INVALID_FORM, form.origin.host(), logger.get());
272 // Don't save credentials for the syncing account. See crbug.com/365832 for
274 if (ShouldDropSyncCredential() &&
275 client_->IsSyncAccountCredential(
276 base::UTF16ToUTF8(form.username_value), form.signon_realm)) {
277 RecordFailure(SYNC_CREDENTIAL, form.origin.host(), logger.get());
281 PasswordForm provisionally_saved_form(form);
282 provisionally_saved_form.ssl_valid =
283 form.origin.SchemeIsSecure() &&
284 !driver_->DidLastPageLoadEncounterSSLErrors();
285 provisionally_saved_form.preferred = true;
287 logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVED_FORM,
288 provisionally_saved_form);
290 PasswordFormManager::OtherPossibleUsernamesAction action =
291 PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES;
292 if (OtherPossibleUsernamesEnabled())
293 action = PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES;
296 Logger::STRING_IGNORE_POSSIBLE_USERNAMES,
297 action == PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
299 manager->ProvisionallySave(provisionally_saved_form, action);
300 provisional_save_manager_.swap(manager);
303 void PasswordManager::RecordFailure(ProvisionalSaveFailure failure,
304 const std::string& form_origin,
305 BrowserSavePasswordProgressLogger* logger) {
306 UMA_HISTOGRAM_ENUMERATION(
307 "PasswordManager.ProvisionalSaveFailure", failure, MAX_FAILURE_VALUE);
309 std::string group_name = metrics_util::GroupIdToString(
310 metrics_util::MonitoredDomainGroupId(form_origin, client_->GetPrefs()));
311 if (!group_name.empty()) {
312 metrics_util::LogUMAHistogramEnumeration(
313 "PasswordManager.ProvisionalSaveFailure_" + group_name,
320 case SAVING_DISABLED:
321 logger->LogMessage(Logger::STRING_SAVING_DISABLED);
324 logger->LogMessage(Logger::STRING_EMPTY_PASSWORD);
326 case MATCHING_NOT_COMPLETE:
327 logger->LogMessage(Logger::STRING_MATCHING_NOT_COMPLETE);
329 case NO_MATCHING_FORM:
330 logger->LogMessage(Logger::STRING_NO_MATCHING_FORM);
332 case FORM_BLACKLISTED:
333 logger->LogMessage(Logger::STRING_FORM_BLACKLISTED);
336 logger->LogMessage(Logger::STRING_INVALID_FORM);
338 case SYNC_CREDENTIAL:
339 logger->LogMessage(Logger::STRING_SYNC_CREDENTIAL);
341 case MAX_FAILURE_VALUE:
345 logger->LogMessage(Logger::STRING_DECISION_DROP);
349 void PasswordManager::AddSubmissionCallback(
350 const PasswordSubmittedCallback& callback) {
351 submission_callbacks_.push_back(callback);
354 void PasswordManager::AddObserver(LoginModelObserver* observer) {
355 observers_.AddObserver(observer);
358 void PasswordManager::RemoveObserver(LoginModelObserver* observer) {
359 observers_.RemoveObserver(observer);
362 void PasswordManager::DidNavigateMainFrame(bool is_in_page) {
363 // Clear data after main frame navigation if the navigation was to a
366 pending_login_managers_.clear();
367 // There is no PasswordAutofillManager on iOS.
368 if (driver_->GetPasswordAutofillManager())
369 driver_->GetPasswordAutofillManager()->Reset();
373 void PasswordManager::OnPasswordFormSubmitted(
374 const PasswordForm& password_form) {
375 ProvisionallySavePassword(password_form);
376 for (size_t i = 0; i < submission_callbacks_.size(); ++i) {
377 submission_callbacks_[i].Run(password_form);
380 pending_login_managers_.clear();
383 void PasswordManager::OnPasswordFormsParsed(
384 const std::vector<PasswordForm>& forms) {
385 CreatePendingLoginManagers(forms);
388 void PasswordManager::CreatePendingLoginManagers(
389 const std::vector<PasswordForm>& forms) {
390 if (!IsEnabledForCurrentPage())
393 // Copy the weak pointers to the currently known login managers for comparison
394 // against the newly added.
395 std::vector<PasswordFormManager*> old_login_managers(
396 pending_login_managers_.get());
397 for (std::vector<PasswordForm>::const_iterator iter = forms.begin();
400 // Don't involve the password manager if this form corresponds to
401 // SpdyProxy authentication, as indicated by the realm.
402 if (EndsWith(iter->signon_realm, kSpdyProxyRealm, true))
404 bool old_manager_found = false;
405 for (std::vector<PasswordFormManager*>::const_iterator old_manager =
406 old_login_managers.begin();
407 !old_manager_found && old_manager != old_login_managers.end();
409 old_manager_found = (*old_manager)->DoesManage(*iter) ==
410 PasswordFormManager::RESULT_COMPLETE_MATCH;
412 if (old_manager_found)
413 continue; // The current form is already managed.
415 bool ssl_valid = iter->origin.SchemeIsSecure();
416 PasswordFormManager* manager =
417 new PasswordFormManager(this, client_, driver_, *iter, ssl_valid);
418 pending_login_managers_.push_back(manager);
420 PasswordStore::AuthorizationPromptPolicy prompt_policy =
421 client_->GetAuthorizationPromptPolicy(*iter);
423 manager->FetchMatchingLoginsFromPasswordStore(prompt_policy);
427 bool PasswordManager::ShouldPromptUserToSavePassword() const {
428 return !client_->IsAutomaticPasswordSavingEnabled() &&
429 provisional_save_manager_->IsNewLogin() &&
430 !provisional_save_manager_->HasGeneratedPassword() &&
431 !provisional_save_manager_->IsPendingCredentialsPublicSuffixMatch();
434 void PasswordManager::OnPasswordFormsRendered(
435 const std::vector<PasswordForm>& visible_forms,
436 bool did_stop_loading) {
437 CreatePendingLoginManagers(visible_forms);
438 scoped_ptr<BrowserSavePasswordProgressLogger> logger;
439 if (client_->IsLoggingActive()) {
440 logger.reset(new BrowserSavePasswordProgressLogger(client_));
441 logger->LogMessage(Logger::STRING_ON_PASSWORD_FORMS_RENDERED_METHOD);
444 if (!provisional_save_manager_.get()) {
446 logger->LogMessage(Logger::STRING_NO_PROVISIONAL_SAVE_MANAGER);
447 logger->LogMessage(Logger::STRING_DECISION_DROP);
452 DCHECK(IsSavingEnabledForCurrentPage());
455 logger->LogNumber(Logger::STRING_NUMBER_OF_VISIBLE_FORMS,
456 visible_forms.size());
459 // Record all visible forms from the frame.
460 all_visible_forms_.insert(all_visible_forms_.end(),
461 visible_forms.begin(),
462 visible_forms.end());
464 // If we see the login form again, then the login failed.
465 if (did_stop_loading) {
466 for (size_t i = 0; i < all_visible_forms_.size(); ++i) {
467 // TODO(vabr): The similarity check is just action equality up to
468 // HTTP<->HTTPS substitution for now. If it becomes more complex, it may
469 // make sense to consider modifying and using
470 // PasswordFormManager::DoesManage for it.
471 if (all_visible_forms_[i].action.is_valid() &&
472 URLsEqualUpToHttpHttpsSubstitution(
473 provisional_save_manager_->pending_credentials().action,
474 all_visible_forms_[i].action)) {
476 logger->LogPasswordForm(Logger::STRING_PASSWORD_FORM_REAPPEARED,
478 logger->LogMessage(Logger::STRING_DECISION_DROP);
480 provisional_save_manager_->SubmitFailed();
481 provisional_save_manager_.reset();
482 // Clear all_visible_forms_ once we found the match.
483 all_visible_forms_.clear();
488 // Clear all_visible_forms_ after checking all the visible forms.
489 all_visible_forms_.clear();
491 // Looks like a successful login attempt. Either show an infobar or
492 // automatically save the login data. We prompt when the user hasn't
493 // already given consent, either through previously accepting the infobar
494 // or by having the browser generate the password.
495 provisional_save_manager_->SubmitPassed();
497 if (ShouldPromptUserToSavePassword()) {
499 logger->LogMessage(Logger::STRING_DECISION_ASK);
500 if (client_->PromptUserToSavePassword(provisional_save_manager_.Pass())) {
502 logger->LogMessage(Logger::STRING_SHOW_PASSWORD_PROMPT);
506 logger->LogMessage(Logger::STRING_DECISION_SAVE);
507 provisional_save_manager_->Save();
509 if (provisional_save_manager_->HasGeneratedPassword()) {
510 client_->AutomaticPasswordSave(provisional_save_manager_.Pass());
512 provisional_save_manager_.reset();
518 void PasswordManager::PossiblyInitializeUsernamesExperiment(
519 const PasswordFormMap& best_matches) const {
520 if (base::FieldTrialList::Find(kOtherPossibleUsernamesExperiment))
523 bool other_possible_usernames_exist = false;
524 for (autofill::PasswordFormMap::const_iterator it = best_matches.begin();
525 it != best_matches.end();
527 if (!it->second->other_possible_usernames.empty()) {
528 other_possible_usernames_exist = true;
533 if (!other_possible_usernames_exist)
536 const base::FieldTrial::Probability kDivisor = 100;
537 scoped_refptr<base::FieldTrial> trial(
538 base::FieldTrialList::FactoryGetFieldTrial(
539 kOtherPossibleUsernamesExperiment,
543 base::FieldTrial::ONE_TIME_RANDOMIZED,
545 base::FieldTrial::Probability enabled_probability =
546 client_->GetProbabilityForExperiment(kOtherPossibleUsernamesExperiment);
547 trial->AppendGroup("Enabled", enabled_probability);
550 bool PasswordManager::OtherPossibleUsernamesEnabled() const {
551 return base::FieldTrialList::FindFullName(
552 kOtherPossibleUsernamesExperiment) == "Enabled";
555 void PasswordManager::Autofill(const PasswordForm& form_for_autofill,
556 const PasswordFormMap& best_matches,
557 const PasswordForm& preferred_match,
558 bool wait_for_username) const {
559 PossiblyInitializeUsernamesExperiment(best_matches);
561 switch (form_for_autofill.scheme) {
562 case PasswordForm::SCHEME_HTML: {
563 // Note the check above is required because the observers_ for a non-HTML
564 // schemed password form may have been freed, so we need to distinguish.
565 autofill::PasswordFormFillData fill_data;
566 InitPasswordFormFillData(form_for_autofill,
570 OtherPossibleUsernamesEnabled(),
572 driver_->FillPasswordForm(fill_data);
579 OnAutofillDataAvailable(preferred_match.username_value,
580 preferred_match.password_value));
584 client_->PasswordWasAutofilled(best_matches);
587 } // namespace password_manager