• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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