Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / password_manager / chrome_password_manager_client.cc
blobf60165313ce646f285a53d350bd21bd34cf4fe3e
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 using password_manager::PasswordManagerInternalsService;
46 using password_manager::PasswordManagerInternalsServiceFactory;
48 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromePasswordManagerClient);
50 // static
51 void ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
52 content::WebContents* contents,
53 autofill::AutofillClient* autofill_client) {
54 if (FromWebContents(contents))
55 return;
57 contents->SetUserData(
58 UserDataKey(),
59 new ChromePasswordManagerClient(contents, autofill_client));
62 ChromePasswordManagerClient::ChromePasswordManagerClient(
63 content::WebContents* web_contents,
64 autofill::AutofillClient* autofill_client)
65 : content::WebContentsObserver(web_contents),
66 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
67 driver_(web_contents, this, autofill_client),
68 credential_manager_dispatcher_(web_contents, this),
69 observer_(NULL),
70 can_use_log_router_(false),
71 autofill_sync_state_(ALLOW_SYNC_CREDENTIALS),
72 sync_credential_was_filtered_(false) {
73 PasswordManagerInternalsService* service =
74 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
75 if (service)
76 can_use_log_router_ = service->RegisterClient(this);
77 SetUpAutofillSyncState();
80 ChromePasswordManagerClient::~ChromePasswordManagerClient() {
81 PasswordManagerInternalsService* service =
82 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
83 if (service)
84 service->UnregisterClient(this);
87 bool ChromePasswordManagerClient::IsAutomaticPasswordSavingEnabled() const {
88 return CommandLine::ForCurrentProcess()->HasSwitch(
89 password_manager::switches::kEnableAutomaticPasswordSaving) &&
90 chrome::VersionInfo::GetChannel() ==
91 chrome::VersionInfo::CHANNEL_UNKNOWN;
94 bool ChromePasswordManagerClient::IsPasswordManagerEnabledForCurrentPage()
95 const {
96 DCHECK(web_contents());
97 content::NavigationEntry* entry =
98 web_contents()->GetController().GetLastCommittedEntry();
99 if (!entry) {
100 // TODO(gcasto): Determine if fix for crbug.com/388246 is relevant here.
101 return true;
104 // Disable the password manager for online password management.
105 if (IsURLPasswordWebsiteReauth(entry->GetURL()))
106 return false;
108 if (EnabledForSyncSignin())
109 return true;
111 // Do not fill nor save password when a user is signing in for sync. This
112 // is because users need to remember their password if they are syncing as
113 // this is effectively their master password.
114 return entry->GetURL().host() != chrome::kChromeUIChromeSigninHost;
117 bool ChromePasswordManagerClient::ShouldFilterAutofillResult(
118 const autofill::PasswordForm& form) {
119 if (!IsSyncAccountCredential(base::UTF16ToUTF8(form.username_value),
120 form.signon_realm))
121 return false;
123 if (autofill_sync_state_ == DISALLOW_SYNC_CREDENTIALS) {
124 sync_credential_was_filtered_ = true;
125 return true;
128 if (autofill_sync_state_ == DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH &&
129 LastLoadWasTransactionalReauthPage()) {
130 sync_credential_was_filtered_ = true;
131 return true;
134 return false;
137 bool ChromePasswordManagerClient::IsSyncAccountCredential(
138 const std::string& username, const std::string& origin) const {
139 return password_manager_sync_metrics::IsSyncAccountCredential(
140 profile_, username, origin);
143 void ChromePasswordManagerClient::AutofillResultsComputed() {
144 UMA_HISTOGRAM_BOOLEAN("PasswordManager.SyncCredentialFiltered",
145 sync_credential_was_filtered_);
146 sync_credential_was_filtered_ = false;
149 bool ChromePasswordManagerClient::PromptUserToSavePassword(
150 scoped_ptr<password_manager::PasswordFormManager> form_to_save) {
151 // Save password infobar and the password bubble prompts in case of
152 // "webby" URLs and do not prompt in case of "non-webby" URLS (e.g. file://).
153 if (!BrowsingDataHelper::IsWebScheme(
154 web_contents()->GetLastCommittedURL().scheme())) {
155 return false;
158 if (IsTheHotNewBubbleUIEnabled()) {
159 ManagePasswordsUIController* manage_passwords_ui_controller =
160 ManagePasswordsUIController::FromWebContents(web_contents());
161 manage_passwords_ui_controller->OnPasswordSubmitted(form_to_save.Pass());
162 } else {
163 std::string uma_histogram_suffix(
164 password_manager::metrics_util::GroupIdToString(
165 password_manager::metrics_util::MonitoredDomainGroupId(
166 form_to_save->realm(), GetPrefs())));
167 SavePasswordInfoBarDelegate::Create(
168 web_contents(), form_to_save.Pass(), uma_histogram_suffix);
170 return true;
173 void ChromePasswordManagerClient::AutomaticPasswordSave(
174 scoped_ptr<password_manager::PasswordFormManager> saved_form) {
175 if (IsTheHotNewBubbleUIEnabled()) {
176 ManagePasswordsUIController* manage_passwords_ui_controller =
177 ManagePasswordsUIController::FromWebContents(web_contents());
178 manage_passwords_ui_controller->OnAutomaticPasswordSave(
179 saved_form.Pass());
183 void ChromePasswordManagerClient::PasswordWasAutofilled(
184 const autofill::PasswordFormMap& best_matches) const {
185 ManagePasswordsUIController* manage_passwords_ui_controller =
186 ManagePasswordsUIController::FromWebContents(web_contents());
187 if (manage_passwords_ui_controller && IsTheHotNewBubbleUIEnabled())
188 manage_passwords_ui_controller->OnPasswordAutofilled(best_matches);
191 void ChromePasswordManagerClient::PasswordAutofillWasBlocked(
192 const autofill::PasswordFormMap& best_matches) const {
193 ManagePasswordsUIController* controller =
194 ManagePasswordsUIController::FromWebContents(web_contents());
195 if (controller && IsTheHotNewBubbleUIEnabled())
196 controller->OnBlacklistBlockedAutofill(best_matches);
199 void ChromePasswordManagerClient::HidePasswordGenerationPopup() {
200 if (popup_controller_)
201 popup_controller_->HideAndDestroy();
204 PrefService* ChromePasswordManagerClient::GetPrefs() {
205 return profile_->GetPrefs();
208 password_manager::PasswordStore*
209 ChromePasswordManagerClient::GetPasswordStore() {
210 // Always use EXPLICIT_ACCESS as the password manager checks IsOffTheRecord
211 // itself when it shouldn't access the PasswordStore.
212 // TODO(gcasto): Is is safe to change this to Profile::IMPLICIT_ACCESS?
213 return PasswordStoreFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS)
214 .get();
217 password_manager::PasswordManagerDriver*
218 ChromePasswordManagerClient::GetDriver() {
219 return &driver_;
222 base::FieldTrial::Probability
223 ChromePasswordManagerClient::GetProbabilityForExperiment(
224 const std::string& experiment_name) {
225 base::FieldTrial::Probability enabled_probability = 0;
226 if (experiment_name ==
227 password_manager::PasswordManager::kOtherPossibleUsernamesExperiment) {
228 switch (chrome::VersionInfo::GetChannel()) {
229 case chrome::VersionInfo::CHANNEL_DEV:
230 case chrome::VersionInfo::CHANNEL_BETA:
231 enabled_probability = 50;
232 break;
233 default:
234 break;
237 return enabled_probability;
240 bool ChromePasswordManagerClient::IsPasswordSyncEnabled() {
241 ProfileSyncService* sync_service =
242 ProfileSyncServiceFactory::GetForProfile(profile_);
243 // Don't consider sync enabled if the user has a custom passphrase. See
244 // crbug.com/358998 for more details.
245 if (sync_service &&
246 sync_service->HasSyncSetupCompleted() &&
247 sync_service->SyncActive() &&
248 !sync_service->IsUsingSecondaryPassphrase()) {
249 return sync_service->GetActiveDataTypes().Has(syncer::PASSWORDS);
251 return false;
254 void ChromePasswordManagerClient::OnLogRouterAvailabilityChanged(
255 bool router_can_be_used) {
256 if (can_use_log_router_ == router_can_be_used)
257 return;
258 can_use_log_router_ = router_can_be_used;
260 NotifyRendererOfLoggingAvailability();
263 void ChromePasswordManagerClient::LogSavePasswordProgress(
264 const std::string& text) {
265 if (!IsLoggingActive())
266 return;
267 PasswordManagerInternalsService* service =
268 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
269 if (service)
270 service->ProcessLog(text);
273 bool ChromePasswordManagerClient::IsLoggingActive() const {
274 // WebUI tabs do not need to log password saving progress. In particular, the
275 // internals page itself should not send any logs.
276 return can_use_log_router_ && !web_contents()->GetWebUI();
279 // static
280 password_manager::PasswordGenerationManager*
281 ChromePasswordManagerClient::GetGenerationManagerFromWebContents(
282 content::WebContents* contents) {
283 ChromePasswordManagerClient* client =
284 ChromePasswordManagerClient::FromWebContents(contents);
285 if (!client)
286 return NULL;
287 return client->GetDriver()->GetPasswordGenerationManager();
290 // static
291 password_manager::PasswordManager*
292 ChromePasswordManagerClient::GetManagerFromWebContents(
293 content::WebContents* contents) {
294 ChromePasswordManagerClient* client =
295 ChromePasswordManagerClient::FromWebContents(contents);
296 if (!client)
297 return NULL;
298 return client->GetDriver()->GetPasswordManager();
301 void ChromePasswordManagerClient::SetTestObserver(
302 autofill::PasswordGenerationPopupObserver* observer) {
303 observer_ = observer;
306 bool ChromePasswordManagerClient::OnMessageReceived(
307 const IPC::Message& message) {
308 bool handled = true;
309 IPC_BEGIN_MESSAGE_MAP(ChromePasswordManagerClient, message)
310 // Autofill messages:
311 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordGenerationPopup,
312 ShowPasswordGenerationPopup)
313 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordEditingPopup,
314 ShowPasswordEditingPopup)
315 IPC_MESSAGE_HANDLER(AutofillHostMsg_HidePasswordGenerationPopup,
316 HidePasswordGenerationPopup)
317 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordAutofillAgentConstructed,
318 NotifyRendererOfLoggingAvailability)
320 // Default:
321 IPC_MESSAGE_UNHANDLED(handled = false)
322 IPC_END_MESSAGE_MAP()
323 return handled;
326 gfx::RectF ChromePasswordManagerClient::GetBoundsInScreenSpace(
327 const gfx::RectF& bounds) {
328 gfx::Rect client_area = web_contents()->GetContainerBounds();
329 return bounds + client_area.OffsetFromOrigin();
332 void ChromePasswordManagerClient::ShowPasswordGenerationPopup(
333 const gfx::RectF& bounds,
334 int max_length,
335 const autofill::PasswordForm& form) {
336 // TODO(gcasto): Validate data in PasswordForm.
338 // Not yet implemented on other platforms.
339 #if defined(USE_AURA) || defined(OS_MACOSX)
340 gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds);
342 popup_controller_ =
343 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate(
344 popup_controller_,
345 element_bounds_in_screen_space,
346 form,
347 max_length,
348 driver_.GetPasswordManager(),
349 observer_,
350 web_contents(),
351 web_contents()->GetNativeView());
352 popup_controller_->Show(true /* display_password */);
353 #endif // defined(USE_AURA) || defined(OS_MACOSX)
356 void ChromePasswordManagerClient::ShowPasswordEditingPopup(
357 const gfx::RectF& bounds,
358 const autofill::PasswordForm& form) {
359 gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds);
360 // Not yet implemented on other platforms.
361 #if defined(USE_AURA) || defined(OS_MACOSX)
362 popup_controller_ =
363 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate(
364 popup_controller_,
365 element_bounds_in_screen_space,
366 form,
367 0, // Unspecified max length.
368 driver_.GetPasswordManager(),
369 observer_,
370 web_contents(),
371 web_contents()->GetNativeView());
372 popup_controller_->Show(false /* display_password */);
373 #endif // defined(USE_AURA) || defined(OS_MACOSX)
376 void ChromePasswordManagerClient::NotifyRendererOfLoggingAvailability() {
377 if (!web_contents())
378 return;
380 web_contents()->GetRenderViewHost()->Send(new AutofillMsg_SetLoggingState(
381 web_contents()->GetRenderViewHost()->GetRoutingID(),
382 can_use_log_router_));
385 bool ChromePasswordManagerClient::LastLoadWasTransactionalReauthPage() const {
386 DCHECK(web_contents());
387 content::NavigationEntry* entry =
388 web_contents()->GetController().GetLastCommittedEntry();
389 if (!entry)
390 return false;
392 if (entry->GetURL().GetOrigin() !=
393 GaiaUrls::GetInstance()->gaia_url().GetOrigin())
394 return false;
396 // "rart" is the transactional reauth paramter.
397 std::string ignored_value;
398 return net::GetValueForKeyInQuery(entry->GetURL(),
399 "rart",
400 &ignored_value);
403 bool ChromePasswordManagerClient::IsURLPasswordWebsiteReauth(
404 const GURL& url) const {
405 if (url.GetOrigin() != GaiaUrls::GetInstance()->gaia_url().GetOrigin())
406 return false;
408 // "rart" param signals this page is for transactional reauth.
409 std::string param_value;
410 if (!net::GetValueForKeyInQuery(url, "rart", &param_value))
411 return false;
413 // Check the "continue" param to see if this reauth page is for the passwords
414 // website.
415 param_value.clear();
416 if (!net::GetValueForKeyInQuery(url, "continue", &param_value))
417 return false;
419 // All password sites, including test sites, have autofilling disabled.
420 CR_DEFINE_STATIC_LOCAL(RE2, account_dashboard_pattern,
421 ("passwords(-([a-z-]+\\.corp))?\\.google\\.com"));
423 return RE2::FullMatch(GURL(param_value).host(), account_dashboard_pattern);
426 bool ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled() {
427 #if !defined(USE_AURA) && !defined(OS_MACOSX)
428 return false;
429 #endif
430 CommandLine* command_line = CommandLine::ForCurrentProcess();
431 if (command_line->HasSwitch(switches::kDisableSavePasswordBubble))
432 return false;
434 if (command_line->HasSwitch(switches::kEnableSavePasswordBubble))
435 return true;
437 std::string group_name =
438 base::FieldTrialList::FindFullName("PasswordManagerUI");
440 // The bubble should be the default case that runs on the bots.
441 return group_name != "Infobar";
444 bool ChromePasswordManagerClient::EnabledForSyncSignin() {
445 CommandLine* command_line = CommandLine::ForCurrentProcess();
446 if (command_line->HasSwitch(
447 password_manager::switches::kDisableManagerForSyncSignin))
448 return false;
450 if (command_line->HasSwitch(
451 password_manager::switches::kEnableManagerForSyncSignin))
452 return true;
454 // Default is enabled.
455 std::string group_name =
456 base::FieldTrialList::FindFullName("PasswordManagerStateForSyncSignin");
457 return group_name != "Disabled";
460 void ChromePasswordManagerClient::SetUpAutofillSyncState() {
461 std::string group_name =
462 base::FieldTrialList::FindFullName("AutofillSyncCredential");
464 CommandLine* command_line = CommandLine::ForCurrentProcess();
465 if (command_line->HasSwitch(
466 password_manager::switches::kAllowAutofillSyncCredential)) {
467 autofill_sync_state_ = ALLOW_SYNC_CREDENTIALS;
468 return;
470 if (command_line->HasSwitch(
471 password_manager::switches::
472 kDisallowAutofillSyncCredentialForReauth)) {
473 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH;
474 return;
476 if (command_line->HasSwitch(
477 password_manager::switches::kDisallowAutofillSyncCredential)) {
478 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS;
479 return;
482 if (group_name == "DisallowSyncCredentialsForReauth") {
483 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH;
484 } else if (group_name == "DisallowSyncCredentials") {
485 autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS;
486 } else {
487 // Allow by default.
488 autofill_sync_state_ = ALLOW_SYNC_CREDENTIALS;