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