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