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
CreateForWebContentsWithAutofillClient(content::WebContents * contents,autofill::AutofillClient * autofill_client)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
ChromePasswordManagerClient(content::WebContents * web_contents,autofill::AutofillClient * autofill_client)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
~ChromePasswordManagerClient()70 ChromePasswordManagerClient::~ChromePasswordManagerClient() {
71 PasswordManagerInternalsService* service =
72 PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
73 if (service)
74 service->UnregisterClient(this);
75 }
76
IsAutomaticPasswordSavingEnabled() const77 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
PromptUserToSavePassword(password_manager::PasswordFormManager * form_to_save)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
PasswordWasAutofilled(const autofill::PasswordFormMap & best_matches) const100 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
PasswordAutofillWasBlocked(const autofill::PasswordFormMap & best_matches) const108 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
AuthenticateAutofillAndFillForm(scoped_ptr<autofill::PasswordFormFillData> fill_data)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
HidePasswordGenerationPopup()131 void ChromePasswordManagerClient::HidePasswordGenerationPopup() {
132 if (popup_controller_)
133 popup_controller_->HideAndDestroy();
134 }
135
GetPrefs()136 PrefService* ChromePasswordManagerClient::GetPrefs() {
137 return profile_->GetPrefs();
138 }
139
140 password_manager::PasswordStore*
GetPasswordStore()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*
GetDriver()150 ChromePasswordManagerClient::GetDriver() {
151 return &driver_;
152 }
153
154 base::FieldTrial::Probability
GetProbabilityForExperiment(const std::string & experiment_name)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
IsPasswordSyncEnabled()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
OnLogRouterAvailabilityChanged(bool router_can_be_used)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
LogSavePasswordProgress(const std::string & text)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
IsLoggingActive() const205 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*
GetGenerationManagerFromWebContents(content::WebContents * contents)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*
GetManagerFromWebContents(content::WebContents * contents)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
SetTestObserver(autofill::PasswordGenerationPopupObserver * observer)233 void ChromePasswordManagerClient::SetTestObserver(
234 autofill::PasswordGenerationPopupObserver* observer) {
235 observer_ = observer;
236 }
237
OnMessageReceived(const IPC::Message & message)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
GetBoundsInScreenSpace(const gfx::RectF & bounds)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
ShowPasswordGenerationPopup(const gfx::RectF & bounds,int max_length,const autofill::PasswordForm & form)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
ShowPasswordEditingPopup(const gfx::RectF & bounds,const autofill::PasswordForm & form)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
NotifyRendererOfLoggingAvailability()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
CommitFillPasswordForm(autofill::PasswordFormFillData * data)314 void ChromePasswordManagerClient::CommitFillPasswordForm(
315 autofill::PasswordFormFillData* data) {
316 driver_.FillPasswordForm(*data);
317 }
318
IsTheHotNewBubbleUIEnabled()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