Commit 70ebea88 authored by mathp@google.com's avatar mathp@google.com

Address bug where the one-click sign-in bar would never show again once

a user (with associated profile) had clicked "Cancel". New behavior
is that we now remember for which email the bar was dismissed, and show
it again in case the user signs in with a different email. If the user
accepts the one-click sign-in at one point, the bar never shows again
for this profile

BUG=118280
TEST=Cancel the one-click sign-in bar, log-in with another Google account,
see that it still shows up.

Review URL: https://chromiumcodereview.appspot.com/10555005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@148760 0039d316-1c4b-4281-b951-d872f2087c98
parent c054444a
...@@ -104,6 +104,11 @@ class PasswordFormManager : public PasswordStoreConsumer { ...@@ -104,6 +104,11 @@ class PasswordFormManager : public PasswordStoreConsumer {
void SubmitPassed(); void SubmitPassed();
void SubmitFailed(); void SubmitFailed();
// Return the username associated with the credentials.
const string16& associated_username() const {
return pending_credentials_.username_value;
}
// Returns the realm URL for the form managed my this manager. // Returns the realm URL for the form managed my this manager.
const std::string& realm() const { const std::string& realm() const {
return pending_credentials_.signon_realm; return pending_credentials_.signon_realm;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "base/metrics/histogram.h" #include "base/metrics/histogram.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_manager.h" #include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/infobars/infobar_tab_helper.h" #include "chrome/browser/infobars/infobar_tab_helper.h"
#include "chrome/browser/password_manager/password_form_manager.h" #include "chrome/browser/password_manager/password_form_manager.h"
...@@ -139,8 +140,12 @@ void PasswordManagerDelegateImpl::AddSavePasswordInfoBarIfPermitted( ...@@ -139,8 +140,12 @@ void PasswordManagerDelegateImpl::AddSavePasswordInfoBarIfPermitted(
// For now, one-click signin is fully implemented only on windows. // For now, one-click signin is fully implemented only on windows.
#if defined(ENABLE_ONE_CLICK_SIGNIN) #if defined(ENABLE_ONE_CLICK_SIGNIN)
GURL realm(form_to_save->realm()); GURL realm(form_to_save->realm());
if (realm == GURL(GaiaUrls::GetInstance()->gaia_login_form_realm()) && // TODO(mathp): Checking only against associated_username() causes a bug
OneClickSigninHelper::CanOffer(tab_contents_->web_contents(), true)) { // referenced here: crbug.com/133275
if ((realm == GURL(GaiaUrls::GetInstance()->gaia_login_form_realm()) ||
realm == GURL("https://www.google.com/")) &&
OneClickSigninHelper::CanOffer(tab_contents_->web_contents(),
UTF16ToUTF8(form_to_save->associated_username()), true)) {
return; return;
} }
#endif #endif
......
...@@ -36,6 +36,8 @@ void SigninManagerFactory::RegisterUserPrefs(PrefService* user_prefs) { ...@@ -36,6 +36,8 @@ void SigninManagerFactory::RegisterUserPrefs(PrefService* user_prefs) {
PrefService::UNSYNCABLE_PREF); PrefService::UNSYNCABLE_PREF);
user_prefs->RegisterBooleanPref(prefs::kReverseAutologinEnabled, true, user_prefs->RegisterBooleanPref(prefs::kReverseAutologinEnabled, true,
PrefService::UNSYNCABLE_PREF); PrefService::UNSYNCABLE_PREF);
user_prefs->RegisterListPref(prefs::kReverseAutologinRejectedEmailList,
new ListValue, PrefService::UNSYNCABLE_PREF);
user_prefs->RegisterBooleanPref(prefs::kIsGooglePlusUser, false, user_prefs->RegisterBooleanPref(prefs::kIsGooglePlusUser, false,
PrefService::UNSYNCABLE_PREF); PrefService::UNSYNCABLE_PREF);
} }
......
...@@ -12,13 +12,13 @@ ...@@ -12,13 +12,13 @@
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/infobars/infobar_tab_helper.h" #include "chrome/browser/infobars/infobar_tab_helper.h"
#include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_info_cache.h" #include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/signin/signin_manager.h" #include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/sync/profile_sync_service.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/confirm_infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_util.h" #include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_finder.h"
...@@ -72,6 +72,10 @@ class OneClickLoginInfoBarDelegate : public ConfirmInfoBarDelegate { ...@@ -72,6 +72,10 @@ class OneClickLoginInfoBarDelegate : public ConfirmInfoBarDelegate {
// show again in this profile. // show again in this profile.
void DisableOneClickSignIn(); void DisableOneClickSignIn();
// Add a specific email to the list of emails rejected for one-click
// sign-in, for this profile.
void AddEmailToOneClickRejectedList(const std::string& email);
// Record the specified action in the histogram for one-click sign in. // Record the specified action in the histogram for one-click sign in.
void RecordHistogramAction(int action); void RecordHistogramAction(int action);
...@@ -146,6 +150,8 @@ void StartSync(content::WebContents* web_contents, ...@@ -146,6 +150,8 @@ void StartSync(content::WebContents* web_contents,
} // namespace } // namespace
bool OneClickLoginInfoBarDelegate::Accept() { bool OneClickLoginInfoBarDelegate::Accept() {
// User has accepted one-click sign-in for this account. Never ask again for
// this profile.
DisableOneClickSignIn(); DisableOneClickSignIn();
content::WebContents* web_contents = owner()->web_contents(); content::WebContents* web_contents = owner()->web_contents();
RecordHistogramAction(one_click_signin::HISTOGRAM_ACCEPTED); RecordHistogramAction(one_click_signin::HISTOGRAM_ACCEPTED);
...@@ -157,7 +163,7 @@ bool OneClickLoginInfoBarDelegate::Accept() { ...@@ -157,7 +163,7 @@ bool OneClickLoginInfoBarDelegate::Accept() {
} }
bool OneClickLoginInfoBarDelegate::Cancel() { bool OneClickLoginInfoBarDelegate::Cancel() {
DisableOneClickSignIn(); AddEmailToOneClickRejectedList(email_);
RecordHistogramAction(one_click_signin::HISTOGRAM_REJECTED); RecordHistogramAction(one_click_signin::HISTOGRAM_REJECTED);
button_pressed_ = true; button_pressed_ = true;
return true; return true;
...@@ -190,6 +196,16 @@ void OneClickLoginInfoBarDelegate::DisableOneClickSignIn() { ...@@ -190,6 +196,16 @@ void OneClickLoginInfoBarDelegate::DisableOneClickSignIn() {
pref_service->SetBoolean(prefs::kReverseAutologinEnabled, false); pref_service->SetBoolean(prefs::kReverseAutologinEnabled, false);
} }
void OneClickLoginInfoBarDelegate::AddEmailToOneClickRejectedList(
const std::string& email) {
PrefService* pref_service =
TabContents::FromWebContents(owner()->web_contents())->
profile()->GetPrefs();
ListPrefUpdate updater(pref_service,
prefs::kReverseAutologinRejectedEmailList);
updater->AppendIfNotPresent(base::Value::CreateStringValue(email));
}
void OneClickLoginInfoBarDelegate::RecordHistogramAction(int action) { void OneClickLoginInfoBarDelegate::RecordHistogramAction(int action) {
UMA_HISTOGRAM_ENUMERATION("AutoLogin.Reverse", action, UMA_HISTOGRAM_ENUMERATION("AutoLogin.Reverse", action,
one_click_signin::HISTOGRAM_MAX); one_click_signin::HISTOGRAM_MAX);
...@@ -197,6 +213,7 @@ void OneClickLoginInfoBarDelegate::RecordHistogramAction(int action) { ...@@ -197,6 +213,7 @@ void OneClickLoginInfoBarDelegate::RecordHistogramAction(int action) {
// static // static
bool OneClickSigninHelper::CanOffer(content::WebContents* web_contents, bool OneClickSigninHelper::CanOffer(content::WebContents* web_contents,
const std::string& email,
bool check_connected) { bool check_connected) {
if (!web_contents) if (!web_contents)
return false; return false;
...@@ -227,20 +244,37 @@ bool OneClickSigninHelper::CanOffer(content::WebContents* web_contents, ...@@ -227,20 +244,37 @@ bool OneClickSigninHelper::CanOffer(content::WebContents* web_contents,
if (!manager->GetAuthenticatedUsername().empty()) if (!manager->GetAuthenticatedUsername().empty())
return false; return false;
// If we're about to show a one-click infobar but the user has started // Make sure this username is not prohibited by policy.
// a concurrent signin flow (perhaps via the promo), we may not have yet if (!manager->IsAllowedUsername(email))
// established an authenticated username but we still shouldn't move
// forward with two simultaneous signin processes. This is a bit
// contentious as the one-click flow is a much smoother flow from the user
// perspective, but it's much more difficult to hijack the other flow from
// here as it is to bail.
ProfileSyncService* service =
ProfileSyncServiceFactory::GetForProfile(profile);
if (!service)
return false; return false;
if (service->FirstSetupInProgress()) // If some profile, not just the current one, is already connected to this
return false; // account, don't show the infobar.
if (g_browser_process) {
ProfileManager* manager = g_browser_process->profile_manager();
if (manager) {
string16 email16 = UTF8ToUTF16(email);
ProfileInfoCache& cache = manager->GetProfileInfoCache();
for (size_t i = 0; i < cache.GetNumberOfProfiles(); ++i) {
if (email16 == cache.GetUserNameOfProfileAtIndex(i))
return false;
}
}
}
// If email was already rejected by this profile for one-click sign-in.
if (!email.empty()) {
const ListValue* rejected_emails = profile->GetPrefs()->GetList(
prefs::kReverseAutologinRejectedEmailList);
if (!rejected_emails->empty()) {
const Value* email_value = Value::CreateStringValue(email);
ListValue::const_iterator iter = rejected_emails->Find(
*email_value);
if (iter != rejected_emails->end())
return false;
}
}
} }
return true; return true;
...@@ -298,29 +332,10 @@ void OneClickSigninHelper::ShowInfoBarUIThread( ...@@ -298,29 +332,10 @@ void OneClickSigninHelper::ShowInfoBarUIThread(
content::WebContents* web_contents = tab_util::GetWebContentsByID(child_id, content::WebContents* web_contents = tab_util::GetWebContentsByID(child_id,
route_id); route_id);
if (!web_contents || !CanOffer(web_contents, true))
return;
// If some profile, not just the current one, is already connected to this
// account, don't show the infobar.
if (g_browser_process) {
ProfileManager* manager = g_browser_process->profile_manager();
if (manager) {
string16 email16 = UTF8ToUTF16(email);
ProfileInfoCache& cache = manager->GetProfileInfoCache();
for (size_t i = 0; i < cache.GetNumberOfProfiles(); ++i) {
if (email16 == cache.GetUserNameOfProfileAtIndex(i))
return;
}
}
}
// Make sure this username is not prohibited by policy. // TODO(mathp): The appearance of this infobar should be tested using a
Profile* profile = // browser_test.
Profile::FromBrowserContext(web_contents->GetBrowserContext()); if (!web_contents || !CanOffer(web_contents, email, true))
SigninManager* signin = SigninManagerFactory::GetForProfile(profile);
if (!signin->IsAllowedUsername(email))
return; return;
TabContents* tab_contents = TabContents::FromWebContents(web_contents); TabContents* tab_contents = TabContents::FromWebContents(web_contents);
......
...@@ -27,9 +27,11 @@ class OneClickSigninHelper : public content::WebContentsObserver { ...@@ -27,9 +27,11 @@ class OneClickSigninHelper : public content::WebContentsObserver {
// Returns true if the one-click signin feature can be offered at this time. // Returns true if the one-click signin feature can be offered at this time.
// It can be offered if the contents is not in an incognito window. If // It can be offered if the contents is not in an incognito window. If
// |check_connected| is true, then the profile is checked to see if it's // |check_connected| is true, then the profile is checked to see if it's
// already connected to a google account, in which case a one click signin // already connected to a google account or if the user has already rejected
// one-click sign-in with this email, in which cases a one click signin
// should not be offered. // should not be offered.
static bool CanOffer(content::WebContents* web_contents, static bool CanOffer(content::WebContents* web_contents,
const std::string& email,
bool check_connected); bool check_connected);
// Looks for the Google-Accounts-SignIn response header, and if found, // Looks for the Google-Accounts-SignIn response header, and if found,
......
...@@ -170,7 +170,7 @@ TabContents::TabContents(WebContents* contents) ...@@ -170,7 +170,7 @@ TabContents::TabContents(WebContents* contents)
// one-click signin helper attached does not cause problems if the profile // one-click signin helper attached does not cause problems if the profile
// happens to be already connected. // happens to be already connected.
#if defined(ENABLE_ONE_CLICK_SIGNIN) #if defined(ENABLE_ONE_CLICK_SIGNIN)
if (OneClickSigninHelper::CanOffer(contents, false)) if (OneClickSigninHelper::CanOffer(contents, "", false))
one_click_signin_helper_.reset(new OneClickSigninHelper(contents)); one_click_signin_helper_.reset(new OneClickSigninHelper(contents));
#endif #endif
} }
......
...@@ -314,6 +314,11 @@ const char kPasswordGenerationEnabled[] = "password_generation.enabled"; ...@@ -314,6 +314,11 @@ const char kPasswordGenerationEnabled[] = "password_generation.enabled";
const char kAutologinEnabled[] = "autologin.enabled"; const char kAutologinEnabled[] = "autologin.enabled";
const char kReverseAutologinEnabled[] = "reverse_autologin.enabled"; const char kReverseAutologinEnabled[] = "reverse_autologin.enabled";
// List to keep track of emails for which the user has rejected one-click
// sign-in.
const char kReverseAutologinRejectedEmailList[] =
"reverse_autologin.rejected_email_list";
// Boolean that is true when SafeBrowsing is enabled. // Boolean that is true when SafeBrowsing is enabled.
const char kSafeBrowsingEnabled[] = "safebrowsing.enabled"; const char kSafeBrowsingEnabled[] = "safebrowsing.enabled";
......
...@@ -139,6 +139,7 @@ extern const char kPasswordManagerAllowShowPasswords[]; ...@@ -139,6 +139,7 @@ extern const char kPasswordManagerAllowShowPasswords[];
extern const char kPasswordGenerationEnabled[]; extern const char kPasswordGenerationEnabled[];
extern const char kAutologinEnabled[]; extern const char kAutologinEnabled[];
extern const char kReverseAutologinEnabled[]; extern const char kReverseAutologinEnabled[];
extern const char kReverseAutologinRejectedEmailList[];
extern const char kSafeBrowsingEnabled[]; extern const char kSafeBrowsingEnabled[];
extern const char kSafeBrowsingReportingEnabled[]; extern const char kSafeBrowsingReportingEnabled[];
extern const char kSafeBrowsingProceedAnywayDisabled[]; extern const char kSafeBrowsingProceedAnywayDisabled[];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment