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