Chromium Code Reviews| Index: chrome/browser/signin/one_click_signin.cc |
| =================================================================== |
| --- chrome/browser/signin/one_click_signin.cc (revision 0) |
| +++ chrome/browser/signin/one_click_signin.cc (revision 0) |
| @@ -0,0 +1,334 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/signin/one_click_signin.h" |
| + |
| +#include "base/metrics/histogram.h" |
| +#include "base/string_split.h" |
| +#include "base/utf_string_conversions.h" |
| +#include "chrome/browser/google/google_util.h" |
| +#include "chrome/browser/infobars/infobar_tab_helper.h" |
| +#include "chrome/browser/prefs/pref_service.h" |
| +#include "chrome/browser/profiles/profile.h" |
| +#include "chrome/browser/signin/signin_manager.h" |
| +#include "chrome/browser/signin/signin_manager_factory.h" |
| +#include "chrome/browser/sync/profile_sync_service.h" |
| +#include "chrome/browser/sync/profile_sync_service_factory.h" |
| +#include "chrome/browser/tab_contents/confirm_infobar_delegate.h" |
| +#include "chrome/browser/tab_contents/tab_util.h" |
| +#include "chrome/browser/ui/one_click_signin_dialog.h" |
| +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| +#include "chrome/browser/ui/webui/signin/login_ui_service.h" |
| +#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" |
| +#include "chrome/common/chrome_notification_types.h" |
| +#include "chrome/common/pref_names.h" |
| +#include "chrome/common/url_constants.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/notification_source.h" |
| +#include "content/public/browser/page_navigator.h" |
| +#include "content/public/browser/web_contents.h" |
| +#include "content/public/common/frame_navigate_params.h" |
| +#include "grit/chromium_strings.h" |
| +#include "grit/generated_resources.h" |
| +#include "grit/theme_resources_standard.h" |
| +#include "net/base/cookie_monster.h" |
| +#include "net/http/http_response_headers.h" |
| +#include "net/url_request/url_request.h" |
| +#include "ui/base/l10n/l10n_util.h" |
| +#include "ui/base/resource/resource_bundle.h" |
| + |
| +namespace { |
| +// Enum values used for UMA histograms. |
| +enum { |
| + // The infobar was shown to the user. |
| + HISTOGRAM_SHOWN, |
| + |
| + // The user pressed the accept button to perform the suggested action. |
| + HISTOGRAM_ACCEPTED, |
| + |
| + // The user pressed the reject to turn off the feature. |
| + HISTOGRAM_REJECTED, |
| + |
| + // The user pressed the X button to dismiss the infobar this time. |
| + HISTOGRAM_DISMISSED, |
| + |
| + // The user completely ignored the infoar. Either they navigated away, or |
| + // they used the page as is. |
| + HISTOGRAM_IGNORED, |
| + |
| + // The user clicked on the learn more link in the infobar. |
| + HISTOGRAM_LEARN_MORE, |
| + |
| + HISTOGRAM_MAX |
| +}; |
| + |
| +// The infobar asking the user if they want to use one-click sign in. |
| +class OneClickLoginInfoBarDelegate : public ConfirmInfoBarDelegate { |
| + public: |
| + OneClickLoginInfoBarDelegate(InfoBarTabHelper* owner, |
| + const std::string& email, |
| + const std::string& password); |
| + virtual ~OneClickLoginInfoBarDelegate(); |
| + |
| + private: |
| + // ConfirmInfoBarDelegate overrides. |
| + virtual void InfoBarDismissed() OVERRIDE; |
| + virtual gfx::Image* GetIcon() const OVERRIDE; |
| + virtual Type GetInfoBarType() const OVERRIDE; |
| + virtual string16 GetMessageText() const OVERRIDE; |
| + virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE; |
| + virtual bool Accept() OVERRIDE; |
| + virtual bool Cancel() OVERRIDE; |
| + |
| + void RecordHistogramAction(int action); |
| + |
| + Profile* profile_; |
| + |
| + // Email address and password of the account that has just logged in. |
| + std::string email_; |
| + std::string password_; |
| + |
| + // Whether any UI controls in the infobar were pressed or not. |
| + bool button_pressed_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(OneClickLoginInfoBarDelegate); |
| +}; |
| + |
| +OneClickLoginInfoBarDelegate::OneClickLoginInfoBarDelegate( |
| + InfoBarTabHelper* owner, |
| + const std::string& email, |
| + const std::string& password) |
| + : ConfirmInfoBarDelegate(owner), |
| + profile_(Profile::FromBrowserContext( |
| + owner->web_contents()->GetBrowserContext())), |
| + email_(email), |
| + password_(password), |
| + button_pressed_(false) { |
| + DCHECK(profile_); |
| + RecordHistogramAction(HISTOGRAM_SHOWN); |
| +} |
| + |
| +OneClickLoginInfoBarDelegate::~OneClickLoginInfoBarDelegate() { |
| + if (!button_pressed_) |
| + RecordHistogramAction(HISTOGRAM_IGNORED); |
| +} |
| + |
| +void OneClickLoginInfoBarDelegate::InfoBarDismissed() { |
| + RecordHistogramAction(HISTOGRAM_DISMISSED); |
| + button_pressed_ = true; |
| +} |
| + |
| +gfx::Image* OneClickLoginInfoBarDelegate::GetIcon() const { |
| + return &ResourceBundle::GetSharedInstance().GetNativeImageNamed( |
| + IDR_INFOBAR_AUTOLOGIN); |
| +} |
| + |
| +InfoBarDelegate::Type OneClickLoginInfoBarDelegate::GetInfoBarType() const { |
| + return PAGE_ACTION_TYPE; |
| +} |
| + |
| +string16 OneClickLoginInfoBarDelegate::GetMessageText() const { |
| + return l10n_util::GetStringUTF16(IDS_ONE_CLICK_SIGNIN_INFOBAR_MESSAGE); |
| +} |
| + |
| +string16 OneClickLoginInfoBarDelegate::GetButtonLabel( |
| + InfoBarButton button) const { |
| + return l10n_util::GetStringUTF16((button == BUTTON_OK) ? |
| + IDS_OK : IDS_ONE_CLICK_SIGNIN_INFOBAR_CANCEL_BUTTON); |
| +} |
| + |
| +bool OneClickLoginInfoBarDelegate::Accept() { |
| + RecordHistogramAction(HISTOGRAM_ACCEPTED); |
| + ShowOneClickSigninDialog(profile_, email_, password_); |
| + button_pressed_ = true; |
| + return true; |
| +} |
| + |
| +bool OneClickLoginInfoBarDelegate::Cancel() { |
| + PrefService* pref_service = |
| + TabContentsWrapper::GetCurrentWrapperForContents( |
| + owner()->web_contents())->profile()->GetPrefs(); |
| + pref_service->SetBoolean(prefs::kReverseAutologinEnabled, false); |
| + RecordHistogramAction(HISTOGRAM_REJECTED); |
| + button_pressed_ = true; |
| + return true; |
| +} |
| + |
| +void OneClickLoginInfoBarDelegate::RecordHistogramAction(int action) { |
| + UMA_HISTOGRAM_ENUMERATION("AutoLogin.Reverse", action, HISTOGRAM_MAX); |
| +} |
| + |
| +} // namespace |
| + |
| +// static |
| +bool OneClickSigninManager::CanOffer(content::WebContents* web_contents) { |
| + return !web_contents->GetBrowserContext()->IsOffTheRecord(); |
| +} |
| + |
| +// static |
| +void OneClickSigninManager::ShowInfoBarIfPossible(net::URLRequest* request, |
| + int child_id, |
| + int route_id) { |
| + // See if the response contains the X-Google-Accounts-SignIn header. |
| + std::string value; |
| + request->GetResponseHeaderByName("X-Google-Accounts-SignIn", &value); |
| + if (value.empty()) |
| + return; |
| + |
| + std::vector<std::pair<std::string, std::string> > pairs; |
| + if (!base::SplitStringIntoKeyValuePairs(value, '=', ',', &pairs)) |
| + return; |
| + |
| + // Parse the information from the value string. |
| + std::string email; |
| + for (size_t i = 0; i < pairs.size(); ++i) { |
| + const std::pair<std::string, std::string>& pair = pairs[i]; |
| + if (pair.first == "email") |
| + TrimString(pair.second, "\"", &email); |
| + } |
| + |
| + if (email.empty()) |
| + return; |
| + |
| + content::BrowserThread::PostTask( |
| + content::BrowserThread::UI, FROM_HERE, |
| + base::Bind(&OneClickSigninManager::ShowInfoBarUIThread, email, |
| + child_id, route_id)); |
| +} |
| + |
| +OneClickSigninManager::OneClickSigninManager(content::WebContents* web_contents) |
| + : content::WebContentsObserver(web_contents) { |
| +} |
| + |
| +OneClickSigninManager::~OneClickSigninManager() { |
| +} |
| + |
| +// static |
| +void OneClickSigninManager::ShowInfoBarUIThread( |
| + const std::string& email, |
| + int child_id, |
| + int route_id) { |
| + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| + |
| + content::WebContents* web_contents = tab_util::GetWebContentsByID(child_id, |
| + route_id); |
| + if (!web_contents) |
| + return; |
| + |
| + Profile* profile = |
| + Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| + |
| + if (!ProfileSyncService::IsSyncEnabled()) |
| + return; |
| + |
| + ProfileSyncService* service = |
| + ProfileSyncServiceFactory::GetForProfile(profile); |
| + |
| + if (!profile->GetPrefs()->GetBoolean(prefs::kReverseAutologinEnabled) || |
| + service->AreCredentialsAvailable()) |
| + return; |
| + |
| + TabContentsWrapper* wrapper = |
| + TabContentsWrapper::GetCurrentWrapperForContents(web_contents); |
| + if (!wrapper) |
| + return; |
| + |
| + // TODO(rogerta): remove this #if once the dialog is fully implemented for |
| + // mac and linux. |
| +#if defined(ENABLE_ONE_CLICK_SIGNIN) |
| + // Save the email in the one-click signin manager. The manager may |
| + // not exist if the contents is incognito or if the profile is already |
| + // connected to a Google account. |
| + OneClickSigninManager* manager = wrapper->one_click_signin_manager(); |
| + if (manager) |
| + manager->SaveEmail(email); |
| +#endif |
| +} |
| + |
| +void OneClickSigninManager::DidNavigateAnyFrame( |
| + const content::LoadCommittedDetails& details, |
| + const content::FrameNavigateParams& params) { |
| + if (params.password_form.origin.is_valid()) |
| + SavePassword(params.password_form); |
| +} |
| + |
| +void OneClickSigninManager::DidStopLoading() { |
| + if (email_.empty() || password_.empty()) |
| + return; |
| + |
| + TabContentsWrapper* wrapper = |
| + TabContentsWrapper::GetCurrentWrapperForContents(web_contents()); |
| + |
| + wrapper->infobar_tab_helper()->AddInfoBar( |
| + new OneClickLoginInfoBarDelegate(wrapper->infobar_tab_helper(), |
| + email_, password_)); |
| + |
| + email_.clear(); |
| + password_.clear(); |
| +} |
| + |
| +void OneClickSigninManager::SaveEmail(const std::string& email) { |
| + // TODO(rogerta): validate that the email address is the same as set in |
| + // the form? |
| + email_ = email; |
| +} |
| + |
| +void OneClickSigninManager::SavePassword( |
| + const webkit::forms::PasswordForm& form) { |
| + // TODO(rogerta): validate that the email address in the form is the same |
| + // as set by SaveEmail? |
| + |
| + // TODO(rogerta): in the case of a 2-factor or captcha or some other type of |
| + // challenge, its possible for the user to never complete the signin. |
| + // Should have a way to detect this and clear the password member. |
| + |
| + // TODO(rogerta): need to make sure this works with multi-login enabled |
| + // accounts. In particular, of the user is already longged into one |
| + // account, adds a second account to the session and decides to connect |
| + // his profile with that one, make sure we use the right account. |
| + password_ = UTF16ToUTF8(form.password_value); |
| +} |
| + |
| + |
| +OneClickSigninSyncStarter::OneClickSigninSyncStarter( |
| + const std::string& email, |
| + const std::string& password, |
| + Profile* profile, |
| + bool use_default_settings) |
| + : profile_(profile), |
| + signin_tracker_(profile, this), |
| + use_default_settings_(use_default_settings) { |
| + DCHECK(profile_); |
| + |
| + SigninManager* manager = SigninManagerFactory::GetForProfile(profile_); |
| + manager->StartSignInWithCredentials(email, password); |
| +} |
| + |
| +OneClickSigninSyncStarter::~OneClickSigninSyncStarter() { |
| +} |
| + |
| +void OneClickSigninSyncStarter::GaiaCredentialsValid() { |
| +} |
| + |
| +void OneClickSigninSyncStarter::SigninFailed() { |
| + delete this; |
| +} |
| + |
| +void OneClickSigninSyncStarter::SigninSuccess() { |
| + ProfileSyncService* profile_sync_service = |
| + ProfileSyncServiceFactory::GetForProfile(profile_); |
| + profile_sync_service->SetSyncSetupCompleted(); |
| + |
| + if (use_default_settings_) { |
| + // Just kick off the sync machine, no need to configure it first. |
| + profile_sync_service->UnsuppressAndStart(); |
| + } else { |
| + // Give the user a chance to configure things. |
| + LoginUIService* login_ui_service = |
| + LoginUIServiceFactory::GetForProfile(profile_); |
| + login_ui_service->ShowLoginUI(); |
|
Andrew T Wilson (Slow)
2012/03/02 19:14:01
BTW, I think there's going to be a bug here, if yo
Roger Tawa OOO till Jul 10th
2012/03/02 22:32:47
Done.
|
| + } |
| + |
| + delete this; |
| +} |
| Property changes on: chrome\browser\signin\one_click_signin.cc |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |