c5c50bf4136126177d73dbf711fad41cdcd6e35e
[platform/framework/web/crosswalk.git] / src / chrome / browser / password_manager / chrome_password_manager_client.cc
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 "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/password_manager/password_manager_util.h"
13 #include "chrome/browser/password_manager/password_store_factory.h"
14 #include "chrome/browser/password_manager/save_password_infobar_delegate.h"
15 #include "chrome/browser/password_manager/sync_metrics.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/sync/profile_sync_service.h"
18 #include "chrome/browser/sync/profile_sync_service_factory.h"
19 #include "chrome/browser/ui/autofill/password_generation_popup_controller_impl.h"
20 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/chrome_version_info.h"
23 #include "chrome/common/url_constants.h"
24 #include "components/autofill/content/common/autofill_messages.h"
25 #include "components/autofill/core/browser/password_generator.h"
26 #include "components/autofill/core/common/password_form.h"
27 #include "components/password_manager/content/browser/password_manager_internals_service_factory.h"
28 #include "components/password_manager/core/browser/log_receiver.h"
29 #include "components/password_manager/core/browser/password_form_manager.h"
30 #include "components/password_manager/core/browser/password_manager.h"
31 #include "components/password_manager/core/browser/password_manager_internals_service.h"
32 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
33 #include "components/password_manager/core/common/password_manager_switches.h"
34 #include "content/public/browser/navigation_entry.h"
35 #include "content/public/browser/render_view_host.h"
36 #include "content/public/browser/web_contents.h"
37 #include "google_apis/gaia/gaia_urls.h"
38 #include "net/base/url_util.h"
39
40 #if defined(OS_ANDROID)
41 #include "chrome/browser/android/password_authentication_manager.h"
42 #endif  // OS_ANDROID
43
44 using password_manager::PasswordManagerInternalsService;
45 using password_manager::PasswordManagerInternalsServiceFactory;
46
47 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromePasswordManagerClient);
48
49 // static
50 void ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
51     content::WebContents* contents,
52     autofill::AutofillClient* autofill_client) {
53   if (FromWebContents(contents))
54     return;
55
56   contents->SetUserData(
57       UserDataKey(),
58       new ChromePasswordManagerClient(contents, autofill_client));
59 }
60
61 ChromePasswordManagerClient::ChromePasswordManagerClient(
62     content::WebContents* web_contents,
63     autofill::AutofillClient* autofill_client)
64     : content::WebContentsObserver(web_contents),
65       profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
66       driver_(web_contents, this, autofill_client),
67       observer_(NULL),
68       weak_factory_(this),
69       can_use_log_router_(false),
70       autofill_sync_state_(ALLOW_SYNC_CREDENTIALS),
71       sync_credential_was_filtered_(false) {
72   PasswordManagerInternalsService* service =
73       PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
74   if (service)
75     can_use_log_router_ = service->RegisterClient(this);
76   SetUpAutofillSyncState();
77 }
78
79 ChromePasswordManagerClient::~ChromePasswordManagerClient() {
80   PasswordManagerInternalsService* service =
81       PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
82   if (service)
83     service->UnregisterClient(this);
84 }
85
86 bool ChromePasswordManagerClient::IsAutomaticPasswordSavingEnabled() const {
87   return CommandLine::ForCurrentProcess()->HasSwitch(
88       password_manager::switches::kEnableAutomaticPasswordSaving) &&
89          chrome::VersionInfo::GetChannel() ==
90              chrome::VersionInfo::CHANNEL_UNKNOWN;
91 }
92
93 bool ChromePasswordManagerClient::IsPasswordManagerEnabledForCurrentPage()
94     const {
95   if (EnabledForSyncSignin())
96     return true;
97
98   DCHECK(web_contents());
99   content::NavigationEntry* entry =
100       web_contents()->GetController().GetLastCommittedEntry();
101   if (!entry) {
102     // TODO(gcasto): Determine if fix for crbug.com/388246 is relevant here.
103     return true;
104   }
105   // Do not fill nor save password when a user is signing in for sync. This
106   // is because users need to remember their password if they are syncing as
107   // this is effectively their master password.
108   return entry->GetURL().host() != chrome::kChromeUIChromeSigninHost;
109 }
110
111 bool ChromePasswordManagerClient::ShouldFilterAutofillResult(
112     const autofill::PasswordForm& form) {
113   if (!IsSyncAccountCredential(base::UTF16ToUTF8(form.username_value),
114                                form.signon_realm))
115     return false;
116
117   if (autofill_sync_state_ == DISALLOW_SYNC_CREDENTIALS) {
118     sync_credential_was_filtered_ = true;
119     return true;
120   }
121
122   if (autofill_sync_state_ == DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH &&
123       LastLoadWasTransactionalReauthPage()) {
124     sync_credential_was_filtered_ = true;
125     return true;
126   }
127
128   return false;
129 }
130
131 bool ChromePasswordManagerClient::IsSyncAccountCredential(
132     const std::string& username, const std::string& origin) const {
133   return password_manager_sync_metrics::IsSyncAccountCredential(
134       profile_, username, origin);
135 }
136
137 void ChromePasswordManagerClient::AutofillResultsComputed() {
138   UMA_HISTOGRAM_BOOLEAN("PasswordManager.SyncCredentialFiltered",
139                         sync_credential_was_filtered_);
140   sync_credential_was_filtered_ = false;
141 }
142
143 void ChromePasswordManagerClient::PromptUserToSavePassword(
144     scoped_ptr<password_manager::PasswordFormManager> form_to_save) {
145   if (IsTheHotNewBubbleUIEnabled()) {
146     ManagePasswordsUIController* manage_passwords_ui_controller =
147         ManagePasswordsUIController::FromWebContents(web_contents());
148     manage_passwords_ui_controller->OnPasswordSubmitted(form_to_save.Pass());
149   } else {
150     std::string uma_histogram_suffix(
151         password_manager::metrics_util::GroupIdToString(
152             password_manager::metrics_util::MonitoredDomainGroupId(
153                 form_to_save->realm(), GetPrefs())));
154     SavePasswordInfoBarDelegate::Create(
155         web_contents(), form_to_save.Pass(), uma_histogram_suffix);
156   }
157 }
158
159 void ChromePasswordManagerClient::AutomaticPasswordSave(
160     scoped_ptr<password_manager::PasswordFormManager> saved_form) {
161   if (IsTheHotNewBubbleUIEnabled()) {
162     ManagePasswordsUIController* manage_passwords_ui_controller =
163         ManagePasswordsUIController::FromWebContents(web_contents());
164     manage_passwords_ui_controller->OnAutomaticPasswordSave(
165         saved_form.Pass());
166   }
167 }
168
169 void ChromePasswordManagerClient::PasswordWasAutofilled(
170     const autofill::PasswordFormMap& best_matches) const {
171   ManagePasswordsUIController* manage_passwords_ui_controller =
172       ManagePasswordsUIController::FromWebContents(web_contents());
173   if (manage_passwords_ui_controller && IsTheHotNewBubbleUIEnabled())
174     manage_passwords_ui_controller->OnPasswordAutofilled(best_matches);
175 }
176
177 void ChromePasswordManagerClient::PasswordAutofillWasBlocked(
178     const autofill::PasswordFormMap& best_matches) const {
179   ManagePasswordsUIController* controller =
180       ManagePasswordsUIController::FromWebContents(web_contents());
181   if (controller && IsTheHotNewBubbleUIEnabled())
182     controller->OnBlacklistBlockedAutofill(best_matches);
183 }
184
185 void ChromePasswordManagerClient::AuthenticateAutofillAndFillForm(
186       scoped_ptr<autofill::PasswordFormFillData> fill_data) {
187 #if defined(OS_ANDROID)
188   PasswordAuthenticationManager::AuthenticatePasswordAutofill(
189       web_contents(),
190       base::Bind(&ChromePasswordManagerClient::CommitFillPasswordForm,
191                  weak_factory_.GetWeakPtr(),
192                  base::Owned(fill_data.release())));
193 #else
194   // Additional authentication is currently only available for Android, so all
195   // other plaftorms should just fill the password form directly.
196   CommitFillPasswordForm(fill_data.get());
197 #endif  // OS_ANDROID
198 }
199
200 void ChromePasswordManagerClient::HidePasswordGenerationPopup() {
201   if (popup_controller_)
202     popup_controller_->HideAndDestroy();
203 }
204
205 PrefService* ChromePasswordManagerClient::GetPrefs() {
206   return profile_->GetPrefs();
207 }
208
209 password_manager::PasswordStore*
210 ChromePasswordManagerClient::GetPasswordStore() {
211   // Always use EXPLICIT_ACCESS as the password manager checks IsOffTheRecord
212   // itself when it shouldn't access the PasswordStore.
213   // TODO(gcasto): Is is safe to change this to Profile::IMPLICIT_ACCESS?
214   return PasswordStoreFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS)
215       .get();
216 }
217
218 password_manager::PasswordManagerDriver*
219 ChromePasswordManagerClient::GetDriver() {
220   return &driver_;
221 }
222
223 base::FieldTrial::Probability
224 ChromePasswordManagerClient::GetProbabilityForExperiment(
225     const std::string& experiment_name) {
226   base::FieldTrial::Probability enabled_probability = 0;
227   if (experiment_name ==
228       password_manager::PasswordManager::kOtherPossibleUsernamesExperiment) {
229     switch (chrome::VersionInfo::GetChannel()) {
230       case chrome::VersionInfo::CHANNEL_DEV:
231       case chrome::VersionInfo::CHANNEL_BETA:
232         enabled_probability = 50;
233         break;
234       default:
235         break;
236     }
237   }
238   return enabled_probability;
239 }
240
241 bool ChromePasswordManagerClient::IsPasswordSyncEnabled() {
242   ProfileSyncService* sync_service =
243       ProfileSyncServiceFactory::GetForProfile(profile_);
244   // Don't consider sync enabled if the user has a custom passphrase. See
245   // crbug.com/358998 for more details.
246   if (sync_service &&
247       sync_service->HasSyncSetupCompleted() &&
248       sync_service->sync_initialized() &&
249       !sync_service->IsUsingSecondaryPassphrase()) {
250     return sync_service->GetActiveDataTypes().Has(syncer::PASSWORDS);
251   }
252   return false;
253 }
254
255 void ChromePasswordManagerClient::OnLogRouterAvailabilityChanged(
256     bool router_can_be_used) {
257   if (can_use_log_router_ == router_can_be_used)
258     return;
259   can_use_log_router_ = router_can_be_used;
260
261   NotifyRendererOfLoggingAvailability();
262 }
263
264 void ChromePasswordManagerClient::LogSavePasswordProgress(
265     const std::string& text) {
266   if (!IsLoggingActive())
267     return;
268   PasswordManagerInternalsService* service =
269       PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_);
270   if (service)
271     service->ProcessLog(text);
272 }
273
274 bool ChromePasswordManagerClient::IsLoggingActive() const {
275   // WebUI tabs do not need to log password saving progress. In particular, the
276   // internals page itself should not send any logs.
277   return can_use_log_router_ && !web_contents()->GetWebUI();
278 }
279
280 // static
281 password_manager::PasswordGenerationManager*
282 ChromePasswordManagerClient::GetGenerationManagerFromWebContents(
283     content::WebContents* contents) {
284   ChromePasswordManagerClient* client =
285       ChromePasswordManagerClient::FromWebContents(contents);
286   if (!client)
287     return NULL;
288   return client->GetDriver()->GetPasswordGenerationManager();
289 }
290
291 // static
292 password_manager::PasswordManager*
293 ChromePasswordManagerClient::GetManagerFromWebContents(
294     content::WebContents* contents) {
295   ChromePasswordManagerClient* client =
296       ChromePasswordManagerClient::FromWebContents(contents);
297   if (!client)
298     return NULL;
299   return client->GetDriver()->GetPasswordManager();
300 }
301
302 void ChromePasswordManagerClient::SetTestObserver(
303     autofill::PasswordGenerationPopupObserver* observer) {
304   observer_ = observer;
305 }
306
307 bool ChromePasswordManagerClient::OnMessageReceived(
308     const IPC::Message& message) {
309   bool handled = true;
310   IPC_BEGIN_MESSAGE_MAP(ChromePasswordManagerClient, message)
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)
319     IPC_MESSAGE_UNHANDLED(handled = false)
320   IPC_END_MESSAGE_MAP()
321   return handled;
322 }
323
324 gfx::RectF ChromePasswordManagerClient::GetBoundsInScreenSpace(
325     const gfx::RectF& bounds) {
326   gfx::Rect client_area = web_contents()->GetContainerBounds();
327   return bounds + client_area.OffsetFromOrigin();
328 }
329
330 void ChromePasswordManagerClient::ShowPasswordGenerationPopup(
331     const gfx::RectF& bounds,
332     int max_length,
333     const autofill::PasswordForm& form) {
334   // TODO(gcasto): Validate data in PasswordForm.
335
336   // Not yet implemented on other platforms.
337 #if defined(USE_AURA) || defined(OS_MACOSX)
338   gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds);
339
340   popup_controller_ =
341       autofill::PasswordGenerationPopupControllerImpl::GetOrCreate(
342           popup_controller_,
343           element_bounds_in_screen_space,
344           form,
345           max_length,
346           driver_.GetPasswordManager(),
347           observer_,
348           web_contents(),
349           web_contents()->GetNativeView());
350   popup_controller_->Show(true /* display_password */);
351 #endif  // defined(USE_AURA) || defined(OS_MACOSX)
352 }
353
354 void ChromePasswordManagerClient::ShowPasswordEditingPopup(
355     const gfx::RectF& bounds,
356     const autofill::PasswordForm& form) {
357   gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds);
358   // Not yet implemented on other platforms.
359 #if defined(USE_AURA) || defined(OS_MACOSX)
360   popup_controller_ =
361       autofill::PasswordGenerationPopupControllerImpl::GetOrCreate(
362           popup_controller_,
363           element_bounds_in_screen_space,
364           form,
365           0,  // Unspecified max length.
366           driver_.GetPasswordManager(),
367           observer_,
368           web_contents(),
369           web_contents()->GetNativeView());
370   popup_controller_->Show(false /* display_password */);
371 #endif  // defined(USE_AURA) || defined(OS_MACOSX)
372 }
373
374 void ChromePasswordManagerClient::NotifyRendererOfLoggingAvailability() {
375   if (!web_contents())
376     return;
377
378   web_contents()->GetRenderViewHost()->Send(new AutofillMsg_SetLoggingState(
379       web_contents()->GetRenderViewHost()->GetRoutingID(),
380       can_use_log_router_));
381 }
382
383 void ChromePasswordManagerClient::CommitFillPasswordForm(
384     autofill::PasswordFormFillData* data) {
385   driver_.FillPasswordForm(*data);
386 }
387
388 bool ChromePasswordManagerClient::LastLoadWasTransactionalReauthPage() const {
389   DCHECK(web_contents());
390   content::NavigationEntry* entry =
391       web_contents()->GetController().GetLastCommittedEntry();
392   if (!entry)
393     return false;
394
395   if (entry->GetURL().GetOrigin() !=
396       GaiaUrls::GetInstance()->gaia_url().GetOrigin())
397     return false;
398
399   // "rart" is the transactional reauth paramter.
400   std::string ignored_value;
401   return net::GetValueForKeyInQuery(entry->GetURL(),
402                                     "rart",
403                                     &ignored_value);
404 }
405
406 bool ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled() {
407 #if !defined(USE_AURA)
408   return false;
409 #endif
410   CommandLine* command_line = CommandLine::ForCurrentProcess();
411   if (command_line->HasSwitch(switches::kDisableSavePasswordBubble))
412     return false;
413
414   if (command_line->HasSwitch(switches::kEnableSavePasswordBubble))
415     return true;
416
417   std::string group_name =
418       base::FieldTrialList::FindFullName("PasswordManagerUI");
419
420   // The bubble should be the default case that runs on the bots.
421   return group_name != "Infobar";
422 }
423
424 bool ChromePasswordManagerClient::EnabledForSyncSignin() {
425   CommandLine* command_line = CommandLine::ForCurrentProcess();
426   if (command_line->HasSwitch(
427           password_manager::switches::kDisableManagerForSyncSignin))
428     return false;
429
430   if (command_line->HasSwitch(
431           password_manager::switches::kEnableManagerForSyncSignin))
432     return true;
433
434   // Default is enabled.
435   std::string group_name =
436       base::FieldTrialList::FindFullName("PasswordManagerStateForSyncSignin");
437   return group_name != "Disabled";
438 }
439
440 void ChromePasswordManagerClient::SetUpAutofillSyncState() {
441   std::string group_name =
442       base::FieldTrialList::FindFullName("AutofillSyncCredential");
443
444   CommandLine* command_line = CommandLine::ForCurrentProcess();
445   if (command_line->HasSwitch(
446           password_manager::switches::kAllowAutofillSyncCredential)) {
447     autofill_sync_state_ = ALLOW_SYNC_CREDENTIALS;
448     return;
449   }
450   if (command_line->HasSwitch(
451           password_manager::switches::
452           kDisallowAutofillSyncCredentialForReauth)) {
453     autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH;
454     return;
455   }
456   if (command_line->HasSwitch(
457           password_manager::switches::kDisallowAutofillSyncCredential)) {
458     autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS;
459     return;
460   }
461
462   if (group_name == "DisallowSyncCredentialsForReauth") {
463     autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH;
464   } else if (group_name == "DisallowSyncCredentials") {
465       autofill_sync_state_ = DISALLOW_SYNC_CREDENTIALS;
466   } else {
467     // Allow by default.
468     autofill_sync_state_ = ALLOW_SYNC_CREDENTIALS;
469   }
470 }