Show user credentials chooser bubble.
[chromium-blink-merge.git] / chrome / browser / password_manager / chrome_password_manager_client.cc
blob016be9d67ef5e99e9af8ee4be7f40c65f7d30a7d
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/browser_save_password_progress_logger.h"
33 #include "components/password_manager/core/browser/log_receiver.h"
34 #include "components/password_manager/core/browser/password_form_manager.h"
35 #include "components/password_manager/core/browser/password_manager.h"
36 #include "components/password_manager/core/browser/password_manager_internals_service.h"
37 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
38 #include "components/password_manager/core/common/password_manager_switches.h"
39 #include "content/public/browser/navigation_entry.h"
40 #include "content/public/browser/render_view_host.h"
41 #include "content/public/browser/web_contents.h"
42 #include "google_apis/gaia/gaia_urls.h"
43 #include "net/base/url_util.h"
44 #include "third_party/re2/re2/re2.h"
46 #if defined(OS_ANDROID)
47 #include "chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h"
48 #endif
50 using password_manager::PasswordManagerInternalsService;
51 using password_manager::PasswordManagerInternalsServiceFactory;
53 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromePasswordManagerClient);
55 // Shorten the name to spare line breaks. The code provides enough context
56 // already.
57 typedef autofill::SavePasswordProgressLogger Logger;
59 // static
60 void ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
61 content::WebContents* contents,
62 autofill::AutofillClient* autofill_client) {
63 if (FromWebContents(contents))
64 return;
66 contents->SetUserData(
67 UserDataKey(),
68 new ChromePasswordManagerClient(contents, autofill_client));
71 ChromePasswordManagerClient::ChromePasswordManagerClient(
72 content::WebContents* web_contents,
73 autofill::AutofillClient* autofill_client)
74 : content::WebContentsObserver(web_contents),
75 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
76 driver_(web_contents, this, autofill_client),
77 credential_manager_dispatcher_(web_contents, this),
78 observer_(NULL),
79 can_use_log_router_(false),
80 autofill_sync_state_(ALLOW_SYNC_CREDENTIALS),
81 sync_credential_was_filtered_(false) {
82 PasswordManagerInternalsService* service =
83 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
84 if (service)
85 can_use_log_router_ = service->RegisterClient(this);
86 SetUpAutofillSyncState();
89 ChromePasswordManagerClient::~ChromePasswordManagerClient() {
90 PasswordManagerInternalsService* service =
91 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
92 if (service)
93 service->UnregisterClient(this);
96 bool ChromePasswordManagerClient::IsAutomaticPasswordSavingEnabled() const {
97 return CommandLine::ForCurrentProcess()->HasSwitch(
98 password_manager::switches::kEnableAutomaticPasswordSaving) &&
99 chrome::VersionInfo::GetChannel() ==
100 chrome::VersionInfo::CHANNEL_UNKNOWN;
103 bool ChromePasswordManagerClient::IsPasswordManagerEnabledForCurrentPage()
104 const {
105 DCHECK(web_contents());
106 content::NavigationEntry* entry =
107 web_contents()->GetController().GetLastCommittedEntry();
108 if (!entry) {
109 // TODO(gcasto): Determine if fix for crbug.com/388246 is relevant here.
110 return true;
113 // Disable the password manager for online password management.
114 if (IsURLPasswordWebsiteReauth(entry->GetURL()))
115 return false;
117 if (EnabledForSyncSignin())
118 return true;
120 // Do not fill nor save password when a user is signing in for sync. This
121 // is because users need to remember their password if they are syncing as
122 // this is effectively their master password.
123 return entry->GetURL().host() != chrome::kChromeUIChromeSigninHost;
126 bool ChromePasswordManagerClient::ShouldFilterAutofillResult(
127 const autofill::PasswordForm& form) {
128 if (!IsSyncAccountCredential(base::UTF16ToUTF8(form.username_value),
129 form.signon_realm))
130 return false;
132 if (autofill_sync_state_ == DISALLOW_SYNC_CREDENTIALS) {
133 sync_credential_was_filtered_ = true;
134 return true;
137 if (autofill_sync_state_ == DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH &&
138 LastLoadWasTransactionalReauthPage()) {
139 sync_credential_was_filtered_ = true;
140 return true;
143 return false;
146 std::string ChromePasswordManagerClient::GetSyncUsername() const {
147 return password_manager_sync_metrics::GetSyncUsername(profile_);
150 bool ChromePasswordManagerClient::IsSyncAccountCredential(
151 const std::string& username, const std::string& origin) const {
152 return password_manager_sync_metrics::IsSyncAccountCredential(
153 profile_, username, origin);
156 void ChromePasswordManagerClient::AutofillResultsComputed() {
157 UMA_HISTOGRAM_BOOLEAN("PasswordManager.SyncCredentialFiltered",
158 sync_credential_was_filtered_);
159 sync_credential_was_filtered_ = false;
162 bool ChromePasswordManagerClient::PromptUserToSavePassword(
163 scoped_ptr<password_manager::PasswordFormManager> form_to_save) {
164 // Save password infobar and the password bubble prompts in case of
165 // "webby" URLs and do not prompt in case of "non-webby" URLS (e.g. file://).
166 if (!BrowsingDataHelper::IsWebScheme(
167 web_contents()->GetLastCommittedURL().scheme())) {
168 return false;
171 if (IsTheHotNewBubbleUIEnabled()) {
172 ManagePasswordsUIController* manage_passwords_ui_controller =
173 ManagePasswordsUIController::FromWebContents(web_contents());
174 manage_passwords_ui_controller->OnPasswordSubmitted(form_to_save.Pass());
175 } else {
176 std::string uma_histogram_suffix(
177 password_manager::metrics_util::GroupIdToString(
178 password_manager::metrics_util::MonitoredDomainGroupId(
179 form_to_save->realm(), GetPrefs())));
180 SavePasswordInfoBarDelegate::Create(
181 web_contents(), form_to_save.Pass(), uma_histogram_suffix);
183 return true;
186 bool ChromePasswordManagerClient::PromptUserToChooseCredentials(
187 const std::vector<autofill::PasswordForm*>& forms,
188 base::Callback<void(const password_manager::CredentialInfo&)> callback) {
189 // Take ownership of all the password form objects in the |results| vector.
190 ScopedVector<autofill::PasswordForm> entries;
191 entries.assign(forms.begin(), forms.end());
192 ManagePasswordsUIController* manage_passwords_ui_controller =
193 ManagePasswordsUIController::FromWebContents(web_contents());
194 return manage_passwords_ui_controller->OnChooseCredentials(entries.Pass(),
195 callback);
198 void ChromePasswordManagerClient::AutomaticPasswordSave(
199 scoped_ptr<password_manager::PasswordFormManager> saved_form) {
200 #if defined(OS_ANDROID)
201 GeneratedPasswordSavedInfoBarDelegateAndroid::Create(web_contents());
202 #else
203 if (IsTheHotNewBubbleUIEnabled()) {
204 ManagePasswordsUIController* manage_passwords_ui_controller =
205 ManagePasswordsUIController::FromWebContents(web_contents());
206 manage_passwords_ui_controller->OnAutomaticPasswordSave(
207 saved_form.Pass());
209 #endif
212 void ChromePasswordManagerClient::PasswordWasAutofilled(
213 const autofill::PasswordFormMap& best_matches) const {
214 ManagePasswordsUIController* manage_passwords_ui_controller =
215 ManagePasswordsUIController::FromWebContents(web_contents());
216 if (manage_passwords_ui_controller && IsTheHotNewBubbleUIEnabled())
217 manage_passwords_ui_controller->OnPasswordAutofilled(best_matches);
220 void ChromePasswordManagerClient::PasswordAutofillWasBlocked(
221 const autofill::PasswordFormMap& best_matches) const {
222 ManagePasswordsUIController* controller =
223 ManagePasswordsUIController::FromWebContents(web_contents());
224 if (controller && IsTheHotNewBubbleUIEnabled())
225 controller->OnBlacklistBlockedAutofill(best_matches);
228 void ChromePasswordManagerClient::HidePasswordGenerationPopup() {
229 if (popup_controller_)
230 popup_controller_->HideAndDestroy();
233 PrefService* ChromePasswordManagerClient::GetPrefs() {
234 return profile_->GetPrefs();
237 password_manager::PasswordStore*
238 ChromePasswordManagerClient::GetPasswordStore() {
239 // Always use EXPLICIT_ACCESS as the password manager checks IsOffTheRecord
240 // itself when it shouldn't access the PasswordStore.
241 // TODO(gcasto): Is is safe to change this to Profile::IMPLICIT_ACCESS?
242 return PasswordStoreFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS)
243 .get();
246 password_manager::PasswordManagerDriver*
247 ChromePasswordManagerClient::GetDriver() {
248 return &driver_;
251 base::FieldTrial::Probability
252 ChromePasswordManagerClient::GetProbabilityForExperiment(
253 const std::string& experiment_name) {
254 base::FieldTrial::Probability enabled_probability = 0;
255 if (experiment_name ==
256 password_manager::PasswordManager::kOtherPossibleUsernamesExperiment) {
257 switch (chrome::VersionInfo::GetChannel()) {
258 case chrome::VersionInfo::CHANNEL_DEV:
259 case chrome::VersionInfo::CHANNEL_BETA:
260 enabled_probability = 50;
261 break;
262 default:
263 break;
266 return enabled_probability;
269 bool ChromePasswordManagerClient::IsPasswordSyncEnabled(
270 password_manager::CustomPassphraseState state) {
271 ProfileSyncService* sync_service =
272 ProfileSyncServiceFactory::GetForProfile(profile_);
273 if (sync_service && sync_service->HasSyncSetupCompleted() &&
274 sync_service->SyncActive() &&
275 sync_service->GetActiveDataTypes().Has(syncer::PASSWORDS)) {
276 if (sync_service->IsUsingSecondaryPassphrase()) {
277 return state == password_manager::ONLY_CUSTOM_PASSPHRASE;
278 } else {
279 return state == password_manager::WITHOUT_CUSTOM_PASSPHRASE;
282 return false;
285 void ChromePasswordManagerClient::OnLogRouterAvailabilityChanged(
286 bool router_can_be_used) {
287 if (can_use_log_router_ == router_can_be_used)
288 return;
289 can_use_log_router_ = router_can_be_used;
291 NotifyRendererOfLoggingAvailability();
294 void ChromePasswordManagerClient::LogSavePasswordProgress(
295 const std::string& text) const {
296 if (!IsLoggingActive())
297 return;
298 PasswordManagerInternalsService* service =
299 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
300 if (service)
301 service->ProcessLog(text);
304 bool ChromePasswordManagerClient::IsLoggingActive() const {
305 // WebUI tabs do not need to log password saving progress. In particular, the
306 // internals page itself should not send any logs.
307 return can_use_log_router_ && !web_contents()->GetWebUI();
310 bool ChromePasswordManagerClient::WasLastNavigationHTTPError() const {
311 DCHECK(web_contents());
313 scoped_ptr<password_manager::BrowserSavePasswordProgressLogger> logger;
314 if (IsLoggingActive()) {
315 logger.reset(new password_manager::BrowserSavePasswordProgressLogger(this));
316 logger->LogMessage(
317 Logger::STRING_WAS_LAST_NAVIGATION_HTTP_ERROR_METHOD);
320 content::NavigationEntry* entry =
321 web_contents()->GetController().GetVisibleEntry();
322 if (!entry)
323 return false;
324 int http_status_code = entry->GetHttpStatusCode();
326 if (logger)
327 logger->LogNumber(Logger::STRING_HTTP_STATUS_CODE, http_status_code);
329 if (http_status_code >= 400 && http_status_code < 600)
330 return true;
331 return false;
334 // static
335 password_manager::PasswordGenerationManager*
336 ChromePasswordManagerClient::GetGenerationManagerFromWebContents(
337 content::WebContents* contents) {
338 ChromePasswordManagerClient* client =
339 ChromePasswordManagerClient::FromWebContents(contents);
340 if (!client)
341 return NULL;
342 return client->GetDriver()->GetPasswordGenerationManager();
345 // static
346 password_manager::PasswordManager*
347 ChromePasswordManagerClient::GetManagerFromWebContents(
348 content::WebContents* contents) {
349 ChromePasswordManagerClient* client =
350 ChromePasswordManagerClient::FromWebContents(contents);
351 if (!client)
352 return NULL;
353 return client->GetDriver()->GetPasswordManager();
356 void ChromePasswordManagerClient::SetTestObserver(
357 autofill::PasswordGenerationPopupObserver* observer) {
358 observer_ = observer;
361 bool ChromePasswordManagerClient::OnMessageReceived(
362 const IPC::Message& message) {
363 bool handled = true;
364 IPC_BEGIN_MESSAGE_MAP(ChromePasswordManagerClient, message)
365 // Autofill messages:
366 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordGenerationPopup,
367 ShowPasswordGenerationPopup)
368 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordEditingPopup,
369 ShowPasswordEditingPopup)
370 IPC_MESSAGE_HANDLER(AutofillHostMsg_HidePasswordGenerationPopup,
371 HidePasswordGenerationPopup)
372 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordAutofillAgentConstructed,
373 NotifyRendererOfLoggingAvailability)
375 // Default:
376 IPC_MESSAGE_UNHANDLED(handled = false)
377 IPC_END_MESSAGE_MAP()
378 return handled;
381 gfx::RectF ChromePasswordManagerClient::GetBoundsInScreenSpace(
382 const gfx::RectF& bounds) {
383 gfx::Rect client_area = web_contents()->GetContainerBounds();
384 return bounds + client_area.OffsetFromOrigin();
387 void ChromePasswordManagerClient::ShowPasswordGenerationPopup(
388 const gfx::RectF& bounds,
389 int max_length,
390 const autofill::PasswordForm& form) {
391 // TODO(gcasto): Validate data in PasswordForm.
393 gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds);
395 popup_controller_ =
396 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate(
397 popup_controller_,
398 element_bounds_in_screen_space,
399 form,
400 max_length,
401 driver_.GetPasswordManager(),
402 observer_,
403 web_contents(),
404 web_contents()->GetNativeView());
405 popup_controller_->Show(true /* display_password */);
408 void ChromePasswordManagerClient::ShowPasswordEditingPopup(
409 const gfx::RectF& bounds,
410 const autofill::PasswordForm& form) {
411 gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds);
412 popup_controller_ =
413 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate(
414 popup_controller_,
415 element_bounds_in_screen_space,
416 form,
417 0, // Unspecified max length.
418 driver_.GetPasswordManager(),
419 observer_,
420 web_contents(),
421 web_contents()->GetNativeView());
422 popup_controller_->Show(false /* display_password */);
425 void ChromePasswordManagerClient::NotifyRendererOfLoggingAvailability() {
426 if (!web_contents())
427 return;
429 web_contents()->GetRenderViewHost()->Send(new AutofillMsg_SetLoggingState(
430 web_contents()->GetRenderViewHost()->GetRoutingID(),
431 can_use_log_router_));
434 bool ChromePasswordManagerClient::LastLoadWasTransactionalReauthPage() const {
435 DCHECK(web_contents());
436 content::NavigationEntry* entry =
437 web_contents()->GetController().GetLastCommittedEntry();
438 if (!entry)
439 return false;
441 if (entry->GetURL().GetOrigin() !=
442 GaiaUrls::GetInstance()->gaia_url().GetOrigin())
443 return false;
445 // "rart" is the transactional reauth paramter.
446 std::string ignored_value;
447 return net::GetValueForKeyInQuery(entry->GetURL(),
448 "rart",
449 &ignored_value);
452 bool ChromePasswordManagerClient::IsURLPasswordWebsiteReauth(
453 const GURL& url) const {
454 if (url.GetOrigin() != GaiaUrls::GetInstance()->gaia_url().GetOrigin())
455 return false;
457 // "rart" param signals this page is for transactional reauth.
458 std::string param_value;
459 if (!net::GetValueForKeyInQuery(url, "rart", &param_value))
460 return false;
462 // Check the "continue" param to see if this reauth page is for the passwords
463 // website.
464 param_value.clear();
465 if (!net::GetValueForKeyInQuery(url, "continue", &param_value))
466 return false;
468 // All password sites, including test sites, have autofilling disabled.
469 CR_DEFINE_STATIC_LOCAL(RE2, account_dashboard_pattern,
470 ("passwords(-([a-z-]+\\.corp))?\\.google\\.com"));
472 return RE2::FullMatch(GURL(param_value).host(), account_dashboard_pattern);
475 bool ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled() {
476 #if !defined(USE_AURA) && !defined(OS_MACOSX)
477 return false;
478 #endif
479 CommandLine* command_line = CommandLine::ForCurrentProcess();
480 if (command_line->HasSwitch(switches::kDisableSavePasswordBubble))
481 return false;
483 if (command_line->HasSwitch(switches::kEnableSavePasswordBubble))
484 return true;
486 std::string group_name =
487 base::FieldTrialList::FindFullName("PasswordManagerUI");
489 // The bubble should be the default case that runs on the bots.
490 return group_name != "Infobar";
493 bool ChromePasswordManagerClient::EnabledForSyncSignin() {
494 CommandLine* command_line = CommandLine::ForCurrentProcess();
495 if (command_line->HasSwitch(
496 password_manager::switches::kDisableManagerForSyncSignin))
497 return false;
499 if (command_line->HasSwitch(
500 password_manager::switches::kEnableManagerForSyncSignin))
501 return true;
503 // Default is enabled.
504 std::string group_name =
505 base::FieldTrialList::FindFullName("PasswordManagerStateForSyncSignin");
506 return group_name != "Disabled";
509 void ChromePasswordManagerClient::SetUpAutofillSyncState() {
510 std::string group_name =
511 base::FieldTrialList::FindFullName("AutofillSyncCredential");
513 CommandLine* command_line = CommandLine::ForCurrentProcess();
514 if (command_line->HasSwitch(
515 password_manager::switches::kAllowAutofillSyncCredential)) {
516 autofill_sync_state_ = ALLOW_SYNC_CREDENTIALS;
517 return;
519 if (command_line->HasSwitch(
520 password_manager::switches::
521 kDisallowAutofillSyncCredentialForReauth)) {
522 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH;
523 return;
525 if (command_line->HasSwitch(
526 password_manager::switches::kDisallowAutofillSyncCredential)) {
527 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS;
528 return;
531 if (group_name == "DisallowSyncCredentialsForReauth") {
532 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH;
533 } else if (group_name == "DisallowSyncCredentials") {
534 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS;
535 } else {
536 // Allow by default.
537 autofill_sync_state_ = ALLOW_SYNC_CREDENTIALS;