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/profiles/profile.h"
     17 #include "chrome/common/chrome_switches.h"
     18 #include "chrome/common/chrome_version_info.h"
     19 #include "chrome/common/pref_names.h"
     20 #include "components/autofill/core/common/autofill_messages.h"
     21 #include "components/user_prefs/pref_registry_syncable.h"
     22 #include "content/public/browser/navigation_details.h"
     23 #include "content/public/browser/user_metrics.h"
     24 #include "content/public/browser/web_contents.h"
     25 #include "content/public/common/frame_navigate_params.h"
     26 #include "grit/generated_resources.h"
     27 
     28 using content::UserMetricsAction;
     29 using content::WebContents;
     30 using content::PasswordForm;
     31 using content::PasswordFormMap;
     32 
     33 DEFINE_WEB_CONTENTS_USER_DATA_KEY(PasswordManager);
     34 
     35 namespace {
     36 
     37 const char kSpdyProxyRealm[] = "/SpdyProxy";
     38 const char kOtherPossibleUsernamesExperiment[] =
     39     "PasswordManagerOtherPossibleUsernames";
     40 
     41 // This routine is called when PasswordManagers are constructed.
     42 //
     43 // Currently we report metrics only once at startup. We require
     44 // that this is only ever called from a single thread in order to
     45 // avoid needing to lock (a static boolean flag is then sufficient to
     46 // guarantee running only once).
     47 void ReportMetrics(bool password_manager_enabled) {
     48   static base::PlatformThreadId initial_thread_id =
     49       base::PlatformThread::CurrentId();
     50   DCHECK(initial_thread_id == base::PlatformThread::CurrentId());
     51 
     52   static bool ran_once = false;
     53   if (ran_once)
     54     return;
     55   ran_once = true;
     56 
     57   // TODO(isherman): This does not actually measure a user action.  It should be
     58   // a boolean histogram.
     59   if (password_manager_enabled)
     60     content::RecordAction(UserMetricsAction("PasswordManager_Enabled"));
     61   else
     62     content::RecordAction(UserMetricsAction("PasswordManager_Disabled"));
     63 }
     64 
     65 }  // namespace
     66 
     67 // static
     68 void PasswordManager::RegisterProfilePrefs(
     69     user_prefs::PrefRegistrySyncable* registry) {
     70   registry->RegisterBooleanPref(
     71       prefs::kPasswordManagerEnabled,
     72       true,
     73       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
     74   registry->RegisterBooleanPref(
     75       prefs::kPasswordManagerAllowShowPasswords,
     76       true,
     77       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
     78 }
     79 
     80 // static
     81 void PasswordManager::CreateForWebContentsAndDelegate(
     82     content::WebContents* contents,
     83     PasswordManagerDelegate* delegate) {
     84   if (FromWebContents(contents)) {
     85     DCHECK_EQ(delegate, FromWebContents(contents)->delegate_);
     86     return;
     87   }
     88 
     89   contents->SetUserData(UserDataKey(),
     90                         new PasswordManager(contents, delegate));
     91 }
     92 
     93 PasswordManager::PasswordManager(WebContents* web_contents,
     94                                  PasswordManagerDelegate* delegate)
     95     : content::WebContentsObserver(web_contents),
     96       delegate_(delegate) {
     97   DCHECK(delegate_);
     98   password_manager_enabled_.Init(prefs::kPasswordManagerEnabled,
     99                                  delegate_->GetProfile()->GetPrefs());
    100 
    101   ReportMetrics(*password_manager_enabled_);
    102 }
    103 
    104 PasswordManager::~PasswordManager() {
    105   FOR_EACH_OBSERVER(LoginModelObserver, observers_, OnLoginModelDestroying());
    106 }
    107 
    108 void PasswordManager::SetFormHasGeneratedPassword(const PasswordForm& form) {
    109   for (ScopedVector<PasswordFormManager>::iterator iter =
    110            pending_login_managers_.begin();
    111        iter != pending_login_managers_.end(); ++iter) {
    112     if ((*iter)->DoesManage(
    113         form, PasswordFormManager::ACTION_MATCH_REQUIRED)) {
    114       (*iter)->SetHasGeneratedPassword();
    115       return;
    116     }
    117   }
    118   // If there is no corresponding PasswordFormManager, we create one. This is
    119   // not the common case, and should only happen when there is a bug in our
    120   // ability to detect forms.
    121   bool ssl_valid = (form.origin.SchemeIsSecure() &&
    122                     !delegate_->DidLastPageLoadEncounterSSLErrors());
    123   PasswordFormManager* manager =
    124       new PasswordFormManager(delegate_->GetProfile(),
    125                               this,
    126                               web_contents(),
    127                               form,
    128                               ssl_valid);
    129   pending_login_managers_.push_back(manager);
    130   manager->SetHasGeneratedPassword();
    131   // TODO(gcasto): Add UMA stats to track this.
    132 }
    133 
    134 bool PasswordManager::IsSavingEnabled() const {
    135   return *password_manager_enabled_ &&
    136          !delegate_->GetProfile()->IsOffTheRecord();
    137 }
    138 
    139 void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) {
    140   if (!IsSavingEnabled())
    141     return;
    142 
    143   // No password to save? Then don't.
    144   if (form.password_value.empty())
    145     return;
    146 
    147   scoped_ptr<PasswordFormManager> manager;
    148   ScopedVector<PasswordFormManager>::iterator matched_manager_it =
    149       pending_login_managers_.end();
    150   for (ScopedVector<PasswordFormManager>::iterator iter =
    151            pending_login_managers_.begin();
    152        iter != pending_login_managers_.end(); ++iter) {
    153     // If we find a manager that exactly matches the submitted form including
    154     // the action URL, exit the loop.
    155     if ((*iter)->DoesManage(
    156         form, PasswordFormManager::ACTION_MATCH_REQUIRED)) {
    157       matched_manager_it = iter;
    158       break;
    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     } else if ((*iter)->DoesManage(
    163         form, PasswordFormManager::ACTION_MATCH_NOT_REQUIRED)) {
    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     return;
    177   }
    178 
    179   // If we found a manager but it didn't finish matching yet, the user has
    180   // tried to submit credentials before we had time to even find matching
    181   // results for the given form and autofill. If this is the case, we just
    182   // give up.
    183   if (!manager->HasCompletedMatching())
    184     return;
    185 
    186   // Also get out of here if the user told us to 'never remember' passwords for
    187   // this form.
    188   if (manager->IsBlacklisted())
    189     return;
    190 
    191   // Bail if we're missing any of the necessary form components.
    192   if (!manager->HasValidPasswordForm())
    193     return;
    194 
    195   // Always save generated passwords, as the user expresses explicit intent for
    196   // Chrome to manage such passwords. For other passwords, respect the
    197   // autocomplete attribute.
    198   if (!manager->HasGeneratedPassword() && !form.password_autocomplete_set)
    199     return;
    200 
    201   PasswordForm provisionally_saved_form(form);
    202   provisionally_saved_form.ssl_valid = form.origin.SchemeIsSecure() &&
    203       !delegate_->DidLastPageLoadEncounterSSLErrors();
    204   provisionally_saved_form.preferred = true;
    205   PasswordFormManager::OtherPossibleUsernamesAction action =
    206       PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES;
    207   if (OtherPossibleUsernamesEnabled())
    208     action = PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES;
    209   manager->ProvisionallySave(provisionally_saved_form, action);
    210   provisional_save_manager_.swap(manager);
    211 }
    212 
    213 void PasswordManager::AddObserver(LoginModelObserver* observer) {
    214   observers_.AddObserver(observer);
    215 }
    216 
    217 void PasswordManager::RemoveObserver(LoginModelObserver* observer) {
    218   observers_.RemoveObserver(observer);
    219 }
    220 
    221 void PasswordManager::DidNavigateAnyFrame(
    222       const content::LoadCommittedDetails& details,
    223       const content::FrameNavigateParams& params) {
    224   bool password_form_submitted = params.password_form.origin.is_valid();
    225 
    226   // Try to save the password if one was submitted.
    227   if (password_form_submitted)
    228     ProvisionallySavePassword(params.password_form);
    229 
    230   // Clear data after submission or main frame navigation. We don't want
    231   // to clear data after subframe navigation as there might be password
    232   // forms on other frames that could be submitted.
    233   if (password_form_submitted || details.is_main_frame)
    234     pending_login_managers_.clear();
    235 }
    236 
    237 bool PasswordManager::OnMessageReceived(const IPC::Message& message) {
    238   bool handled = true;
    239   IPC_BEGIN_MESSAGE_MAP(PasswordManager, message)
    240     IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsParsed,
    241                         OnPasswordFormsParsed)
    242     IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsRendered,
    243                         OnPasswordFormsRendered)
    244     IPC_MESSAGE_UNHANDLED(handled = false)
    245   IPC_END_MESSAGE_MAP()
    246   return handled;
    247 }
    248 
    249 void PasswordManager::OnPasswordFormsParsed(
    250     const std::vector<PasswordForm>& forms) {
    251   // Ask the SSLManager for current security.
    252   bool had_ssl_error = delegate_->DidLastPageLoadEncounterSSLErrors();
    253 
    254   for (std::vector<PasswordForm>::const_iterator iter = forms.begin();
    255        iter != forms.end(); ++iter) {
    256     // Don't involve the password manager if this form corresponds to
    257     // SpdyProxy authentication, as indicated by the realm.
    258     if (EndsWith(iter->signon_realm, kSpdyProxyRealm, true))
    259       continue;
    260 
    261     bool ssl_valid = iter->origin.SchemeIsSecure() && !had_ssl_error;
    262     PasswordFormManager* manager =
    263         new PasswordFormManager(delegate_->GetProfile(),
    264                                 this,
    265                                 web_contents(),
    266                                 *iter,
    267                                 ssl_valid);
    268     pending_login_managers_.push_back(manager);
    269     manager->FetchMatchingLoginsFromPasswordStore();
    270   }
    271 }
    272 
    273 bool PasswordManager::ShouldShowSavePasswordInfoBar() const {
    274   return provisional_save_manager_->IsNewLogin() &&
    275       !provisional_save_manager_->HasGeneratedPassword() &&
    276       !provisional_save_manager_->IsPendingCredentialsPublicSuffixMatch();
    277 }
    278 
    279 void PasswordManager::OnPasswordFormsRendered(
    280     const std::vector<PasswordForm>& visible_forms) {
    281   if (!provisional_save_manager_.get())
    282     return;
    283 
    284   DCHECK(IsSavingEnabled());
    285 
    286   // First, check for a failed login attempt.
    287   for (std::vector<PasswordForm>::const_iterator iter = visible_forms.begin();
    288        iter != visible_forms.end(); ++iter) {
    289     if (provisional_save_manager_->DoesManage(
    290         *iter, PasswordFormManager::ACTION_MATCH_REQUIRED)) {
    291       // The form trying to be saved has immediately re-appeared. Assume login
    292       // failure and abort this save, by clearing provisional_save_manager_.
    293       provisional_save_manager_->SubmitFailed();
    294       provisional_save_manager_.reset();
    295       return;
    296     }
    297   }
    298 
    299   if (!provisional_save_manager_->HasValidPasswordForm()) {
    300     // Form is not completely valid - we do not support it.
    301     NOTREACHED();
    302     provisional_save_manager_.reset();
    303     return;
    304   }
    305 
    306   // Looks like a successful login attempt. Either show an infobar or
    307   // automatically save the login data. We prompt when the user hasn't already
    308   // given consent, either through previously accepting the infobar or by having
    309   // the browser generate the password.
    310   provisional_save_manager_->SubmitPassed();
    311   if (provisional_save_manager_->HasGeneratedPassword())
    312     UMA_HISTOGRAM_COUNTS("PasswordGeneration.Submitted", 1);
    313 
    314   if (!CommandLine::ForCurrentProcess()->HasSwitch(
    315           switches::kEnableSavePasswordBubble)) {
    316     if (ShouldShowSavePasswordInfoBar()) {
    317       delegate_->AddSavePasswordInfoBarIfPermitted(
    318           provisional_save_manager_.release());
    319     } else {
    320       provisional_save_manager_->Save();
    321       provisional_save_manager_.reset();
    322     }
    323   }
    324 }
    325 
    326 void PasswordManager::PossiblyInitializeUsernamesExperiment(
    327     const PasswordFormMap& best_matches) const {
    328   if (base::FieldTrialList::Find(kOtherPossibleUsernamesExperiment))
    329     return;
    330 
    331   bool other_possible_usernames_exist = false;
    332   for (content::PasswordFormMap::const_iterator it = best_matches.begin();
    333        it != best_matches.end(); ++it) {
    334     if (!it->second->other_possible_usernames.empty()) {
    335       other_possible_usernames_exist = true;
    336       break;
    337     }
    338   }
    339 
    340   if (!other_possible_usernames_exist)
    341     return;
    342 
    343   const base::FieldTrial::Probability kDivisor = 100;
    344   scoped_refptr<base::FieldTrial> trial(
    345       base::FieldTrialList::FactoryGetFieldTrial(
    346           kOtherPossibleUsernamesExperiment,
    347           kDivisor, "Disabled", 2013, 12, 31,
    348           base::FieldTrial::ONE_TIME_RANDOMIZED, NULL));
    349   base::FieldTrial::Probability enabled_probability = 0;
    350 
    351   switch (chrome::VersionInfo::GetChannel()) {
    352     case chrome::VersionInfo::CHANNEL_DEV:
    353     case chrome::VersionInfo::CHANNEL_BETA:
    354       enabled_probability = 50;
    355       break;
    356     default:
    357       break;
    358   }
    359 
    360   trial->AppendGroup("Enabled", enabled_probability);
    361 }
    362 
    363 bool PasswordManager::OtherPossibleUsernamesEnabled() const {
    364   return base::FieldTrialList::FindFullName(
    365       kOtherPossibleUsernamesExperiment) == "Enabled";
    366 }
    367 
    368 void PasswordManager::Autofill(
    369     const PasswordForm& form_for_autofill,
    370     const PasswordFormMap& best_matches,
    371     const PasswordForm& preferred_match,
    372     bool wait_for_username) const {
    373   PossiblyInitializeUsernamesExperiment(best_matches);
    374   switch (form_for_autofill.scheme) {
    375     case PasswordForm::SCHEME_HTML: {
    376       // Note the check above is required because the observer_ for a non-HTML
    377       // schemed password form may have been freed, so we need to distinguish.
    378       autofill::PasswordFormFillData fill_data;
    379       InitPasswordFormFillData(form_for_autofill,
    380                                best_matches,
    381                                &preferred_match,
    382                                wait_for_username,
    383                                OtherPossibleUsernamesEnabled(),
    384                                &fill_data);
    385       delegate_->FillPasswordForm(fill_data);
    386       return;
    387     }
    388     default:
    389       FOR_EACH_OBSERVER(
    390           LoginModelObserver,
    391           observers_,
    392           OnAutofillDataAvailable(preferred_match.username_value,
    393                                   preferred_match.password_value));
    394   }
    395 }
    396