Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / chrome / browser / password_manager / chrome_password_manager_client.cc
blobf7060ba64fdb09f646ec0401bed1afa3f686d9d6
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.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/memory/singleton.h"
11 #include "base/metrics/histogram.h"
12 #include "base/prefs/pref_service.h"
13 #include "chrome/browser/browsing_data/browsing_data_helper.h"
14 #include "chrome/browser/password_manager/password_store_factory.h"
15 #include "chrome/browser/password_manager/save_password_infobar_delegate.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/signin/signin_manager_factory.h"
18 #include "chrome/browser/sync/profile_sync_service.h"
19 #include "chrome/browser/sync/profile_sync_service_factory.h"
20 #include "chrome/browser/ui/autofill/password_generation_popup_controller_impl.h"
21 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
22 #include "chrome/common/channel_info.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/common/url_constants.h"
25 #include "components/autofill/content/browser/content_autofill_driver.h"
26 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
27 #include "components/autofill/content/common/autofill_messages.h"
28 #include "components/autofill/core/browser/password_generator.h"
29 #include "components/autofill/core/common/password_form.h"
30 #include "components/password_manager/content/browser/content_password_manager_driver.h"
31 #include "components/password_manager/content/browser/password_manager_internals_service_factory.h"
32 #include "components/password_manager/content/common/credential_manager_messages.h"
33 #include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
34 #include "components/password_manager/core/browser/log_receiver.h"
35 #include "components/password_manager/core/browser/password_form_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/browser/password_manager_util.h"
39 #include "components/password_manager/core/common/credential_manager_types.h"
40 #include "components/password_manager/core/common/password_manager_pref_names.h"
41 #include "components/password_manager/core/common/password_manager_switches.h"
42 #include "components/password_manager/sync/browser/password_sync_util.h"
43 #include "components/signin/core/browser/signin_manager.h"
44 #include "components/version_info/version_info.h"
45 #include "content/public/browser/navigation_entry.h"
46 #include "content/public/browser/render_view_host.h"
47 #include "content/public/browser/web_contents.h"
48 #include "google_apis/gaia/gaia_urls.h"
49 #include "net/base/url_util.h"
50 #include "third_party/re2/re2/re2.h"
52 #if defined(OS_ANDROID)
53 #include "chrome/browser/android/tab_android.h"
54 #include "chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h"
55 #include "chrome/browser/ui/android/snackbars/auto_signin_snackbar_controller.h"
56 #endif
58 using password_manager::ContentPasswordManagerDriverFactory;
59 using password_manager::PasswordManagerInternalsService;
60 using password_manager::PasswordManagerInternalsServiceFactory;
62 // Shorten the name to spare line breaks. The code provides enough context
63 // already.
64 typedef autofill::SavePasswordProgressLogger Logger;
66 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromePasswordManagerClient);
68 namespace {
70 const sync_driver::SyncService* GetSyncService(Profile* profile) {
71 if (ProfileSyncServiceFactory::HasProfileSyncService(profile))
72 return ProfileSyncServiceFactory::GetForProfile(profile);
73 return nullptr;
76 const SigninManagerBase* GetSigninManager(Profile* profile) {
77 return SigninManagerFactory::GetForProfile(profile);
80 // This routine is called when PasswordManagerClient is constructed.
81 // Currently we report metrics only once at startup. We require
82 // that this is only ever called from a single thread in order to
83 // avoid needing to lock (a static boolean flag is then sufficient to
84 // guarantee running only once).
85 void ReportMetrics(bool password_manager_enabled,
86 password_manager::PasswordManagerClient* client,
87 Profile* profile) {
88 static base::PlatformThreadId initial_thread_id =
89 base::PlatformThread::CurrentId();
90 DCHECK_EQ(base::PlatformThread::CurrentId(), initial_thread_id);
92 static bool ran_once = false;
93 if (ran_once)
94 return;
95 ran_once = true;
97 password_manager::PasswordStore* store = client->GetPasswordStore();
98 // May be null in tests.
99 if (store) {
100 store->ReportMetrics(
101 password_manager::sync_util::GetSyncUsernameIfSyncingPasswords(
102 GetSyncService(profile), GetSigninManager(profile)),
103 client->GetPasswordSyncState() ==
104 password_manager::SYNCING_WITH_CUSTOM_PASSPHRASE);
106 UMA_HISTOGRAM_BOOLEAN("PasswordManager.Enabled", password_manager_enabled);
109 } // namespace
111 // static
112 void ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
113 content::WebContents* contents,
114 autofill::AutofillClient* autofill_client) {
115 if (FromWebContents(contents))
116 return;
118 contents->SetUserData(
119 UserDataKey(),
120 new ChromePasswordManagerClient(contents, autofill_client));
123 ChromePasswordManagerClient::ChromePasswordManagerClient(
124 content::WebContents* web_contents,
125 autofill::AutofillClient* autofill_client)
126 : content::WebContentsObserver(web_contents),
127 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
128 password_manager_(this),
129 driver_factory_(nullptr),
130 credential_manager_dispatcher_(web_contents, this),
131 observer_(nullptr),
132 can_use_log_router_(false),
133 credentials_filter_(this,
134 base::Bind(&GetSyncService, profile_),
135 base::Bind(&GetSigninManager, profile_)) {
136 ContentPasswordManagerDriverFactory::CreateForWebContents(web_contents, this,
137 autofill_client);
138 driver_factory_ =
139 ContentPasswordManagerDriverFactory::FromWebContents(web_contents);
141 PasswordManagerInternalsService* service =
142 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
143 if (service)
144 can_use_log_router_ = service->RegisterClient(this);
145 saving_passwords_enabled_.Init(
146 password_manager::prefs::kPasswordManagerSavingEnabled, GetPrefs());
147 ReportMetrics(*saving_passwords_enabled_, this, profile_);
150 ChromePasswordManagerClient::~ChromePasswordManagerClient() {
151 PasswordManagerInternalsService* service =
152 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
153 if (service)
154 service->UnregisterClient(this);
157 bool ChromePasswordManagerClient::IsAutomaticPasswordSavingEnabled() const {
158 return base::CommandLine::ForCurrentProcess()->HasSwitch(
159 password_manager::switches::kEnableAutomaticPasswordSaving) &&
160 chrome::GetChannel() == version_info::Channel::UNKNOWN;
163 bool ChromePasswordManagerClient::IsPasswordManagementEnabledForCurrentPage()
164 const {
165 DCHECK(web_contents());
166 content::NavigationEntry* entry =
167 web_contents()->GetController().GetLastCommittedEntry();
168 bool is_enabled = false;
169 if (!entry) {
170 // TODO(gcasto): Determine if fix for crbug.com/388246 is relevant here.
171 is_enabled = true;
172 } else if (IsURLPasswordWebsiteReauth(entry->GetURL())) {
173 // Disable the password manager for online password management.
174 is_enabled = false;
175 } else if (EnabledForSyncSignin()) {
176 is_enabled = true;
177 } else {
178 // Do not fill nor save password when a user is signing in for sync. This
179 // is because users need to remember their password if they are syncing as
180 // this is effectively their master password.
181 is_enabled = entry->GetURL().host() != chrome::kChromeUIChromeSigninHost;
183 if (IsLoggingActive()) {
184 password_manager::BrowserSavePasswordProgressLogger logger(this);
185 logger.LogBoolean(
186 Logger::STRING_PASSWORD_MANAGEMENT_ENABLED_FOR_CURRENT_PAGE,
187 is_enabled);
189 return is_enabled;
192 bool ChromePasswordManagerClient::IsSavingEnabledForCurrentPage() const {
193 return *saving_passwords_enabled_ && !IsOffTheRecord() &&
194 !DidLastPageLoadEncounterSSLErrors() &&
195 IsPasswordManagementEnabledForCurrentPage();
198 bool ChromePasswordManagerClient::PromptUserToSaveOrUpdatePassword(
199 scoped_ptr<password_manager::PasswordFormManager> form_to_save,
200 password_manager::CredentialSourceType type,
201 bool update_password) {
202 // Save password infobar and the password bubble prompts in case of
203 // "webby" URLs and do not prompt in case of "non-webby" URLS (e.g. file://).
204 if (!BrowsingDataHelper::IsWebScheme(
205 web_contents()->GetLastCommittedURL().scheme())) {
206 return false;
209 if (IsTheHotNewBubbleUIEnabled()) {
210 ManagePasswordsUIController* manage_passwords_ui_controller =
211 ManagePasswordsUIController::FromWebContents(web_contents());
212 if (update_password && IsUpdatePasswordUIEnabled()) {
213 manage_passwords_ui_controller->OnUpdatePasswordSubmitted(
214 form_to_save.Pass());
215 } else {
216 manage_passwords_ui_controller->OnPasswordSubmitted(form_to_save.Pass());
218 } else {
219 if (form_to_save->IsBlacklisted())
220 return false;
221 std::string uma_histogram_suffix(
222 password_manager::metrics_util::GroupIdToString(
223 password_manager::metrics_util::MonitoredDomainGroupId(
224 form_to_save->pending_credentials().signon_realm, GetPrefs())));
225 SavePasswordInfoBarDelegate::Create(
226 web_contents(), form_to_save.Pass(), uma_histogram_suffix, type);
228 return true;
231 bool ChromePasswordManagerClient::PromptUserToChooseCredentials(
232 ScopedVector<autofill::PasswordForm> local_forms,
233 ScopedVector<autofill::PasswordForm> federated_forms,
234 const GURL& origin,
235 base::Callback<void(const password_manager::CredentialInfo&)> callback) {
236 return ManagePasswordsUIController::FromWebContents(web_contents())->
237 OnChooseCredentials(local_forms.Pass(), federated_forms.Pass(), origin,
238 callback);
241 void ChromePasswordManagerClient::ForceSavePassword() {
242 password_manager::ContentPasswordManagerDriver* driver =
243 driver_factory_->GetDriverForFrame(web_contents()->GetFocusedFrame());
244 driver->ForceSavePassword();
247 void ChromePasswordManagerClient::NotifyUserAutoSignin(
248 ScopedVector<autofill::PasswordForm> local_forms) {
249 DCHECK(!local_forms.empty());
250 #if defined(OS_ANDROID)
251 TabAndroid *tab = TabAndroid::FromWebContents(web_contents());
252 ShowAutoSigninSnackbar(tab, local_forms[0]->username_value);
253 #else
254 ManagePasswordsUIController::FromWebContents(web_contents())->
255 OnAutoSignin(local_forms.Pass());
257 #endif
260 void ChromePasswordManagerClient::AutomaticPasswordSave(
261 scoped_ptr<password_manager::PasswordFormManager> saved_form) {
262 #if defined(OS_ANDROID)
263 GeneratedPasswordSavedInfoBarDelegateAndroid::Create(web_contents());
264 #else
265 if (IsTheHotNewBubbleUIEnabled()) {
266 ManagePasswordsUIController* manage_passwords_ui_controller =
267 ManagePasswordsUIController::FromWebContents(web_contents());
268 manage_passwords_ui_controller->OnAutomaticPasswordSave(
269 saved_form.Pass());
271 #endif
274 void ChromePasswordManagerClient::PasswordWasAutofilled(
275 const autofill::PasswordFormMap& best_matches) const {
276 ManagePasswordsUIController* manage_passwords_ui_controller =
277 ManagePasswordsUIController::FromWebContents(web_contents());
278 if (manage_passwords_ui_controller && IsTheHotNewBubbleUIEnabled())
279 manage_passwords_ui_controller->OnPasswordAutofilled(best_matches);
282 void ChromePasswordManagerClient::PasswordAutofillWasBlocked(
283 const autofill::PasswordFormMap& best_matches) const {
284 ManagePasswordsUIController* controller =
285 ManagePasswordsUIController::FromWebContents(web_contents());
286 if (controller && IsTheHotNewBubbleUIEnabled())
287 controller->OnBlacklistBlockedAutofill(best_matches);
290 void ChromePasswordManagerClient::HidePasswordGenerationPopup() {
291 if (popup_controller_)
292 popup_controller_->HideAndDestroy();
295 PrefService* ChromePasswordManagerClient::GetPrefs() {
296 return profile_->GetPrefs();
299 password_manager::PasswordStore*
300 ChromePasswordManagerClient::GetPasswordStore() const {
301 // Always use EXPLICIT_ACCESS as the password manager checks IsOffTheRecord
302 // itself when it shouldn't access the PasswordStore.
303 // TODO(gcasto): Is is safe to change this to
304 // ServiceAccessType::IMPLICIT_ACCESS?
305 return PasswordStoreFactory::GetForProfile(
306 profile_, ServiceAccessType::EXPLICIT_ACCESS).get();
309 password_manager::PasswordSyncState
310 ChromePasswordManagerClient::GetPasswordSyncState() const {
311 const ProfileSyncService* sync_service =
312 ProfileSyncServiceFactory::GetForProfile(profile_);
313 return password_manager_util::GetPasswordSyncState(sync_service);
316 void ChromePasswordManagerClient::OnLogRouterAvailabilityChanged(
317 bool router_can_be_used) {
318 if (can_use_log_router_ == router_can_be_used)
319 return;
320 can_use_log_router_ = router_can_be_used;
322 NotifyRendererOfLoggingAvailability();
325 void ChromePasswordManagerClient::LogSavePasswordProgress(
326 const std::string& text) const {
327 if (!IsLoggingActive())
328 return;
329 PasswordManagerInternalsService* service =
330 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
331 if (service)
332 service->ProcessLog(text);
335 bool ChromePasswordManagerClient::IsLoggingActive() const {
336 // WebUI tabs do not need to log password saving progress. In particular, the
337 // internals page itself should not send any logs.
338 return can_use_log_router_ && !web_contents()->GetWebUI();
341 bool ChromePasswordManagerClient::WasLastNavigationHTTPError() const {
342 DCHECK(web_contents());
344 scoped_ptr<password_manager::BrowserSavePasswordProgressLogger> logger;
345 if (IsLoggingActive()) {
346 logger.reset(new password_manager::BrowserSavePasswordProgressLogger(this));
347 logger->LogMessage(
348 Logger::STRING_WAS_LAST_NAVIGATION_HTTP_ERROR_METHOD);
351 content::NavigationEntry* entry =
352 web_contents()->GetController().GetVisibleEntry();
353 if (!entry)
354 return false;
355 int http_status_code = entry->GetHttpStatusCode();
357 if (logger)
358 logger->LogNumber(Logger::STRING_HTTP_STATUS_CODE, http_status_code);
360 if (http_status_code >= 400 && http_status_code < 600)
361 return true;
362 return false;
365 bool ChromePasswordManagerClient::DidLastPageLoadEncounterSSLErrors() const {
366 content::NavigationEntry* entry =
367 web_contents()->GetController().GetLastCommittedEntry();
368 bool ssl_errors = true;
369 if (!entry) {
370 ssl_errors = false;
371 } else {
372 ssl_errors = net::IsCertStatusError(entry->GetSSL().cert_status);
374 if (IsLoggingActive()) {
375 password_manager::BrowserSavePasswordProgressLogger logger(this);
376 logger.LogBoolean(Logger::STRING_SSL_ERRORS_PRESENT, ssl_errors);
378 return ssl_errors;
381 bool ChromePasswordManagerClient::IsOffTheRecord() const {
382 return web_contents()->GetBrowserContext()->IsOffTheRecord();
385 password_manager::PasswordManager*
386 ChromePasswordManagerClient::GetPasswordManager() {
387 return &password_manager_;
390 autofill::AutofillManager*
391 ChromePasswordManagerClient::GetAutofillManagerForMainFrame() {
392 autofill::ContentAutofillDriverFactory* factory =
393 autofill::ContentAutofillDriverFactory::FromWebContents(web_contents());
394 return factory
395 ? factory->DriverForFrame(web_contents()->GetMainFrame())
396 ->autofill_manager()
397 : nullptr;
400 void ChromePasswordManagerClient::SetTestObserver(
401 autofill::PasswordGenerationPopupObserver* observer) {
402 observer_ = observer;
405 bool ChromePasswordManagerClient::OnMessageReceived(
406 const IPC::Message& message,
407 content::RenderFrameHost* render_frame_host) {
408 bool handled = true;
409 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(ChromePasswordManagerClient, message,
410 render_frame_host)
411 // Autofill messages:
412 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordGenerationPopup,
413 ShowPasswordGenerationPopup)
414 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordEditingPopup,
415 ShowPasswordEditingPopup)
416 IPC_END_MESSAGE_MAP()
418 IPC_BEGIN_MESSAGE_MAP(ChromePasswordManagerClient, message)
419 IPC_MESSAGE_HANDLER(AutofillHostMsg_HidePasswordGenerationPopup,
420 HidePasswordGenerationPopup)
421 IPC_MESSAGE_HANDLER(AutofillHostMsg_GenerationAvailableForForm,
422 GenerationAvailableForForm)
423 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordAutofillAgentConstructed,
424 NotifyRendererOfLoggingAvailability)
425 // Default:
426 IPC_MESSAGE_UNHANDLED(handled = false)
427 IPC_END_MESSAGE_MAP()
429 return handled;
432 gfx::RectF ChromePasswordManagerClient::GetBoundsInScreenSpace(
433 const gfx::RectF& bounds) {
434 gfx::Rect client_area = web_contents()->GetContainerBounds();
435 return bounds + client_area.OffsetFromOrigin();
438 void ChromePasswordManagerClient::ShowPasswordGenerationPopup(
439 content::RenderFrameHost* render_frame_host,
440 const gfx::RectF& bounds,
441 int max_length,
442 const autofill::PasswordForm& form) {
443 // TODO(gcasto): Validate data in PasswordForm.
445 gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds);
447 popup_controller_ =
448 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate(
449 popup_controller_, element_bounds_in_screen_space, form, max_length,
450 &password_manager_,
451 driver_factory_->GetDriverForFrame(render_frame_host), observer_,
452 web_contents(), web_contents()->GetNativeView());
453 popup_controller_->Show(true /* display_password */);
456 void ChromePasswordManagerClient::ShowPasswordEditingPopup(
457 content::RenderFrameHost* render_frame_host,
458 const gfx::RectF& bounds,
459 const autofill::PasswordForm& form) {
460 gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds);
461 popup_controller_ =
462 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate(
463 popup_controller_, element_bounds_in_screen_space, form,
464 0, // Unspecified max length.
465 &password_manager_,
466 driver_factory_->GetDriverForFrame(render_frame_host), observer_,
467 web_contents(), web_contents()->GetNativeView());
468 popup_controller_->Show(false /* display_password */);
471 void ChromePasswordManagerClient::GenerationAvailableForForm(
472 const autofill::PasswordForm& form) {
473 password_manager_.GenerationAvailableForForm(form);
476 void ChromePasswordManagerClient::NotifyRendererOfLoggingAvailability() {
477 if (!web_contents())
478 return;
480 web_contents()->GetRenderViewHost()->Send(new AutofillMsg_SetLoggingState(
481 web_contents()->GetRenderViewHost()->GetRoutingID(),
482 can_use_log_router_));
485 bool ChromePasswordManagerClient::IsURLPasswordWebsiteReauth(
486 const GURL& url) const {
487 if (url.GetOrigin() != GaiaUrls::GetInstance()->gaia_url().GetOrigin())
488 return false;
490 // "rart" param signals this page is for transactional reauth.
491 std::string param_value;
492 if (!net::GetValueForKeyInQuery(url, "rart", &param_value))
493 return false;
495 // Check the "continue" param to see if this reauth page is for the passwords
496 // website.
497 param_value.clear();
498 if (!net::GetValueForKeyInQuery(url, "continue", &param_value))
499 return false;
501 // All password sites, including test sites, have autofilling disabled.
502 CR_DEFINE_STATIC_LOCAL(RE2, account_dashboard_pattern,
503 ("passwords(-([a-z-]+\\.corp))?\\.google\\.com"));
505 return RE2::FullMatch(GURL(param_value).host(), account_dashboard_pattern);
508 bool ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled() {
509 #if !defined(USE_AURA) && !defined(OS_MACOSX)
510 return false;
511 #endif
512 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
513 if (command_line->HasSwitch(switches::kDisableSavePasswordBubble))
514 return false;
516 if (command_line->HasSwitch(switches::kEnableSavePasswordBubble))
517 return true;
519 std::string group_name =
520 base::FieldTrialList::FindFullName("PasswordManagerUI");
522 // The bubble should be the default case that runs on the bots.
523 return group_name != "Infobar";
526 bool ChromePasswordManagerClient::IsUpdatePasswordUIEnabled() const {
527 #if defined(OS_MACOSX)
528 return false;
529 #else
530 return IsTheHotNewBubbleUIEnabled();
531 #endif
534 bool ChromePasswordManagerClient::EnabledForSyncSignin() {
535 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
536 if (command_line->HasSwitch(
537 password_manager::switches::kDisableManagerForSyncSignin))
538 return false;
540 if (command_line->HasSwitch(
541 password_manager::switches::kEnableManagerForSyncSignin))
542 return true;
544 // Default is enabled.
545 std::string group_name =
546 base::FieldTrialList::FindFullName("PasswordManagerStateForSyncSignin");
547 return group_name != "Disabled";
550 const GURL& ChromePasswordManagerClient::GetMainFrameURL() const {
551 return web_contents()->GetVisibleURL();
554 const GURL& ChromePasswordManagerClient::GetLastCommittedEntryURL() const {
555 DCHECK(web_contents());
556 content::NavigationEntry* entry =
557 web_contents()->GetController().GetLastCommittedEntry();
558 if (!entry)
559 return GURL::EmptyGURL();
561 return entry->GetURL();
564 const password_manager::CredentialsFilter*
565 ChromePasswordManagerClient::GetStoreResultFilter() const {
566 return &credentials_filter_;