1 // Copyright (c) 2011 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 <vector> 8 9 #include "base/stl_util-inl.h" 10 #include "base/threading/platform_thread.h" 11 #include "base/utf_string_conversions.h" 12 #include "chrome/browser/metrics/user_metrics.h" 13 #include "chrome/browser/password_manager/password_form_manager.h" 14 #include "chrome/browser/password_manager/password_manager_delegate.h" 15 #include "chrome/browser/prefs/pref_service.h" 16 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/common/autofill_messages.h" 18 #include "chrome/common/pref_names.h" 19 #include "content/common/view_messages.h" 20 #include "grit/generated_resources.h" 21 22 using webkit_glue::PasswordForm; 23 using webkit_glue::PasswordFormMap; 24 25 // static 26 void PasswordManager::RegisterUserPrefs(PrefService* prefs) { 27 prefs->RegisterBooleanPref(prefs::kPasswordManagerEnabled, true); 28 prefs->RegisterBooleanPref(prefs::kPasswordManagerAllowShowPasswords, true); 29 } 30 31 // This routine is called when PasswordManagers are constructed. 32 // 33 // Currently we report metrics only once at startup. We require 34 // that this is only ever called from a single thread in order to 35 // avoid needing to lock (a static boolean flag is then sufficient to 36 // guarantee running only once). 37 static void ReportMetrics(bool password_manager_enabled) { 38 static base::PlatformThreadId initial_thread_id = 39 base::PlatformThread::CurrentId(); 40 DCHECK(initial_thread_id == base::PlatformThread::CurrentId()); 41 42 static bool ran_once = false; 43 if (ran_once) 44 return; 45 ran_once = true; 46 47 if (password_manager_enabled) 48 UserMetrics::RecordAction(UserMetricsAction("PasswordManager_Enabled")); 49 else 50 UserMetrics::RecordAction(UserMetricsAction("PasswordManager_Disabled")); 51 } 52 53 PasswordManager::PasswordManager(TabContents* tab_contents, 54 PasswordManagerDelegate* delegate) 55 : TabContentsObserver(tab_contents), 56 login_managers_deleter_(&pending_login_managers_), 57 delegate_(delegate), 58 observer_(NULL) { 59 DCHECK(delegate_); 60 password_manager_enabled_.Init(prefs::kPasswordManagerEnabled, 61 delegate_->GetProfileForPasswordManager()->GetPrefs(), NULL); 62 63 ReportMetrics(*password_manager_enabled_); 64 } 65 66 PasswordManager::~PasswordManager() { 67 } 68 69 void PasswordManager::ProvisionallySavePassword(PasswordForm form) { 70 if (!delegate_->GetProfileForPasswordManager() || 71 delegate_->GetProfileForPasswordManager()->IsOffTheRecord() || 72 !*password_manager_enabled_) 73 return; 74 75 // No password to save? Then don't. 76 if (form.password_value.empty()) 77 return; 78 79 LoginManagers::iterator iter; 80 PasswordFormManager* manager = NULL; 81 for (iter = pending_login_managers_.begin(); 82 iter != pending_login_managers_.end(); iter++) { 83 if ((*iter)->DoesManage(form)) { 84 manager = *iter; 85 break; 86 } 87 } 88 // If we didn't find a manager, this means a form was submitted without 89 // first loading the page containing the form. Don't offer to save 90 // passwords in this case. 91 if (!manager) 92 return; 93 94 // If we found a manager but it didn't finish matching yet, the user has 95 // tried to submit credentials before we had time to even find matching 96 // results for the given form and autofill. If this is the case, we just 97 // give up. 98 if (!manager->HasCompletedMatching()) 99 return; 100 101 // Also get out of here if the user told us to 'never remember' passwords for 102 // this form. 103 if (manager->IsBlacklisted()) 104 return; 105 106 form.ssl_valid = form.origin.SchemeIsSecure() && 107 !delegate_->DidLastPageLoadEncounterSSLErrors(); 108 form.preferred = true; 109 manager->ProvisionallySave(form); 110 provisional_save_manager_.reset(manager); 111 pending_login_managers_.erase(iter); 112 // We don't care about the rest of the forms on the page now that one 113 // was selected. 114 STLDeleteElements(&pending_login_managers_); 115 } 116 117 void PasswordManager::DidNavigate() { 118 // As long as this navigation isn't due to a currently pending 119 // password form submit, we're ready to reset and move on. 120 if (!provisional_save_manager_.get() && !pending_login_managers_.empty()) 121 STLDeleteElements(&pending_login_managers_); 122 } 123 124 void PasswordManager::ClearProvisionalSave() { 125 provisional_save_manager_.reset(); 126 } 127 128 void PasswordManager::SetObserver(LoginModelObserver* observer) { 129 observer_ = observer; 130 } 131 132 void PasswordManager::DidStopLoading() { 133 if (!provisional_save_manager_.get()) 134 return; 135 136 DCHECK(!delegate_->GetProfileForPasswordManager()->IsOffTheRecord()); 137 DCHECK(!provisional_save_manager_->IsBlacklisted()); 138 139 if (!delegate_->GetProfileForPasswordManager()) 140 return; 141 // Form is not completely valid - we do not support it. 142 if (!provisional_save_manager_->HasValidPasswordForm()) 143 return; 144 145 provisional_save_manager_->SubmitPassed(); 146 if (provisional_save_manager_->IsNewLogin()) { 147 delegate_->AddSavePasswordInfoBar(provisional_save_manager_.release()); 148 } else { 149 // If the save is not a new username entry, then we just want to save this 150 // data (since the user already has related data saved), so don't prompt. 151 provisional_save_manager_->Save(); 152 provisional_save_manager_.reset(); 153 } 154 } 155 156 void PasswordManager::DidNavigateAnyFramePostCommit( 157 const NavigationController::LoadCommittedDetails& details, 158 const ViewHostMsg_FrameNavigate_Params& params) { 159 if (params.password_form.origin.is_valid()) 160 ProvisionallySavePassword(params.password_form); 161 } 162 163 bool PasswordManager::OnMessageReceived(const IPC::Message& message) { 164 bool handled = true; 165 IPC_BEGIN_MESSAGE_MAP(PasswordManager, message) 166 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsFound, 167 OnPasswordFormsFound) 168 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsVisible, 169 OnPasswordFormsVisible) 170 IPC_MESSAGE_UNHANDLED(handled = false) 171 IPC_END_MESSAGE_MAP() 172 return handled; 173 } 174 175 void PasswordManager::OnPasswordFormsFound( 176 const std::vector<PasswordForm>& forms) { 177 if (!delegate_->GetProfileForPasswordManager()) 178 return; 179 if (!*password_manager_enabled_) 180 return; 181 182 // Ask the SSLManager for current security. 183 bool had_ssl_error = delegate_->DidLastPageLoadEncounterSSLErrors(); 184 185 std::vector<PasswordForm>::const_iterator iter; 186 for (iter = forms.begin(); iter != forms.end(); iter++) { 187 bool ssl_valid = iter->origin.SchemeIsSecure() && !had_ssl_error; 188 PasswordFormManager* manager = 189 new PasswordFormManager(delegate_->GetProfileForPasswordManager(), 190 this, *iter, ssl_valid); 191 pending_login_managers_.push_back(manager); 192 manager->FetchMatchingLoginsFromPasswordStore(); 193 } 194 } 195 196 void PasswordManager::OnPasswordFormsVisible( 197 const std::vector<PasswordForm>& visible_forms) { 198 if (!provisional_save_manager_.get()) 199 return; 200 std::vector<PasswordForm>::const_iterator iter; 201 for (iter = visible_forms.begin(); iter != visible_forms.end(); iter++) { 202 if (provisional_save_manager_->DoesManage(*iter)) { 203 // The form trying to be saved has immediately re-appeared. Assume login 204 // failure and abort this save, by clearing provisional_save_manager_. 205 // Don't delete the login managers since the user may try again 206 // and we want to be able to save in that case. 207 provisional_save_manager_->SubmitFailed(); 208 ClearProvisionalSave(); 209 break; 210 } 211 } 212 } 213 214 void PasswordManager::Autofill( 215 const PasswordForm& form_for_autofill, 216 const PasswordFormMap& best_matches, 217 const PasswordForm* const preferred_match, 218 bool wait_for_username) const { 219 DCHECK(preferred_match); 220 switch (form_for_autofill.scheme) { 221 case PasswordForm::SCHEME_HTML: { 222 // Note the check above is required because the observer_ for a non-HTML 223 // schemed password form may have been freed, so we need to distinguish. 224 webkit_glue::PasswordFormFillData fill_data; 225 webkit_glue::PasswordFormDomManager::InitFillData(form_for_autofill, 226 best_matches, 227 preferred_match, 228 wait_for_username, 229 &fill_data); 230 delegate_->FillPasswordForm(fill_data); 231 return; 232 } 233 default: 234 if (observer_) { 235 observer_->OnAutofillDataAvailable( 236 UTF16ToWideHack(preferred_match->username_value), 237 UTF16ToWideHack(preferred_match->password_value)); 238 } 239 } 240 } 241