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