Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / components / password_manager / core / browser / 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 "components/password_manager/core/browser/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 "components/autofill/core/common/password_autofill_util.h"
15 #include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
16 #include "components/password_manager/core/browser/password_autofill_manager.h"
17 #include "components/password_manager/core/browser/password_form_manager.h"
18 #include "components/password_manager/core/browser/password_manager_client.h"
19 #include "components/password_manager/core/browser/password_manager_driver.h"
20 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
21 #include "components/password_manager/core/common/password_manager_pref_names.h"
22 #include "components/password_manager/core/common/password_manager_switches.h"
23 #include "components/pref_registry/pref_registry_syncable.h"
24
25 using autofill::PasswordForm;
26 using autofill::PasswordFormMap;
27
28 namespace password_manager {
29
30 namespace {
31
32 const char kSpdyProxyRealm[] = "/SpdyProxy";
33
34 // Shorten the name to spare line breaks. The code provides enough context
35 // already.
36 typedef autofill::SavePasswordProgressLogger Logger;
37
38 // This routine is called when PasswordManagers are constructed.
39 //
40 // Currently we report metrics only once at startup. We require
41 // that this is only ever called from a single thread in order to
42 // avoid needing to lock (a static boolean flag is then sufficient to
43 // guarantee running only once).
44 void ReportMetrics(bool password_manager_enabled) {
45   static base::PlatformThreadId initial_thread_id =
46       base::PlatformThread::CurrentId();
47   DCHECK(initial_thread_id == base::PlatformThread::CurrentId());
48
49   static bool ran_once = false;
50   if (ran_once)
51     return;
52   ran_once = true;
53
54   UMA_HISTOGRAM_BOOLEAN("PasswordManager.Enabled", password_manager_enabled);
55 }
56
57 bool ShouldDropSyncCredential() {
58   std::string group_name =
59       base::FieldTrialList::FindFullName("PasswordManagerDropSyncCredential");
60
61   CommandLine* command_line = CommandLine::ForCurrentProcess();
62   if (command_line->HasSwitch(switches::kEnableDropSyncCredential))
63     return true;
64
65   if (command_line->HasSwitch(switches::kDisableDropSyncCredential))
66     return false;
67
68   // Default to not saving.
69   return group_name != "Disabled";
70 }
71
72 }  // namespace
73
74 const char PasswordManager::kOtherPossibleUsernamesExperiment[] =
75     "PasswordManagerOtherPossibleUsernames";
76
77 // static
78 void PasswordManager::RegisterProfilePrefs(
79     user_prefs::PrefRegistrySyncable* registry) {
80   registry->RegisterBooleanPref(
81       prefs::kPasswordManagerSavingEnabled,
82       true,
83       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
84   registry->RegisterBooleanPref(
85       prefs::kPasswordManagerAllowShowPasswords,
86       true,
87       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
88   registry->RegisterListPref(prefs::kPasswordManagerGroupsForDomains,
89                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
90 }
91
92 PasswordManager::PasswordManager(PasswordManagerClient* client)
93     : client_(client), driver_(client->GetDriver()) {
94   DCHECK(client_);
95   DCHECK(driver_);
96   saving_passwords_enabled_.Init(prefs::kPasswordManagerSavingEnabled,
97                                  client_->GetPrefs());
98
99   ReportMetrics(*saving_passwords_enabled_);
100 }
101
102 PasswordManager::~PasswordManager() {
103   FOR_EACH_OBSERVER(LoginModelObserver, observers_, OnLoginModelDestroying());
104 }
105
106 void PasswordManager::SetFormHasGeneratedPassword(const PasswordForm& form) {
107   DCHECK(IsSavingEnabledForCurrentPage());
108
109   for (ScopedVector<PasswordFormManager>::iterator iter =
110            pending_login_managers_.begin();
111        iter != pending_login_managers_.end();
112        ++iter) {
113     if ((*iter)->DoesManage(form) ==
114         PasswordFormManager::RESULT_COMPLETE_MATCH) {
115       (*iter)->SetHasGeneratedPassword();
116       return;
117     }
118   }
119   // If there is no corresponding PasswordFormManager, we create one. This is
120   // not the common case, and should only happen when there is a bug in our
121   // ability to detect forms.
122   bool ssl_valid = form.origin.SchemeIsSecure();
123   PasswordFormManager* manager =
124       new PasswordFormManager(this, client_, driver_, form, ssl_valid);
125   pending_login_managers_.push_back(manager);
126   manager->SetHasGeneratedPassword();
127   // TODO(gcasto): Add UMA stats to track this.
128 }
129
130 bool PasswordManager::IsEnabledForCurrentPage() const {
131   return !driver_->DidLastPageLoadEncounterSSLErrors() &&
132       client_->IsPasswordManagerEnabledForCurrentPage();
133 }
134
135 bool PasswordManager::IsSavingEnabledForCurrentPage() const {
136   return *saving_passwords_enabled_ && !driver_->IsOffTheRecord() &&
137          IsEnabledForCurrentPage();
138 }
139
140 void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) {
141   bool is_saving_enabled = IsSavingEnabledForCurrentPage();
142
143   scoped_ptr<BrowserSavePasswordProgressLogger> logger;
144   if (client_->IsLoggingActive()) {
145     logger.reset(new BrowserSavePasswordProgressLogger(client_));
146     logger->LogMessage(Logger::STRING_PROVISIONALLY_SAVE_PASSWORD_METHOD);
147     logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVE_PASSWORD_FORM,
148                             form);
149     logger->LogBoolean(Logger::STRING_IS_SAVING_ENABLED, is_saving_enabled);
150     logger->LogBoolean(Logger::STRING_SSL_ERRORS_PRESENT,
151                        driver_->DidLastPageLoadEncounterSSLErrors());
152   }
153
154   if (!is_saving_enabled) {
155     RecordFailure(SAVING_DISABLED, form.origin.host(), logger.get());
156     return;
157   }
158
159   // No password to save? Then don't.
160   if (form.password_value.empty() && form.new_password_value.empty()) {
161     RecordFailure(EMPTY_PASSWORD, form.origin.host(), logger.get());
162     return;
163   }
164
165   scoped_ptr<PasswordFormManager> manager;
166   ScopedVector<PasswordFormManager>::iterator matched_manager_it =
167       pending_login_managers_.end();
168   // Below, "matching" is in DoesManage-sense and "not ready" in
169   // !HasCompletedMatching sense. We keep track of such PasswordFormManager
170   // instances for UMA.
171   bool has_found_matching_managers_which_were_not_ready = false;
172   for (ScopedVector<PasswordFormManager>::iterator iter =
173            pending_login_managers_.begin();
174        iter != pending_login_managers_.end();
175        ++iter) {
176     PasswordFormManager::MatchResultMask result = (*iter)->DoesManage(form);
177
178     if (!(*iter)->HasCompletedMatching()) {
179       if (result != PasswordFormManager::RESULT_NO_MATCH)
180         has_found_matching_managers_which_were_not_ready = true;
181       continue;
182     }
183
184     if (result == PasswordFormManager::RESULT_COMPLETE_MATCH) {
185       // If we find a manager that exactly matches the submitted form including
186       // the action URL, exit the loop.
187       if (logger)
188         logger->LogMessage(Logger::STRING_EXACT_MATCH);
189       matched_manager_it = iter;
190       break;
191     } else if (result == (PasswordFormManager::RESULT_COMPLETE_MATCH &
192                           ~PasswordFormManager::RESULT_ACTION_MATCH)) {
193       // If the current manager matches the submitted form excluding the action
194       // URL, remember it as a candidate and continue searching for an exact
195       // match. See http://crbug.com/27246 for an example where actions can
196       // change.
197       if (logger)
198         logger->LogMessage(Logger::STRING_MATCH_WITHOUT_ACTION);
199       matched_manager_it = iter;
200     }
201   }
202   // If we didn't find a manager, this means a form was submitted without
203   // first loading the page containing the form. Don't offer to save
204   // passwords in this case.
205   if (matched_manager_it != pending_login_managers_.end()) {
206     // Transfer ownership of the manager from |pending_login_managers_| to
207     // |manager|.
208     manager.reset(*matched_manager_it);
209     pending_login_managers_.weak_erase(matched_manager_it);
210   } else if (has_found_matching_managers_which_were_not_ready) {
211     // We found some managers, but none finished matching yet. The user has
212     // tried to submit credentials before we had time to even find matching
213     // results for the given form and autofill. If this is the case, we just
214     // give up.
215     RecordFailure(MATCHING_NOT_COMPLETE, form.origin.host(), logger.get());
216     return;
217   } else {
218     RecordFailure(NO_MATCHING_FORM, form.origin.host(), logger.get());
219     return;
220   }
221
222   // Also get out of here if the user told us to 'never remember' passwords for
223   // this form.
224   if (manager->IsBlacklisted()) {
225     RecordFailure(FORM_BLACKLISTED, form.origin.host(), logger.get());
226     return;
227   }
228
229   // Bail if we're missing any of the necessary form components.
230   if (!manager->HasValidPasswordForm()) {
231     RecordFailure(INVALID_FORM, form.origin.host(), logger.get());
232     return;
233   }
234
235   // Don't save credentials for the syncing account. See crbug.com/365832 for
236   // background.
237   if (ShouldDropSyncCredential() &&
238       client_->IsSyncAccountCredential(
239           base::UTF16ToUTF8(form.username_value), form.signon_realm)) {
240     RecordFailure(SYNC_CREDENTIAL, form.origin.host(), logger.get());
241     return;
242   }
243
244   // Always save generated passwords, as the user expresses explicit intent for
245   // Chrome to manage such passwords. For other passwords, respect the
246   // autocomplete attribute if autocomplete='off' is not ignored.
247   if (!autofill::ShouldIgnoreAutocompleteOffForPasswordFields() &&
248       !manager->HasGeneratedPassword() && !form.password_autocomplete_set) {
249     RecordFailure(AUTOCOMPLETE_OFF, form.origin.host(), logger.get());
250     return;
251   }
252
253   PasswordForm provisionally_saved_form(form);
254   provisionally_saved_form.ssl_valid =
255       form.origin.SchemeIsSecure() &&
256       !driver_->DidLastPageLoadEncounterSSLErrors();
257   provisionally_saved_form.preferred = true;
258   if (logger) {
259     logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVED_FORM,
260                             provisionally_saved_form);
261   }
262   PasswordFormManager::OtherPossibleUsernamesAction action =
263       PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES;
264   if (OtherPossibleUsernamesEnabled())
265     action = PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES;
266   if (logger) {
267     logger->LogBoolean(
268         Logger::STRING_IGNORE_POSSIBLE_USERNAMES,
269         action == PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
270   }
271   manager->ProvisionallySave(provisionally_saved_form, action);
272   provisional_save_manager_.swap(manager);
273 }
274
275 void PasswordManager::RecordFailure(ProvisionalSaveFailure failure,
276                                     const std::string& form_origin,
277                                     BrowserSavePasswordProgressLogger* logger) {
278   UMA_HISTOGRAM_ENUMERATION(
279       "PasswordManager.ProvisionalSaveFailure", failure, MAX_FAILURE_VALUE);
280
281   std::string group_name = metrics_util::GroupIdToString(
282       metrics_util::MonitoredDomainGroupId(form_origin, client_->GetPrefs()));
283   if (!group_name.empty()) {
284     metrics_util::LogUMAHistogramEnumeration(
285         "PasswordManager.ProvisionalSaveFailure_" + group_name,
286         failure,
287         MAX_FAILURE_VALUE);
288   }
289
290   if (logger) {
291     switch (failure) {
292       case SAVING_DISABLED:
293         logger->LogMessage(Logger::STRING_SAVING_DISABLED);
294         break;
295       case EMPTY_PASSWORD:
296         logger->LogMessage(Logger::STRING_EMPTY_PASSWORD);
297         break;
298       case MATCHING_NOT_COMPLETE:
299         logger->LogMessage(Logger::STRING_MATCHING_NOT_COMPLETE);
300         break;
301       case NO_MATCHING_FORM:
302         logger->LogMessage(Logger::STRING_NO_MATCHING_FORM);
303         break;
304       case FORM_BLACKLISTED:
305         logger->LogMessage(Logger::STRING_FORM_BLACKLISTED);
306         break;
307       case INVALID_FORM:
308         logger->LogMessage(Logger::STRING_INVALID_FORM);
309         break;
310       case AUTOCOMPLETE_OFF:
311         logger->LogMessage(Logger::STRING_AUTOCOMPLETE_OFF);
312         break;
313       case SYNC_CREDENTIAL:
314         logger->LogMessage(Logger::STRING_SYNC_CREDENTIAL);
315         break;
316       case MAX_FAILURE_VALUE:
317         NOTREACHED();
318         return;
319     }
320     logger->LogMessage(Logger::STRING_DECISION_DROP);
321   }
322 }
323
324 void PasswordManager::AddSubmissionCallback(
325     const PasswordSubmittedCallback& callback) {
326   submission_callbacks_.push_back(callback);
327 }
328
329 void PasswordManager::AddObserver(LoginModelObserver* observer) {
330   observers_.AddObserver(observer);
331 }
332
333 void PasswordManager::RemoveObserver(LoginModelObserver* observer) {
334   observers_.RemoveObserver(observer);
335 }
336
337 void PasswordManager::DidNavigateMainFrame(bool is_in_page) {
338   // Clear data after main frame navigation if the navigation was to a
339   // different page.
340   if (!is_in_page) {
341     pending_login_managers_.clear();
342     driver_->GetPasswordAutofillManager()->Reset();
343   }
344 }
345
346 void PasswordManager::OnPasswordFormSubmitted(
347     const PasswordForm& password_form) {
348   ProvisionallySavePassword(password_form);
349   for (size_t i = 0; i < submission_callbacks_.size(); ++i) {
350     submission_callbacks_[i].Run(password_form);
351   }
352
353   pending_login_managers_.clear();
354 }
355
356 void PasswordManager::OnPasswordFormsParsed(
357     const std::vector<PasswordForm>& forms) {
358   CreatePendingLoginManagers(forms);
359 }
360
361 void PasswordManager::CreatePendingLoginManagers(
362     const std::vector<PasswordForm>& forms) {
363   if (!IsEnabledForCurrentPage())
364     return;
365
366   // Copy the weak pointers to the currently known login managers for comparison
367   // against the newly added.
368   std::vector<PasswordFormManager*> old_login_managers(
369       pending_login_managers_.get());
370   for (std::vector<PasswordForm>::const_iterator iter = forms.begin();
371        iter != forms.end();
372        ++iter) {
373     // Don't involve the password manager if this form corresponds to
374     // SpdyProxy authentication, as indicated by the realm.
375     if (EndsWith(iter->signon_realm, kSpdyProxyRealm, true))
376       continue;
377     bool old_manager_found = false;
378     for (std::vector<PasswordFormManager*>::const_iterator old_manager =
379              old_login_managers.begin();
380          !old_manager_found && old_manager != old_login_managers.end();
381          ++old_manager) {
382       old_manager_found = (*old_manager)->DoesManage(*iter) ==
383                           PasswordFormManager::RESULT_COMPLETE_MATCH;
384     }
385     if (old_manager_found)
386       continue;  // The current form is already managed.
387
388     bool ssl_valid = iter->origin.SchemeIsSecure();
389     PasswordFormManager* manager =
390         new PasswordFormManager(this, client_, driver_, *iter, ssl_valid);
391     pending_login_managers_.push_back(manager);
392
393     PasswordStore::AuthorizationPromptPolicy prompt_policy =
394         client_->GetAuthorizationPromptPolicy(*iter);
395
396     manager->FetchMatchingLoginsFromPasswordStore(prompt_policy);
397   }
398 }
399
400 bool PasswordManager::ShouldPromptUserToSavePassword() const {
401   return !client_->IsAutomaticPasswordSavingEnabled() &&
402          provisional_save_manager_->IsNewLogin() &&
403          !provisional_save_manager_->HasGeneratedPassword() &&
404          !provisional_save_manager_->IsPendingCredentialsPublicSuffixMatch();
405 }
406
407 void PasswordManager::OnPasswordFormsRendered(
408     const std::vector<PasswordForm>& visible_forms,
409     bool did_stop_loading) {
410   CreatePendingLoginManagers(visible_forms);
411   scoped_ptr<BrowserSavePasswordProgressLogger> logger;
412   if (client_->IsLoggingActive()) {
413     logger.reset(new BrowserSavePasswordProgressLogger(client_));
414     logger->LogMessage(Logger::STRING_ON_PASSWORD_FORMS_RENDERED_METHOD);
415   }
416
417   if (!provisional_save_manager_.get()) {
418     if (logger) {
419       logger->LogMessage(Logger::STRING_NO_PROVISIONAL_SAVE_MANAGER);
420       logger->LogMessage(Logger::STRING_DECISION_DROP);
421     }
422     return;
423   }
424
425   DCHECK(IsSavingEnabledForCurrentPage());
426
427   if (logger) {
428     logger->LogNumber(Logger::STRING_NUMBER_OF_VISIBLE_FORMS,
429                       visible_forms.size());
430   }
431
432   // Record all visible forms from the frame.
433   all_visible_forms_.insert(all_visible_forms_.end(),
434                             visible_forms.begin(),
435                             visible_forms.end());
436
437   // If we see the login form again, then the login failed.
438   if (did_stop_loading) {
439     for (size_t i = 0; i < all_visible_forms_.size(); ++i) {
440       // TODO(vabr): The similarity check is just action equality for now. If it
441       // becomes more complex, it may make sense to consider modifying and using
442       // PasswordFormManager::DoesManage for it.
443       if (all_visible_forms_[i].action.is_valid() &&
444           provisional_save_manager_->pending_credentials().action ==
445               all_visible_forms_[i].action) {
446         if (logger) {
447           logger->LogPasswordForm(Logger::STRING_PASSWORD_FORM_REAPPEARED,
448                                   visible_forms[i]);
449           logger->LogMessage(Logger::STRING_DECISION_DROP);
450         }
451         provisional_save_manager_->SubmitFailed();
452         provisional_save_manager_.reset();
453         // Clear all_visible_forms_ once we found the match.
454         all_visible_forms_.clear();
455         return;
456       }
457     }
458
459     // Clear all_visible_forms_ after checking all the visible forms.
460     all_visible_forms_.clear();
461
462     // Looks like a successful login attempt. Either show an infobar or
463     // automatically save the login data. We prompt when the user hasn't
464     // already given consent, either through previously accepting the infobar
465     // or by having the browser generate the password.
466     provisional_save_manager_->SubmitPassed();
467
468     if (ShouldPromptUserToSavePassword()) {
469       if (logger)
470         logger->LogMessage(Logger::STRING_DECISION_ASK);
471       client_->PromptUserToSavePassword(provisional_save_manager_.Pass());
472     } else {
473       if (logger)
474         logger->LogMessage(Logger::STRING_DECISION_SAVE);
475       provisional_save_manager_->Save();
476
477       if (provisional_save_manager_->HasGeneratedPassword()) {
478         client_->AutomaticPasswordSave(provisional_save_manager_.Pass());
479       } else {
480         provisional_save_manager_.reset();
481       }
482     }
483   }
484 }
485
486 void PasswordManager::PossiblyInitializeUsernamesExperiment(
487     const PasswordFormMap& best_matches) const {
488   if (base::FieldTrialList::Find(kOtherPossibleUsernamesExperiment))
489     return;
490
491   bool other_possible_usernames_exist = false;
492   for (autofill::PasswordFormMap::const_iterator it = best_matches.begin();
493        it != best_matches.end();
494        ++it) {
495     if (!it->second->other_possible_usernames.empty()) {
496       other_possible_usernames_exist = true;
497       break;
498     }
499   }
500
501   if (!other_possible_usernames_exist)
502     return;
503
504   const base::FieldTrial::Probability kDivisor = 100;
505   scoped_refptr<base::FieldTrial> trial(
506       base::FieldTrialList::FactoryGetFieldTrial(
507           kOtherPossibleUsernamesExperiment,
508           kDivisor,
509           "Disabled",
510           2013, 12, 31,
511           base::FieldTrial::ONE_TIME_RANDOMIZED,
512           NULL));
513   base::FieldTrial::Probability enabled_probability =
514       client_->GetProbabilityForExperiment(kOtherPossibleUsernamesExperiment);
515   trial->AppendGroup("Enabled", enabled_probability);
516 }
517
518 bool PasswordManager::OtherPossibleUsernamesEnabled() const {
519   return base::FieldTrialList::FindFullName(
520              kOtherPossibleUsernamesExperiment) == "Enabled";
521 }
522
523 void PasswordManager::Autofill(const PasswordForm& form_for_autofill,
524                                const PasswordFormMap& best_matches,
525                                const PasswordForm& preferred_match,
526                                bool wait_for_username) const {
527   PossiblyInitializeUsernamesExperiment(best_matches);
528
529   // TODO(tedchoc): Switch to only requesting authentication if the user is
530   //                acting on the autofilled forms (crbug.com/342594) instead
531   //                of on page load.
532   bool authentication_required = preferred_match.use_additional_authentication;
533   for (autofill::PasswordFormMap::const_iterator it = best_matches.begin();
534        !authentication_required && it != best_matches.end();
535        ++it) {
536     if (it->second->use_additional_authentication)
537       authentication_required = true;
538   }
539
540   switch (form_for_autofill.scheme) {
541     case PasswordForm::SCHEME_HTML: {
542       // Note the check above is required because the observers_ for a non-HTML
543       // schemed password form may have been freed, so we need to distinguish.
544       scoped_ptr<autofill::PasswordFormFillData> fill_data(
545           new autofill::PasswordFormFillData());
546       InitPasswordFormFillData(form_for_autofill,
547                                best_matches,
548                                &preferred_match,
549                                wait_for_username,
550                                OtherPossibleUsernamesEnabled(),
551                                fill_data.get());
552       if (authentication_required)
553         client_->AuthenticateAutofillAndFillForm(fill_data.Pass());
554       else
555         driver_->FillPasswordForm(*fill_data.get());
556       break;
557     }
558     default:
559       FOR_EACH_OBSERVER(
560           LoginModelObserver,
561           observers_,
562           OnAutofillDataAvailable(preferred_match.username_value,
563                                   preferred_match.password_value));
564       break;
565   }
566
567   client_->PasswordWasAutofilled(best_matches);
568 }
569
570 }  // namespace password_manager