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