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. 4 5 #include "chrome/browser/password_manager/chrome_password_manager_client.h" 6 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" 44 45 #if defined(OS_ANDROID) 46 #include "chrome/browser/android/password_authentication_manager.h" 47 #endif // OS_ANDROID 48 49 using password_manager::PasswordManagerInternalsService; 50 using password_manager::PasswordManagerInternalsServiceFactory; 51 52 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromePasswordManagerClient); 53 54 // static 55 void ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient( 56 content::WebContents* contents, 57 autofill::AutofillClient* autofill_client) { 58 if (FromWebContents(contents)) 59 return; 60 61 contents->SetUserData( 62 UserDataKey(), 63 new ChromePasswordManagerClient(contents, autofill_client)); 64 } 65 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 observer_(NULL), 73 can_use_log_router_(false), 74 autofill_sync_state_(ALLOW_SYNC_CREDENTIALS), 75 sync_credential_was_filtered_(false), 76 weak_factory_(this) { 77 PasswordManagerInternalsService* service = 78 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_); 79 if (service) 80 can_use_log_router_ = service->RegisterClient(this); 81 SetUpAutofillSyncState(); 82 } 83 84 ChromePasswordManagerClient::~ChromePasswordManagerClient() { 85 PasswordManagerInternalsService* service = 86 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_); 87 if (service) 88 service->UnregisterClient(this); 89 } 90 91 bool ChromePasswordManagerClient::IsAutomaticPasswordSavingEnabled() const { 92 return CommandLine::ForCurrentProcess()->HasSwitch( 93 password_manager::switches::kEnableAutomaticPasswordSaving) && 94 chrome::VersionInfo::GetChannel() == 95 chrome::VersionInfo::CHANNEL_UNKNOWN; 96 } 97 98 bool ChromePasswordManagerClient::IsPasswordManagerEnabledForCurrentPage() 99 const { 100 DCHECK(web_contents()); 101 content::NavigationEntry* entry = 102 web_contents()->GetController().GetLastCommittedEntry(); 103 if (!entry) { 104 // TODO(gcasto): Determine if fix for crbug.com/388246 is relevant here. 105 return true; 106 } 107 108 // Disable the password manager for online password management. 109 if (IsURLPasswordWebsiteReauth(entry->GetURL())) 110 return false; 111 112 if (EnabledForSyncSignin()) 113 return true; 114 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; 119 } 120 121 bool ChromePasswordManagerClient::ShouldFilterAutofillResult( 122 const autofill::PasswordForm& form) { 123 if (!IsSyncAccountCredential(base::UTF16ToUTF8(form.username_value), 124 form.signon_realm)) 125 return false; 126 127 if (autofill_sync_state_ == DISALLOW_SYNC_CREDENTIALS) { 128 sync_credential_was_filtered_ = true; 129 return true; 130 } 131 132 if (autofill_sync_state_ == DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH && 133 LastLoadWasTransactionalReauthPage()) { 134 sync_credential_was_filtered_ = true; 135 return true; 136 } 137 138 return false; 139 } 140 141 bool ChromePasswordManagerClient::IsSyncAccountCredential( 142 const std::string& username, const std::string& origin) const { 143 return password_manager_sync_metrics::IsSyncAccountCredential( 144 profile_, username, origin); 145 } 146 147 void ChromePasswordManagerClient::AutofillResultsComputed() { 148 UMA_HISTOGRAM_BOOLEAN("PasswordManager.SyncCredentialFiltered", 149 sync_credential_was_filtered_); 150 sync_credential_was_filtered_ = false; 151 } 152 153 bool ChromePasswordManagerClient::PromptUserToSavePassword( 154 scoped_ptr<password_manager::PasswordFormManager> form_to_save) { 155 // Save password infobar and the password bubble prompts in case of 156 // "webby" URLs and do not prompt in case of "non-webby" URLS (e.g. file://). 157 if (!BrowsingDataHelper::IsWebScheme( 158 web_contents()->GetLastCommittedURL().scheme())) { 159 return false; 160 } 161 162 if (IsTheHotNewBubbleUIEnabled()) { 163 ManagePasswordsUIController* manage_passwords_ui_controller = 164 ManagePasswordsUIController::FromWebContents(web_contents()); 165 manage_passwords_ui_controller->OnPasswordSubmitted(form_to_save.Pass()); 166 } else { 167 std::string uma_histogram_suffix( 168 password_manager::metrics_util::GroupIdToString( 169 password_manager::metrics_util::MonitoredDomainGroupId( 170 form_to_save->realm(), GetPrefs()))); 171 SavePasswordInfoBarDelegate::Create( 172 web_contents(), form_to_save.Pass(), uma_histogram_suffix); 173 } 174 return true; 175 } 176 177 void ChromePasswordManagerClient::AutomaticPasswordSave( 178 scoped_ptr<password_manager::PasswordFormManager> saved_form) { 179 if (IsTheHotNewBubbleUIEnabled()) { 180 ManagePasswordsUIController* manage_passwords_ui_controller = 181 ManagePasswordsUIController::FromWebContents(web_contents()); 182 manage_passwords_ui_controller->OnAutomaticPasswordSave( 183 saved_form.Pass()); 184 } 185 } 186 187 void ChromePasswordManagerClient::PasswordWasAutofilled( 188 const autofill::PasswordFormMap& best_matches) const { 189 ManagePasswordsUIController* manage_passwords_ui_controller = 190 ManagePasswordsUIController::FromWebContents(web_contents()); 191 if (manage_passwords_ui_controller && IsTheHotNewBubbleUIEnabled()) 192 manage_passwords_ui_controller->OnPasswordAutofilled(best_matches); 193 } 194 195 void ChromePasswordManagerClient::PasswordAutofillWasBlocked( 196 const autofill::PasswordFormMap& best_matches) const { 197 ManagePasswordsUIController* controller = 198 ManagePasswordsUIController::FromWebContents(web_contents()); 199 if (controller && IsTheHotNewBubbleUIEnabled()) 200 controller->OnBlacklistBlockedAutofill(best_matches); 201 } 202 203 void ChromePasswordManagerClient::AuthenticateAutofillAndFillForm( 204 scoped_ptr<autofill::PasswordFormFillData> fill_data) { 205 #if defined(OS_ANDROID) 206 PasswordAuthenticationManager::AuthenticatePasswordAutofill( 207 web_contents(), 208 base::Bind(&ChromePasswordManagerClient::CommitFillPasswordForm, 209 weak_factory_.GetWeakPtr(), 210 base::Owned(fill_data.release()))); 211 #else 212 // Additional authentication is currently only available for Android, so all 213 // other plaftorms should just fill the password form directly. 214 CommitFillPasswordForm(fill_data.get()); 215 #endif // OS_ANDROID 216 } 217 218 void ChromePasswordManagerClient::HidePasswordGenerationPopup() { 219 if (popup_controller_) 220 popup_controller_->HideAndDestroy(); 221 } 222 223 PrefService* ChromePasswordManagerClient::GetPrefs() { 224 return profile_->GetPrefs(); 225 } 226 227 password_manager::PasswordStore* 228 ChromePasswordManagerClient::GetPasswordStore() { 229 // Always use EXPLICIT_ACCESS as the password manager checks IsOffTheRecord 230 // itself when it shouldn't access the PasswordStore. 231 // TODO(gcasto): Is is safe to change this to Profile::IMPLICIT_ACCESS? 232 return PasswordStoreFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS) 233 .get(); 234 } 235 236 password_manager::PasswordManagerDriver* 237 ChromePasswordManagerClient::GetDriver() { 238 return &driver_; 239 } 240 241 base::FieldTrial::Probability 242 ChromePasswordManagerClient::GetProbabilityForExperiment( 243 const std::string& experiment_name) { 244 base::FieldTrial::Probability enabled_probability = 0; 245 if (experiment_name == 246 password_manager::PasswordManager::kOtherPossibleUsernamesExperiment) { 247 switch (chrome::VersionInfo::GetChannel()) { 248 case chrome::VersionInfo::CHANNEL_DEV: 249 case chrome::VersionInfo::CHANNEL_BETA: 250 enabled_probability = 50; 251 break; 252 default: 253 break; 254 } 255 } 256 return enabled_probability; 257 } 258 259 bool ChromePasswordManagerClient::IsPasswordSyncEnabled() { 260 ProfileSyncService* sync_service = 261 ProfileSyncServiceFactory::GetForProfile(profile_); 262 // Don't consider sync enabled if the user has a custom passphrase. See 263 // crbug.com/358998 for more details. 264 if (sync_service && 265 sync_service->HasSyncSetupCompleted() && 266 sync_service->sync_initialized() && 267 !sync_service->IsUsingSecondaryPassphrase()) { 268 return sync_service->GetActiveDataTypes().Has(syncer::PASSWORDS); 269 } 270 return false; 271 } 272 273 void ChromePasswordManagerClient::OnLogRouterAvailabilityChanged( 274 bool router_can_be_used) { 275 if (can_use_log_router_ == router_can_be_used) 276 return; 277 can_use_log_router_ = router_can_be_used; 278 279 NotifyRendererOfLoggingAvailability(); 280 } 281 282 void ChromePasswordManagerClient::LogSavePasswordProgress( 283 const std::string& text) { 284 if (!IsLoggingActive()) 285 return; 286 PasswordManagerInternalsService* service = 287 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_); 288 if (service) 289 service->ProcessLog(text); 290 } 291 292 bool ChromePasswordManagerClient::IsLoggingActive() const { 293 // WebUI tabs do not need to log password saving progress. In particular, the 294 // internals page itself should not send any logs. 295 return can_use_log_router_ && !web_contents()->GetWebUI(); 296 } 297 298 void ChromePasswordManagerClient::OnNotifyFailedSignIn( 299 int request_id, 300 const password_manager::CredentialInfo&) { 301 // TODO(mkwst): This is a stub. 302 web_contents()->GetRenderViewHost()->Send( 303 new CredentialManagerMsg_AcknowledgeFailedSignIn( 304 web_contents()->GetRenderViewHost()->GetRoutingID(), request_id)); 305 } 306 307 void ChromePasswordManagerClient::OnNotifySignedIn( 308 int request_id, 309 const password_manager::CredentialInfo&) { 310 // TODO(mkwst): This is a stub. 311 web_contents()->GetRenderViewHost()->Send( 312 new CredentialManagerMsg_AcknowledgeSignedIn( 313 web_contents()->GetRenderViewHost()->GetRoutingID(), request_id)); 314 } 315 316 void ChromePasswordManagerClient::OnNotifySignedOut(int request_id) { 317 // TODO(mkwst): This is a stub. 318 web_contents()->GetRenderViewHost()->Send( 319 new CredentialManagerMsg_AcknowledgeSignedOut( 320 web_contents()->GetRenderViewHost()->GetRoutingID(), request_id)); 321 } 322 323 void ChromePasswordManagerClient::OnRequestCredential( 324 int request_id, 325 bool zero_click_only, 326 const std::vector<GURL>& federations) { 327 // TODO(mkwst): This is a stub. 328 password_manager::CredentialInfo info(base::ASCIIToUTF16("id"), 329 base::ASCIIToUTF16("name"), 330 GURL("https://example.com/image.png")); 331 web_contents()->GetRenderViewHost()->Send( 332 new CredentialManagerMsg_SendCredential( 333 web_contents()->GetRenderViewHost()->GetRoutingID(), 334 request_id, 335 info)); 336 } 337 338 // static 339 password_manager::PasswordGenerationManager* 340 ChromePasswordManagerClient::GetGenerationManagerFromWebContents( 341 content::WebContents* contents) { 342 ChromePasswordManagerClient* client = 343 ChromePasswordManagerClient::FromWebContents(contents); 344 if (!client) 345 return NULL; 346 return client->GetDriver()->GetPasswordGenerationManager(); 347 } 348 349 // static 350 password_manager::PasswordManager* 351 ChromePasswordManagerClient::GetManagerFromWebContents( 352 content::WebContents* contents) { 353 ChromePasswordManagerClient* client = 354 ChromePasswordManagerClient::FromWebContents(contents); 355 if (!client) 356 return NULL; 357 return client->GetDriver()->GetPasswordManager(); 358 } 359 360 void ChromePasswordManagerClient::SetTestObserver( 361 autofill::PasswordGenerationPopupObserver* observer) { 362 observer_ = observer; 363 } 364 365 bool ChromePasswordManagerClient::OnMessageReceived( 366 const IPC::Message& message) { 367 bool handled = true; 368 IPC_BEGIN_MESSAGE_MAP(ChromePasswordManagerClient, message) 369 // Autofill messages: 370 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordGenerationPopup, 371 ShowPasswordGenerationPopup) 372 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordEditingPopup, 373 ShowPasswordEditingPopup) 374 IPC_MESSAGE_HANDLER(AutofillHostMsg_HidePasswordGenerationPopup, 375 HidePasswordGenerationPopup) 376 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordAutofillAgentConstructed, 377 NotifyRendererOfLoggingAvailability) 378 379 // Credential Manager messages: 380 IPC_MESSAGE_HANDLER(CredentialManagerHostMsg_NotifyFailedSignIn, 381 OnNotifyFailedSignIn); 382 IPC_MESSAGE_HANDLER(CredentialManagerHostMsg_NotifySignedIn, 383 OnNotifySignedIn); 384 IPC_MESSAGE_HANDLER(CredentialManagerHostMsg_NotifySignedOut, 385 OnNotifySignedOut); 386 IPC_MESSAGE_HANDLER(CredentialManagerHostMsg_RequestCredential, 387 OnRequestCredential); 388 389 // Default: 390 IPC_MESSAGE_UNHANDLED(handled = false) 391 IPC_END_MESSAGE_MAP() 392 return handled; 393 } 394 395 gfx::RectF ChromePasswordManagerClient::GetBoundsInScreenSpace( 396 const gfx::RectF& bounds) { 397 gfx::Rect client_area = web_contents()->GetContainerBounds(); 398 return bounds + client_area.OffsetFromOrigin(); 399 } 400 401 void ChromePasswordManagerClient::ShowPasswordGenerationPopup( 402 const gfx::RectF& bounds, 403 int max_length, 404 const autofill::PasswordForm& form) { 405 // TODO(gcasto): Validate data in PasswordForm. 406 407 // Not yet implemented on other platforms. 408 #if defined(USE_AURA) || defined(OS_MACOSX) 409 gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds); 410 411 popup_controller_ = 412 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate( 413 popup_controller_, 414 element_bounds_in_screen_space, 415 form, 416 max_length, 417 driver_.GetPasswordManager(), 418 observer_, 419 web_contents(), 420 web_contents()->GetNativeView()); 421 popup_controller_->Show(true /* display_password */); 422 #endif // defined(USE_AURA) || defined(OS_MACOSX) 423 } 424 425 void ChromePasswordManagerClient::ShowPasswordEditingPopup( 426 const gfx::RectF& bounds, 427 const autofill::PasswordForm& form) { 428 gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds); 429 // Not yet implemented on other platforms. 430 #if defined(USE_AURA) || defined(OS_MACOSX) 431 popup_controller_ = 432 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate( 433 popup_controller_, 434 element_bounds_in_screen_space, 435 form, 436 0, // Unspecified max length. 437 driver_.GetPasswordManager(), 438 observer_, 439 web_contents(), 440 web_contents()->GetNativeView()); 441 popup_controller_->Show(false /* display_password */); 442 #endif // defined(USE_AURA) || defined(OS_MACOSX) 443 } 444 445 void ChromePasswordManagerClient::NotifyRendererOfLoggingAvailability() { 446 if (!web_contents()) 447 return; 448 449 web_contents()->GetRenderViewHost()->Send(new AutofillMsg_SetLoggingState( 450 web_contents()->GetRenderViewHost()->GetRoutingID(), 451 can_use_log_router_)); 452 } 453 454 void ChromePasswordManagerClient::CommitFillPasswordForm( 455 autofill::PasswordFormFillData* data) { 456 driver_.FillPasswordForm(*data); 457 } 458 459 bool ChromePasswordManagerClient::LastLoadWasTransactionalReauthPage() const { 460 DCHECK(web_contents()); 461 content::NavigationEntry* entry = 462 web_contents()->GetController().GetLastCommittedEntry(); 463 if (!entry) 464 return false; 465 466 if (entry->GetURL().GetOrigin() != 467 GaiaUrls::GetInstance()->gaia_url().GetOrigin()) 468 return false; 469 470 // "rart" is the transactional reauth paramter. 471 std::string ignored_value; 472 return net::GetValueForKeyInQuery(entry->GetURL(), 473 "rart", 474 &ignored_value); 475 } 476 477 bool ChromePasswordManagerClient::IsURLPasswordWebsiteReauth( 478 const GURL& url) const { 479 if (url.GetOrigin() != GaiaUrls::GetInstance()->gaia_url().GetOrigin()) 480 return false; 481 482 // "rart" param signals this page is for transactional reauth. 483 std::string param_value; 484 if (!net::GetValueForKeyInQuery(url, "rart", ¶m_value)) 485 return false; 486 487 // Check the "continue" param to see if this reauth page is for the passwords 488 // website. 489 param_value.clear(); 490 if (!net::GetValueForKeyInQuery(url, "continue", ¶m_value)) 491 return false; 492 493 // All password sites, including test sites, have autofilling disabled. 494 CR_DEFINE_STATIC_LOCAL(RE2, account_dashboard_pattern, 495 ("passwords(-([a-z-]+\\.corp))?\\.google\\.com")); 496 497 return RE2::FullMatch(GURL(param_value).host(), account_dashboard_pattern); 498 } 499 500 bool ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled() { 501 #if !defined(USE_AURA) && !defined(OS_MACOSX) 502 return false; 503 #endif 504 CommandLine* command_line = CommandLine::ForCurrentProcess(); 505 if (command_line->HasSwitch(switches::kDisableSavePasswordBubble)) 506 return false; 507 508 if (command_line->HasSwitch(switches::kEnableSavePasswordBubble)) 509 return true; 510 511 std::string group_name = 512 base::FieldTrialList::FindFullName("PasswordManagerUI"); 513 514 // The bubble should be the default case that runs on the bots. 515 return group_name != "Infobar"; 516 } 517 518 bool ChromePasswordManagerClient::EnabledForSyncSignin() { 519 CommandLine* command_line = CommandLine::ForCurrentProcess(); 520 if (command_line->HasSwitch( 521 password_manager::switches::kDisableManagerForSyncSignin)) 522 return false; 523 524 if (command_line->HasSwitch( 525 password_manager::switches::kEnableManagerForSyncSignin)) 526 return true; 527 528 // Default is enabled. 529 std::string group_name = 530 base::FieldTrialList::FindFullName("PasswordManagerStateForSyncSignin"); 531 return group_name != "Disabled"; 532 } 533 534 void ChromePasswordManagerClient::SetUpAutofillSyncState() { 535 std::string group_name = 536 base::FieldTrialList::FindFullName("AutofillSyncCredential"); 537 538 CommandLine* command_line = CommandLine::ForCurrentProcess(); 539 if (command_line->HasSwitch( 540 password_manager::switches::kAllowAutofillSyncCredential)) { 541 autofill_sync_state_ = ALLOW_SYNC_CREDENTIALS; 542 return; 543 } 544 if (command_line->HasSwitch( 545 password_manager::switches:: 546 kDisallowAutofillSyncCredentialForReauth)) { 547 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH; 548 return; 549 } 550 if (command_line->HasSwitch( 551 password_manager::switches::kDisallowAutofillSyncCredential)) { 552 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS; 553 return; 554 } 555 556 if (group_name == "DisallowSyncCredentialsForReauth") { 557 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH; 558 } else if (group_name == "DisallowSyncCredentials") { 559 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS; 560 } else { 561 // Allow by default. 562 autofill_sync_state_ = ALLOW_SYNC_CREDENTIALS; 563 } 564 } 565