blob: 3092558e40125685e0afe7de0f7eb595200c38e4 [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 "chrome/browser/signin/account_consistency_mode_manager.h"
#include <string>
#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/account_consistency_mode_manager_factory.h"
#include "chrome/browser/signin/chrome_signin_client_factory.h"
#include "chrome/common/pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/base/signin_buildflags.h"
#include "components/signin/public/base/signin_pref_names.h"
#include "google_apis/google_api_keys.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/account_manager/account_manager_util.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/lacros/account_manager_util.h"
#endif
using signin::AccountConsistencyMethod;
namespace {
// By default, DICE is not enabled in builds lacking an API key. May be set to
// true for tests.
bool g_ignore_missing_oauth_client_for_testing = false;
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
// Preference indicating that the Dice migraton has happened.
const char kDiceMigrationCompletePref[] = "signin.DiceMigrationComplete";
const char kAllowBrowserSigninArgument[] = "allow-browser-signin";
bool IsBrowserSigninAllowedByCommandLine() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(kAllowBrowserSigninArgument)) {
std::string allowBrowserSignin =
command_line->GetSwitchValueASCII(kAllowBrowserSigninArgument);
return base::ToLowerASCII(allowBrowserSignin) == "true";
}
// If the commandline flag is not provided, the default is true.
return true;
}
// Returns true if Desktop Identity Consistency can be enabled for this build
// (i.e. if OAuth client ID and client secret are configured).
bool CanEnableDiceForBuild() {
if (g_ignore_missing_oauth_client_for_testing ||
google_apis::HasOAuthClientConfigured()) {
return true;
}
// Only log this once.
static bool logged_warning = []() {
LOG(WARNING) << "Desktop Identity Consistency cannot be enabled as no "
"OAuth client ID and client secret have been configured.";
return true;
}();
ALLOW_UNUSED_LOCAL(logged_warning);
return false;
}
#endif
} // namespace
// static
AccountConsistencyModeManager* AccountConsistencyModeManager::GetForProfile(
Profile* profile) {
return AccountConsistencyModeManagerFactory::GetForProfile(profile);
}
AccountConsistencyModeManager::AccountConsistencyModeManager(Profile* profile)
: profile_(profile),
account_consistency_(signin::AccountConsistencyMethod::kDisabled),
account_consistency_initialized_(false) {
DCHECK(profile_);
DCHECK(ShouldBuildServiceForProfile(profile));
#if BUILDFLAG(IS_CHROMEOS_LACROS)
// Lacros doesn't support account inconsistency.
// TODO(crbug.com/1220066): Remove this section when Lacros stops building
// with DICE.
profile->GetPrefs()->SetBoolean(prefs::kSigninAllowed, true);
#elif BUILDFLAG(ENABLE_DICE_SUPPORT)
PrefService* prefs = profile->GetPrefs();
// Propagate settings changes from the previous launch to the signin-allowed
// pref.
bool signin_allowed = IsDiceSignInAllowed() &&
prefs->GetBoolean(prefs::kSigninAllowedOnNextStartup);
prefs->SetBoolean(prefs::kSigninAllowed, signin_allowed);
UMA_HISTOGRAM_BOOLEAN("Signin.SigninAllowed", signin_allowed);
#endif
account_consistency_ = ComputeAccountConsistencyMethod(profile_);
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
// New profiles don't need Dice migration. Old profiles may need it if they
// were created before Dice.
if (profile_->IsNewProfile())
SetDiceMigrationCompleted();
#endif
DCHECK_EQ(account_consistency_, ComputeAccountConsistencyMethod(profile_));
account_consistency_initialized_ = true;
}
AccountConsistencyModeManager::~AccountConsistencyModeManager() {}
// static
void AccountConsistencyModeManager::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
registry->RegisterBooleanPref(kDiceMigrationCompletePref, false);
#endif
registry->RegisterBooleanPref(prefs::kSigninAllowedOnNextStartup, true);
}
// static
AccountConsistencyMethod AccountConsistencyModeManager::GetMethodForProfile(
Profile* profile) {
if (!ShouldBuildServiceForProfile(profile))
return AccountConsistencyMethod::kDisabled;
return AccountConsistencyModeManager::GetForProfile(profile)
->GetAccountConsistencyMethod();
}
// static
bool AccountConsistencyModeManager::IsDiceEnabledForProfile(Profile* profile) {
return GetMethodForProfile(profile) == AccountConsistencyMethod::kDice;
}
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
void AccountConsistencyModeManager::SetDiceMigrationCompleted() {
VLOG(1) << "Dice migration completed.";
profile_->GetPrefs()->SetBoolean(kDiceMigrationCompletePref, true);
}
// static
bool AccountConsistencyModeManager::IsDiceMigrationCompleted(Profile* profile) {
return profile->GetPrefs()->GetBoolean(kDiceMigrationCompletePref);
}
// static
bool AccountConsistencyModeManager::IsDiceSignInAllowed() {
return CanEnableDiceForBuild() && IsBrowserSigninAllowedByCommandLine();
}
#endif // BUILDFLAG(ENABLE_DICE_SUPPORT)
// static
bool AccountConsistencyModeManager::IsMirrorEnabledForProfile(
Profile* profile) {
return GetMethodForProfile(profile) == AccountConsistencyMethod::kMirror;
}
// static
void AccountConsistencyModeManager::SetIgnoreMissingOAuthClientForTesting() {
g_ignore_missing_oauth_client_for_testing = true;
}
// static
bool AccountConsistencyModeManager::ShouldBuildServiceForProfile(
Profile* profile) {
return profile->IsRegularProfile() || profile->IsEphemeralGuestProfile();
}
AccountConsistencyMethod
AccountConsistencyModeManager::GetAccountConsistencyMethod() {
#if BUILDFLAG(IS_CHROMEOS_ASH)
// TODO(https://crbug.com/860671): ChromeOS should use the cached value.
// Changing the value dynamically is not supported.
return ComputeAccountConsistencyMethod(profile_);
#else
// The account consistency method should not change during the lifetime of a
// profile. We always return the cached value, but still check that it did not
// change, in order to detect inconsisent states. See https://crbug.com/860471
CHECK(account_consistency_initialized_);
CHECK_EQ(ComputeAccountConsistencyMethod(profile_), account_consistency_);
return account_consistency_;
#endif
}
// static
signin::AccountConsistencyMethod
AccountConsistencyModeManager::ComputeAccountConsistencyMethod(
Profile* profile) {
DCHECK(ShouldBuildServiceForProfile(profile));
#if BUILDFLAG(ENABLE_MIRROR)
return AccountConsistencyMethod::kMirror;
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
return ash::IsAccountManagerAvailable(profile)
? AccountConsistencyMethod::kMirror
: AccountConsistencyMethod::kDisabled;
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
// Mirror / Account Manager is available only for the first / Main Profile.
if (IsAccountManagerAvailable(profile))
return AccountConsistencyMethod::kMirror;
// else: Fall through to ENABLE_DICE_SUPPORT section below.
// TODO(crbug.com/1198490): Return `AccountConsistencyMethod::kDisabled` if
// AccountManager is not available, when DICE has been disabled on Lacros.
#endif
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
if (!profile->GetPrefs()->GetBoolean(prefs::kSigninAllowed)) {
VLOG(1) << "Desktop Identity Consistency disabled as sign-in to Chrome"
"is not allowed";
return AccountConsistencyMethod::kDisabled;
}
return AccountConsistencyMethod::kDice;
#endif
NOTREACHED();
return AccountConsistencyMethod::kDisabled;
}