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/common/autofill_messages.h"
27 #include "components/autofill/core/browser/password_generator.h"
28 #include "components/autofill/core/common/password_form.h"
29 #include "components/password_manager/content/browser/password_manager_internals_service_factory.h"
30 #include "components/password_manager/content/common/credential_manager_messages.h"
31 #include "components/password_manager/content/common/credential_manager_types.h"
32 #include "components/password_manager/core/browser/log_receiver.h"
33 #include "components/password_manager/core/browser/password_form_manager.h"
34 #include "components/password_manager/core/browser/password_manager.h"
35 #include "components/password_manager/core/browser/password_manager_internals_service.h"
36 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
37 #include "components/password_manager/core/common/password_manager_switches.h"
38 #include "content/public/browser/navigation_entry.h"
39 #include "content/public/browser/render_view_host.h"
40 #include "content/public/browser/web_contents.h"
41 #include "google_apis/gaia/gaia_urls.h"
42 #include "net/base/url_util.h"
43 #include "third_party/re2/re2/re2.h"
45 #if defined(OS_ANDROID)
46 #include "chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h"
49 using password_manager::PasswordManagerInternalsService;
50 using password_manager::PasswordManagerInternalsServiceFactory;
52 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromePasswordManagerClient);
55 void ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
56 content::WebContents* contents,
57 autofill::AutofillClient* autofill_client) {
58 if (FromWebContents(contents))
61 contents->SetUserData(
63 new ChromePasswordManagerClient(contents, autofill_client));
66 ChromePasswordManagerClient::ChromePasswordManagerClient(
67 content::WebContents* web_contents,
68 autofill::AutofillClient* autofill_client)
69 : content::WebContentsObserver(web_contents),
70 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
71 driver_(web_contents, this, autofill_client),
72 credential_manager_dispatcher_(web_contents, this),
74 can_use_log_router_(false),
75 autofill_sync_state_(ALLOW_SYNC_CREDENTIALS),
76 sync_credential_was_filtered_(false) {
77 PasswordManagerInternalsService* service =
78 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
80 can_use_log_router_ = service->RegisterClient(this);
81 SetUpAutofillSyncState();
84 ChromePasswordManagerClient::~ChromePasswordManagerClient() {
85 PasswordManagerInternalsService* service =
86 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
88 service->UnregisterClient(this);
91 bool ChromePasswordManagerClient::IsAutomaticPasswordSavingEnabled() const {
92 return CommandLine::ForCurrentProcess()->HasSwitch(
93 password_manager::switches::kEnableAutomaticPasswordSaving) &&
94 chrome::VersionInfo::GetChannel() ==
95 chrome::VersionInfo::CHANNEL_UNKNOWN;
98 bool ChromePasswordManagerClient::IsPasswordManagerEnabledForCurrentPage()
100 DCHECK(web_contents());
101 content::NavigationEntry* entry =
102 web_contents()->GetController().GetLastCommittedEntry();
104 // TODO(gcasto): Determine if fix for crbug.com/388246 is relevant here.
108 // Disable the password manager for online password management.
109 if (IsURLPasswordWebsiteReauth(entry->GetURL()))
112 if (EnabledForSyncSignin())
115 // Do not fill nor save password when a user is signing in for sync. This
116 // is because users need to remember their password if they are syncing as
117 // this is effectively their master password.
118 return entry->GetURL().host() != chrome::kChromeUIChromeSigninHost;
121 bool ChromePasswordManagerClient::ShouldFilterAutofillResult(
122 const autofill::PasswordForm& form) {
123 if (!IsSyncAccountCredential(base::UTF16ToUTF8(form.username_value),
127 if (autofill_sync_state_ == DISALLOW_SYNC_CREDENTIALS) {
128 sync_credential_was_filtered_ = true;
132 if (autofill_sync_state_ == DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH &&
133 LastLoadWasTransactionalReauthPage()) {
134 sync_credential_was_filtered_ = true;
141 std::string ChromePasswordManagerClient::GetSyncUsername() const {
142 return password_manager_sync_metrics::GetSyncUsername(profile_);
145 bool ChromePasswordManagerClient::IsSyncAccountCredential(
146 const std::string& username, const std::string& origin) const {
147 return password_manager_sync_metrics::IsSyncAccountCredential(
148 profile_, username, origin);
151 void ChromePasswordManagerClient::AutofillResultsComputed() {
152 UMA_HISTOGRAM_BOOLEAN("PasswordManager.SyncCredentialFiltered",
153 sync_credential_was_filtered_);
154 sync_credential_was_filtered_ = false;
157 bool ChromePasswordManagerClient::PromptUserToSavePassword(
158 scoped_ptr<password_manager::PasswordFormManager> form_to_save) {
159 // Save password infobar and the password bubble prompts in case of
160 // "webby" URLs and do not prompt in case of "non-webby" URLS (e.g. file://).
161 if (!BrowsingDataHelper::IsWebScheme(
162 web_contents()->GetLastCommittedURL().scheme())) {
166 if (IsTheHotNewBubbleUIEnabled()) {
167 ManagePasswordsUIController* manage_passwords_ui_controller =
168 ManagePasswordsUIController::FromWebContents(web_contents());
169 manage_passwords_ui_controller->OnPasswordSubmitted(form_to_save.Pass());
171 std::string uma_histogram_suffix(
172 password_manager::metrics_util::GroupIdToString(
173 password_manager::metrics_util::MonitoredDomainGroupId(
174 form_to_save->realm(), GetPrefs())));
175 SavePasswordInfoBarDelegate::Create(
176 web_contents(), form_to_save.Pass(), uma_histogram_suffix);
181 void ChromePasswordManagerClient::AutomaticPasswordSave(
182 scoped_ptr<password_manager::PasswordFormManager> saved_form) {
183 #if defined(OS_ANDROID)
184 GeneratedPasswordSavedInfoBarDelegateAndroid::Create(web_contents());
186 if (IsTheHotNewBubbleUIEnabled()) {
187 ManagePasswordsUIController* manage_passwords_ui_controller =
188 ManagePasswordsUIController::FromWebContents(web_contents());
189 manage_passwords_ui_controller->OnAutomaticPasswordSave(
195 void ChromePasswordManagerClient::PasswordWasAutofilled(
196 const autofill::PasswordFormMap& best_matches) const {
197 ManagePasswordsUIController* manage_passwords_ui_controller =
198 ManagePasswordsUIController::FromWebContents(web_contents());
199 if (manage_passwords_ui_controller && IsTheHotNewBubbleUIEnabled())
200 manage_passwords_ui_controller->OnPasswordAutofilled(best_matches);
203 void ChromePasswordManagerClient::PasswordAutofillWasBlocked(
204 const autofill::PasswordFormMap& best_matches) const {
205 ManagePasswordsUIController* controller =
206 ManagePasswordsUIController::FromWebContents(web_contents());
207 if (controller && IsTheHotNewBubbleUIEnabled())
208 controller->OnBlacklistBlockedAutofill(best_matches);
211 void ChromePasswordManagerClient::HidePasswordGenerationPopup() {
212 if (popup_controller_)
213 popup_controller_->HideAndDestroy();
216 PrefService* ChromePasswordManagerClient::GetPrefs() {
217 return profile_->GetPrefs();
220 password_manager::PasswordStore*
221 ChromePasswordManagerClient::GetPasswordStore() {
222 // Always use EXPLICIT_ACCESS as the password manager checks IsOffTheRecord
223 // itself when it shouldn't access the PasswordStore.
224 // TODO(gcasto): Is is safe to change this to Profile::IMPLICIT_ACCESS?
225 return PasswordStoreFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS)
229 password_manager::PasswordManagerDriver*
230 ChromePasswordManagerClient::GetDriver() {
234 base::FieldTrial::Probability
235 ChromePasswordManagerClient::GetProbabilityForExperiment(
236 const std::string& experiment_name) {
237 base::FieldTrial::Probability enabled_probability = 0;
238 if (experiment_name ==
239 password_manager::PasswordManager::kOtherPossibleUsernamesExperiment) {
240 switch (chrome::VersionInfo::GetChannel()) {
241 case chrome::VersionInfo::CHANNEL_DEV:
242 case chrome::VersionInfo::CHANNEL_BETA:
243 enabled_probability = 50;
249 return enabled_probability;
252 bool ChromePasswordManagerClient::IsPasswordSyncEnabled(
253 password_manager::CustomPassphraseState state) {
254 ProfileSyncService* sync_service =
255 ProfileSyncServiceFactory::GetForProfile(profile_);
256 if (sync_service && sync_service->HasSyncSetupCompleted() &&
257 sync_service->SyncActive() &&
258 sync_service->GetActiveDataTypes().Has(syncer::PASSWORDS)) {
259 if (sync_service->IsUsingSecondaryPassphrase()) {
260 return state == password_manager::ONLY_CUSTOM_PASSPHRASE;
262 return state == password_manager::WITHOUT_CUSTOM_PASSPHRASE;
268 void ChromePasswordManagerClient::OnLogRouterAvailabilityChanged(
269 bool router_can_be_used) {
270 if (can_use_log_router_ == router_can_be_used)
272 can_use_log_router_ = router_can_be_used;
274 NotifyRendererOfLoggingAvailability();
277 void ChromePasswordManagerClient::LogSavePasswordProgress(
278 const std::string& text) {
279 if (!IsLoggingActive())
281 PasswordManagerInternalsService* service =
282 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
284 service->ProcessLog(text);
287 bool ChromePasswordManagerClient::IsLoggingActive() const {
288 // WebUI tabs do not need to log password saving progress. In particular, the
289 // internals page itself should not send any logs.
290 return can_use_log_router_ && !web_contents()->GetWebUI();
294 password_manager::PasswordGenerationManager*
295 ChromePasswordManagerClient::GetGenerationManagerFromWebContents(
296 content::WebContents* contents) {
297 ChromePasswordManagerClient* client =
298 ChromePasswordManagerClient::FromWebContents(contents);
301 return client->GetDriver()->GetPasswordGenerationManager();
305 password_manager::PasswordManager*
306 ChromePasswordManagerClient::GetManagerFromWebContents(
307 content::WebContents* contents) {
308 ChromePasswordManagerClient* client =
309 ChromePasswordManagerClient::FromWebContents(contents);
312 return client->GetDriver()->GetPasswordManager();
315 void ChromePasswordManagerClient::SetTestObserver(
316 autofill::PasswordGenerationPopupObserver* observer) {
317 observer_ = observer;
320 bool ChromePasswordManagerClient::OnMessageReceived(
321 const IPC::Message& message) {
323 IPC_BEGIN_MESSAGE_MAP(ChromePasswordManagerClient, message)
324 // Autofill messages:
325 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordGenerationPopup,
326 ShowPasswordGenerationPopup)
327 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordEditingPopup,
328 ShowPasswordEditingPopup)
329 IPC_MESSAGE_HANDLER(AutofillHostMsg_HidePasswordGenerationPopup,
330 HidePasswordGenerationPopup)
331 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordAutofillAgentConstructed,
332 NotifyRendererOfLoggingAvailability)
335 IPC_MESSAGE_UNHANDLED(handled = false)
336 IPC_END_MESSAGE_MAP()
340 gfx::RectF ChromePasswordManagerClient::GetBoundsInScreenSpace(
341 const gfx::RectF& bounds) {
342 gfx::Rect client_area = web_contents()->GetContainerBounds();
343 return bounds + client_area.OffsetFromOrigin();
346 void ChromePasswordManagerClient::ShowPasswordGenerationPopup(
347 const gfx::RectF& bounds,
349 const autofill::PasswordForm& form) {
350 // TODO(gcasto): Validate data in PasswordForm.
352 gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds);
355 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate(
357 element_bounds_in_screen_space,
360 driver_.GetPasswordManager(),
363 web_contents()->GetNativeView());
364 popup_controller_->Show(true /* display_password */);
367 void ChromePasswordManagerClient::ShowPasswordEditingPopup(
368 const gfx::RectF& bounds,
369 const autofill::PasswordForm& form) {
370 gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds);
372 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate(
374 element_bounds_in_screen_space,
376 0, // Unspecified max length.
377 driver_.GetPasswordManager(),
380 web_contents()->GetNativeView());
381 popup_controller_->Show(false /* display_password */);
384 void ChromePasswordManagerClient::NotifyRendererOfLoggingAvailability() {
388 web_contents()->GetRenderViewHost()->Send(new AutofillMsg_SetLoggingState(
389 web_contents()->GetRenderViewHost()->GetRoutingID(),
390 can_use_log_router_));
393 bool ChromePasswordManagerClient::LastLoadWasTransactionalReauthPage() const {
394 DCHECK(web_contents());
395 content::NavigationEntry* entry =
396 web_contents()->GetController().GetLastCommittedEntry();
400 if (entry->GetURL().GetOrigin() !=
401 GaiaUrls::GetInstance()->gaia_url().GetOrigin())
404 // "rart" is the transactional reauth paramter.
405 std::string ignored_value;
406 return net::GetValueForKeyInQuery(entry->GetURL(),
411 bool ChromePasswordManagerClient::IsURLPasswordWebsiteReauth(
412 const GURL& url) const {
413 if (url.GetOrigin() != GaiaUrls::GetInstance()->gaia_url().GetOrigin())
416 // "rart" param signals this page is for transactional reauth.
417 std::string param_value;
418 if (!net::GetValueForKeyInQuery(url, "rart", ¶m_value))
421 // Check the "continue" param to see if this reauth page is for the passwords
424 if (!net::GetValueForKeyInQuery(url, "continue", ¶m_value))
427 // All password sites, including test sites, have autofilling disabled.
428 CR_DEFINE_STATIC_LOCAL(RE2, account_dashboard_pattern,
429 ("passwords(-([a-z-]+\\.corp))?\\.google\\.com"));
431 return RE2::FullMatch(GURL(param_value).host(), account_dashboard_pattern);
434 bool ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled() {
435 #if !defined(USE_AURA) && !defined(OS_MACOSX)
438 CommandLine* command_line = CommandLine::ForCurrentProcess();
439 if (command_line->HasSwitch(switches::kDisableSavePasswordBubble))
442 if (command_line->HasSwitch(switches::kEnableSavePasswordBubble))
445 std::string group_name =
446 base::FieldTrialList::FindFullName("PasswordManagerUI");
448 // The bubble should be the default case that runs on the bots.
449 return group_name != "Infobar";
452 bool ChromePasswordManagerClient::EnabledForSyncSignin() {
453 CommandLine* command_line = CommandLine::ForCurrentProcess();
454 if (command_line->HasSwitch(
455 password_manager::switches::kDisableManagerForSyncSignin))
458 if (command_line->HasSwitch(
459 password_manager::switches::kEnableManagerForSyncSignin))
462 // Default is enabled.
463 std::string group_name =
464 base::FieldTrialList::FindFullName("PasswordManagerStateForSyncSignin");
465 return group_name != "Disabled";
468 void ChromePasswordManagerClient::SetUpAutofillSyncState() {
469 std::string group_name =
470 base::FieldTrialList::FindFullName("AutofillSyncCredential");
472 CommandLine* command_line = CommandLine::ForCurrentProcess();
473 if (command_line->HasSwitch(
474 password_manager::switches::kAllowAutofillSyncCredential)) {
475 autofill_sync_state_ = ALLOW_SYNC_CREDENTIALS;
478 if (command_line->HasSwitch(
479 password_manager::switches::
480 kDisallowAutofillSyncCredentialForReauth)) {
481 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH;
484 if (command_line->HasSwitch(
485 password_manager::switches::kDisallowAutofillSyncCredential)) {
486 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS;
490 if (group_name == "DisallowSyncCredentialsForReauth") {
491 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH;
492 } else if (group_name == "DisallowSyncCredentials") {
493 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS;
496 autofill_sync_state_ = ALLOW_SYNC_CREDENTIALS;