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