| // 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"; |
| } |
| } |
| } // 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(); |
| } |
| |
| 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 |
| } |