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 "chrome/browser/password_manager/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 "chrome/browser/password_manager/password_form_manager.h" 15 #include "chrome/browser/password_manager/password_manager_delegate.h" 16 #include "chrome/browser/password_manager/password_manager_metrics_util.h" 17 #include "chrome/browser/password_manager/password_manager_util.h" 18 #include "chrome/browser/profiles/profile.h" 19 #include "chrome/browser/ui/passwords/manage_passwords_bubble_ui_controller.h" 20 #include "chrome/common/chrome_switches.h" 21 #include "chrome/common/chrome_version_info.h" 22 #include "chrome/common/pref_names.h" 23 #include "components/autofill/content/common/autofill_messages.h" 24 #include "components/autofill/core/common/password_autofill_util.h" 25 #include "components/user_prefs/pref_registry_syncable.h" 26 #include "content/public/browser/browser_thread.h" 27 #include "content/public/browser/navigation_details.h" 28 #include "content/public/browser/user_metrics.h" 29 #include "content/public/browser/web_contents.h" 30 #include "content/public/common/frame_navigate_params.h" 31 #include "grit/generated_resources.h" 32 33 using autofill::PasswordForm; 34 using autofill::PasswordFormMap; 35 using content::BrowserThread; 36 using content::UserMetricsAction; 37 using content::WebContents; 38 39 DEFINE_WEB_CONTENTS_USER_DATA_KEY(PasswordManager); 40 41 namespace { 42 43 const char kSpdyProxyRealm[] = "/SpdyProxy"; 44 const char kOtherPossibleUsernamesExperiment[] = 45 "PasswordManagerOtherPossibleUsernames"; 46 47 // This routine is called when PasswordManagers are constructed. 48 // 49 // Currently we report metrics only once at startup. We require 50 // that this is only ever called from a single thread in order to 51 // avoid needing to lock (a static boolean flag is then sufficient to 52 // guarantee running only once). 53 void ReportMetrics(bool password_manager_enabled) { 54 static base::PlatformThreadId initial_thread_id = 55 base::PlatformThread::CurrentId(); 56 DCHECK(initial_thread_id == base::PlatformThread::CurrentId()); 57 58 static bool ran_once = false; 59 if (ran_once) 60 return; 61 ran_once = true; 62 63 UMA_HISTOGRAM_BOOLEAN("PasswordManager.Enabled", password_manager_enabled); 64 } 65 66 } // namespace 67 68 // static 69 void PasswordManager::RegisterProfilePrefs( 70 user_prefs::PrefRegistrySyncable* registry) { 71 registry->RegisterBooleanPref( 72 prefs::kPasswordManagerEnabled, 73 true, 74 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); 75 registry->RegisterBooleanPref( 76 prefs::kPasswordManagerAllowShowPasswords, 77 true, 78 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 79 registry->RegisterListPref(prefs::kPasswordManagerGroupsForDomains, 80 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 81 } 82 83 // static 84 void PasswordManager::CreateForWebContentsAndDelegate( 85 content::WebContents* contents, 86 PasswordManagerDelegate* delegate) { 87 if (FromWebContents(contents)) { 88 DCHECK_EQ(delegate, FromWebContents(contents)->delegate_); 89 return; 90 } 91 92 contents->SetUserData(UserDataKey(), 93 new PasswordManager(contents, delegate)); 94 } 95 96 PasswordManager::PasswordManager(WebContents* web_contents, 97 PasswordManagerDelegate* delegate) 98 : content::WebContentsObserver(web_contents), 99 delegate_(delegate) { 100 DCHECK(delegate_); 101 password_manager_enabled_.Init(prefs::kPasswordManagerEnabled, 102 delegate_->GetProfile()->GetPrefs()); 103 104 ReportMetrics(*password_manager_enabled_); 105 } 106 107 PasswordManager::~PasswordManager() { 108 FOR_EACH_OBSERVER(LoginModelObserver, observers_, OnLoginModelDestroying()); 109 } 110 111 void PasswordManager::SetFormHasGeneratedPassword(const PasswordForm& form) { 112 for (ScopedVector<PasswordFormManager>::iterator iter = 113 pending_login_managers_.begin(); 114 iter != pending_login_managers_.end(); ++iter) { 115 if ((*iter)->DoesManage( 116 form, PasswordFormManager::ACTION_MATCH_REQUIRED)) { 117 (*iter)->SetHasGeneratedPassword(); 118 return; 119 } 120 } 121 // If there is no corresponding PasswordFormManager, we create one. This is 122 // not the common case, and should only happen when there is a bug in our 123 // ability to detect forms. 124 bool ssl_valid = (form.origin.SchemeIsSecure() && 125 !delegate_->DidLastPageLoadEncounterSSLErrors()); 126 PasswordFormManager* manager = 127 new PasswordFormManager(delegate_->GetProfile(), 128 this, 129 web_contents(), 130 form, 131 ssl_valid); 132 pending_login_managers_.push_back(manager); 133 manager->SetHasGeneratedPassword(); 134 // TODO(gcasto): Add UMA stats to track this. 135 } 136 137 bool PasswordManager::IsSavingEnabled() const { 138 return *password_manager_enabled_ && 139 !delegate_->GetProfile()->IsOffTheRecord(); 140 } 141 142 void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) { 143 if (!IsSavingEnabled()) { 144 RecordFailure(SAVING_DISABLED, form.origin.host()); 145 return; 146 } 147 148 // No password to save? Then don't. 149 if (form.password_value.empty()) { 150 RecordFailure(EMPTY_PASSWORD, form.origin.host()); 151 return; 152 } 153 154 scoped_ptr<PasswordFormManager> manager; 155 ScopedVector<PasswordFormManager>::iterator matched_manager_it = 156 pending_login_managers_.end(); 157 for (ScopedVector<PasswordFormManager>::iterator iter = 158 pending_login_managers_.begin(); 159 iter != pending_login_managers_.end(); ++iter) { 160 // If we find a manager that exactly matches the submitted form including 161 // the action URL, exit the loop. 162 if ((*iter)->DoesManage( 163 form, PasswordFormManager::ACTION_MATCH_REQUIRED)) { 164 matched_manager_it = iter; 165 break; 166 // If the current manager matches the submitted form excluding the action 167 // URL, remember it as a candidate and continue searching for an exact 168 // match. 169 } else if ((*iter)->DoesManage( 170 form, PasswordFormManager::ACTION_MATCH_NOT_REQUIRED)) { 171 matched_manager_it = iter; 172 } 173 } 174 // If we didn't find a manager, this means a form was submitted without 175 // first loading the page containing the form. Don't offer to save 176 // passwords in this case. 177 if (matched_manager_it != pending_login_managers_.end()) { 178 // Transfer ownership of the manager from |pending_login_managers_| to 179 // |manager|. 180 manager.reset(*matched_manager_it); 181 pending_login_managers_.weak_erase(matched_manager_it); 182 } else { 183 RecordFailure(NO_MATCHING_FORM, form.origin.host()); 184 return; 185 } 186 187 // If we found a manager but it didn't finish matching yet, the user has 188 // tried to submit credentials before we had time to even find matching 189 // results for the given form and autofill. If this is the case, we just 190 // give up. 191 if (!manager->HasCompletedMatching()) { 192 RecordFailure(MATCHING_NOT_COMPLETE, form.origin.host()); 193 return; 194 } 195 196 // Also get out of here if the user told us to 'never remember' passwords for 197 // this form. 198 if (manager->IsBlacklisted()) { 199 RecordFailure(FORM_BLACKLISTED, form.origin.host()); 200 return; 201 } 202 203 // Bail if we're missing any of the necessary form components. 204 if (!manager->HasValidPasswordForm()) { 205 RecordFailure(INVALID_FORM, form.origin.host()); 206 return; 207 } 208 209 // Always save generated passwords, as the user expresses explicit intent for 210 // Chrome to manage such passwords. For other passwords, respect the 211 // autocomplete attribute if autocomplete='off' is not ignored. 212 if (!autofill::ShouldIgnoreAutocompleteOffForPasswordFields() && 213 !manager->HasGeneratedPassword() && 214 !form.password_autocomplete_set) { 215 RecordFailure(AUTOCOMPLETE_OFF, form.origin.host()); 216 return; 217 } 218 219 PasswordForm provisionally_saved_form(form); 220 provisionally_saved_form.ssl_valid = form.origin.SchemeIsSecure() && 221 !delegate_->DidLastPageLoadEncounterSSLErrors(); 222 provisionally_saved_form.preferred = true; 223 PasswordFormManager::OtherPossibleUsernamesAction action = 224 PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES; 225 if (OtherPossibleUsernamesEnabled()) 226 action = PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES; 227 manager->ProvisionallySave(provisionally_saved_form, action); 228 provisional_save_manager_.swap(manager); 229 } 230 231 void PasswordManager::RecordFailure(ProvisionalSaveFailure failure, 232 const std::string& form_origin) { 233 UMA_HISTOGRAM_ENUMERATION("PasswordManager.ProvisionalSaveFailure", 234 failure, MAX_FAILURE_VALUE); 235 236 std::string group_name = password_manager_metrics_util::GroupIdToString( 237 password_manager_metrics_util::MonitoredDomainGroupId( 238 form_origin, delegate_->GetProfile()->GetPrefs())); 239 if (!group_name.empty()) { 240 password_manager_metrics_util::LogUMAHistogramEnumeration( 241 "PasswordManager.ProvisionalSaveFailure_" + group_name, failure, 242 MAX_FAILURE_VALUE); 243 } 244 } 245 246 void PasswordManager::AddSubmissionCallback( 247 const PasswordSubmittedCallback& callback) { 248 submission_callbacks_.push_back(callback); 249 } 250 251 void PasswordManager::AddObserver(LoginModelObserver* observer) { 252 observers_.AddObserver(observer); 253 } 254 255 void PasswordManager::RemoveObserver(LoginModelObserver* observer) { 256 observers_.RemoveObserver(observer); 257 } 258 259 void PasswordManager::DidNavigateMainFrame( 260 const content::LoadCommittedDetails& details, 261 const content::FrameNavigateParams& params) { 262 // Clear data after main frame navigation. We don't want to clear data after 263 // subframe navigation as there might be password forms on other frames that 264 // could be submitted. 265 if (!details.is_in_page) 266 pending_login_managers_.clear(); 267 } 268 269 bool PasswordManager::OnMessageReceived(const IPC::Message& message) { 270 bool handled = true; 271 IPC_BEGIN_MESSAGE_MAP(PasswordManager, message) 272 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsParsed, 273 OnPasswordFormsParsed) 274 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsRendered, 275 OnPasswordFormsRendered) 276 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormSubmitted, 277 OnPasswordFormSubmitted) 278 IPC_MESSAGE_UNHANDLED(handled = false) 279 IPC_END_MESSAGE_MAP() 280 return handled; 281 } 282 283 void PasswordManager::OnPasswordFormSubmitted( 284 const PasswordForm& password_form) { 285 ProvisionallySavePassword(password_form); 286 for (size_t i = 0; i < submission_callbacks_.size(); ++i) { 287 submission_callbacks_[i].Run(password_form); 288 } 289 290 pending_login_managers_.clear(); 291 } 292 293 void PasswordManager::OnPasswordFormsParsed( 294 const std::vector<PasswordForm>& forms) { 295 // Ask the SSLManager for current security. 296 bool had_ssl_error = delegate_->DidLastPageLoadEncounterSSLErrors(); 297 298 for (std::vector<PasswordForm>::const_iterator iter = forms.begin(); 299 iter != forms.end(); ++iter) { 300 // Don't involve the password manager if this form corresponds to 301 // SpdyProxy authentication, as indicated by the realm. 302 if (EndsWith(iter->signon_realm, kSpdyProxyRealm, true)) 303 continue; 304 305 bool ssl_valid = iter->origin.SchemeIsSecure() && !had_ssl_error; 306 PasswordFormManager* manager = 307 new PasswordFormManager(delegate_->GetProfile(), 308 this, 309 web_contents(), 310 *iter, 311 ssl_valid); 312 pending_login_managers_.push_back(manager); 313 314 // Avoid prompting the user for access to a password if they don't have 315 // password saving enabled. 316 PasswordStore::AuthorizationPromptPolicy prompt_policy = 317 *password_manager_enabled_ ? PasswordStore::ALLOW_PROMPT 318 : PasswordStore::DISALLOW_PROMPT; 319 320 manager->FetchMatchingLoginsFromPasswordStore(prompt_policy); 321 } 322 } 323 324 bool PasswordManager::ShouldShowSavePasswordInfoBar() const { 325 return provisional_save_manager_->IsNewLogin() && 326 !provisional_save_manager_->HasGeneratedPassword() && 327 !provisional_save_manager_->IsPendingCredentialsPublicSuffixMatch(); 328 } 329 330 void PasswordManager::OnPasswordFormsRendered( 331 const std::vector<PasswordForm>& visible_forms) { 332 if (!provisional_save_manager_.get()) 333 return; 334 335 DCHECK(IsSavingEnabled()); 336 337 // We now assume that if there is at least one visible password form 338 // that means that the previous login attempt failed. 339 if (!visible_forms.empty()) { 340 provisional_save_manager_->SubmitFailed(); 341 provisional_save_manager_.reset(); 342 return; 343 } 344 345 // Looks like a successful login attempt. Either show an infobar or 346 // automatically save the login data. We prompt when the user hasn't already 347 // given consent, either through previously accepting the infobar or by having 348 // the browser generate the password. 349 provisional_save_manager_->SubmitPassed(); 350 if (provisional_save_manager_->HasGeneratedPassword()) 351 UMA_HISTOGRAM_COUNTS("PasswordGeneration.Submitted", 1); 352 353 if (ShouldShowSavePasswordInfoBar()) { 354 if (CommandLine::ForCurrentProcess()->HasSwitch( 355 switches::kEnableSavePasswordBubble)) { 356 ManagePasswordsBubbleUIController* manage_passwords_bubble_ui_controller = 357 ManagePasswordsBubbleUIController::FromWebContents(web_contents()); 358 if (manage_passwords_bubble_ui_controller) { 359 manage_passwords_bubble_ui_controller->OnPasswordSubmitted( 360 provisional_save_manager_.release()); 361 } else { 362 provisional_save_manager_.reset(); 363 } 364 } else { 365 delegate_->AddSavePasswordInfoBarIfPermitted( 366 provisional_save_manager_.release()); 367 } 368 } else { 369 provisional_save_manager_->Save(); 370 provisional_save_manager_.reset(); 371 } 372 } 373 374 void PasswordManager::PossiblyInitializeUsernamesExperiment( 375 const PasswordFormMap& best_matches) const { 376 if (base::FieldTrialList::Find(kOtherPossibleUsernamesExperiment)) 377 return; 378 379 bool other_possible_usernames_exist = false; 380 for (autofill::PasswordFormMap::const_iterator it = best_matches.begin(); 381 it != best_matches.end(); ++it) { 382 if (!it->second->other_possible_usernames.empty()) { 383 other_possible_usernames_exist = true; 384 break; 385 } 386 } 387 388 if (!other_possible_usernames_exist) 389 return; 390 391 const base::FieldTrial::Probability kDivisor = 100; 392 scoped_refptr<base::FieldTrial> trial( 393 base::FieldTrialList::FactoryGetFieldTrial( 394 kOtherPossibleUsernamesExperiment, 395 kDivisor, "Disabled", 2013, 12, 31, 396 base::FieldTrial::ONE_TIME_RANDOMIZED, NULL)); 397 base::FieldTrial::Probability enabled_probability = 0; 398 399 switch (chrome::VersionInfo::GetChannel()) { 400 case chrome::VersionInfo::CHANNEL_DEV: 401 case chrome::VersionInfo::CHANNEL_BETA: 402 enabled_probability = 50; 403 break; 404 default: 405 break; 406 } 407 408 trial->AppendGroup("Enabled", enabled_probability); 409 } 410 411 bool PasswordManager::OtherPossibleUsernamesEnabled() const { 412 return base::FieldTrialList::FindFullName( 413 kOtherPossibleUsernamesExperiment) == "Enabled"; 414 } 415 416 void PasswordManager::Autofill( 417 const PasswordForm& form_for_autofill, 418 const PasswordFormMap& best_matches, 419 const PasswordForm& preferred_match, 420 bool wait_for_username) const { 421 PossiblyInitializeUsernamesExperiment(best_matches); 422 switch (form_for_autofill.scheme) { 423 case PasswordForm::SCHEME_HTML: { 424 // Note the check above is required because the observers_ for a non-HTML 425 // schemed password form may have been freed, so we need to distinguish. 426 autofill::PasswordFormFillData fill_data; 427 InitPasswordFormFillData(form_for_autofill, 428 best_matches, 429 &preferred_match, 430 wait_for_username, 431 OtherPossibleUsernamesEnabled(), 432 &fill_data); 433 delegate_->FillPasswordForm(fill_data); 434 break; 435 } 436 default: 437 FOR_EACH_OBSERVER( 438 LoginModelObserver, 439 observers_, 440 OnAutofillDataAvailable(preferred_match.username_value, 441 preferred_match.password_value)); 442 break; 443 } 444 445 ManagePasswordsBubbleUIController* manage_passwords_bubble_ui_controller = 446 ManagePasswordsBubbleUIController::FromWebContents(web_contents()); 447 if (manage_passwords_bubble_ui_controller && 448 CommandLine::ForCurrentProcess()->HasSwitch( 449 switches::kEnableSavePasswordBubble)) { 450 manage_passwords_bubble_ui_controller->OnPasswordAutofilled(best_matches); 451 } 452 } 453