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/strings/string16.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/browsing_data/browsing_data_helper.h"
14 #include "chrome/browser/password_manager/password_manager_util.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/common/credential_manager_types.h"
40 #include "components/password_manager/core/common/password_manager_switches.h"
41 #include "content/public/browser/navigation_entry.h"
42 #include "content/public/browser/render_view_host.h"
43 #include "content/public/browser/web_contents.h"
44 #include "google_apis/gaia/gaia_urls.h"
45 #include "net/base/url_util.h"
46 #include "third_party/re2/re2/re2.h"
48 #if defined(OS_ANDROID)
49 #include "chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h"
52 using password_manager::ContentPasswordManagerDriverFactory
;
53 using password_manager::PasswordManagerInternalsService
;
54 using password_manager::PasswordManagerInternalsServiceFactory
;
56 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromePasswordManagerClient
);
58 // Shorten the name to spare line breaks. The code provides enough context
60 typedef autofill::SavePasswordProgressLogger Logger
;
63 void ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
64 content::WebContents
* contents
,
65 autofill::AutofillClient
* autofill_client
) {
66 if (FromWebContents(contents
))
69 contents
->SetUserData(
71 new ChromePasswordManagerClient(contents
, autofill_client
));
74 ChromePasswordManagerClient::ChromePasswordManagerClient(
75 content::WebContents
* web_contents
,
76 autofill::AutofillClient
* autofill_client
)
77 : content::WebContentsObserver(web_contents
),
78 profile_(Profile::FromBrowserContext(web_contents
->GetBrowserContext())),
79 password_manager_(this),
80 driver_factory_(nullptr),
81 credential_manager_dispatcher_(web_contents
, this),
83 can_use_log_router_(false),
84 autofill_sync_state_(ALLOW_SYNC_CREDENTIALS
),
85 sync_credential_was_filtered_(false) {
86 ContentPasswordManagerDriverFactory::CreateForWebContents(web_contents
, this,
89 ContentPasswordManagerDriverFactory::FromWebContents(web_contents
);
91 PasswordManagerInternalsService
* service
=
92 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_
);
94 can_use_log_router_
= service
->RegisterClient(this);
95 SetUpAutofillSyncState();
98 ChromePasswordManagerClient::~ChromePasswordManagerClient() {
99 PasswordManagerInternalsService
* service
=
100 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_
);
102 service
->UnregisterClient(this);
105 bool ChromePasswordManagerClient::IsAutomaticPasswordSavingEnabled() const {
106 return base::CommandLine::ForCurrentProcess()->HasSwitch(
107 password_manager::switches::kEnableAutomaticPasswordSaving
) &&
108 chrome::VersionInfo::GetChannel() ==
109 chrome::VersionInfo::CHANNEL_UNKNOWN
;
112 bool ChromePasswordManagerClient::IsPasswordManagerEnabledForCurrentPage()
114 DCHECK(web_contents());
115 content::NavigationEntry
* entry
=
116 web_contents()->GetController().GetLastCommittedEntry();
118 // TODO(gcasto): Determine if fix for crbug.com/388246 is relevant here.
122 // Disable the password manager for online password management.
123 if (IsURLPasswordWebsiteReauth(entry
->GetURL()))
126 if (EnabledForSyncSignin())
129 // Do not fill nor save password when a user is signing in for sync. This
130 // is because users need to remember their password if they are syncing as
131 // this is effectively their master password.
132 return entry
->GetURL().host() != chrome::kChromeUIChromeSigninHost
;
135 bool ChromePasswordManagerClient::ShouldFilterAutofillResult(
136 const autofill::PasswordForm
& form
) {
137 if (!IsSyncAccountCredential(base::UTF16ToUTF8(form
.username_value
),
141 if (autofill_sync_state_
== DISALLOW_SYNC_CREDENTIALS
) {
142 sync_credential_was_filtered_
= true;
146 if (autofill_sync_state_
== DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH
&&
147 LastLoadWasTransactionalReauthPage()) {
148 sync_credential_was_filtered_
= true;
155 std::string
ChromePasswordManagerClient::GetSyncUsername() const {
156 return password_manager_sync_metrics::GetSyncUsername(profile_
);
159 bool ChromePasswordManagerClient::IsSyncAccountCredential(
160 const std::string
& username
, const std::string
& origin
) const {
161 return password_manager_sync_metrics::IsSyncAccountCredential(
162 profile_
, username
, origin
);
165 void ChromePasswordManagerClient::AutofillResultsComputed() {
166 UMA_HISTOGRAM_BOOLEAN("PasswordManager.SyncCredentialFiltered",
167 sync_credential_was_filtered_
);
168 sync_credential_was_filtered_
= false;
171 bool ChromePasswordManagerClient::PromptUserToSavePassword(
172 scoped_ptr
<password_manager::PasswordFormManager
> form_to_save
,
173 password_manager::CredentialSourceType type
) {
174 // Save password infobar and the password bubble prompts in case of
175 // "webby" URLs and do not prompt in case of "non-webby" URLS (e.g. file://).
176 if (!BrowsingDataHelper::IsWebScheme(
177 web_contents()->GetLastCommittedURL().scheme())) {
181 if (IsTheHotNewBubbleUIEnabled()) {
182 ManagePasswordsUIController
* manage_passwords_ui_controller
=
183 ManagePasswordsUIController::FromWebContents(web_contents());
184 manage_passwords_ui_controller
->OnPasswordSubmitted(form_to_save
.Pass());
186 // TODO(melandory): If type is CREDENTIAL_SOURCE_API then new bubble should
188 std::string
uma_histogram_suffix(
189 password_manager::metrics_util::GroupIdToString(
190 password_manager::metrics_util::MonitoredDomainGroupId(
191 form_to_save
->realm(), GetPrefs())));
192 SavePasswordInfoBarDelegate::Create(
193 web_contents(), form_to_save
.Pass(), uma_histogram_suffix
, type
);
198 bool ChromePasswordManagerClient::PromptUserToChooseCredentials(
199 ScopedVector
<autofill::PasswordForm
> local_forms
,
200 ScopedVector
<autofill::PasswordForm
> federated_forms
,
202 base::Callback
<void(const password_manager::CredentialInfo
&)> callback
) {
203 return ManagePasswordsUIController::FromWebContents(web_contents())->
204 OnChooseCredentials(local_forms
.Pass(), federated_forms
.Pass(), origin
,
208 void ChromePasswordManagerClient::NotifyUserAutoSignin(
209 ScopedVector
<autofill::PasswordForm
> local_forms
) {
210 DCHECK(!local_forms
.empty());
211 ManagePasswordsUIController::FromWebContents(web_contents())->
212 OnAutoSignin(local_forms
.Pass());
215 void ChromePasswordManagerClient::AutomaticPasswordSave(
216 scoped_ptr
<password_manager::PasswordFormManager
> saved_form
) {
217 #if defined(OS_ANDROID)
218 GeneratedPasswordSavedInfoBarDelegateAndroid::Create(web_contents());
220 if (IsTheHotNewBubbleUIEnabled()) {
221 ManagePasswordsUIController
* manage_passwords_ui_controller
=
222 ManagePasswordsUIController::FromWebContents(web_contents());
223 manage_passwords_ui_controller
->OnAutomaticPasswordSave(
229 void ChromePasswordManagerClient::PasswordWasAutofilled(
230 const autofill::PasswordFormMap
& best_matches
) const {
231 ManagePasswordsUIController
* manage_passwords_ui_controller
=
232 ManagePasswordsUIController::FromWebContents(web_contents());
233 if (manage_passwords_ui_controller
&& IsTheHotNewBubbleUIEnabled())
234 manage_passwords_ui_controller
->OnPasswordAutofilled(best_matches
);
237 void ChromePasswordManagerClient::PasswordAutofillWasBlocked(
238 const autofill::PasswordFormMap
& best_matches
) const {
239 ManagePasswordsUIController
* controller
=
240 ManagePasswordsUIController::FromWebContents(web_contents());
241 if (controller
&& IsTheHotNewBubbleUIEnabled())
242 controller
->OnBlacklistBlockedAutofill(best_matches
);
245 void ChromePasswordManagerClient::HidePasswordGenerationPopup() {
246 if (popup_controller_
)
247 popup_controller_
->HideAndDestroy();
250 PrefService
* ChromePasswordManagerClient::GetPrefs() {
251 return profile_
->GetPrefs();
254 password_manager::PasswordStore
*
255 ChromePasswordManagerClient::GetPasswordStore() const {
256 // Always use EXPLICIT_ACCESS as the password manager checks IsOffTheRecord
257 // itself when it shouldn't access the PasswordStore.
258 // TODO(gcasto): Is is safe to change this to
259 // ServiceAccessType::IMPLICIT_ACCESS?
260 return PasswordStoreFactory::GetForProfile(
261 profile_
, ServiceAccessType::EXPLICIT_ACCESS
).get();
264 bool ChromePasswordManagerClient::IsPasswordSyncEnabled(
265 password_manager::CustomPassphraseState state
) const {
266 ProfileSyncService
* sync_service
=
267 ProfileSyncServiceFactory::GetForProfile(profile_
);
268 if (sync_service
&& sync_service
->HasSyncSetupCompleted() &&
269 sync_service
->SyncActive() &&
270 sync_service
->GetActiveDataTypes().Has(syncer::PASSWORDS
)) {
271 if (sync_service
->IsUsingSecondaryPassphrase()) {
272 return state
== password_manager::ONLY_CUSTOM_PASSPHRASE
;
274 return state
== password_manager::WITHOUT_CUSTOM_PASSPHRASE
;
280 void ChromePasswordManagerClient::OnLogRouterAvailabilityChanged(
281 bool router_can_be_used
) {
282 if (can_use_log_router_
== router_can_be_used
)
284 can_use_log_router_
= router_can_be_used
;
286 NotifyRendererOfLoggingAvailability();
289 void ChromePasswordManagerClient::LogSavePasswordProgress(
290 const std::string
& text
) const {
291 if (!IsLoggingActive())
293 PasswordManagerInternalsService
* service
=
294 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_
);
296 service
->ProcessLog(text
);
299 bool ChromePasswordManagerClient::IsLoggingActive() const {
300 // WebUI tabs do not need to log password saving progress. In particular, the
301 // internals page itself should not send any logs.
302 return can_use_log_router_
&& !web_contents()->GetWebUI();
305 bool ChromePasswordManagerClient::WasLastNavigationHTTPError() const {
306 DCHECK(web_contents());
308 scoped_ptr
<password_manager::BrowserSavePasswordProgressLogger
> logger
;
309 if (IsLoggingActive()) {
310 logger
.reset(new password_manager::BrowserSavePasswordProgressLogger(this));
312 Logger::STRING_WAS_LAST_NAVIGATION_HTTP_ERROR_METHOD
);
315 content::NavigationEntry
* entry
=
316 web_contents()->GetController().GetVisibleEntry();
319 int http_status_code
= entry
->GetHttpStatusCode();
322 logger
->LogNumber(Logger::STRING_HTTP_STATUS_CODE
, http_status_code
);
324 if (http_status_code
>= 400 && http_status_code
< 600)
329 bool ChromePasswordManagerClient::DidLastPageLoadEncounterSSLErrors() const {
330 content::NavigationEntry
* entry
=
331 web_contents()->GetController().GetLastCommittedEntry();
335 return net::IsCertStatusError(entry
->GetSSL().cert_status
);
338 bool ChromePasswordManagerClient::IsOffTheRecord() const {
339 return web_contents()->GetBrowserContext()->IsOffTheRecord();
342 password_manager::PasswordManager
*
343 ChromePasswordManagerClient::GetPasswordManager() {
344 return &password_manager_
;
347 autofill::AutofillManager
*
348 ChromePasswordManagerClient::GetAutofillManagerForMainFrame() {
349 autofill::ContentAutofillDriverFactory
* factory
=
350 autofill::ContentAutofillDriverFactory::FromWebContents(web_contents());
352 ? factory
->DriverForFrame(web_contents()->GetMainFrame())
357 void ChromePasswordManagerClient::SetTestObserver(
358 autofill::PasswordGenerationPopupObserver
* observer
) {
359 observer_
= observer
;
362 bool ChromePasswordManagerClient::OnMessageReceived(
363 const IPC::Message
& message
,
364 content::RenderFrameHost
* render_frame_host
) {
366 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(ChromePasswordManagerClient
, message
,
368 // Autofill messages:
369 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordGenerationPopup
,
370 ShowPasswordGenerationPopup
)
371 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordEditingPopup
,
372 ShowPasswordEditingPopup
)
373 IPC_END_MESSAGE_MAP()
375 IPC_BEGIN_MESSAGE_MAP(ChromePasswordManagerClient
, message
)
376 IPC_MESSAGE_HANDLER(AutofillHostMsg_HidePasswordGenerationPopup
,
377 HidePasswordGenerationPopup
)
378 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordAutofillAgentConstructed
,
379 NotifyRendererOfLoggingAvailability
)
381 IPC_MESSAGE_UNHANDLED(handled
= false)
382 IPC_END_MESSAGE_MAP()
387 gfx::RectF
ChromePasswordManagerClient::GetBoundsInScreenSpace(
388 const gfx::RectF
& bounds
) {
389 gfx::Rect client_area
= web_contents()->GetContainerBounds();
390 return bounds
+ client_area
.OffsetFromOrigin();
393 void ChromePasswordManagerClient::ShowPasswordGenerationPopup(
394 content::RenderFrameHost
* render_frame_host
,
395 const gfx::RectF
& bounds
,
397 const autofill::PasswordForm
& form
) {
398 // TODO(gcasto): Validate data in PasswordForm.
400 gfx::RectF element_bounds_in_screen_space
= GetBoundsInScreenSpace(bounds
);
403 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate(
404 popup_controller_
, element_bounds_in_screen_space
, form
, max_length
,
406 driver_factory_
->GetDriverForFrame(render_frame_host
), observer_
,
407 web_contents(), web_contents()->GetNativeView());
408 popup_controller_
->Show(true /* display_password */);
411 void ChromePasswordManagerClient::ShowPasswordEditingPopup(
412 content::RenderFrameHost
* render_frame_host
,
413 const gfx::RectF
& bounds
,
414 const autofill::PasswordForm
& form
) {
415 gfx::RectF element_bounds_in_screen_space
= GetBoundsInScreenSpace(bounds
);
417 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate(
418 popup_controller_
, element_bounds_in_screen_space
, form
,
419 0, // Unspecified max length.
421 driver_factory_
->GetDriverForFrame(render_frame_host
), observer_
,
422 web_contents(), web_contents()->GetNativeView());
423 popup_controller_
->Show(false /* display_password */);
426 void ChromePasswordManagerClient::NotifyRendererOfLoggingAvailability() {
430 web_contents()->GetRenderViewHost()->Send(new AutofillMsg_SetLoggingState(
431 web_contents()->GetRenderViewHost()->GetRoutingID(),
432 can_use_log_router_
));
435 bool ChromePasswordManagerClient::LastLoadWasTransactionalReauthPage() const {
436 DCHECK(web_contents());
437 content::NavigationEntry
* entry
=
438 web_contents()->GetController().GetLastCommittedEntry();
442 if (entry
->GetURL().GetOrigin() !=
443 GaiaUrls::GetInstance()->gaia_url().GetOrigin())
446 // "rart" is the transactional reauth paramter.
447 std::string ignored_value
;
448 return net::GetValueForKeyInQuery(entry
->GetURL(),
453 bool ChromePasswordManagerClient::IsURLPasswordWebsiteReauth(
454 const GURL
& url
) const {
455 if (url
.GetOrigin() != GaiaUrls::GetInstance()->gaia_url().GetOrigin())
458 // "rart" param signals this page is for transactional reauth.
459 std::string param_value
;
460 if (!net::GetValueForKeyInQuery(url
, "rart", ¶m_value
))
463 // Check the "continue" param to see if this reauth page is for the passwords
466 if (!net::GetValueForKeyInQuery(url
, "continue", ¶m_value
))
469 // All password sites, including test sites, have autofilling disabled.
470 CR_DEFINE_STATIC_LOCAL(RE2
, account_dashboard_pattern
,
471 ("passwords(-([a-z-]+\\.corp))?\\.google\\.com"));
473 return RE2::FullMatch(GURL(param_value
).host(), account_dashboard_pattern
);
476 bool ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled() {
477 #if !defined(USE_AURA) && !defined(OS_MACOSX)
480 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
481 if (command_line
->HasSwitch(switches::kDisableSavePasswordBubble
))
484 if (command_line
->HasSwitch(switches::kEnableSavePasswordBubble
))
487 std::string group_name
=
488 base::FieldTrialList::FindFullName("PasswordManagerUI");
490 // The bubble should be the default case that runs on the bots.
491 return group_name
!= "Infobar";
494 bool ChromePasswordManagerClient::EnabledForSyncSignin() {
495 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
496 if (command_line
->HasSwitch(
497 password_manager::switches::kDisableManagerForSyncSignin
))
500 if (command_line
->HasSwitch(
501 password_manager::switches::kEnableManagerForSyncSignin
))
504 // Default is enabled.
505 std::string group_name
=
506 base::FieldTrialList::FindFullName("PasswordManagerStateForSyncSignin");
507 return group_name
!= "Disabled";
510 void ChromePasswordManagerClient::SetUpAutofillSyncState() {
511 std::string group_name
=
512 base::FieldTrialList::FindFullName("AutofillSyncCredential");
514 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
515 if (command_line
->HasSwitch(
516 password_manager::switches::kAllowAutofillSyncCredential
)) {
517 autofill_sync_state_
= ALLOW_SYNC_CREDENTIALS
;
520 if (command_line
->HasSwitch(
521 password_manager::switches::
522 kDisallowAutofillSyncCredentialForReauth
)) {
523 autofill_sync_state_
= DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH
;
526 if (command_line
->HasSwitch(
527 password_manager::switches::kDisallowAutofillSyncCredential
)) {
528 autofill_sync_state_
= DISALLOW_SYNC_CREDENTIALS
;
532 if (group_name
== "DisallowSyncCredentialsForReauth") {
533 autofill_sync_state_
= DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH
;
534 } else if (group_name
== "DisallowSyncCredentials") {
535 autofill_sync_state_
= DISALLOW_SYNC_CREDENTIALS
;
538 autofill_sync_state_
= ALLOW_SYNC_CREDENTIALS
;
542 const GURL
& ChromePasswordManagerClient::GetMainFrameURL() const {
543 return web_contents()->GetVisibleURL();