summaryrefslogtreecommitdiff
path: root/chromium/chrome/browser/signin/dice_intercepted_session_startup_helper.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/chrome/browser/signin/dice_intercepted_session_startup_helper.cc')
-rw-r--r--chromium/chrome/browser/signin/dice_intercepted_session_startup_helper.cc179
1 files changed, 179 insertions, 0 deletions
diff --git a/chromium/chrome/browser/signin/dice_intercepted_session_startup_helper.cc b/chromium/chrome/browser/signin/dice_intercepted_session_startup_helper.cc
new file mode 100644
index 00000000000..ecd8893f92b
--- /dev/null
+++ b/chromium/chrome/browser/signin/dice_intercepted_session_startup_helper.cc
@@ -0,0 +1,179 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/signin/dice_intercepted_session_startup_helper.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "chrome/browser/signin/account_reconcilor_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/browser_navigator_params.h"
+#include "chrome/common/webui_url_constants.h"
+#include "components/signin/public/base/multilogin_parameters.h"
+#include "components/signin/public/identity_manager/accounts_cookie_mutator.h"
+#include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
+#include "components/signin/public/identity_manager/set_accounts_in_cookie_result.h"
+#include "content/public/browser/web_contents.h"
+#include "google_apis/gaia/gaia_auth_fetcher.h"
+#include "google_apis/gaia/gaia_auth_util.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "url/gurl.h"
+
+namespace {
+
+// Returns true if |account_id| is signed in the cookies.
+bool CookieInfoContains(const signin::AccountsInCookieJarInfo& cookie_info,
+ const CoreAccountId& account_id) {
+ const std::vector<gaia::ListedAccount>& accounts =
+ cookie_info.signed_in_accounts;
+ return std::find_if(accounts.begin(), accounts.end(),
+ [&account_id](const gaia::ListedAccount& account) {
+ return account.id == account_id;
+ }) != accounts.end();
+}
+
+} // namespace
+
+DiceInterceptedSessionStartupHelper::DiceInterceptedSessionStartupHelper(
+ Profile* profile,
+ bool is_new_profile,
+ CoreAccountId account_id,
+ content::WebContents* tab_to_move)
+ : profile_(profile),
+ use_multilogin_(is_new_profile),
+ account_id_(account_id) {
+ if (tab_to_move)
+ web_contents_ = tab_to_move->GetWeakPtr();
+}
+
+DiceInterceptedSessionStartupHelper::~DiceInterceptedSessionStartupHelper() =
+ default;
+
+void DiceInterceptedSessionStartupHelper::Startup(base::OnceClosure callback) {
+ callback_ = std::move(callback);
+
+ // Wait until the account is set in cookies of the newly created profile
+ // before opening the URL, so that the user is signed-in in content area. If
+ // the account is still not in the cookie after some timeout, proceed without
+ // cookies, so that the user can at least take some action in the new profile.
+ signin::IdentityManager* identity_manager =
+ IdentityManagerFactory::GetForProfile(profile_);
+ signin::AccountsInCookieJarInfo cookie_info =
+ identity_manager->GetAccountsInCookieJar();
+ if (cookie_info.accounts_are_fresh &&
+ CookieInfoContains(cookie_info, account_id_)) {
+ MoveTab();
+ } else {
+ // Set the timeout.
+ on_cookie_update_timeout_.Reset(base::BindOnce(
+ &DiceInterceptedSessionStartupHelper::MoveTab, base::Unretained(this)));
+ // Adding accounts to the cookies can be an expensive operation. In
+ // particular the ExternalCCResult fetch may time out after multiple seconds
+ // (see kExternalCCResultTimeoutSeconds and https://crbug.com/750316#c37).
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, on_cookie_update_timeout_.callback(), base::Seconds(12));
+
+ accounts_in_cookie_observer_.Observe(identity_manager);
+ if (use_multilogin_)
+ StartupMultilogin(identity_manager);
+ else
+ StartupReconcilor(identity_manager);
+ }
+}
+
+void DiceInterceptedSessionStartupHelper::OnAccountsInCookieUpdated(
+ const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
+ const GoogleServiceAuthError& error) {
+ if (error != GoogleServiceAuthError::AuthErrorNone())
+ return;
+ if (!accounts_in_cookie_jar_info.accounts_are_fresh)
+ return;
+ if (!CookieInfoContains(accounts_in_cookie_jar_info, account_id_))
+ return;
+
+ MoveTab();
+}
+
+void DiceInterceptedSessionStartupHelper::OnStateChanged(
+ signin_metrics::AccountReconcilorState state) {
+ DCHECK(!use_multilogin_);
+ if (state == signin_metrics::ACCOUNT_RECONCILOR_ERROR) {
+ reconcile_error_encountered_ = true;
+ return;
+ }
+
+ // TODO(https://crbug.com/1051864): remove this when the cookie updates are
+ // correctly sent after reconciliation.
+ if (state == signin_metrics::ACCOUNT_RECONCILOR_OK) {
+ signin::IdentityManager* identity_manager =
+ IdentityManagerFactory::GetForProfile(profile_);
+ // GetAccountsInCookieJar() automatically re-schedules a /ListAccounts call
+ // if the cookie is not fresh.
+ signin::AccountsInCookieJarInfo cookie_info =
+ identity_manager->GetAccountsInCookieJar();
+ OnAccountsInCookieUpdated(cookie_info,
+ GoogleServiceAuthError::AuthErrorNone());
+ }
+}
+
+void DiceInterceptedSessionStartupHelper::StartupMultilogin(
+ signin::IdentityManager* identity_manager) {
+ // Lock the reconcilor to avoid making multiple multilogin calls.
+ reconcilor_lock_ = std::make_unique<AccountReconcilor::Lock>(
+ AccountReconcilorFactory::GetForProfile(profile_));
+
+ // Start the multilogin call.
+ signin::MultiloginParameters params = {
+ /*mode=*/gaia::MultiloginMode::MULTILOGIN_UPDATE_COOKIE_ACCOUNTS_ORDER,
+ /*accounts_to_send=*/{account_id_}};
+ identity_manager->GetAccountsCookieMutator()->SetAccountsInCookie(
+ params, gaia::GaiaSource::kChrome,
+ base::BindOnce(
+ &DiceInterceptedSessionStartupHelper::OnSetAccountInCookieCompleted,
+ weak_factory_.GetWeakPtr()));
+}
+
+void DiceInterceptedSessionStartupHelper::StartupReconcilor(
+ signin::IdentityManager* identity_manager) {
+ // TODO(https://crbug.com/1051864): cookie notifications are not triggered
+ // when the account is added by the reconcilor. Observe the reconcilor and
+ // re-trigger the cookie update when it completes.
+ reconcilor_observer_.Observe(
+ AccountReconcilorFactory::GetForProfile(profile_));
+ identity_manager->GetAccountsCookieMutator()->TriggerCookieJarUpdate();
+}
+
+void DiceInterceptedSessionStartupHelper::OnSetAccountInCookieCompleted(
+ signin::SetAccountsInCookieResult result) {
+ DCHECK(use_multilogin_);
+ MoveTab();
+}
+
+void DiceInterceptedSessionStartupHelper::MoveTab() {
+ accounts_in_cookie_observer_.Reset();
+ reconcilor_observer_.Reset();
+ on_cookie_update_timeout_.Cancel();
+ reconcilor_lock_.reset();
+
+ GURL url_to_open = GURL(chrome::kChromeUINewTabURL);
+ // If the intercepted web contents is still alive, close it now.
+ if (web_contents_) {
+ url_to_open = web_contents_->GetURL();
+ web_contents_->Close();
+ }
+
+ // Open a new browser.
+ NavigateParams params(profile_, url_to_open,
+ ui::PAGE_TRANSITION_AUTO_BOOKMARK);
+ Navigate(&params);
+
+ if (callback_)
+ std::move(callback_).Run();
+}