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). 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 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 72 bool URLsEqualUpToScheme(const GURL& a, const GURL& b) { 73 return (a.GetContent() == b.GetContent()); 74 } 75 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 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 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 118 PasswordManager::~PasswordManager() { 119 FOR_EACH_OBSERVER(LoginModelObserver, observers_, OnLoginModelDestroying()); 120 } 121 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 146 bool PasswordManager::IsEnabledForCurrentPage() const { 147 return !driver_->DidLastPageLoadEncounterSSLErrors() && 148 client_->IsPasswordManagerEnabledForCurrentPage(); 149 } 150 151 bool PasswordManager::IsSavingEnabledForCurrentPage() const { 152 return *saving_passwords_enabled_ && !driver_->IsOffTheRecord() && 153 IsEnabledForCurrentPage(); 154 } 155 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 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 341 void PasswordManager::AddSubmissionCallback( 342 const PasswordSubmittedCallback& callback) { 343 submission_callbacks_.push_back(callback); 344 } 345 346 void PasswordManager::AddObserver(LoginModelObserver* observer) { 347 observers_.AddObserver(observer); 348 } 349 350 void PasswordManager::RemoveObserver(LoginModelObserver* observer) { 351 observers_.RemoveObserver(observer); 352 } 353 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 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 373 void PasswordManager::OnPasswordFormsParsed( 374 const std::vector<PasswordForm>& forms) { 375 CreatePendingLoginManagers(forms); 376 } 377 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 417 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 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 508 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 540 bool PasswordManager::OtherPossibleUsernamesEnabled() const { 541 return base::FieldTrialList::FindFullName( 542 kOtherPossibleUsernamesExperiment) == "Enabled"; 543 } 544 545 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