• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
RegisterUserPrefs(PrefService * prefs)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).
ReportMetrics(bool password_manager_enabled)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 
PasswordManager(TabContents * tab_contents,PasswordManagerDelegate * delegate)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 
~PasswordManager()66 PasswordManager::~PasswordManager() {
67 }
68 
ProvisionallySavePassword(PasswordForm form)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 
DidNavigate()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 
ClearProvisionalSave()124 void PasswordManager::ClearProvisionalSave() {
125   provisional_save_manager_.reset();
126 }
127 
SetObserver(LoginModelObserver * observer)128 void PasswordManager::SetObserver(LoginModelObserver* observer) {
129   observer_ = observer;
130 }
131 
DidStopLoading()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 
DidNavigateAnyFramePostCommit(const NavigationController::LoadCommittedDetails & details,const ViewHostMsg_FrameNavigate_Params & params)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 
OnMessageReceived(const IPC::Message & message)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 
OnPasswordFormsFound(const std::vector<PasswordForm> & forms)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 
OnPasswordFormsVisible(const std::vector<PasswordForm> & visible_forms)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 
Autofill(const PasswordForm & form_for_autofill,const PasswordFormMap & best_matches,const PasswordForm * const preferred_match,bool wait_for_username) const214 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