• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "components/password_manager/core/browser/password_manager.h"
6 
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/pref_registry/pref_registry_syncable.h"
23 
24 using autofill::PasswordForm;
25 using autofill::PasswordFormMap;
26 
27 namespace password_manager {
28 
29 namespace {
30 
31 const char kSpdyProxyRealm[] = "/SpdyProxy";
32 
33 // Shorten the name to spare line breaks. The code provides enough context
34 // already.
35 typedef autofill::SavePasswordProgressLogger Logger;
36 
37 // This routine is called when PasswordManagers are constructed.
38 //
39 // Currently we report metrics only once at startup. We require
40 // that this is only ever called from a single thread in order to
41 // avoid needing to lock (a static boolean flag is then sufficient to
42 // guarantee running only once).
ReportMetrics(bool password_manager_enabled)43 void ReportMetrics(bool password_manager_enabled) {
44   static base::PlatformThreadId initial_thread_id =
45       base::PlatformThread::CurrentId();
46   DCHECK(initial_thread_id == base::PlatformThread::CurrentId());
47 
48   static bool ran_once = false;
49   if (ran_once)
50     return;
51   ran_once = true;
52 
53   UMA_HISTOGRAM_BOOLEAN("PasswordManager.Enabled", password_manager_enabled);
54 }
55 
56 }  // namespace
57 
58 const char PasswordManager::kOtherPossibleUsernamesExperiment[] =
59     "PasswordManagerOtherPossibleUsernames";
60 
61 // static
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)62 void PasswordManager::RegisterProfilePrefs(
63     user_prefs::PrefRegistrySyncable* registry) {
64   registry->RegisterBooleanPref(
65       prefs::kPasswordManagerEnabled,
66       true,
67       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
68   registry->RegisterBooleanPref(
69       prefs::kPasswordManagerAllowShowPasswords,
70       true,
71       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
72   registry->RegisterListPref(prefs::kPasswordManagerGroupsForDomains,
73                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
74 }
75 
PasswordManager(PasswordManagerClient * client)76 PasswordManager::PasswordManager(PasswordManagerClient* client)
77     : client_(client), driver_(client->GetDriver()) {
78   DCHECK(client_);
79   DCHECK(driver_);
80   password_manager_enabled_.Init(prefs::kPasswordManagerEnabled,
81                                  client_->GetPrefs());
82 
83   ReportMetrics(*password_manager_enabled_);
84 }
85 
~PasswordManager()86 PasswordManager::~PasswordManager() {
87   FOR_EACH_OBSERVER(LoginModelObserver, observers_, OnLoginModelDestroying());
88 }
89 
SetFormHasGeneratedPassword(const PasswordForm & form)90 void PasswordManager::SetFormHasGeneratedPassword(const PasswordForm& form) {
91   DCHECK(IsSavingEnabledForCurrentPage());
92 
93   for (ScopedVector<PasswordFormManager>::iterator iter =
94            pending_login_managers_.begin();
95        iter != pending_login_managers_.end();
96        ++iter) {
97     if ((*iter)->DoesManage(form, PasswordFormManager::ACTION_MATCH_REQUIRED)) {
98       (*iter)->SetHasGeneratedPassword();
99       return;
100     }
101   }
102   // If there is no corresponding PasswordFormManager, we create one. This is
103   // not the common case, and should only happen when there is a bug in our
104   // ability to detect forms.
105   bool ssl_valid = form.origin.SchemeIsSecure();
106   PasswordFormManager* manager =
107       new PasswordFormManager(this, client_, driver_, form, ssl_valid);
108   pending_login_managers_.push_back(manager);
109   manager->SetHasGeneratedPassword();
110   // TODO(gcasto): Add UMA stats to track this.
111 }
112 
IsSavingEnabledForCurrentPage() const113 bool PasswordManager::IsSavingEnabledForCurrentPage() const {
114   return *password_manager_enabled_ && !driver_->IsOffTheRecord() &&
115          !driver_->DidLastPageLoadEncounterSSLErrors();
116 }
117 
ProvisionallySavePassword(const PasswordForm & form)118 void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) {
119   bool is_saving_enabled = IsSavingEnabledForCurrentPage();
120 
121   scoped_ptr<BrowserSavePasswordProgressLogger> logger;
122   if (client_->IsLoggingActive()) {
123     logger.reset(new BrowserSavePasswordProgressLogger(client_));
124     logger->LogMessage(Logger::STRING_PROVISIONALLY_SAVE_PASSWORD_METHOD);
125     logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVE_PASSWORD_FORM,
126                             form);
127     logger->LogBoolean(Logger::STRING_IS_SAVING_ENABLED, is_saving_enabled);
128     logger->LogBoolean(Logger::STRING_SSL_ERRORS_PRESENT,
129                        driver_->DidLastPageLoadEncounterSSLErrors());
130   }
131 
132   if (!is_saving_enabled) {
133     RecordFailure(SAVING_DISABLED, form.origin.host(), logger.get());
134     return;
135   }
136 
137   // No password to save? Then don't.
138   if (form.password_value.empty()) {
139     RecordFailure(EMPTY_PASSWORD, form.origin.host(), logger.get());
140     return;
141   }
142 
143   scoped_ptr<PasswordFormManager> manager;
144   ScopedVector<PasswordFormManager>::iterator matched_manager_it =
145       pending_login_managers_.end();
146   for (ScopedVector<PasswordFormManager>::iterator iter =
147            pending_login_managers_.begin();
148        iter != pending_login_managers_.end();
149        ++iter) {
150     if ((*iter)->DoesManage(form, PasswordFormManager::ACTION_MATCH_REQUIRED)) {
151       // If we find a manager that exactly matches the submitted form including
152       // the action URL, exit the loop.
153       if (logger)
154         logger->LogMessage(Logger::STRING_EXACT_MATCH);
155       matched_manager_it = iter;
156       break;
157     } else if ((*iter)->DoesManage(
158                    form, PasswordFormManager::ACTION_MATCH_NOT_REQUIRED)) {
159       // If the current manager matches the submitted form excluding the action
160       // URL, remember it as a candidate and continue searching for an exact
161       // match.
162       if (logger)
163         logger->LogMessage(Logger::STRING_MATCH_WITHOUT_ACTION);
164       matched_manager_it = iter;
165     }
166   }
167   // If we didn't find a manager, this means a form was submitted without
168   // first loading the page containing the form. Don't offer to save
169   // passwords in this case.
170   if (matched_manager_it != pending_login_managers_.end()) {
171     // Transfer ownership of the manager from |pending_login_managers_| to
172     // |manager|.
173     manager.reset(*matched_manager_it);
174     pending_login_managers_.weak_erase(matched_manager_it);
175   } else {
176     RecordFailure(NO_MATCHING_FORM, form.origin.host(), logger.get());
177     return;
178   }
179 
180   // If we found a manager but it didn't finish matching yet, the user has
181   // tried to submit credentials before we had time to even find matching
182   // results for the given form and autofill. If this is the case, we just
183   // give up.
184   if (!manager->HasCompletedMatching()) {
185     RecordFailure(MATCHING_NOT_COMPLETE, form.origin.host(), logger.get());
186     return;
187   }
188 
189   // Also get out of here if the user told us to 'never remember' passwords for
190   // this form.
191   if (manager->IsBlacklisted()) {
192     RecordFailure(FORM_BLACKLISTED, form.origin.host(), logger.get());
193     return;
194   }
195 
196   // Bail if we're missing any of the necessary form components.
197   if (!manager->HasValidPasswordForm()) {
198     RecordFailure(INVALID_FORM, form.origin.host(), logger.get());
199     return;
200   }
201 
202   // Always save generated passwords, as the user expresses explicit intent for
203   // Chrome to manage such passwords. For other passwords, respect the
204   // autocomplete attribute if autocomplete='off' is not ignored.
205   if (!autofill::ShouldIgnoreAutocompleteOffForPasswordFields() &&
206       !manager->HasGeneratedPassword() && !form.password_autocomplete_set) {
207     RecordFailure(AUTOCOMPLETE_OFF, form.origin.host(), logger.get());
208     return;
209   }
210 
211   PasswordForm provisionally_saved_form(form);
212   provisionally_saved_form.ssl_valid =
213       form.origin.SchemeIsSecure() &&
214       !driver_->DidLastPageLoadEncounterSSLErrors();
215   provisionally_saved_form.preferred = true;
216   if (logger) {
217     logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVED_FORM,
218                             provisionally_saved_form);
219   }
220   PasswordFormManager::OtherPossibleUsernamesAction action =
221       PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES;
222   if (OtherPossibleUsernamesEnabled())
223     action = PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES;
224   if (logger) {
225     logger->LogBoolean(
226         Logger::STRING_IGNORE_POSSIBLE_USERNAMES,
227         action == PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
228   }
229   manager->ProvisionallySave(provisionally_saved_form, action);
230   provisional_save_manager_.swap(manager);
231 }
232 
RecordFailure(ProvisionalSaveFailure failure,const std::string & form_origin,BrowserSavePasswordProgressLogger * logger)233 void PasswordManager::RecordFailure(ProvisionalSaveFailure failure,
234                                     const std::string& form_origin,
235                                     BrowserSavePasswordProgressLogger* logger) {
236   UMA_HISTOGRAM_ENUMERATION(
237       "PasswordManager.ProvisionalSaveFailure", failure, MAX_FAILURE_VALUE);
238 
239   std::string group_name = metrics_util::GroupIdToString(
240       metrics_util::MonitoredDomainGroupId(form_origin, client_->GetPrefs()));
241   if (!group_name.empty()) {
242     metrics_util::LogUMAHistogramEnumeration(
243         "PasswordManager.ProvisionalSaveFailure_" + group_name,
244         failure,
245         MAX_FAILURE_VALUE);
246   }
247 
248   if (logger) {
249     switch (failure) {
250       case SAVING_DISABLED:
251         logger->LogMessage(Logger::STRING_SAVING_DISABLED);
252         break;
253       case EMPTY_PASSWORD:
254         logger->LogMessage(Logger::STRING_EMPTY_PASSWORD);
255         break;
256       case MATCHING_NOT_COMPLETE:
257         logger->LogMessage(Logger::STRING_NO_FORM_MANAGER);
258         break;
259       case NO_MATCHING_FORM:
260         logger->LogMessage(Logger::STRING_NO_MATCHING_FORM);
261         break;
262       case FORM_BLACKLISTED:
263         logger->LogMessage(Logger::STRING_FORM_BLACKLISTED);
264         break;
265       case INVALID_FORM:
266         logger->LogMessage(Logger::STRING_INVALID_FORM);
267         break;
268       case AUTOCOMPLETE_OFF:
269         logger->LogMessage(Logger::STRING_AUTOCOMPLETE_OFF);
270         break;
271       case MAX_FAILURE_VALUE:
272         NOTREACHED();
273         return;
274     }
275     logger->LogMessage(Logger::STRING_DECISION_DROP);
276   }
277 }
278 
AddSubmissionCallback(const PasswordSubmittedCallback & callback)279 void PasswordManager::AddSubmissionCallback(
280     const PasswordSubmittedCallback& callback) {
281   submission_callbacks_.push_back(callback);
282 }
283 
AddObserver(LoginModelObserver * observer)284 void PasswordManager::AddObserver(LoginModelObserver* observer) {
285   observers_.AddObserver(observer);
286 }
287 
RemoveObserver(LoginModelObserver * observer)288 void PasswordManager::RemoveObserver(LoginModelObserver* observer) {
289   observers_.RemoveObserver(observer);
290 }
291 
DidNavigateMainFrame(bool is_in_page)292 void PasswordManager::DidNavigateMainFrame(bool is_in_page) {
293   // Clear data after main frame navigation if the navigation was to a
294   // different page.
295   if (!is_in_page) {
296     pending_login_managers_.clear();
297     driver_->GetPasswordAutofillManager()->Reset();
298   }
299 }
300 
OnPasswordFormSubmitted(const PasswordForm & password_form)301 void PasswordManager::OnPasswordFormSubmitted(
302     const PasswordForm& password_form) {
303   ProvisionallySavePassword(password_form);
304   for (size_t i = 0; i < submission_callbacks_.size(); ++i) {
305     submission_callbacks_[i].Run(password_form);
306   }
307 
308   pending_login_managers_.clear();
309 }
310 
OnPasswordFormsParsed(const std::vector<PasswordForm> & forms)311 void PasswordManager::OnPasswordFormsParsed(
312     const std::vector<PasswordForm>& forms) {
313   CreatePendingLoginManagers(forms);
314 }
315 
CreatePendingLoginManagers(const std::vector<PasswordForm> & forms)316 void PasswordManager::CreatePendingLoginManagers(
317     const std::vector<PasswordForm>& forms) {
318   // Don't try to autofill or save passwords in the presence of SSL errors.
319   if (driver_->DidLastPageLoadEncounterSSLErrors())
320     return;
321 
322   // Copy the weak pointers to the currently known login managers for comparison
323   // against the newly added.
324   std::vector<PasswordFormManager*> old_login_managers(
325       pending_login_managers_.get());
326   for (std::vector<PasswordForm>::const_iterator iter = forms.begin();
327        iter != forms.end();
328        ++iter) {
329     // Don't involve the password manager if this form corresponds to
330     // SpdyProxy authentication, as indicated by the realm.
331     if (EndsWith(iter->signon_realm, kSpdyProxyRealm, true))
332       continue;
333     bool old_manager_found = false;
334     for (std::vector<PasswordFormManager*>::const_iterator old_manager =
335              old_login_managers.begin();
336          !old_manager_found && old_manager != old_login_managers.end();
337          ++old_manager) {
338       old_manager_found |= (*old_manager)->DoesManage(
339           *iter, PasswordFormManager::ACTION_MATCH_REQUIRED);
340     }
341     if (old_manager_found)
342       continue;  // The current form is already managed.
343 
344     bool ssl_valid = iter->origin.SchemeIsSecure();
345     PasswordFormManager* manager =
346         new PasswordFormManager(this, client_, driver_, *iter, ssl_valid);
347     pending_login_managers_.push_back(manager);
348 
349     // Avoid prompting the user for access to a password if they don't have
350     // password saving enabled.
351     PasswordStore::AuthorizationPromptPolicy prompt_policy =
352         *password_manager_enabled_ ? PasswordStore::ALLOW_PROMPT
353                                    : PasswordStore::DISALLOW_PROMPT;
354 
355     manager->FetchMatchingLoginsFromPasswordStore(prompt_policy);
356   }
357 }
358 
ShouldPromptUserToSavePassword() const359 bool PasswordManager::ShouldPromptUserToSavePassword() const {
360   return !client_->IsAutomaticPasswordSavingEnabled() &&
361          provisional_save_manager_->IsNewLogin() &&
362          !provisional_save_manager_->HasGeneratedPassword() &&
363          !provisional_save_manager_->IsPendingCredentialsPublicSuffixMatch();
364 }
365 
OnPasswordFormsRendered(const std::vector<PasswordForm> & visible_forms)366 void PasswordManager::OnPasswordFormsRendered(
367     const std::vector<PasswordForm>& visible_forms) {
368   CreatePendingLoginManagers(visible_forms);
369 
370   scoped_ptr<BrowserSavePasswordProgressLogger> logger;
371   if (client_->IsLoggingActive()) {
372     logger.reset(new BrowserSavePasswordProgressLogger(client_));
373     logger->LogMessage(Logger::STRING_ON_PASSWORD_FORMS_RENDERED_METHOD);
374   }
375 
376   if (!provisional_save_manager_.get()) {
377     if (logger) {
378       logger->LogMessage(Logger::STRING_NO_PROVISIONAL_SAVE_MANAGER);
379       logger->LogMessage(Logger::STRING_DECISION_DROP);
380     }
381     return;
382   }
383 
384   DCHECK(IsSavingEnabledForCurrentPage());
385 
386   if (logger) {
387     logger->LogNumber(Logger::STRING_NUMBER_OF_VISIBLE_FORMS,
388                       visible_forms.size());
389   }
390 
391   // If we see the login form again, then the login failed.
392   for (size_t i = 0; i < visible_forms.size(); ++i) {
393     // TODO(vabr): The similarity check is just action equality for now. If it
394     // becomes more complex, it may make sense to consider modifying and using
395     // PasswordFormManager::DoesManage for it.
396     if (visible_forms[i].action.is_valid() &&
397         provisional_save_manager_->pending_credentials().action ==
398             visible_forms[i].action) {
399       if (logger) {
400         logger->LogPasswordForm(Logger::STRING_PASSWORD_FORM_REAPPEARED,
401                                 visible_forms[i]);
402         logger->LogMessage(Logger::STRING_DECISION_DROP);
403       }
404       provisional_save_manager_->SubmitFailed();
405       provisional_save_manager_.reset();
406       return;
407     }
408   }
409 
410   // Looks like a successful login attempt. Either show an infobar or
411   // automatically save the login data. We prompt when the user hasn't already
412   // given consent, either through previously accepting the infobar or by having
413   // the browser generate the password.
414   provisional_save_manager_->SubmitPassed();
415 
416   if (ShouldPromptUserToSavePassword()) {
417     if (logger)
418       logger->LogMessage(Logger::STRING_DECISION_ASK);
419     client_->PromptUserToSavePassword(provisional_save_manager_.release());
420   } else {
421     if (logger)
422       logger->LogMessage(Logger::STRING_DECISION_SAVE);
423     provisional_save_manager_->Save();
424     provisional_save_manager_.reset();
425   }
426 }
427 
PossiblyInitializeUsernamesExperiment(const PasswordFormMap & best_matches) const428 void PasswordManager::PossiblyInitializeUsernamesExperiment(
429     const PasswordFormMap& best_matches) const {
430   if (base::FieldTrialList::Find(kOtherPossibleUsernamesExperiment))
431     return;
432 
433   bool other_possible_usernames_exist = false;
434   for (autofill::PasswordFormMap::const_iterator it = best_matches.begin();
435        it != best_matches.end();
436        ++it) {
437     if (!it->second->other_possible_usernames.empty()) {
438       other_possible_usernames_exist = true;
439       break;
440     }
441   }
442 
443   if (!other_possible_usernames_exist)
444     return;
445 
446   const base::FieldTrial::Probability kDivisor = 100;
447   scoped_refptr<base::FieldTrial> trial(
448       base::FieldTrialList::FactoryGetFieldTrial(
449           kOtherPossibleUsernamesExperiment,
450           kDivisor,
451           "Disabled",
452           2013, 12, 31,
453           base::FieldTrial::ONE_TIME_RANDOMIZED,
454           NULL));
455   base::FieldTrial::Probability enabled_probability =
456       client_->GetProbabilityForExperiment(kOtherPossibleUsernamesExperiment);
457   trial->AppendGroup("Enabled", enabled_probability);
458 }
459 
OtherPossibleUsernamesEnabled() const460 bool PasswordManager::OtherPossibleUsernamesEnabled() const {
461   return base::FieldTrialList::FindFullName(
462              kOtherPossibleUsernamesExperiment) == "Enabled";
463 }
464 
Autofill(const PasswordForm & form_for_autofill,const PasswordFormMap & best_matches,const PasswordForm & preferred_match,bool wait_for_username) const465 void PasswordManager::Autofill(const PasswordForm& form_for_autofill,
466                                const PasswordFormMap& best_matches,
467                                const PasswordForm& preferred_match,
468                                bool wait_for_username) const {
469   PossiblyInitializeUsernamesExperiment(best_matches);
470 
471   // TODO(tedchoc): Switch to only requesting authentication if the user is
472   //                acting on the autofilled forms (crbug.com/342594) instead
473   //                of on page load.
474   bool authentication_required = preferred_match.use_additional_authentication;
475   for (autofill::PasswordFormMap::const_iterator it = best_matches.begin();
476        !authentication_required && it != best_matches.end();
477        ++it) {
478     if (it->second->use_additional_authentication)
479       authentication_required = true;
480   }
481 
482   switch (form_for_autofill.scheme) {
483     case PasswordForm::SCHEME_HTML: {
484       // Note the check above is required because the observers_ for a non-HTML
485       // schemed password form may have been freed, so we need to distinguish.
486       scoped_ptr<autofill::PasswordFormFillData> fill_data(
487           new autofill::PasswordFormFillData());
488       InitPasswordFormFillData(form_for_autofill,
489                                best_matches,
490                                &preferred_match,
491                                wait_for_username,
492                                OtherPossibleUsernamesEnabled(),
493                                fill_data.get());
494       if (authentication_required)
495         client_->AuthenticateAutofillAndFillForm(fill_data.Pass());
496       else
497         driver_->FillPasswordForm(*fill_data.get());
498       break;
499     }
500     default:
501       FOR_EACH_OBSERVER(
502           LoginModelObserver,
503           observers_,
504           OnAutofillDataAvailable(preferred_match.username_value,
505                                   preferred_match.password_value));
506       break;
507   }
508 
509   client_->PasswordWasAutofilled(best_matches);
510 }
511 
512 }  // namespace password_manager
513