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