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