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_delegate_impl.h"
      6 
      7 #include "base/memory/singleton.h"
      8 #include "base/metrics/histogram.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "base/timer/elapsed_timer.h"
     11 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
     12 #include "chrome/browser/infobars/infobar.h"
     13 #include "chrome/browser/infobars/infobar_service.h"
     14 #include "chrome/browser/password_manager/password_form_manager.h"
     15 #include "chrome/browser/password_manager/password_manager.h"
     16 #include "chrome/browser/password_manager/password_manager_metrics_util.h"
     17 #include "chrome/browser/profiles/profile.h"
     18 #include "chrome/browser/ui/sync/one_click_signin_helper.h"
     19 #include "components/autofill/content/browser/autofill_driver_impl.h"
     20 #include "components/autofill/content/common/autofill_messages.h"
     21 #include "components/autofill/core/browser/autofill_manager.h"
     22 #include "components/autofill/core/common/password_form.h"
     23 #include "content/public/browser/navigation_entry.h"
     24 #include "content/public/browser/render_view_host.h"
     25 #include "content/public/browser/web_contents.h"
     26 #include "content/public/common/ssl_status.h"
     27 #include "google_apis/gaia/gaia_urls.h"
     28 #include "grit/chromium_strings.h"
     29 #include "grit/generated_resources.h"
     30 #include "grit/theme_resources.h"
     31 #include "net/cert/cert_status_flags.h"
     32 #include "ui/base/l10n/l10n_util.h"
     33 
     34 
     35 // SavePasswordInfoBarDelegate ------------------------------------------------
     36 
     37 // After a successful *new* login attempt, we take the PasswordFormManager in
     38 // provisional_save_manager_ and move it to a SavePasswordInfoBarDelegate while
     39 // the user makes up their mind with the "save password" infobar. Note if the
     40 // login is one we already know about, the end of the line is
     41 // provisional_save_manager_ because we just update it on success and so such
     42 // forms never end up in an infobar.
     43 class SavePasswordInfoBarDelegate : public ConfirmInfoBarDelegate {
     44  public:
     45   // If we won't be showing the one-click signin infobar, creates a save
     46   // password infobar and delegate and adds the infobar to the InfoBarService
     47   // for |web_contents|.  |uma_histogram_suffix| is empty, or one of the
     48   // "group_X" suffixes used in the histogram names for infobar usage reporting;
     49   // if empty, the usage is not reported, otherwise the suffix is used to choose
     50   // the right histogram.
     51   static void Create(content::WebContents* web_contents,
     52                      PasswordFormManager* form_to_save,
     53                      const std::string& uma_histogram_suffix);
     54 
     55  private:
     56   enum ResponseType {
     57     NO_RESPONSE = 0,
     58     REMEMBER_PASSWORD,
     59     NEVER_REMEMBER_PASSWORD,
     60     INFOBAR_DISMISSED,
     61     NUM_RESPONSE_TYPES,
     62   };
     63 
     64   SavePasswordInfoBarDelegate(PasswordFormManager* form_to_save,
     65                               const std::string& uma_histogram_suffix);
     66   virtual ~SavePasswordInfoBarDelegate();
     67 
     68   // ConfirmInfoBarDelegate
     69   virtual int GetIconID() const OVERRIDE;
     70   virtual Type GetInfoBarType() const OVERRIDE;
     71   virtual base::string16 GetMessageText() const OVERRIDE;
     72   virtual base::string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
     73   virtual bool Accept() OVERRIDE;
     74   virtual bool Cancel() OVERRIDE;
     75   virtual void InfoBarDismissed() OVERRIDE;
     76 
     77   virtual InfoBarAutomationType GetInfoBarAutomationType() const OVERRIDE;
     78 
     79   // The PasswordFormManager managing the form we're asking the user about,
     80   // and should update as per her decision.
     81   scoped_ptr<PasswordFormManager> form_to_save_;
     82 
     83   // Used to track the results we get from the info bar.
     84   ResponseType infobar_response_;
     85 
     86   // Measures the "Save password?" prompt lifetime. Used to report an UMA
     87   // signal.
     88   base::ElapsedTimer timer_;
     89 
     90   // The group name corresponding to the domain name of |form_to_save_| if the
     91   // form is on a monitored domain. Otherwise, an empty string.
     92   const std::string uma_histogram_suffix_;
     93 
     94   DISALLOW_COPY_AND_ASSIGN(SavePasswordInfoBarDelegate);
     95 };
     96 
     97 // static
     98 void SavePasswordInfoBarDelegate::Create(
     99     content::WebContents* web_contents,
    100     PasswordFormManager* form_to_save,
    101     const std::string& uma_histogram_suffix) {
    102 #if defined(ENABLE_ONE_CLICK_SIGNIN)
    103   // Don't show the password manager infobar if this form is for a google
    104   // account and we are going to show the one-click signin infobar.
    105   GURL realm(form_to_save->realm());
    106   // TODO(mathp): Checking only against associated_username() causes a bug
    107   // referenced here: crbug.com/133275
    108   if (((realm == GaiaUrls::GetInstance()->gaia_login_form_realm()) ||
    109        (realm == GURL("https://www.google.com/"))) &&
    110       OneClickSigninHelper::CanOffer(
    111           web_contents, OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
    112           UTF16ToUTF8(form_to_save->associated_username()), NULL))
    113     return;
    114 #endif
    115 
    116   InfoBarService::FromWebContents(web_contents)->AddInfoBar(
    117       ConfirmInfoBarDelegate::CreateInfoBar(scoped_ptr<ConfirmInfoBarDelegate>(
    118           new SavePasswordInfoBarDelegate(form_to_save,
    119                                           uma_histogram_suffix))));
    120 }
    121 
    122 SavePasswordInfoBarDelegate::SavePasswordInfoBarDelegate(
    123     PasswordFormManager* form_to_save,
    124     const std::string& uma_histogram_suffix)
    125     : ConfirmInfoBarDelegate(),
    126       form_to_save_(form_to_save),
    127       infobar_response_(NO_RESPONSE),
    128       uma_histogram_suffix_(uma_histogram_suffix) {
    129   if (!uma_histogram_suffix_.empty()) {
    130     password_manager_metrics_util::LogUMAHistogramBoolean(
    131         "PasswordManager.SavePasswordPromptDisplayed_" + uma_histogram_suffix_,
    132         true);
    133   }
    134 }
    135 
    136 SavePasswordInfoBarDelegate::~SavePasswordInfoBarDelegate() {
    137   UMA_HISTOGRAM_ENUMERATION("PasswordManager.InfoBarResponse",
    138                             infobar_response_, NUM_RESPONSE_TYPES);
    139 
    140   // The shortest period for which the prompt needs to live, so that we don't
    141   // consider it killed prematurely, as might happen, e.g., if a pre-rendered
    142   // page gets swapped in (and the current WebContents is destroyed).
    143   const base::TimeDelta kMinimumPromptDisplayTime =
    144       base::TimeDelta::FromSeconds(1);
    145 
    146   if (!uma_histogram_suffix_.empty()) {
    147     password_manager_metrics_util::LogUMAHistogramEnumeration(
    148         "PasswordManager.SavePasswordPromptResponse_" + uma_histogram_suffix_,
    149         infobar_response_, NUM_RESPONSE_TYPES);
    150     password_manager_metrics_util::LogUMAHistogramBoolean(
    151         "PasswordManager.SavePasswordPromptDisappearedQuickly_" +
    152             uma_histogram_suffix_,
    153         timer_.Elapsed() < kMinimumPromptDisplayTime);
    154   }
    155 }
    156 
    157 int SavePasswordInfoBarDelegate::GetIconID() const {
    158   return IDR_INFOBAR_SAVE_PASSWORD;
    159 }
    160 
    161 InfoBarDelegate::Type SavePasswordInfoBarDelegate::GetInfoBarType() const {
    162   return PAGE_ACTION_TYPE;
    163 }
    164 
    165 base::string16 SavePasswordInfoBarDelegate::GetMessageText() const {
    166   return l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT);
    167 }
    168 
    169 base::string16 SavePasswordInfoBarDelegate::GetButtonLabel(
    170     InfoBarButton button) const {
    171   return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
    172       IDS_PASSWORD_MANAGER_SAVE_BUTTON : IDS_PASSWORD_MANAGER_BLACKLIST_BUTTON);
    173 }
    174 
    175 bool SavePasswordInfoBarDelegate::Accept() {
    176   DCHECK(form_to_save_.get());
    177   form_to_save_->Save();
    178   infobar_response_ = REMEMBER_PASSWORD;
    179   return true;
    180 }
    181 
    182 bool SavePasswordInfoBarDelegate::Cancel() {
    183   DCHECK(form_to_save_.get());
    184   form_to_save_->PermanentlyBlacklist();
    185   infobar_response_ = NEVER_REMEMBER_PASSWORD;
    186   return true;
    187 }
    188 
    189 void SavePasswordInfoBarDelegate::InfoBarDismissed() {
    190   DCHECK(form_to_save_.get());
    191   infobar_response_ = INFOBAR_DISMISSED;
    192 }
    193 
    194 InfoBarDelegate::InfoBarAutomationType
    195     SavePasswordInfoBarDelegate::GetInfoBarAutomationType() const {
    196   return PASSWORD_INFOBAR;
    197 }
    198 
    199 
    200 // PasswordManagerDelegateImpl ------------------------------------------------
    201 
    202 DEFINE_WEB_CONTENTS_USER_DATA_KEY(PasswordManagerDelegateImpl);
    203 
    204 PasswordManagerDelegateImpl::PasswordManagerDelegateImpl(
    205     content::WebContents* web_contents)
    206     : web_contents_(web_contents) {
    207 }
    208 
    209 PasswordManagerDelegateImpl::~PasswordManagerDelegateImpl() {
    210 }
    211 
    212 void PasswordManagerDelegateImpl::FillPasswordForm(
    213     const autofill::PasswordFormFillData& form_data) {
    214   web_contents_->GetRenderViewHost()->Send(
    215       new AutofillMsg_FillPasswordForm(
    216           web_contents_->GetRenderViewHost()->GetRoutingID(),
    217           form_data));
    218 }
    219 
    220 void PasswordManagerDelegateImpl::AddSavePasswordInfoBarIfPermitted(
    221     PasswordFormManager* form_to_save) {
    222   std::string uma_histogram_suffix(
    223       password_manager_metrics_util::GroupIdToString(
    224           password_manager_metrics_util::MonitoredDomainGroupId(
    225               form_to_save->realm(), GetProfile()->GetPrefs())));
    226   SavePasswordInfoBarDelegate::Create(
    227       web_contents_, form_to_save, uma_histogram_suffix);
    228 }
    229 
    230 Profile* PasswordManagerDelegateImpl::GetProfile() {
    231   return Profile::FromBrowserContext(web_contents_->GetBrowserContext());
    232 }
    233 
    234 bool PasswordManagerDelegateImpl::DidLastPageLoadEncounterSSLErrors() {
    235   content::NavigationEntry* entry =
    236       web_contents_->GetController().GetActiveEntry();
    237   if (!entry) {
    238     NOTREACHED();
    239     return false;
    240   }
    241 
    242   return net::IsCertStatusError(entry->GetSSL().cert_status);
    243 }
    244