#include "chrome/browser/ui/webui/signin/inline_login_handler_impl.h"
-#include "base/atomic_sequence_num.h"
#include "base/bind.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/sync/one_click_signin_helper.h"
+#include "chrome/browser/ui/sync/one_click_signin_histogram.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
namespace {
-// Global SequenceNumber used for generating unique webview partition IDs.
-base::StaticAtomicSequenceNumber next_partition_id;
-
} // empty namespace
InlineLoginHandlerImpl::InlineLoginHandlerImpl()
- : weak_factory_(this), choose_what_to_sync_(false), partition_id_("") {
+ : weak_factory_(this),
+ choose_what_to_sync_(false),
+ complete_login_triggered_(false) {
}
InlineLoginHandlerImpl::~InlineLoginHandlerImpl() {}
}
void InlineLoginHandlerImpl::SetExtraInitParams(base::DictionaryValue& params) {
- params.SetInteger("authMode", InlineLoginHandler::kInlineAuthMode);
+ params.SetInteger("authMode", InlineLoginHandler::kDesktopAuthMode);
const GURL& current_url = web_ui()->GetWebContents()->GetURL();
signin::Source source = signin::GetSourceForPromoURL(current_url);
params.SetString("continueUrl",
signin::GetLandingURL("source", static_cast<int>(source)).spec());
+ std::string default_email;
if (source != signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT) {
- std::string last_email = Profile::FromWebUI(web_ui())->GetPrefs()->
+ default_email = Profile::FromWebUI(web_ui())->GetPrefs()->
GetString(prefs::kGoogleServicesLastUsername);
- if (!last_email.empty())
- params.SetString("email", last_email);
+ } else {
+ if (!net::GetValueForKeyInQuery(current_url, "email", &default_email))
+ default_email.clear();
}
+ if (!default_email.empty())
+ params.SetString("email", default_email);
std::string frame_url;
net::GetValueForKeyInQuery(current_url, "frameUrl", &frame_url);
if (!is_constrained.empty())
params.SetString("constrained", is_constrained);
- net::GetValueForKeyInQuery(current_url, "partitionId", &partition_id_);
- if (partition_id_.empty()) {
- partition_id_ =
- "gaia-webview-" + base::IntToString(next_partition_id.GetNext());
- }
- params.SetString("partitionId", partition_id_);
-}
+ // TODO(rogerta): this needs to be passed on to gaia somehow.
+ std::string read_only_email;
+ net::GetValueForKeyInQuery(current_url, "readOnlyEmail", &read_only_email);
+ if (!read_only_email.empty())
+ params.SetString("readOnlyEmail", read_only_email);
+ OneClickSigninHelper::LogHistogramValue(
+ source, one_click_signin::HISTOGRAM_SHOWN);
+}
void InlineLoginHandlerImpl::HandleSwitchToFullTabMessage(
const base::ListValue* args) {
GURL main_frame_url(web_contents->GetURL());
main_frame_url = net::AppendOrReplaceQueryParameter(
main_frame_url, "frameUrl", UTF16ToASCII(url_str));
- main_frame_url = net::AppendOrReplaceQueryParameter(
- main_frame_url, "partitionId", partition_id_);
chrome::NavigateParams params(
Profile::FromWebUI(web_ui()),
net::AppendOrReplaceQueryParameter(main_frame_url, "constrained", "0"),
}
void InlineLoginHandlerImpl::CompleteLogin(const base::ListValue* args) {
- DCHECK(email_.empty() && password_.empty());
+ if (complete_login_triggered_) {
+ // Gaia is supposed to trigger CompleteLogin by sending a completelogin
+ // message to Chrome, since Gaia does not always do this, Chrome injects
+ // some code into the Gaia page to handle that. This may result in duplicate
+ // completelogin messages when Gaia does send the message.
+ // TODO(guohui): coordinate with Gaia team to only send the completeLogin
+ // message on Chrome versions that do not inject similar code into Gaia.
+ VLOG(1) << "InlineLoginHandlerImpl::CompleteLogin called more than once";
+ return;
+ }
+ complete_login_triggered_ = true;
+
+ content::WebContents* contents = web_ui()->GetWebContents();
+ const GURL& current_url = contents->GetURL();
const base::DictionaryValue* dict = NULL;
- base::string16 email;
- if (!args->GetDictionary(0, &dict) || !dict ||
- !dict->GetString("email", &email)) {
- // User cancelled the signin by clicking 'skip for now'.
- bool skip_for_now = false;
- DCHECK(dict->GetBoolean("skipForNow", &skip_for_now) && skip_for_now);
+ args->GetDictionary(0, &dict);
+ bool skip_for_now = false;
+ dict->GetBoolean("skipForNow", &skip_for_now);
+ if (skip_for_now) {
signin::SetUserSkippedPromo(Profile::FromWebUI(web_ui()));
SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE);
return;
}
+ base::string16 email;
+ dict->GetString("email", &email);
+ DCHECK(!email.empty());
email_ = UTF16ToASCII(email);
base::string16 password;
dict->GetString("password", &password);
password_ = UTF16ToASCII(password);
+ // When doing a SAML sign in, this email check may result in a false
+ // positive. This happens when the user types one email address in the
+ // gaia sign in page, but signs in to a different account in the SAML sign in
+ // page.
+ std::string default_email;
+ std::string validate_email;
+ if (net::GetValueForKeyInQuery(current_url, "email", &default_email) &&
+ net::GetValueForKeyInQuery(current_url, "validateEmail",
+ &validate_email) &&
+ validate_email == "1") {
+ if (email_ != default_email) {
+ SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE);
+ return;
+ }
+ }
+
+ base::string16 session_index;
+ dict->GetString("sessionIndex", &session_index);
+ session_index_ = UTF16ToASCII(session_index);
+ DCHECK(!session_index_.empty());
dict->GetBoolean("chooseWhatToSync", &choose_what_to_sync_);
- content::WebContents* contents = web_ui()->GetWebContents();
- signin::Source source = signin::GetSourceForPromoURL(contents->GetURL());
- OneClickSigninHelper::CanOfferFor can_offer =
+ signin::Source source = signin::GetSourceForPromoURL(current_url);
+ OneClickSigninHelper::LogHistogramValue(
+ source, one_click_signin::HISTOGRAM_ACCEPTED);
+ bool switch_to_advanced =
+ choose_what_to_sync_ && (source != signin::SOURCE_SETTINGS);
+ OneClickSigninHelper::LogHistogramValue(
+ source,
+ switch_to_advanced ? one_click_signin::HISTOGRAM_WITH_ADVANCED :
+ one_click_signin::HISTOGRAM_WITH_DEFAULTS);
+
+ OneClickSigninHelper::CanOfferFor can_offer_for =
source == signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT ?
OneClickSigninHelper::CAN_OFFER_FOR_SECONDARY_ACCOUNT :
OneClickSigninHelper::CAN_OFFER_FOR_ALL;
std::string error_msg;
- OneClickSigninHelper::CanOffer(
- contents, can_offer, email_, &error_msg);
- if (!error_msg.empty()) {
+ bool can_offer = OneClickSigninHelper::CanOffer(
+ contents, can_offer_for, email_, &error_msg);
+ if (!can_offer) {
HandleLoginError(error_msg);
return;
}
content::StoragePartition* partition =
content::BrowserContext::GetStoragePartitionForSite(
contents->GetBrowserContext(),
- GURL("chrome-guest://mfffpogegjflfpflabcdkioaeobkgjik/?" +
- partition_id_));
+ GURL(chrome::kChromeUIChromeSigninURL));
auth_fetcher_.reset(new GaiaAuthFetcher(this,
GaiaConstants::kChromeSource,
partition->GetURLRequestContext()));
- auth_fetcher_->StartCookieForOAuthCodeExchange("0");
+ auth_fetcher_->StartCookieForOAuthCodeExchange(session_index_);
}
void InlineLoginHandlerImpl::OnClientOAuthCodeSuccess(
// SigninOAuthHelper will delete itself.
SigninOAuthHelper* helper = new SigninOAuthHelper(profile);
helper->StartAddingAccount(oauth_code);
+
+ if (signin::IsAutoCloseEnabledInURL(current_url)) {
+ // Close the gaia sign in tab via a task to make sure we aren't in the
+ // middle of any webui handler code.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&InlineLoginHandlerImpl::CloseTab,
+ weak_factory_.GetWeakPtr()));
+ }
} else {
OneClickSigninSyncStarter::StartSyncMode start_mode =
source == signin::SOURCE_SETTINGS || choose_what_to_sync_ ?
// Call OneClickSigninSyncStarter to exchange oauth code for tokens.
// OneClickSigninSyncStarter will delete itself once the job is done.
new OneClickSigninSyncStarter(
- profile, NULL, "" /* session_index, not used */,
+ profile, GetDesktopBrowser(), "" /* session_index, not used */,
email_, password_, oauth_code,
start_mode,
contents,
email_.clear();
password_.clear();
+ session_index_.clear();
web_ui()->CallJavascriptFunction("inline.login.closeDialog");
}
void InlineLoginHandlerImpl::HandleLoginError(const std::string& error_msg) {
SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE);
+ Browser* browser = GetDesktopBrowser();
+ if (browser && !error_msg.empty()) {
+ VLOG(1) << "InlineLoginHandlerImpl::HandleLoginError shows error message: "
+ << error_msg;
+ OneClickSigninHelper::ShowSigninErrorBubble(browser, error_msg);
+ }
+
+ email_.clear();
+ password_.clear();
+ session_index_.clear();
+}
+
+Browser* InlineLoginHandlerImpl::GetDesktopBrowser() {
Browser* browser = chrome::FindBrowserWithWebContents(
web_ui()->GetWebContents());
if (!browser) {
browser = chrome::FindLastActiveWithProfile(
Profile::FromWebUI(web_ui()), chrome::GetActiveDesktop());
}
- if (browser)
- OneClickSigninHelper::ShowSigninErrorBubble(browser, error_msg);
-
- email_.clear();
- password_.clear();
+ return browser;
}
void InlineLoginHandlerImpl::SyncStarterCallback(
OneClickSigninSyncStarter::SyncSetupResult result) {
content::WebContents* contents = web_ui()->GetWebContents();
- const GURL& current_url = contents->GetURL();
+
+ if (contents->GetController().GetPendingEntry()) {
+ // Do nothing if a navigation is pending, since this call can be triggered
+ // from DidStartLoading. This avoids deleting the pending entry while we are
+ // still navigating to it. See crbug/346632.
+ return;
+ }
+
+ const GURL& current_url = contents->GetLastCommittedURL();
+ signin::Source source = signin::GetSourceForPromoURL(current_url);
+ DCHECK(source != signin::SOURCE_UNKNOWN);
bool auto_close = signin::IsAutoCloseEnabledInURL(current_url);
- if (auto_close) {
+
+ if (result == OneClickSigninSyncStarter::SYNC_SETUP_FAILURE) {
+ OneClickSigninHelper::RedirectToNtpOrAppsPage(contents, source);
+ } else if (auto_close) {
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&InlineLoginHandlerImpl::CloseTab,
weak_factory_.GetWeakPtr()));
} else {
- signin::Source source = signin::GetSourceForPromoURL(current_url);
- DCHECK(source != signin::SOURCE_UNKNOWN);
OneClickSigninHelper::RedirectToNtpOrAppsPageIfNecessary(contents, source);
}
}