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 "chrome/browser/password_manager/password_manager_util.h" 12 #include "chrome/browser/password_manager/password_store_factory.h" 13 #include "chrome/browser/password_manager/save_password_infobar_delegate.h" 14 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/sync/profile_sync_service.h" 16 #include "chrome/browser/sync/profile_sync_service_factory.h" 17 #include "chrome/browser/ui/autofill/password_generation_popup_controller_impl.h" 18 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h" 19 #include "chrome/common/chrome_switches.h" 20 #include "chrome/common/chrome_version_info.h" 21 #include "components/autofill/content/common/autofill_messages.h" 22 #include "components/autofill/core/browser/password_generator.h" 23 #include "components/autofill/core/common/password_form.h" 24 #include "components/password_manager/content/browser/password_manager_internals_service_factory.h" 25 #include "components/password_manager/core/browser/log_receiver.h" 26 #include "components/password_manager/core/browser/password_form_manager.h" 27 #include "components/password_manager/core/browser/password_manager.h" 28 #include "components/password_manager/core/browser/password_manager_internals_service.h" 29 #include "components/password_manager/core/browser/password_manager_metrics_util.h" 30 #include "components/password_manager/core/common/password_manager_switches.h" 31 #include "content/public/browser/render_view_host.h" 32 #include "content/public/browser/web_contents.h" 33 34 #if defined(OS_ANDROID) 35 #include "chrome/browser/android/password_authentication_manager.h" 36 #endif // OS_ANDROID 37 38 using password_manager::PasswordManagerInternalsService; 39 using password_manager::PasswordManagerInternalsServiceFactory; 40 41 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromePasswordManagerClient); 42 43 // static 44 void ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient( 45 content::WebContents* contents, 46 autofill::AutofillClient* autofill_client) { 47 if (FromWebContents(contents)) 48 return; 49 50 contents->SetUserData( 51 UserDataKey(), 52 new ChromePasswordManagerClient(contents, autofill_client)); 53 } 54 55 ChromePasswordManagerClient::ChromePasswordManagerClient( 56 content::WebContents* web_contents, 57 autofill::AutofillClient* autofill_client) 58 : content::WebContentsObserver(web_contents), 59 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())), 60 driver_(web_contents, this, autofill_client), 61 observer_(NULL), 62 weak_factory_(this), 63 can_use_log_router_(false) { 64 PasswordManagerInternalsService* service = 65 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_); 66 if (service) 67 can_use_log_router_ = service->RegisterClient(this); 68 } 69 70 ChromePasswordManagerClient::~ChromePasswordManagerClient() { 71 PasswordManagerInternalsService* service = 72 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_); 73 if (service) 74 service->UnregisterClient(this); 75 } 76 77 bool ChromePasswordManagerClient::IsAutomaticPasswordSavingEnabled() const { 78 return CommandLine::ForCurrentProcess()->HasSwitch( 79 password_manager::switches::kEnableAutomaticPasswordSaving) && 80 chrome::VersionInfo::GetChannel() == 81 chrome::VersionInfo::CHANNEL_UNKNOWN; 82 } 83 84 void ChromePasswordManagerClient::PromptUserToSavePassword( 85 password_manager::PasswordFormManager* form_to_save) { 86 if (IsTheHotNewBubbleUIEnabled()) { 87 ManagePasswordsUIController* manage_passwords_ui_controller = 88 ManagePasswordsUIController::FromWebContents(web_contents()); 89 manage_passwords_ui_controller->OnPasswordSubmitted(form_to_save); 90 } else { 91 std::string uma_histogram_suffix( 92 password_manager::metrics_util::GroupIdToString( 93 password_manager::metrics_util::MonitoredDomainGroupId( 94 form_to_save->realm(), GetPrefs()))); 95 SavePasswordInfoBarDelegate::Create( 96 web_contents(), form_to_save, uma_histogram_suffix); 97 } 98 } 99 100 void ChromePasswordManagerClient::PasswordWasAutofilled( 101 const autofill::PasswordFormMap& best_matches) const { 102 ManagePasswordsUIController* manage_passwords_ui_controller = 103 ManagePasswordsUIController::FromWebContents(web_contents()); 104 if (manage_passwords_ui_controller && IsTheHotNewBubbleUIEnabled()) 105 manage_passwords_ui_controller->OnPasswordAutofilled(best_matches); 106 } 107 108 void ChromePasswordManagerClient::PasswordAutofillWasBlocked( 109 const autofill::PasswordFormMap& best_matches) const { 110 ManagePasswordsUIController* controller = 111 ManagePasswordsUIController::FromWebContents(web_contents()); 112 if (controller && IsTheHotNewBubbleUIEnabled()) 113 controller->OnBlacklistBlockedAutofill(best_matches); 114 } 115 116 void ChromePasswordManagerClient::AuthenticateAutofillAndFillForm( 117 scoped_ptr<autofill::PasswordFormFillData> fill_data) { 118 #if defined(OS_ANDROID) 119 PasswordAuthenticationManager::AuthenticatePasswordAutofill( 120 web_contents(), 121 base::Bind(&ChromePasswordManagerClient::CommitFillPasswordForm, 122 weak_factory_.GetWeakPtr(), 123 base::Owned(fill_data.release()))); 124 #else 125 // Additional authentication is currently only available for Android, so all 126 // other plaftorms should just fill the password form directly. 127 CommitFillPasswordForm(fill_data.get()); 128 #endif // OS_ANDROID 129 } 130 131 void ChromePasswordManagerClient::HidePasswordGenerationPopup() { 132 if (popup_controller_) 133 popup_controller_->HideAndDestroy(); 134 } 135 136 PrefService* ChromePasswordManagerClient::GetPrefs() { 137 return profile_->GetPrefs(); 138 } 139 140 password_manager::PasswordStore* 141 ChromePasswordManagerClient::GetPasswordStore() { 142 // Always use EXPLICIT_ACCESS as the password manager checks IsOffTheRecord 143 // itself when it shouldn't access the PasswordStore. 144 // TODO(gcasto): Is is safe to change this to Profile::IMPLICIT_ACCESS? 145 return PasswordStoreFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS) 146 .get(); 147 } 148 149 password_manager::PasswordManagerDriver* 150 ChromePasswordManagerClient::GetDriver() { 151 return &driver_; 152 } 153 154 base::FieldTrial::Probability 155 ChromePasswordManagerClient::GetProbabilityForExperiment( 156 const std::string& experiment_name) { 157 base::FieldTrial::Probability enabled_probability = 0; 158 if (experiment_name == 159 password_manager::PasswordManager::kOtherPossibleUsernamesExperiment) { 160 switch (chrome::VersionInfo::GetChannel()) { 161 case chrome::VersionInfo::CHANNEL_DEV: 162 case chrome::VersionInfo::CHANNEL_BETA: 163 enabled_probability = 50; 164 break; 165 default: 166 break; 167 } 168 } 169 return enabled_probability; 170 } 171 172 bool ChromePasswordManagerClient::IsPasswordSyncEnabled() { 173 ProfileSyncService* sync_service = 174 ProfileSyncServiceFactory::GetForProfile(profile_); 175 // Don't consider sync enabled if the user has a custom passphrase. See 176 // crbug.com/358998 for more details. 177 if (sync_service && 178 sync_service->HasSyncSetupCompleted() && 179 sync_service->sync_initialized() && 180 !sync_service->IsUsingSecondaryPassphrase()) { 181 return sync_service->GetActiveDataTypes().Has(syncer::PASSWORDS); 182 } 183 return false; 184 } 185 186 void ChromePasswordManagerClient::OnLogRouterAvailabilityChanged( 187 bool router_can_be_used) { 188 if (can_use_log_router_ == router_can_be_used) 189 return; 190 can_use_log_router_ = router_can_be_used; 191 192 NotifyRendererOfLoggingAvailability(); 193 } 194 195 void ChromePasswordManagerClient::LogSavePasswordProgress( 196 const std::string& text) { 197 if (!IsLoggingActive()) 198 return; 199 PasswordManagerInternalsService* service = 200 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_); 201 if (service) 202 service->ProcessLog(text); 203 } 204 205 bool ChromePasswordManagerClient::IsLoggingActive() const { 206 // WebUI tabs do not need to log password saving progress. In particular, the 207 // internals page itself should not send any logs. 208 return can_use_log_router_ && !web_contents()->GetWebUI(); 209 } 210 211 // static 212 password_manager::PasswordGenerationManager* 213 ChromePasswordManagerClient::GetGenerationManagerFromWebContents( 214 content::WebContents* contents) { 215 ChromePasswordManagerClient* client = 216 ChromePasswordManagerClient::FromWebContents(contents); 217 if (!client) 218 return NULL; 219 return client->GetDriver()->GetPasswordGenerationManager(); 220 } 221 222 // static 223 password_manager::PasswordManager* 224 ChromePasswordManagerClient::GetManagerFromWebContents( 225 content::WebContents* contents) { 226 ChromePasswordManagerClient* client = 227 ChromePasswordManagerClient::FromWebContents(contents); 228 if (!client) 229 return NULL; 230 return client->GetDriver()->GetPasswordManager(); 231 } 232 233 void ChromePasswordManagerClient::SetTestObserver( 234 autofill::PasswordGenerationPopupObserver* observer) { 235 observer_ = observer; 236 } 237 238 bool ChromePasswordManagerClient::OnMessageReceived( 239 const IPC::Message& message) { 240 bool handled = true; 241 IPC_BEGIN_MESSAGE_MAP(ChromePasswordManagerClient, message) 242 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordGenerationPopup, 243 ShowPasswordGenerationPopup) 244 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordEditingPopup, 245 ShowPasswordEditingPopup) 246 IPC_MESSAGE_HANDLER(AutofillHostMsg_HidePasswordGenerationPopup, 247 HidePasswordGenerationPopup) 248 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordAutofillAgentConstructed, 249 NotifyRendererOfLoggingAvailability) 250 IPC_MESSAGE_UNHANDLED(handled = false) 251 IPC_END_MESSAGE_MAP() 252 return handled; 253 } 254 255 gfx::RectF ChromePasswordManagerClient::GetBoundsInScreenSpace( 256 const gfx::RectF& bounds) { 257 gfx::Rect client_area = web_contents()->GetContainerBounds(); 258 return bounds + client_area.OffsetFromOrigin(); 259 } 260 261 void ChromePasswordManagerClient::ShowPasswordGenerationPopup( 262 const gfx::RectF& bounds, 263 int max_length, 264 const autofill::PasswordForm& form) { 265 // TODO(gcasto): Validate data in PasswordForm. 266 267 // Not yet implemented on other platforms. 268 #if defined(USE_AURA) || defined(OS_MACOSX) 269 gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds); 270 271 popup_controller_ = 272 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate( 273 popup_controller_, 274 element_bounds_in_screen_space, 275 form, 276 max_length, 277 driver_.GetPasswordManager(), 278 observer_, 279 web_contents(), 280 web_contents()->GetNativeView()); 281 popup_controller_->Show(true /* display_password */); 282 #endif // defined(USE_AURA) || defined(OS_MACOSX) 283 } 284 285 void ChromePasswordManagerClient::ShowPasswordEditingPopup( 286 const gfx::RectF& bounds, 287 const autofill::PasswordForm& form) { 288 gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds); 289 // Not yet implemented on other platforms. 290 #if defined(USE_AURA) || defined(OS_MACOSX) 291 popup_controller_ = 292 autofill::PasswordGenerationPopupControllerImpl::GetOrCreate( 293 popup_controller_, 294 element_bounds_in_screen_space, 295 form, 296 0, // Unspecified max length. 297 driver_.GetPasswordManager(), 298 observer_, 299 web_contents(), 300 web_contents()->GetNativeView()); 301 popup_controller_->Show(false /* display_password */); 302 #endif // defined(USE_AURA) || defined(OS_MACOSX) 303 } 304 305 void ChromePasswordManagerClient::NotifyRendererOfLoggingAvailability() { 306 if (!web_contents()) 307 return; 308 309 web_contents()->GetRenderViewHost()->Send(new AutofillMsg_SetLoggingState( 310 web_contents()->GetRenderViewHost()->GetRoutingID(), 311 can_use_log_router_)); 312 } 313 314 void ChromePasswordManagerClient::CommitFillPasswordForm( 315 autofill::PasswordFormFillData* data) { 316 driver_.FillPasswordForm(*data); 317 } 318 319 bool ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled() { 320 #if !defined(USE_AURA) 321 return false; 322 #endif 323 CommandLine* command_line = CommandLine::ForCurrentProcess(); 324 if (command_line->HasSwitch(switches::kDisableSavePasswordBubble)) 325 return false; 326 327 if (command_line->HasSwitch(switches::kEnableSavePasswordBubble)) 328 return true; 329 330 std::string group_name = 331 base::FieldTrialList::FindFullName("PasswordManagerUI"); 332 333 // The bubble should be the default case that runs on the bots. 334 return group_name != "Infobar"; 335 } 336