blob: 50fb83dd5ce3a59d66ac90100beb287af0dc7e93 [file] [log] [blame]
// Copyright 2014 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/profile_oauth2_token_service.h"
#include "base/auto_reset.h"
#include "base/logging.h"
#include "build/build_config.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/signin/core/browser/device_id_helper.h"
#include "components/signin/core/browser/signin_pref_names.h"
using signin_metrics::SourceForRefreshTokenOperation;
namespace {
std::string SourceToString(SourceForRefreshTokenOperation source) {
switch (source) {
case SourceForRefreshTokenOperation::kUnknown:
return "Unknown";
case SourceForRefreshTokenOperation::kTokenService_LoadCredentials:
return "TokenService::LoadCredentials";
case SourceForRefreshTokenOperation::kSupervisedUser_InitSync:
return "SupervisedUser::InitSync";
case SourceForRefreshTokenOperation::kInlineLoginHandler_Signin:
return "InlineLoginHandler::Signin";
case SourceForRefreshTokenOperation::kSigninManager_ClearPrimaryAccount:
return "SigninManager::ClearPrimaryAccount";
case SourceForRefreshTokenOperation::kSigninManager_LegacyPreDiceSigninFlow:
return "SigninManager::LegacyPreDiceSigninFlow";
case SourceForRefreshTokenOperation::kUserMenu_RemoveAccount:
return "UserMenu::RemoveAccount";
case SourceForRefreshTokenOperation::kUserMenu_SignOutAllAccounts:
return "UserMenu::SignOutAllAccounts";
case SourceForRefreshTokenOperation::kSettings_Signout:
return "Settings::Signout";
case SourceForRefreshTokenOperation::kSettings_PauseSync:
return "Settings::PauseSync";
case SourceForRefreshTokenOperation::
kAccountReconcilor_GaiaCookiesDeletedByUser:
return "AccountReconcilor::GaiaCookiesDeletedByUser";
case SourceForRefreshTokenOperation::kAccountReconcilor_GaiaCookiesUpdated:
return "AccountReconcilor::GaiaCookiesUpdated";
case SourceForRefreshTokenOperation::kAccountReconcilor_Reconcile:
return "AccountReconcilor::Reconcile";
case SourceForRefreshTokenOperation::kDiceResponseHandler_Signin:
return "DiceResponseHandler::Signin";
case SourceForRefreshTokenOperation::kDiceResponseHandler_Signout:
return "DiceResponseHandler::Signout";
case SourceForRefreshTokenOperation::kDiceTurnOnSyncHelper_Abort:
return "DiceTurnOnSyncHelper::Abort";
case SourceForRefreshTokenOperation::kMachineLogon_CredentialProvider:
return "MachineLogon::CredentialProvider";
case SourceForRefreshTokenOperation::kTokenService_ExtractCredentials:
return "TokenService::ExtractCredentials";
}
}
} // namespace
ProfileOAuth2TokenService::ProfileOAuth2TokenService(
PrefService* user_prefs,
std::unique_ptr<OAuth2TokenServiceDelegate> delegate)
: OAuth2TokenService(std::move(delegate)),
user_prefs_(user_prefs),
all_credentials_loaded_(false) {
DCHECK(user_prefs_);
AddObserver(this);
}
ProfileOAuth2TokenService::~ProfileOAuth2TokenService() {
RemoveObserver(this);
}
// static
void ProfileOAuth2TokenService::RegisterProfilePrefs(
PrefRegistrySimple* registry) {
#if defined(OS_IOS)
registry->RegisterBooleanPref(prefs::kTokenServiceExcludeAllSecondaryAccounts,
false);
registry->RegisterListPref(prefs::kTokenServiceExcludedSecondaryAccounts);
#endif
registry->RegisterStringPref(prefs::kGoogleServicesSigninScopedDeviceId,
std::string());
}
void ProfileOAuth2TokenService::Shutdown() {
CancelAllRequests();
GetDelegate()->Shutdown();
}
void ProfileOAuth2TokenService::LoadCredentials(
const std::string& primary_account_id) {
DCHECK_EQ(SourceForRefreshTokenOperation::kUnknown,
update_refresh_token_source_);
update_refresh_token_source_ =
SourceForRefreshTokenOperation::kTokenService_LoadCredentials;
GetDelegate()->LoadCredentials(primary_account_id);
}
bool ProfileOAuth2TokenService::AreAllCredentialsLoaded() {
return all_credentials_loaded_;
}
void ProfileOAuth2TokenService::UpdateCredentials(
const std::string& account_id,
const std::string& refresh_token,
SourceForRefreshTokenOperation source) {
base::AutoReset<SourceForRefreshTokenOperation> auto_reset(
&update_refresh_token_source_, source);
GetDelegate()->UpdateCredentials(account_id, refresh_token);
}
void ProfileOAuth2TokenService::RevokeCredentials(
const std::string& account_id,
SourceForRefreshTokenOperation source) {
base::AutoReset<SourceForRefreshTokenOperation> auto_reset(
&update_refresh_token_source_, source);
GetDelegate()->RevokeCredentials(account_id);
}
void ProfileOAuth2TokenService::RevokeAllCredentials(
SourceForRefreshTokenOperation source) {
base::AutoReset<SourceForRefreshTokenOperation> auto_reset(
&update_refresh_token_source_, source);
CancelAllRequests();
ClearCache();
GetDelegate()->RevokeAllCredentials();
}
const net::BackoffEntry* ProfileOAuth2TokenService::GetDelegateBackoffEntry() {
return GetDelegate()->BackoffEntry();
}
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
void ProfileOAuth2TokenService::ExtractCredentials(
ProfileOAuth2TokenService* to_service,
const std::string& account_id) {
base::AutoReset<SourceForRefreshTokenOperation> auto_reset(
&update_refresh_token_source_,
SourceForRefreshTokenOperation::kTokenService_ExtractCredentials);
GetDelegate()->ExtractCredentials(to_service, account_id);
}
#endif
void ProfileOAuth2TokenService::OnRefreshTokenAvailable(
const std::string& account_id) {
// Check if the newly-updated token is valid (invalid tokens are inserted when
// the user signs out on the web with DICE enabled).
bool is_valid = true;
GoogleServiceAuthError token_error = GetAuthError(account_id);
if (token_error == GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
GoogleServiceAuthError::InvalidGaiaCredentialsReason::
CREDENTIALS_REJECTED_BY_CLIENT)) {
is_valid = false;
}
CancelRequestsForAccount(account_id);
ClearCacheForAccount(account_id);
signin_metrics::RecordRefreshTokenUpdatedFromSource(
is_valid, update_refresh_token_source_);
std::string source_string = SourceToString(update_refresh_token_source_);
for (auto& diagnostic_observer : GetDiagnicsObservers()) {
diagnostic_observer.OnRefreshTokenAvailableFromSource(account_id, is_valid,
source_string);
}
}
void ProfileOAuth2TokenService::OnRefreshTokenRevoked(
const std::string& account_id) {
// If this was the last token, recreate the device ID.
RecreateDeviceIdIfNeeded();
CancelRequestsForAccount(account_id);
ClearCacheForAccount(account_id);
signin_metrics::RecordRefreshTokenRevokedFromSource(
update_refresh_token_source_);
std::string source_string = SourceToString(update_refresh_token_source_);
for (auto& diagnostic_observer : GetDiagnicsObservers()) {
diagnostic_observer.OnRefreshTokenRevokedFromSource(account_id,
source_string);
}
}
void ProfileOAuth2TokenService::OnRefreshTokensLoaded() {
DCHECK_NE(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_NOT_STARTED,
GetDelegate()->load_credentials_state());
DCHECK_NE(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_IN_PROGRESS,
GetDelegate()->load_credentials_state());
all_credentials_loaded_ = true;
// Reset the state for update refresh token operations to Unknown as this
// was the original state before LoadCredentials was called.
update_refresh_token_source_ = SourceForRefreshTokenOperation::kUnknown;
// Ensure the device ID is not empty, and recreate it if all tokens were
// cleared during the loading process.
RecreateDeviceIdIfNeeded();
}
bool ProfileOAuth2TokenService::HasLoadCredentialsFinishedWithNoErrors() {
switch (GetDelegate()->load_credentials_state()) {
case OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_NOT_STARTED:
case OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_IN_PROGRESS:
// LoadCredentials has not finished.
return false;
case OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_FINISHED_WITH_DB_ERRORS:
case OAuth2TokenServiceDelegate::
LOAD_CREDENTIALS_FINISHED_WITH_DECRYPT_ERRORS:
case OAuth2TokenServiceDelegate::
LOAD_CREDENTIALS_FINISHED_WITH_UNKNOWN_ERRORS:
// LoadCredentials finished, but with errors
return false;
case OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS:
case OAuth2TokenServiceDelegate::
LOAD_CREDENTIALS_FINISHED_WITH_NO_TOKEN_FOR_PRIMARY_ACCOUNT:
// Load credentials finished with success.
return true;
}
}
void ProfileOAuth2TokenService::RecreateDeviceIdIfNeeded() {
// On ChromeOS the device ID is not managed by the token service.
#if !defined(OS_CHROMEOS)
if (AreAllCredentialsLoaded() && HasLoadCredentialsFinishedWithNoErrors() &&
GetAccounts().empty()) {
signin::RecreateSigninScopedDeviceId(user_prefs_);
}
#endif
}