Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6335)

Unified Diff: chrome/browser/ui/sync/one_click_signin_helper.cc

Issue 11494003: Enable "Let me choose what to sync" checkbox in gaia sign in page. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased, and adjusted gaia URL Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/sync/one_click_signin_helper.cc
diff --git a/chrome/browser/ui/sync/one_click_signin_helper.cc b/chrome/browser/ui/sync/one_click_signin_helper.cc
index a3aa899990b468f92ab93a806f3870c039ef8819..cd45d45299b5ba0776f3ae477855c9ff2c148f2c 100644
--- a/chrome/browser/ui/sync/one_click_signin_helper.cc
+++ b/chrome/browser/ui/sync/one_click_signin_helper.cc
@@ -10,12 +10,14 @@
#include "base/metrics/histogram.h"
#include "base/metrics/field_trial.h"
#include "base/string_split.h"
+#include "base/string_util.h"
#include "base/supports_user_data.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/api/infobars/infobar_service.h"
#include "chrome/browser/api/infobars/one_click_signin_infobar_delegate.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/defaults.h"
+#include "chrome/browser/google/google_util.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/profiles/profile.h"
@@ -51,7 +53,6 @@
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
-#include "net/base/escape.h"
#include "net/cookies/cookie_monster.h"
#include "net/url_request/url_request.h"
#include "ui/base/l10n/l10n_util.h"
@@ -67,6 +68,16 @@ namespace {
// experimental group.
bool use_blue_on_white = false;
+// Add a specific email to the list of emails rejected for one-click
+// sign-in, for this profile.
+void AddEmailToOneClickRejectedList(Profile* profile,
+ const std::string& email) {
+ PrefService* pref_service = profile->GetPrefs();
+ ListPrefUpdate updater(pref_service,
+ prefs::kReverseAutologinRejectedEmailList);
+ updater->AppendIfNotPresent(new base::StringValue(email));
+}
+
// Start syncing with the given user information.
void StartSync(Browser* browser,
OneClickSigninHelper::AutoAccept auto_accept,
@@ -83,13 +94,13 @@ void StartSync(Browser* browser,
case OneClickSigninHelper::AUTO_ACCEPT_EXPLICIT:
action = one_click_signin::HISTOGRAM_AUTO_WITH_DEFAULTS;
break;
- case OneClickSigninHelper::AUTO_ACCEPT:
+ case OneClickSigninHelper::AUTO_ACCEPT_ACCEPTED:
action =
start_mode == OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS ?
one_click_signin::HISTOGRAM_AUTO_WITH_DEFAULTS :
one_click_signin::HISTOGRAM_AUTO_WITH_ADVANCED;
break;
- case OneClickSigninHelper::NO_AUTO_ACCEPT:
+ case OneClickSigninHelper::AUTO_ACCEPT_NONE:
action =
start_mode == OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS ?
one_click_signin::HISTOGRAM_WITH_DEFAULTS :
@@ -108,25 +119,62 @@ void StartSync(Browser* browser,
one_click_signin::HISTOGRAM_MAX);
}
-// Determines the source of the sign in. Its either one of the known sign in
-// access point (first run, NTP, menu, settings) or its an implicit sign in
-// via another Google property. In the former case, "service" is also
-// checked to make sure its "chromiumsync".
-SyncPromoUI::Source GetSigninSource(const GURL& url) {
+// Determines the source of the sign in and the continue URL. Its either one
+// of the known sign in access point (first run, NTP, menu, settings) or its
+// an implicit sign in via another Google property. In the former case,
+// "service" is also checked to make sure its "chromiumsync".
+SyncPromoUI::Source GetSigninSource(const GURL& url, GURL* continue_url) {
std::string value;
chrome_common_net::GetValueForKeyInQuery(url, "service", &value);
- bool is_explicit_signin = value == "chromiumsync";
+ bool possibly_an_explicit_signin = value == "chromiumsync";
+
+ // Find the final continue URL for this sign in. In some cases, Gaia can
+ // continue to itself, with the original continue URL buried under a couple
+ // of layers of indirection. Peel those layers away.
+ GURL local_continue_url = url;
+ do {
+ local_continue_url =
+ SyncPromoUI::GetNextPageURLForSyncPromoURL(local_continue_url);
+ } while (gaia::IsGaiaSignonRealm(local_continue_url.GetOrigin()));
+
+ if (continue_url && local_continue_url.is_valid()) {
+ DCHECK(!continue_url->is_valid() || *continue_url == local_continue_url);
+ *continue_url = local_continue_url;
+ }
- chrome_common_net::GetValueForKeyInQuery(url, "continue", &value);
- SyncPromoUI::Source source =
- SyncPromoUI::GetSourceForSyncPromoURL(GURL(
- net::UnescapeURLComponent(value,
- net::UnescapeRule::URL_SPECIAL_CHARS)));
+ return possibly_an_explicit_signin ?
+ SyncPromoUI::GetSourceForSyncPromoURL(local_continue_url) :
+ SyncPromoUI::SOURCE_UNKNOWN;
+}
+
+// Returns true if |url| is a valid URL that can occur during the sign in
+// process. Valid URLs are of the form:
+//
+// https://accounts.google.{TLD}/...
+// https://accounts.youtube.com/...
+// https://accounts.blogger.com/...
+//
+// All special headers used by one click sign in occur on
+// https://accounts.google.com URLs. However, the sign in process may redirect
+// to intermediate Gaia URLs that do not end with .com. For example, an account
+// that uses SMS 2-factor outside the US may redirect to country specific URLs.
+//
+// The sign in process may also redirect to youtube and blogger account URLs
+// so that Gaia acts as a single signon service.
+bool IsValidGaiaSigninRedirectOrResponseURL(const GURL& url) {
+ std::string hostname = url.host();
+ if (google_util::IsGoogleHostname(hostname, google_util::ALLOW_SUBDOMAIN)) {
+ // Also using IsGaiaSignonRealm() to handle overriding with command line.
+ return gaia::IsGaiaSignonRealm(url.GetOrigin()) ||
+ StartsWithASCII(hostname, "accounts.", false);
+ }
- if (!is_explicit_signin)
- source = SyncPromoUI::SOURCE_UNKNOWN;
+ GURL origin = url.GetOrigin();
+ if (origin == GURL("https://accounts.youtube.com") ||
+ origin == GURL("https://accounts.blogger.com"))
+ return true;
- return source;
+ return false;
}
// This class is associated as user data with a given URLRequest object, in
@@ -208,10 +256,6 @@ class OneClickInfoBarDelegateImpl : public OneClickSigninInfoBarDelegate {
// OneClickSigninInfoBarDelegate overrides.
virtual void GetAlternateColors(AlternateColors* alt_colors) OVERRIDE;
- // 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.
void RecordHistogramAction(int action);
@@ -275,25 +319,27 @@ string16 OneClickInfoBarDelegateImpl::GetButtonLabel(
}
bool OneClickInfoBarDelegateImpl::Accept() {
+ content::WebContents* web_contents = owner()->GetWebContents();
+ Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
+ Profile* profile = Profile::FromBrowserContext(
+ web_contents->GetBrowserContext());
+
// User has accepted one-click sign-in for this account. Never ask again for
// this profile.
- Profile* profile = Profile::FromBrowserContext(
- owner()->GetWebContents()->GetBrowserContext());
SigninManager::DisableOneClickSignIn(profile);
-
- content::WebContents* web_contents = owner()->GetWebContents();
- Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
RecordHistogramAction(one_click_signin::HISTOGRAM_ACCEPTED);
chrome::FindBrowserWithWebContents(web_contents)->window()->
- ShowOneClickSigninBubble(base::Bind(&StartSync, browser,
- OneClickSigninHelper::NO_AUTO_ACCEPT,
- session_index_, email_, password_));
+ ShowOneClickSigninBubble(
+ base::Bind(&StartSync, browser,
+ OneClickSigninHelper::AUTO_ACCEPT_NONE, session_index_,
+ email_, password_));
button_pressed_ = true;
return true;
}
bool OneClickInfoBarDelegateImpl::Cancel() {
- AddEmailToOneClickRejectedList(email_);
+ AddEmailToOneClickRejectedList(Profile::FromBrowserContext(
+ owner()->GetWebContents()->GetBrowserContext()), email_);
RecordHistogramAction(one_click_signin::HISTOGRAM_REJECTED);
button_pressed_ = true;
return true;
@@ -328,16 +374,6 @@ void OneClickInfoBarDelegateImpl::GetAlternateColors(
return OneClickSigninInfoBarDelegate::GetAlternateColors(alt_colors);
}
-void OneClickInfoBarDelegateImpl::AddEmailToOneClickRejectedList(
- const std::string& email) {
- Profile* profile = Profile::FromBrowserContext(
- owner()->GetWebContents()->GetBrowserContext());
- PrefService* pref_service = profile->GetPrefs();
- ListPrefUpdate updater(pref_service,
- prefs::kReverseAutologinRejectedEmailList);
- updater->AppendIfNotPresent(new base::StringValue(email));
-}
-
void OneClickInfoBarDelegateImpl::RecordHistogramAction(int action) {
UMA_HISTOGRAM_ENUMERATION("AutoLogin.Reverse", action,
one_click_signin::HISTOGRAM_MAX);
@@ -345,7 +381,7 @@ void OneClickInfoBarDelegateImpl::RecordHistogramAction(int action) {
OneClickSigninHelper::OneClickSigninHelper(content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
- auto_accept_(NO_AUTO_ACCEPT),
+ auto_accept_(AUTO_ACCEPT_NONE),
source_(SyncPromoUI::SOURCE_UNKNOWN) {
}
@@ -365,6 +401,7 @@ bool OneClickSigninHelper::CanOffer(content::WebContents* web_contents,
const std::string& email,
int* error_message_id) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ VLOG(1) << "OneClickSigninHelper::CanOffer";
if (error_message_id)
*error_message_id = 0;
@@ -457,6 +494,7 @@ bool OneClickSigninHelper::CanOffer(content::WebContents* web_contents,
}
}
+ VLOG(1) << "OneClickSigninHelper::CanOffer: yes we can";
return true;
}
@@ -483,13 +521,6 @@ OneClickSigninHelper::Offer OneClickSigninHelper::CanOfferOnIOThreadImpl(
if (!SyncPromoUI::UseWebBasedSigninFlow())
return DONT_OFFER;
- // Don't offer if the source is known, as that means it's an explicit sign
- // in request.
- if (GetSigninSource(url) != SyncPromoUI::SOURCE_UNKNOWN ||
- GetSigninSource(GURL(referrer)) != SyncPromoUI::SOURCE_UNKNOWN) {
- return DONT_OFFER;
- }
-
if (!ProfileSyncService::IsSyncEnabled())
return DONT_OFFER;
@@ -567,9 +598,12 @@ void OneClickSigninHelper::ShowInfoBarIfPossible(net::URLRequest* request,
request->GetResponseHeaderByName("Google-Accounts-SignIn",
&google_accounts_signin_value);
- VLOG(1) << "OneClickSigninHelper::ShowInfoBarIfPossible:"
- << " g-a-s='" << google_accounts_signin_value << "'"
- << " g-c-s='" << google_chrome_signin_value << "'";
+ if (!google_accounts_signin_value.empty() ||
+ !google_chrome_signin_value.empty()) {
+ VLOG(1) << "OneClickSigninHelper::ShowInfoBarIfPossible:"
+ << " g-a-s='" << google_accounts_signin_value << "'"
+ << " g-c-s='" << google_chrome_signin_value << "'";
+ }
if (!SyncPromoUI::UseWebBasedSigninFlow() &&
google_accounts_signin_value.empty()) {
@@ -602,54 +636,58 @@ void OneClickSigninHelper::ShowInfoBarIfPossible(net::URLRequest* request,
if (SyncPromoUI::UseWebBasedSigninFlow() && !email.empty())
OneClickSigninRequestUserData::AssociateWithRequest(request, email);
- VLOG(1) << "OneClickSigninHelper::ShowInfoBarIfPossible:"
- << " email=" << email
- << " sessionindex=" << session_index;
+ if (!email.empty() || !session_index.empty()) {
+ VLOG(1) << "OneClickSigninHelper::ShowInfoBarIfPossible:"
+ << " email=" << email
+ << " sessionindex=" << session_index;
+ }
// Parse Google-Chrome-SignIn.
- AutoAccept auto_accept = NO_AUTO_ACCEPT;
+ AutoAccept auto_accept = AUTO_ACCEPT_NONE;
SyncPromoUI::Source source = SyncPromoUI::SOURCE_UNKNOWN;
+ GURL continue_url;
if (SyncPromoUI::UseWebBasedSigninFlow()) {
std::vector<std::string> tokens;
base::SplitString(google_chrome_signin_value, ',', &tokens);
for (size_t i = 0; i < tokens.size(); ++i) {
const std::string& token = tokens[i];
if (token == "accepted") {
- auto_accept = AUTO_ACCEPT;
+ auto_accept = AUTO_ACCEPT_ACCEPTED;
} else if (token == "configure") {
auto_accept = AUTO_ACCEPT_CONFIGURE;
} else if (token == "rejected-for-profile") {
- auto_accept = REJECTED_FOR_PROFILE;
+ auto_accept = AUTO_ACCEPT_REJECTED_FOR_PROFILE;
}
}
// If this is an explicit sign in (i.e., first run, NTP, menu,settings)
// then force the auto accept type to explicit.
- source = GetSigninSource(request->original_url());
- if (source == SyncPromoUI::SOURCE_UNKNOWN)
- source = GetSigninSource(GURL(request->referrer()));
-
+ source = GetSigninSource(request->original_url(), &continue_url);
if (source != SyncPromoUI::SOURCE_UNKNOWN)
auto_accept = AUTO_ACCEPT_EXPLICIT;
}
- VLOG(1) << "OneClickSigninHelper::ShowInfoBarIfPossible:"
- << " auto_accept=" << auto_accept;
+ if (auto_accept != AUTO_ACCEPT_NONE) {
+ VLOG(1) << "OneClickSigninHelper::ShowInfoBarIfPossible:"
+ << " auto_accept=" << auto_accept;
+ }
- // If |session_index|, |email|, and |auto_accept| all have their default
- // value, don't bother posting a task to the UI thread. It will be a noop
- // anyway.
+ // If |session_index|, |email|, |auto_accept|, and |continue_url| all have
+ // their default value, don't bother posting a task to the UI thread.
+ // It will be a noop anyway.
//
// The two headers above may (but not always) come in different http requests
// so a post to the UI thread is still needed if |auto_accept| is not its
// default value, but |email| and |session_index| are.
- if (session_index.empty() && email.empty() && auto_accept == NO_AUTO_ACCEPT)
+ if (session_index.empty() && email.empty() &&
+ auto_accept == AUTO_ACCEPT_NONE && !continue_url.is_valid()) {
return;
+ }
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(&OneClickSigninHelper::ShowInfoBarUIThread, session_index,
- email, auto_accept, source, child_id, route_id));
+ email, auto_accept, source, continue_url, child_id, route_id));
}
// static
@@ -658,6 +696,7 @@ void OneClickSigninHelper::ShowInfoBarUIThread(
const std::string& email,
AutoAccept auto_accept,
SyncPromoUI::Source source,
+ const GURL& continue_url,
int child_id,
int route_id) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
@@ -697,13 +736,24 @@ void OneClickSigninHelper::ShowInfoBarUIThread(
if (!email.empty())
helper->email_ = email;
- if (auto_accept != NO_AUTO_ACCEPT) {
+ if (auto_accept != AUTO_ACCEPT_NONE) {
helper->auto_accept_ = auto_accept;
helper->source_ = source;
}
+
+ if (continue_url.is_valid()) {
+ // When Gaia finally redirects to the continue URL, Gaia will add some
+ // extra query parameters. So ignore the parameters when checking to see
+ // if the user has continued.
+ GURL::Replacements replacements;
+ replacements.ClearQuery();
+ helper->continue_url_ = continue_url.ReplaceComponents(replacements);
+ }
}
void OneClickSigninHelper::RedirectToNTP() {
+ VLOG(1) << "OneClickSigninHelper::RedirectToNTP";
+
// Redirect to NTP with sign in bubble visible.
content::WebContents* contents = web_contents();
Profile* profile =
@@ -722,10 +772,12 @@ void OneClickSigninHelper::RedirectToNTP() {
}
void OneClickSigninHelper::CleanTransientState() {
+ VLOG(1) << "OneClickSigninHelper::CleanTransientState";
email_.clear();
password_.clear();
- auto_accept_ = NO_AUTO_ACCEPT;
+ auto_accept_ = AUTO_ACCEPT_NONE;
source_ = SyncPromoUI::SOURCE_UNKNOWN;
+ continue_url_ = GURL();
}
void OneClickSigninHelper::DidNavigateAnyFrame(
@@ -745,6 +797,8 @@ void OneClickSigninHelper::DidStopLoading(
// If the user left the sign in process, clear all members.
// TODO(rogerta): might need to allow some youtube URLs.
content::WebContents* contents = web_contents();
+ const GURL url = contents->GetURL();
+ VLOG(1) << "OneClickSigninHelper::DidStopLoading: url=" << url.spec();
// If an error has already occured during the sign in flow, make sure to
// display it to the user and abort the process. Do this only for
@@ -759,22 +813,87 @@ void OneClickSigninHelper::DidStopLoading(
if (email_.empty() || password_.empty())
return;
+ // When the user use the firt-run, ntp, or hotdog menu to sign in, then have
+ // the option of checking the the box "Let me choose what to sync". When the
+ // sign in process started, the source parameter in the continue URL may have
+ // indicated one of the three options above. However, once this box is
+ // checked, the source parameter will indicate settings. This will only be
+ // comminucated back to chrome when Gaia redirects to the continue URL, and
+ // this is considered here a last minute change to the source. See a little
+ // further below for when this variable is set to true.
+ bool last_minute_source_change = false;
+
+ if (SyncPromoUI::UseWebBasedSigninFlow()) {
+ if (IsValidGaiaSigninRedirectOrResponseURL(url))
+ return;
+
+ // During an explicit sign in, if the user has not yet reached the final
+ // continue URL, wait for it to arrive. Note that Gaia will add some extra
+ // query parameters to the continue URL. Ignore them when checking to
+ // see if the user has continued.
+ //
+ // If this is not an explicit sign in, we don't need to check if we landed
+ // on the right continue URL. This is important because the continue URL
+ // may itself lead to a redirect, which means this function will never see
+ // the continue URL go by.
+ if (auto_accept_ == AUTO_ACCEPT_EXPLICIT) {
+ DCHECK(source_ != SyncPromoUI::SOURCE_UNKNOWN);
+ GURL::Replacements replacements;
+ replacements.ClearQuery();
+ const bool continue_url_match =
+ url.ReplaceComponents(replacements) == continue_url_;
+ if (!continue_url_match) {
+ VLOG(1) << "OneClickSigninHelper::DidStopLoading: invalid url='"
+ << url.spec()
+ << "' expected continue url=" << continue_url_;
+ CleanTransientState();
+ return;
+ }
+
+ // In explicit sign ins, the user may have checked the box
+ // "Let me choose what to sync". This is reflected as a change in the
+ // source of the continue URL. Make one last check of the current URL
+ // to see if there is a valid source and its set to settings. If so,
+ // it overrides the current source.
+ SyncPromoUI::Source source =
+ SyncPromoUI::GetSourceForSyncPromoURL(url);
+ if (source == SyncPromoUI::SOURCE_SETTINGS) {
+ source_ = SyncPromoUI::SOURCE_SETTINGS;
+ last_minute_source_change = true;
+ }
+ }
+ }
+
Browser* browser = chrome::FindBrowserWithWebContents(contents);
- InfoBarService* infobar_service =
+ Profile* profile =
+ Profile::FromBrowserContext(contents->GetBrowserContext());
+ InfoBarService* infobar_tab_helper =
InfoBarService::FromWebContents(contents);
+ VLOG(1) << "OneClickSigninHelper::DidStopLoading: signin is go."
+ << " auto_accept=" << auto_accept_
+ << " source=" << source_;
+
switch (auto_accept_) {
- case AUTO_ACCEPT:
+ case AUTO_ACCEPT_NONE:
+ if (SyncPromoUI::UseWebBasedSigninFlow()) {
+ UMA_HISTOGRAM_ENUMERATION("AutoLogin.Reverse",
+ one_click_signin::HISTOGRAM_DISMISSED,
+ one_click_signin::HISTOGRAM_MAX);
+ } else {
+ infobar_tab_helper->AddInfoBar(
+ new OneClickInfoBarDelegateImpl(infobar_tab_helper, session_index_,
+ email_, password_));
+ }
+ break;
+ case AUTO_ACCEPT_ACCEPTED:
+ SigninManager::DisableOneClickSignIn(profile);
browser->window()->ShowOneClickSigninBubble(
base::Bind(&StartSync, browser, auto_accept_, session_index_,
email_, password_));
break;
- case NO_AUTO_ACCEPT:
- infobar_service->AddInfoBar(
- new OneClickInfoBarDelegateImpl(infobar_service, session_index_,
- email_, password_));
- break;
case AUTO_ACCEPT_CONFIGURE:
+ SigninManager::DisableOneClickSignIn(profile);
StartSync(browser, auto_accept_, session_index_, email_, password_,
OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST);
break;
@@ -783,8 +902,20 @@ void OneClickSigninHelper::DidStopLoading(
source_ == SyncPromoUI::SOURCE_SETTINGS ?
OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST :
OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS);
+
+ // If this was a last minute switch to the settings page, this means the
+ // started with first-run/NTP/wrench menu, and checked the "configure
+ // first" checkbox. Replace the default blank continue page with an
+ // about:blank page, so that when the settings page is displayed, it
+ // reuses the tab.
+ if (last_minute_source_change) {
+ contents->GetController().LoadURL(
+ GURL("about:blank"), content::Referrer(),
+ content::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
+ }
break;
- case REJECTED_FOR_PROFILE:
+ case AUTO_ACCEPT_REJECTED_FOR_PROFILE:
+ AddEmailToOneClickRejectedList(profile, email_);
UMA_HISTOGRAM_ENUMERATION("AutoLogin.Reverse",
one_click_signin::HISTOGRAM_REJECTED,
one_click_signin::HISTOGRAM_MAX);
@@ -799,8 +930,6 @@ void OneClickSigninHelper::DidStopLoading(
// by SyncSetupHandler.
if (auto_accept_ == AUTO_ACCEPT_EXPLICIT &&
source_ != SyncPromoUI::SOURCE_SETTINGS) {
- Profile* profile =
- Profile::FromBrowserContext(contents->GetBrowserContext());
signin_tracker_.reset(new SigninTracker(profile, this));
}
« no previous file with comments | « chrome/browser/ui/sync/one_click_signin_helper.h ('k') | chrome/browser/ui/sync/one_click_signin_helper_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698