blob: 4191a21fa7a0dc247c8a721a77a8b9adbdef8220 [file] [log] [blame]
// Copyright 2017 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 "components/signin/core/browser/dice_account_reconcilor_delegate.h"
#include <vector>
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "components/prefs/pref_service.h"
#include "components/signin/core/browser/signin_client.h"
#include "components/signin/core/browser/signin_pref_names.h"
namespace signin {
DiceAccountReconcilorDelegate::DiceAccountReconcilorDelegate(
SigninClient* signin_client,
AccountConsistencyMethod account_consistency)
: signin_client_(signin_client), account_consistency_(account_consistency) {
DCHECK(signin_client_);
}
bool DiceAccountReconcilorDelegate::IsReconcileEnabled() const {
return DiceMethodGreaterOrEqual(account_consistency_,
AccountConsistencyMethod::kDiceMigration);
}
bool DiceAccountReconcilorDelegate::IsAccountConsistencyEnforced() const {
return account_consistency_ == AccountConsistencyMethod::kDice;
}
std::string DiceAccountReconcilorDelegate::GetGaiaApiSource() const {
return "ChromiumAccountReconcilorDice";
}
// - On first execution, the candidates are examined in this order:
// 1. The primary account
// 2. The current first Gaia account
// 3. The last known first Gaia account
// 4. The first account in the token service
// - On subsequent executions, the order is:
// 1. The current first Gaia account
// 2. The primary account
// 3. The last known first Gaia account
// 4. The first account in the token service
std::string DiceAccountReconcilorDelegate::GetFirstGaiaAccountForReconcile(
const std::vector<std::string>& chrome_accounts,
const std::vector<gaia::ListedAccount>& gaia_accounts,
const std::string& primary_account,
bool first_execution,
bool will_logout) const {
bool primary_account_has_token =
!primary_account.empty() &&
base::ContainsValue(chrome_accounts, primary_account);
if (gaia_accounts.empty()) {
if (primary_account_has_token)
return primary_account;
// Try the last known account. This happens when the cookies are cleared
// while Sync is disabled.
if (base::ContainsValue(chrome_accounts, last_known_first_account_))
return last_known_first_account_;
// As a last resort, use the first Chrome account.
return chrome_accounts.empty() ? std::string() : chrome_accounts[0];
}
const std::string& first_gaia_account = gaia_accounts[0].id;
bool first_gaia_account_has_token =
base::ContainsValue(chrome_accounts, first_gaia_account);
if (!first_gaia_account_has_token &&
(primary_account == first_gaia_account) && gaia_accounts[0].valid) {
// The primary account is also the first Gaia account, and has no token.
// Logout everything.
return std::string();
}
// If the primary Chrome account and the default Gaia account are both in
// error, then the first gaia account can be kept, to avoid logging the user
// out of their other accounts.
// It's only possible when the reconcilor will not perform a logout, because
// that account cannot be rebuilt.
if (!primary_account_has_token && !gaia_accounts[0].valid && !will_logout)
return first_gaia_account;
if (first_execution) {
// On first execution, try the primary account, and then the first Gaia
// account.
if (primary_account_has_token)
return primary_account;
if (first_gaia_account_has_token)
return first_gaia_account;
// As a last resort, use the first Chrome account.
return chrome_accounts.empty() ? std::string() : chrome_accounts[0];
}
// While Chrome is running, try the first Gaia account, and then the
// primary account.
if (first_gaia_account_has_token)
return first_gaia_account;
if (primary_account_has_token)
return primary_account;
// Changing the first Gaia account while Chrome is running would be
// confusing for the user. Logout everything.
return std::string();
}
AccountReconcilorDelegate::RevokeTokenOption
DiceAccountReconcilorDelegate::ShouldRevokeSecondaryTokensBeforeReconcile(
const std::vector<gaia::ListedAccount>& gaia_accounts) {
// During the Dice migration step, before Dice is actually enabled, chrome
// tokens must be cleared when the cookies are cleared.
if ((account_consistency_ == AccountConsistencyMethod::kDiceMigration) &&
gaia_accounts.empty()) {
return RevokeTokenOption::kRevoke;
}
return (account_consistency_ == AccountConsistencyMethod::kDice)
? RevokeTokenOption::kRevokeIfInError
: RevokeTokenOption::kDoNotRevoke;
}
void DiceAccountReconcilorDelegate::OnReconcileFinished(
const std::string& first_account,
bool reconcile_is_noop) {
last_known_first_account_ = first_account;
// Migration happens on startup if the last reconcile was a no-op and the
// refresh tokens are Dice-compatible.
if (DiceMethodGreaterOrEqual(account_consistency_,
AccountConsistencyMethod::kDiceMigration)) {
signin_client_->SetReadyForDiceMigration(
reconcile_is_noop && signin_client_->GetPrefs()->GetBoolean(
prefs::kTokenServiceDiceCompatible));
}
}
} // namespace signin