Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / signin / inline_login_handler_impl.cc
index c665804..8b41c80 100644 (file)
@@ -4,7 +4,6 @@
 
 #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() {}
@@ -50,7 +50,7 @@ void InlineLoginHandlerImpl::RegisterMessages() {
 }
 
 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);
@@ -66,12 +66,16 @@ void InlineLoginHandlerImpl::SetExtraInitParams(base::DictionaryValue& params) {
   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);
@@ -83,14 +87,15 @@ void InlineLoginHandlerImpl::SetExtraInitParams(base::DictionaryValue& params) {
   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) {
@@ -101,8 +106,6 @@ void InlineLoginHandlerImpl::HandleSwitchToFullTabMessage(
   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"),
@@ -113,38 +116,80 @@ void InlineLoginHandlerImpl::HandleSwitchToFullTabMessage(
 }
 
 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;
   }
@@ -152,13 +197,12 @@ void InlineLoginHandlerImpl::CompleteLogin(const base::ListValue* args) {
   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(
@@ -176,6 +220,15 @@ 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_ ?
@@ -205,7 +258,7 @@ void InlineLoginHandlerImpl::OnClientOAuthCodeSuccess(
         // 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,
@@ -216,6 +269,7 @@ void InlineLoginHandlerImpl::OnClientOAuthCodeSuccess(
 
   email_.clear();
   password_.clear();
+  session_index_.clear();
   web_ui()->CallJavascriptFunction("inline.login.closeDialog");
 }
 
@@ -228,32 +282,52 @@ void InlineLoginHandlerImpl::OnClientOAuthCodeFailure(
 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);
   }
 }