Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / signin / inline_login_handler_impl.cc
index c665804..25dce57 100644 (file)
 
 #include "chrome/browser/ui/webui/signin/inline_login_handler_impl.h"
 
-#include "base/atomic_sequence_num.h"
+#include <string>
+
 #include "base/bind.h"
-#include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/signin_global_error.h"
-#include "chrome/browser/signin/signin_oauth_helper.h"
-#include "chrome/browser/signin/signin_promo.h"
+#include "chrome/browser/signin/about_signin_internals_factory.h"
+#include "chrome/browser/signin/chrome_signin_client_factory.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_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_factory.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.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/browser/ui/webui/signin/inline_login_ui.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/url_constants.h"
+#include "components/signin/core/browser/about_signin_internals.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/signin_error_controller.h"
+#include "components/signin/core/browser/signin_oauth_helper.h"
+#include "components/signin/core/common/profile_management_switches.h"
 #include "content/public/browser/storage_partition.h"
-#include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "google_apis/gaia/gaia_auth_fetcher.h"
+#include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "net/base/url_util.h"
 
 namespace {
 
-// Global SequenceNumber used for generating unique webview partition IDs.
-base::StaticAtomicSequenceNumber next_partition_id;
+class InlineSigninHelper : public SigninOAuthHelper::Consumer {
+ public:
+  InlineSigninHelper(
+      base::WeakPtr<InlineLoginHandlerImpl> handler,
+      net::URLRequestContextGetter* getter,
+      Profile* profile,
+      const GURL& current_url,
+      const std::string& email,
+      const std::string& password,
+      const std::string& session_index,
+      const std::string& signin_scoped_device_id,
+      bool choose_what_to_sync,
+      bool confirm_untrusted_signin);
+
+ private:
+  // Overriden from SigninOAuthHelper::Consumer.
+  virtual void OnSigninOAuthInformationAvailable(
+      const std::string& email,
+      const std::string& display_email,
+      const std::string& refresh_token) OVERRIDE;
+  virtual void OnSigninOAuthInformationFailure(
+      const GoogleServiceAuthError& error) OVERRIDE;
+
+  SigninOAuthHelper signin_oauth_helper_;
+  base::WeakPtr<InlineLoginHandlerImpl> handler_;
+  Profile* profile_;
+  GURL current_url_;
+  std::string email_;
+  std::string password_;
+  std::string session_index_;
+  bool choose_what_to_sync_;
+  bool confirm_untrusted_signin_;
+
+  DISALLOW_COPY_AND_ASSIGN(InlineSigninHelper);
+};
+
+InlineSigninHelper::InlineSigninHelper(
+    base::WeakPtr<InlineLoginHandlerImpl> handler,
+    net::URLRequestContextGetter* getter,
+    Profile* profile,
+    const GURL& current_url,
+    const std::string& email,
+    const std::string& password,
+    const std::string& session_index,
+    const std::string& signin_scoped_device_id,
+    bool choose_what_to_sync,
+    bool confirm_untrusted_signin)
+    : signin_oauth_helper_(getter, session_index, signin_scoped_device_id,
+                           this),
+      handler_(handler),
+      profile_(profile),
+      current_url_(current_url),
+      email_(email),
+      password_(password),
+      session_index_(session_index),
+      choose_what_to_sync_(choose_what_to_sync),
+      confirm_untrusted_signin_(confirm_untrusted_signin) {
+  DCHECK(profile_);
+  DCHECK(!email_.empty());
+}
 
-} // empty namespace
+void InlineSigninHelper::OnSigninOAuthInformationAvailable(
+    const std::string& email,
+    const std::string& display_email,
+    const std::string& refresh_token) {
+  content::WebContents* contents = NULL;
+  Browser* browser = NULL;
+  if (handler_) {
+    contents = handler_->web_ui()->GetWebContents();
+    browser = handler_->GetDesktopBrowser();
+  }
 
-InlineLoginHandlerImpl::InlineLoginHandlerImpl()
-      : weak_factory_(this), choose_what_to_sync_(false), partition_id_("") {
+  AboutSigninInternals* about_signin_internals =
+    AboutSigninInternalsFactory::GetForProfile(profile_);
+  about_signin_internals->OnRefreshTokenReceived("Successful");
+
+  signin::Source source = signin::GetSourceForPromoURL(current_url_);
+  if (source == signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT ||
+      source == signin::SOURCE_REAUTH) {
+    ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
+        UpdateCredentials(email, refresh_token);
+
+    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,
+          handler_,
+          signin::ShouldShowAccountManagement(current_url_)));
+    }
+  } else {
+    ProfileSyncService* sync_service =
+        ProfileSyncServiceFactory::GetForProfile(profile_);
+    SigninErrorController* error_controller =
+        ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
+            signin_error_controller();
+
+    bool is_new_avatar_menu = switches::IsNewAvatarMenu();
+
+    OneClickSigninSyncStarter::StartSyncMode start_mode;
+    if (source == signin::SOURCE_SETTINGS || choose_what_to_sync_) {
+      bool show_settings_without_configure =
+          error_controller->HasError() &&
+          sync_service &&
+          sync_service->HasSyncSetupCompleted();
+      start_mode = show_settings_without_configure ?
+          OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE :
+          OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST;
+    } else {
+      start_mode = is_new_avatar_menu ?
+          OneClickSigninSyncStarter::CONFIRM_SYNC_SETTINGS_FIRST :
+          OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS;
+    }
+
+    OneClickSigninSyncStarter::ConfirmationRequired confirmation_required;
+    if (confirm_untrusted_signin_) {
+      confirmation_required =
+          OneClickSigninSyncStarter::CONFIRM_UNTRUSTED_SIGNIN;
+    } else if (is_new_avatar_menu) {
+      confirmation_required = OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN;
+    } else {
+      confirmation_required =
+          source == signin::SOURCE_SETTINGS ||
+          source == signin::SOURCE_WEBSTORE_INSTALL ||
+          choose_what_to_sync_ ?
+              OneClickSigninSyncStarter::NO_CONFIRMATION :
+              OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN;
+    }
+
+    bool start_signin =
+        !OneClickSigninHelper::HandleCrossAccountError(
+            profile_, "",
+            email, password_, refresh_token,
+            OneClickSigninHelper::AUTO_ACCEPT_EXPLICIT,
+            source, start_mode,
+            base::Bind(&InlineLoginHandlerImpl::SyncStarterCallback,
+                       handler_));
+    if (start_signin) {
+      // Call OneClickSigninSyncStarter to exchange oauth code for tokens.
+      // OneClickSigninSyncStarter will delete itself once the job is done.
+      new OneClickSigninSyncStarter(
+          profile_, browser,
+          email, password_, refresh_token,
+          start_mode,
+          contents,
+          confirmation_required,
+          signin::GetNextPageURLForPromoURL(current_url_),
+          base::Bind(&InlineLoginHandlerImpl::SyncStarterCallback, handler_));
+    }
+  }
+
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
 }
 
-InlineLoginHandlerImpl::~InlineLoginHandlerImpl() {}
+void InlineSigninHelper::OnSigninOAuthInformationFailure(
+  const GoogleServiceAuthError& error) {
+  if (handler_)
+    handler_->HandleLoginError(error.ToString());
 
-void InlineLoginHandlerImpl::RegisterMessages() {
-  InlineLoginHandler::RegisterMessages();
+  AboutSigninInternals* about_signin_internals =
+    AboutSigninInternalsFactory::GetForProfile(profile_);
+  about_signin_internals->OnRefreshTokenReceived("Failure");
 
-  web_ui()->RegisterMessageCallback("switchToFullTab",
-      base::Bind(&InlineLoginHandlerImpl::HandleSwitchToFullTabMessage,
-                  base::Unretained(this)));
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
 }
 
-void InlineLoginHandlerImpl::SetExtraInitParams(base::DictionaryValue& params) {
-  params.SetInteger("authMode", InlineLoginHandler::kInlineAuthMode);
+}  // namespace
 
-  const GURL& current_url = web_ui()->GetWebContents()->GetURL();
-  signin::Source source = signin::GetSourceForPromoURL(current_url);
-  DCHECK(source != signin::SOURCE_UNKNOWN);
-  if (source == signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT ||
-      source == signin::SOURCE_AVATAR_BUBBLE_SIGN_IN) {
-    // Drop the leading slash in the path.
-    params.SetString("gaiaPath",
-        GaiaUrls::GetInstance()->embedded_signin_url().path().substr(1));
-  }
+InlineLoginHandlerImpl::InlineLoginHandlerImpl()
+      : weak_factory_(this),
+        confirm_untrusted_signin_(false) {
+}
 
-  params.SetString("service", "chromiumsync");
-  params.SetString("continueUrl",
-      signin::GetLandingURL("source", static_cast<int>(source)).spec());
-
-  if (source != signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT) {
-    std::string last_email = Profile::FromWebUI(web_ui())->GetPrefs()->
-        GetString(prefs::kGoogleServicesLastUsername);
-    if (!last_email.empty())
-      params.SetString("email", last_email);
-  }
+InlineLoginHandlerImpl::~InlineLoginHandlerImpl() {}
 
-  std::string frame_url;
-  net::GetValueForKeyInQuery(current_url, "frameUrl", &frame_url);
-  if (!frame_url.empty())
-    params.SetString("frameUrl", frame_url);
+bool InlineLoginHandlerImpl::HandleContextMenu(
+    const content::ContextMenuParams& params) {
+#ifndef NDEBUG
+  return false;
+#else
+  return true;
+#endif
+}
 
-  std::string is_constrained;
-  net::GetValueForKeyInQuery(current_url, "constrained", &is_constrained);
-  if (!is_constrained.empty())
-    params.SetString("constrained", is_constrained);
+void InlineLoginHandlerImpl::DidCommitProvisionalLoadForFrame(
+    content::RenderFrameHost* render_frame_host,
+    const GURL& url,
+    content::PageTransition transition_type) {
+  if (!web_contents())
+    return;
 
-  net::GetValueForKeyInQuery(current_url, "partitionId", &partition_id_);
-  if (partition_id_.empty()) {
-    partition_id_ =
-        "gaia-webview-" + base::IntToString(next_partition_id.GetNext());
+  // Returns early if this is not a gaia iframe navigation.
+  const GURL kGaiaExtOrigin(
+      "chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik/");
+  content::RenderFrameHost* gaia_iframe = InlineLoginUI::GetAuthIframe(
+      web_contents(), kGaiaExtOrigin, "signin-frame");
+  if (render_frame_host != gaia_iframe)
+    return;
+
+  // Loading any untrusted (e.g., HTTP) URLs in the privileged sign-in process
+  // will require confirmation before the sign in takes effect.
+  if (!url.is_empty() &&
+      url.spec() != url::kAboutBlankURL &&
+      !gaia::IsGaiaSignonRealm(url.GetOrigin()) &&
+      !signin::IsContinueUrlForWebBasedSigninFlow(url)) {
+    confirm_untrusted_signin_ = true;
   }
-  params.SetString("partitionId", partition_id_);
 }
 
+void InlineLoginHandlerImpl::SetExtraInitParams(base::DictionaryValue& params) {
+  params.SetString("service", "chromiumsync");
 
-void InlineLoginHandlerImpl::HandleSwitchToFullTabMessage(
-    const base::ListValue* args) {
-  base::string16 url_str;
-  CHECK(args->GetString(0, &url_str));
+  content::WebContents* contents = web_ui()->GetWebContents();
+  const GURL& current_url = contents->GetURL();
+  std::string is_constrained;
+  net::GetValueForKeyInQuery(current_url, "constrained", &is_constrained);
+  if (is_constrained == "1")
+    contents->SetDelegate(this);
 
-  content::WebContents* web_contents = web_ui()->GetWebContents();
-  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"),
-      content::PAGE_TRANSITION_AUTO_TOPLEVEL);
-  chrome::Navigate(&params);
+  content::WebContentsObserver::Observe(contents);
 
-  web_ui()->CallJavascriptFunction("inline.login.closeDialog");
+  signin::Source source = signin::GetSourceForPromoURL(current_url);
+  OneClickSigninHelper::LogHistogramValue(
+      source, one_click_signin::HISTOGRAM_SHOWN);
 }
 
 void InlineLoginHandlerImpl::CompleteLogin(const base::ListValue* args) {
-  DCHECK(email_.empty() && password_.empty());
+  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;
   }
 
-  email_ = UTF16ToASCII(email);
-  base::string16 password;
-  dict->GetString("password", &password);
-  password_ = UTF16ToASCII(password);
+  base::string16 email_string16;
+  dict->GetString("email", &email_string16);
+  DCHECK(!email_string16.empty());
+  std::string email(base::UTF16ToASCII(email_string16));
+
+  base::string16 password_string16;
+  dict->GetString("password", &password_string16);
+  std::string password(base::UTF16ToASCII(password_string16));
+
+  // 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 (!gaia::AreEmailsSame(email, default_email)) {
+      SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE);
+      return;
+    }
+  }
+
+  base::string16 session_index_string16;
+  dict->GetString("sessionIndex", &session_index_string16);
+  std::string session_index = base::UTF16ToASCII(session_index_string16);
+  DCHECK(!session_index.empty());
 
-  dict->GetBoolean("chooseWhatToSync", &choose_what_to_sync_);
+  bool choose_what_to_sync = false;
+  dict->GetBoolean("chooseWhatToSync", &choose_what_to_sync);
 
-  content::WebContents* contents = web_ui()->GetWebContents();
-  signin::Source source = signin::GetSourceForPromoURL(contents->GetURL());
-  OneClickSigninHelper::CanOfferFor can_offer =
-      source == signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT ?
-      OneClickSigninHelper::CAN_OFFER_FOR_SECONDARY_ACCOUNT :
+  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 =
       OneClickSigninHelper::CAN_OFFER_FOR_ALL;
+  switch (source) {
+    case signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT:
+      can_offer_for = OneClickSigninHelper::CAN_OFFER_FOR_SECONDARY_ACCOUNT;
+      break;
+    case signin::SOURCE_REAUTH: {
+      std::string primary_username =
+          SigninManagerFactory::GetForProfile(
+              Profile::FromWebUI(web_ui()))->GetAuthenticatedUsername();
+      if (!gaia::AreEmailsSame(default_email, primary_username))
+        can_offer_for = OneClickSigninHelper::CAN_OFFER_FOR_SECONDARY_ACCOUNT;
+      break;
+    }
+    default:
+      // No need to change |can_offer_for|.
+      break;
+  }
+
   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;
   }
 
+  AboutSigninInternals* about_signin_internals =
+      AboutSigninInternalsFactory::GetForProfile(Profile::FromWebUI(web_ui()));
+  about_signin_internals->OnAuthenticationResultReceived(
+      "GAIA Auth Successful");
+
   content::StoragePartition* partition =
       content::BrowserContext::GetStoragePartitionForSite(
           contents->GetBrowserContext(),
-          GURL("chrome-guest://mfffpogegjflfpflabcdkioaeobkgjik/?" +
-                partition_id_));
-
-  auth_fetcher_.reset(new GaiaAuthFetcher(this,
-                                          GaiaConstants::kChromeSource,
-                                          partition->GetURLRequestContext()));
-  auth_fetcher_->StartCookieForOAuthCodeExchange("0");
-}
-
-void InlineLoginHandlerImpl::OnClientOAuthCodeSuccess(
-    const std::string& oauth_code) {
-  DCHECK(!oauth_code.empty());
-
-  content::WebContents* contents = web_ui()->GetWebContents();
-  Profile* profile = Profile::FromWebUI(web_ui());
-  ProfileSyncService* sync_service =
-      ProfileSyncServiceFactory::GetForProfile(profile);
-  const GURL& current_url = contents->GetURL();
-  signin::Source source = signin::GetSourceForPromoURL(current_url);
+          GURL(chrome::kChromeUIChromeSigninURL));
+
+  SigninClient* signin_client =
+      ChromeSigninClientFactory::GetForProfile(Profile::FromWebUI(web_ui()));
+  std::string signin_scoped_device_id =
+      signin_client->GetSigninScopedDeviceId();
+  // InlineSigninHelper will delete itself.
+  new InlineSigninHelper(GetWeakPtr(), partition->GetURLRequestContext(),
+                         Profile::FromWebUI(web_ui()), current_url,
+                         email, password, session_index,
+                         signin_scoped_device_id, choose_what_to_sync,
+                         confirm_untrusted_signin_);
 
-  if (source == signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT) {
-    // SigninOAuthHelper will delete itself.
-    SigninOAuthHelper* helper = new SigninOAuthHelper(profile);
-    helper->StartAddingAccount(oauth_code);
-  } else {
-    OneClickSigninSyncStarter::StartSyncMode start_mode =
-        source == signin::SOURCE_SETTINGS || choose_what_to_sync_ ?
-            (SigninGlobalError::GetForProfile(profile)->HasMenuItem() &&
-              sync_service && sync_service->HasSyncSetupCompleted()) ?
-                OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE :
-                OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST :
-            OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS;
-    OneClickSigninSyncStarter::ConfirmationRequired confirmation_required =
-        source == signin::SOURCE_SETTINGS ||
-        source == signin::SOURCE_WEBSTORE_INSTALL ||
-        choose_what_to_sync_?
-            OneClickSigninSyncStarter::NO_CONFIRMATION :
-            OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN;
-      OneClickSigninSyncStarter::Callback sync_callback = base::Bind(
-          &InlineLoginHandlerImpl::SyncStarterCallback,
-          weak_factory_.GetWeakPtr());
-
-      bool cross_account_error_handled =
-          OneClickSigninHelper::HandleCrossAccountError(
-              contents, "" /* session_index, not used */,
-              email_, password_, oauth_code,
-              OneClickSigninHelper::AUTO_ACCEPT_EXPLICIT,
-              source, start_mode, sync_callback);
-
-      if (!cross_account_error_handled) {
-        // 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 */,
-            email_, password_, oauth_code,
-            start_mode,
-            contents,
-            confirmation_required,
-            sync_callback);
-      }
-  }
-
-  email_.clear();
-  password_.clear();
   web_ui()->CallJavascriptFunction("inline.login.closeDialog");
 }
 
-void InlineLoginHandlerImpl::OnClientOAuthCodeFailure(
-    const GoogleServiceAuthError& error) {
-  LOG(ERROR) << "InlineLoginUI::OnClientOAuthCodeFailure";
-  HandleLoginError(error.ToString());
-}
-
 void InlineLoginHandlerImpl::HandleLoginError(const std::string& error_msg) {
   SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE);
 
+  Browser* browser = GetDesktopBrowser();
+  if (browser && !error_msg.empty()) {
+    LoginUIServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()))->
+        DisplayLoginResult(browser, base::UTF8ToUTF16(error_msg));
+  }
+}
+
+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);
   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()));
+                   weak_factory_.GetWeakPtr(),
+                   signin::ShouldShowAccountManagement(current_url)));
   } else {
-     signin::Source source = signin::GetSourceForPromoURL(current_url);
-     DCHECK(source != signin::SOURCE_UNKNOWN);
      OneClickSigninHelper::RedirectToNtpOrAppsPageIfNecessary(contents, source);
   }
 }
 
-void InlineLoginHandlerImpl::CloseTab() {
+void InlineLoginHandlerImpl::CloseTab(bool show_account_management) {
   content::WebContents* tab = web_ui()->GetWebContents();
   Browser* browser = chrome::FindBrowserWithWebContents(tab);
   if (browser) {
@@ -270,5 +438,11 @@ void InlineLoginHandlerImpl::CloseTab() {
             index, TabStripModel::CommandCloseTab);
       }
     }
+
+    if (show_account_management) {
+      browser->window()->ShowAvatarBubbleFromAvatarButton(
+            BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT,
+            signin::ManageAccountsParams());
+    }
   }
 }