1 // Copyright 2014 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.
5 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
7 #include "base/bind_helpers.h"
8 #include "base/command_line.h"
9 #include "base/memory/singleton.h"
10 #include "base/metrics/histogram.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/string16.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/browsing_data/browsing_data_helper.h"
15 #include "chrome/browser/password_manager/password_store_factory.h"
16 #include "chrome/browser/password_manager/save_password_infobar_delegate.h"
17 #include "chrome/browser/password_manager/sync_metrics.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/sync/profile_sync_service.h"
20 #include "chrome/browser/sync/profile_sync_service_factory.h"
21 #include "chrome/browser/ui/autofill/password_generation_popup_controller_impl.h"
22 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/common/chrome_version_info.h"
25 #include "chrome/common/url_constants.h"
26 #include "components/autofill/content/browser/content_autofill_driver.h"
27 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
28 #include "components/autofill/content/common/autofill_messages.h"
29 #include "components/autofill/core/browser/password_generator.h"
30 #include "components/autofill/core/common/password_form.h"
31 #include "components/password_manager/content/browser/content_password_manager_driver.h"
32 #include "components/password_manager/content/browser/password_manager_internals_service_factory.h"
33 #include "components/password_manager/content/common/credential_manager_messages.h"
34 #include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
35 #include "components/password_manager/core/browser/log_receiver.h"
36 #include "components/password_manager/core/browser/password_form_manager.h"
37 #include "components/password_manager/core/browser/password_manager_internals_service.h"
38 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
39 #include "components/password_manager/core/browser/password_manager_util.h"
40 #include "components/password_manager/core/common/credential_manager_types.h"
41 #include "components/password_manager/core/common/password_manager_pref_names.h"
42 #include "components/password_manager/core/common/password_manager_switches.h"
43 #include "content/public/browser/navigation_entry.h"
44 #include "content/public/browser/render_view_host.h"
45 #include "content/public/browser/web_contents.h"
46 #include "google_apis/gaia/gaia_urls.h"
47 #include "net/base/url_util.h"
48 #include "third_party/re2/re2/re2.h"
50 #if defined(OS_ANDROID)
51 #include "chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h"
54 using password_manager::ContentPasswordManagerDriverFactory
;
55 using password_manager::PasswordManagerInternalsService
;
56 using password_manager::PasswordManagerInternalsServiceFactory
;
58 // Shorten the name to spare line breaks. The code provides enough context
60 typedef autofill::SavePasswordProgressLogger Logger
;
62 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromePasswordManagerClient
);
65 // This routine is called when PasswordManagerClient is constructed.
66 // Currently we report metrics only once at startup. We require
67 // that this is only ever called from a single thread in order to
68 // avoid needing to lock (a static boolean flag is then sufficient to
69 // guarantee running only once).
70 void ReportMetrics(bool password_manager_enabled
,
71 password_manager::PasswordManagerClient
* client
) {
72 static base::PlatformThreadId initial_thread_id
=
73 base::PlatformThread::CurrentId();
74 DCHECK_EQ(base::PlatformThread::CurrentId(), initial_thread_id
);
76 static bool ran_once
= false;
81 password_manager::PasswordStore
* store
= client
->GetPasswordStore();
82 // May be null in tests.
84 store
->ReportMetrics(client
->GetSyncUsername(),
85 client
->GetPasswordSyncState() ==
86 password_manager::SYNCING_WITH_CUSTOM_PASSPHRASE
);
88 UMA_HISTOGRAM_BOOLEAN("PasswordManager.Enabled", password_manager_enabled
);
94 void ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
95 content::WebContents
* contents
,
96 autofill::AutofillClient
* autofill_client
) {
97 if (FromWebContents(contents
))
100 contents
->SetUserData(
102 new ChromePasswordManagerClient(contents
, autofill_client
));
105 ChromePasswordManagerClient::ChromePasswordManagerClient(
106 content::WebContents
* web_contents
,
107 autofill::AutofillClient
* autofill_client
)
108 : content::WebContentsObserver(web_contents
),
109 profile_(Profile::FromBrowserContext(web_contents
->GetBrowserContext())),
110 password_manager_(this),
111 driver_factory_(nullptr),
112 credential_manager_dispatcher_(web_contents
, this),
114 can_use_log_router_(false),
115 autofill_sync_state_(ALLOW_SYNC_CREDENTIALS
),
116 sync_credential_was_filtered_(false) {
117 ContentPasswordManagerDriverFactory::CreateForWebContents(web_contents
, this,
120 ContentPasswordManagerDriverFactory::FromWebContents(web_contents
);
122 PasswordManagerInternalsService
* service
=
123 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_
);
125 can_use_log_router_
= service
->RegisterClient(this);
126 SetUpAutofillSyncState();
127 saving_passwords_enabled_
.Init(
128 password_manager::prefs::kPasswordManagerSavingEnabled
, GetPrefs());
129 ReportMetrics(*saving_passwords_enabled_
, this);
132 ChromePasswordManagerClient::~ChromePasswordManagerClient() {
133 PasswordManagerInternalsService
* service
=
134 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_
);
136 service
->UnregisterClient(this);
139 bool ChromePasswordManagerClient::IsAutomaticPasswordSavingEnabled() const {
140 return base::CommandLine::ForCurrentProcess()->HasSwitch(
141 password_manager::switches::kEnableAutomaticPasswordSaving
) &&
142 chrome::VersionInfo::GetChannel() ==
143 chrome::VersionInfo::CHANNEL_UNKNOWN
;
146 bool ChromePasswordManagerClient::IsPasswordManagementEnabledForCurrentPage()
148 DCHECK(web_contents());
149 content::NavigationEntry
* entry
=
150 web_contents()->GetController().GetLastCommittedEntry();
151 bool is_enabled
= false;
153 // TODO(gcasto): Determine if fix for crbug.com/388246 is relevant here.
155 } else if (IsURLPasswordWebsiteReauth(entry
->GetURL())) {
156 // Disable the password manager for online password management.
158 } else if (EnabledForSyncSignin()) {
161 // Do not fill nor save password when a user is signing in for sync. This
162 // is because users need to remember their password if they are syncing as
163 // this is effectively their master password.
164 is_enabled
= entry
->GetURL().host() != chrome::kChromeUIChromeSigninHost
;
166 if (IsLoggingActive()) {
167 password_manager::BrowserSavePasswordProgressLogger
logger(this);
169 Logger::STRING_PASSWORD_MANAGEMENT_ENABLED_FOR_CURRENT_PAGE
,
175 bool ChromePasswordManagerClient::IsSavingEnabledForCurrentPage() const {
176 return *saving_passwords_enabled_
&& !IsOffTheRecord() &&
177 !DidLastPageLoadEncounterSSLErrors() &&
178 IsPasswordManagementEnabledForCurrentPage();
181 bool ChromePasswordManagerClient::ShouldFilterAutofillResult(
182 const autofill::PasswordForm
& form
) {
183 if (!IsSyncAccountCredential(base::UTF16ToUTF8(form
.username_value
),
187 if (autofill_sync_state_
== DISALLOW_SYNC_CREDENTIALS
) {
188 sync_credential_was_filtered_
= true;
192 if (autofill_sync_state_
== DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH
&&
193 LastLoadWasTransactionalReauthPage()) {
194 sync_credential_was_filtered_
= true;
201 std::string
ChromePasswordManagerClient::GetSyncUsername() const {
202 return password_manager_sync_metrics::GetSyncUsername(profile_
);
205 bool ChromePasswordManagerClient::IsSyncAccountCredential(
206 const std::string
& username
,
207 const std::string
& realm
) const {
208 return password_manager_sync_metrics::IsSyncAccountCredential(
209 profile_
, username
, realm
);
212 void ChromePasswordManagerClient::AutofillResultsComputed() {
213 UMA_HISTOGRAM_BOOLEAN("PasswordManager.SyncCredentialFiltered",
214 sync_credential_was_filtered_
);
215 sync_credential_was_filtered_
= false;
218 bool ChromePasswordManagerClient::PromptUserToSavePassword(
219 scoped_ptr
<password_manager::PasswordFormManager
> form_to_save
,
220 password_manager::CredentialSourceType type
) {
221 // Save password infobar and the password bubble prompts in case of
222 // "webby" URLs and do not prompt in case of "non-webby" URLS (e.g. file://).
223 if (!BrowsingDataHelper::IsWebScheme(
224 web_contents()->GetLastCommittedURL().scheme())) {
228 if (IsTheHotNewBubbleUIEnabled()) {
229 ManagePasswordsUIController
* manage_passwords_ui_controller
=
230 ManagePasswordsUIController::FromWebContents(web_contents());
231 manage_passwords_ui_controller
->OnPasswordSubmitted(form_to_save
.Pass());
233 std::string
uma_histogram_suffix(
234 password_manager::metrics_util::GroupIdToString(
235 password_manager::metrics_util::MonitoredDomainGroupId(
236 form_to_save
->realm(), GetPrefs())));
237 SavePasswordInfoBarDelegate::Create(
238 web_contents(), form_to_save
.Pass(), uma_histogram_suffix
, type
);
243 bool ChromePasswordManagerClient::PromptUserToChooseCredentials(
244 ScopedVector
<autofill::PasswordForm
> local_forms
,
245 ScopedVector
<autofill::PasswordForm
> federated_forms
,
247 base::Callback
<void(const password_manager::CredentialInfo
&)> callback
) {
248 return ManagePasswordsUIController::FromWebContents(web_contents())->
249 OnChooseCredentials(local_forms
.Pass(), federated_forms
.Pass(), origin
,
253 void ChromePasswordManagerClient::ForceSavePassword() {
254 password_manager::ContentPasswordManagerDriver
* driver
=
255 driver_factory_
->GetDriverForFrame(web_contents()->GetFocusedFrame());
256 driver
->ForceSavePassword();
259 void ChromePasswordManagerClient::NotifyUserAutoSignin(
260 ScopedVector
<autofill::PasswordForm
> local_forms
) {
261 DCHECK(!local_forms
.empty());
262 ManagePasswordsUIController::FromWebContents(web_contents())->
263 OnAutoSignin(local_forms
.Pass());
266 void ChromePasswordManagerClient::AutomaticPasswordSave(
267 scoped_ptr
<password_manager::PasswordFormManager
> saved_form
) {
268 #if defined(OS_ANDROID)
269 GeneratedPasswordSavedInfoBarDelegateAndroid::Create(web_contents());
271 if (IsTheHotNewBubbleUIEnabled()) {
272 ManagePasswordsUIController
* manage_passwords_ui_controller
=
273 ManagePasswordsUIController::FromWebContents(web_contents());
274 manage_passwords_ui_controller
->OnAutomaticPasswordSave(
280 void ChromePasswordManagerClient::PasswordWasAutofilled(
281 const autofill::PasswordFormMap
& best_matches
) const {
282 ManagePasswordsUIController
* manage_passwords_ui_controller
=
283 ManagePasswordsUIController::FromWebContents(web_contents());
284 if (manage_passwords_ui_controller
&& IsTheHotNewBubbleUIEnabled())
285 manage_passwords_ui_controller
->OnPasswordAutofilled(best_matches
);
288 void ChromePasswordManagerClient::PasswordAutofillWasBlocked(
289 const autofill::PasswordFormMap
& best_matches
) const {
290 ManagePasswordsUIController
* controller
=
291 ManagePasswordsUIController::FromWebContents(web_contents());
292 if (controller
&& IsTheHotNewBubbleUIEnabled())
293 controller
->OnBlacklistBlockedAutofill(best_matches
);
296 void ChromePasswordManagerClient::HidePasswordGenerationPopup() {
297 if (popup_controller_
)
298 popup_controller_
->HideAndDestroy();
301 PrefService
* ChromePasswordManagerClient::GetPrefs() {
302 return profile_
->GetPrefs();
305 password_manager::PasswordStore
*
306 ChromePasswordManagerClient::GetPasswordStore() const {
307 // Always use EXPLICIT_ACCESS as the password manager checks IsOffTheRecord
308 // itself when it shouldn't access the PasswordStore.
309 // TODO(gcasto): Is is safe to change this to
310 // ServiceAccessType::IMPLICIT_ACCESS?
311 return PasswordStoreFactory::GetForProfile(
312 profile_
, ServiceAccessType::EXPLICIT_ACCESS
).get();
315 password_manager::PasswordSyncState
316 ChromePasswordManagerClient::GetPasswordSyncState() const {
317 const ProfileSyncService
* sync_service
=
318 ProfileSyncServiceFactory::GetForProfile(profile_
);
319 return password_manager_util::GetPasswordSyncState(sync_service
);
322 void ChromePasswordManagerClient::OnLogRouterAvailabilityChanged(
323 bool router_can_be_used
) {
324 if (can_use_log_router_
== router_can_be_used
)
326 can_use_log_router_
= router_can_be_used
;
328 NotifyRendererOfLoggingAvailability();
331 void ChromePasswordManagerClient::LogSavePasswordProgress(
332 const std::string
& text
) const {
333 if (!IsLoggingActive())
335 PasswordManagerInternalsService
* service
=
336 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_
);
338 service
->ProcessLog(text
);
341 bool ChromePasswordManagerClient::IsLoggingActive() const {
342 // WebUI tabs do not need to log password saving progress. In particular, the
343 // internals page itself should not send any logs.
344 return can_use_log_router_
&& !web_contents()->GetWebUI();
347 bool ChromePasswordManagerClient::WasLastNavigationHTTPError() const {
348 DCHECK(web_contents());
350 scoped_ptr
<password_manager::BrowserSavePasswordProgressLogger
> logger
;
351 if (IsLoggingActive()) {
352 logger
.reset(new password_manager::BrowserSavePasswordProgressLogger(this));
354 Logger::STRING_WAS_LAST_NAVIGATION_HTTP_ERROR_METHOD
);
357 content::NavigationEntry
* entry
=
358 web_contents()->GetController().GetVisibleEntry();
361 int http_status_code
= entry
->GetHttpStatusCode();
364 logger
->LogNumber(Logger::STRING_HTTP_STATUS_CODE
, http_status_code
);
366 if (http_status_code
>= 400 && http_status_code
< 600)
371 bool ChromePasswordManagerClient::DidLastPageLoadEncounterSSLErrors() const {
372 content::NavigationEntry
* entry
=
373 web_contents()->GetController().GetLastCommittedEntry();
374 bool ssl_errors
= true;
378 ssl_errors
= net::IsCertStatusError(entry
->GetSSL().cert_status
);
380 if (IsLoggingActive()) {
381 password_manager::BrowserSavePasswordProgressLogger
logger(this);
382 logger
.LogBoolean(Logger::STRING_SSL_ERRORS_PRESENT
, ssl_errors
);
387 bool ChromePasswordManagerClient::IsOffTheRecord() const {
388 return web_contents()->GetBrowserContext()->IsOffTheRecord();
391 password_manager::PasswordManager
*
392 ChromePasswordManagerClient::GetPasswordManager() {
393 return &password_manager_
;
396 autofill::AutofillManager
*
397 ChromePasswordManagerClient::GetAutofillManagerForMainFrame() {
398 autofill::ContentAutofillDriverFactory
* factory
=
399 autofill::ContentAutofillDriverFactory::FromWebContents(web_contents());
401 ? factory
->DriverForFrame(web_contents()->GetMainFrame())
406 void ChromePasswordManagerClient::SetTestObserver(
407 autofill::PasswordGenerationPopupObserver
* observer
) {
408 observer_
= observer
;
411 bool ChromePasswordManagerClient::OnMessageReceived(
412 const IPC::Message
& message
,
413 content::RenderFrameHost
* render_frame_host
) {
415 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(ChromePasswordManagerClient
, message
,
417 // Autofill messages:
418 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordGenerationPopup
,
419 ShowPasswordGenerationPopup
)
420 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordEditingPopup
,
421 ShowPasswordEditingPopup
)
422 IPC_END_MESSAGE_MAP()
424 IPC_BEGIN_MESSAGE_MAP(ChromePasswordManagerClient
, message
)
425 IPC_MESSAGE_HANDLER(AutofillHostMsg_HidePasswordGenerationPopup
,
426 HidePasswordGenerationPopup
)
427 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordAutofillAgentConstructed
,
428 NotifyRendererOfLoggingAvailability
)
430 IPC_MESSAGE_UNHANDLED(handled
= false)
431 IPC_END_MESSAGE_MAP()
436 gfx::RectF
ChromePasswordManagerClient::GetBoundsInScreenSpace(
437 const gfx::RectF
& bounds
) {
438 gfx::Rect client_area
= web_contents()->GetContainerBounds();
439 return bounds
+ client_area
.OffsetFromOrigin();
442 void ChromePasswordManagerClient::ShowPasswordGenerationPopup(
443 content::RenderFrameHost
* render_frame_host
,
444 const gfx::RectF
& bounds
,
446 const autofill::PasswordForm
& form
) {
447 // TODO(gcasto): Validate data in PasswordForm.
449 gfx::RectF element_bounds_in_screen_space
= GetBoundsInScreenSpace(bounds
);
452 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate(
453 popup_controller_
, element_bounds_in_screen_space
, form
, max_length
,
455 driver_factory_
->GetDriverForFrame(render_frame_host
), observer_
,
456 web_contents(), web_contents()->GetNativeView());
457 popup_controller_
->Show(true /* display_password */);
460 void ChromePasswordManagerClient::ShowPasswordEditingPopup(
461 content::RenderFrameHost
* render_frame_host
,
462 const gfx::RectF
& bounds
,
463 const autofill::PasswordForm
& form
) {
464 gfx::RectF element_bounds_in_screen_space
= GetBoundsInScreenSpace(bounds
);
466 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate(
467 popup_controller_
, element_bounds_in_screen_space
, form
,
468 0, // Unspecified max length.
470 driver_factory_
->GetDriverForFrame(render_frame_host
), observer_
,
471 web_contents(), web_contents()->GetNativeView());
472 popup_controller_
->Show(false /* display_password */);
475 void ChromePasswordManagerClient::NotifyRendererOfLoggingAvailability() {
479 web_contents()->GetRenderViewHost()->Send(new AutofillMsg_SetLoggingState(
480 web_contents()->GetRenderViewHost()->GetRoutingID(),
481 can_use_log_router_
));
484 bool ChromePasswordManagerClient::LastLoadWasTransactionalReauthPage() const {
485 DCHECK(web_contents());
486 content::NavigationEntry
* entry
=
487 web_contents()->GetController().GetLastCommittedEntry();
491 if (entry
->GetURL().GetOrigin() !=
492 GaiaUrls::GetInstance()->gaia_url().GetOrigin())
495 // "rart" is the transactional reauth paramter.
496 std::string ignored_value
;
497 return net::GetValueForKeyInQuery(entry
->GetURL(),
502 bool ChromePasswordManagerClient::IsURLPasswordWebsiteReauth(
503 const GURL
& url
) const {
504 if (url
.GetOrigin() != GaiaUrls::GetInstance()->gaia_url().GetOrigin())
507 // "rart" param signals this page is for transactional reauth.
508 std::string param_value
;
509 if (!net::GetValueForKeyInQuery(url
, "rart", ¶m_value
))
512 // Check the "continue" param to see if this reauth page is for the passwords
515 if (!net::GetValueForKeyInQuery(url
, "continue", ¶m_value
))
518 // All password sites, including test sites, have autofilling disabled.
519 CR_DEFINE_STATIC_LOCAL(RE2
, account_dashboard_pattern
,
520 ("passwords(-([a-z-]+\\.corp))?\\.google\\.com"));
522 return RE2::FullMatch(GURL(param_value
).host(), account_dashboard_pattern
);
525 bool ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled() {
526 #if !defined(USE_AURA) && !defined(OS_MACOSX)
529 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
530 if (command_line
->HasSwitch(switches::kDisableSavePasswordBubble
))
533 if (command_line
->HasSwitch(switches::kEnableSavePasswordBubble
))
536 std::string group_name
=
537 base::FieldTrialList::FindFullName("PasswordManagerUI");
539 // The bubble should be the default case that runs on the bots.
540 return group_name
!= "Infobar";
543 bool ChromePasswordManagerClient::EnabledForSyncSignin() {
544 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
545 if (command_line
->HasSwitch(
546 password_manager::switches::kDisableManagerForSyncSignin
))
549 if (command_line
->HasSwitch(
550 password_manager::switches::kEnableManagerForSyncSignin
))
553 // Default is enabled.
554 std::string group_name
=
555 base::FieldTrialList::FindFullName("PasswordManagerStateForSyncSignin");
556 return group_name
!= "Disabled";
559 void ChromePasswordManagerClient::SetUpAutofillSyncState() {
560 std::string group_name
=
561 base::FieldTrialList::FindFullName("AutofillSyncCredential");
563 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
564 if (command_line
->HasSwitch(
565 password_manager::switches::kAllowAutofillSyncCredential
)) {
566 autofill_sync_state_
= ALLOW_SYNC_CREDENTIALS
;
569 if (command_line
->HasSwitch(
570 password_manager::switches::
571 kDisallowAutofillSyncCredentialForReauth
)) {
572 autofill_sync_state_
= DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH
;
575 if (command_line
->HasSwitch(
576 password_manager::switches::kDisallowAutofillSyncCredential
)) {
577 autofill_sync_state_
= DISALLOW_SYNC_CREDENTIALS
;
581 if (group_name
== "DisallowSyncCredentialsForReauth") {
582 autofill_sync_state_
= DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH
;
583 } else if (group_name
== "DisallowSyncCredentials") {
584 autofill_sync_state_
= DISALLOW_SYNC_CREDENTIALS
;
587 autofill_sync_state_
= ALLOW_SYNC_CREDENTIALS
;
591 const GURL
& ChromePasswordManagerClient::GetMainFrameURL() const {
592 return web_contents()->GetVisibleURL();