Ash: Store a mapping of token handles against refresh token hash
This will be used in follow-up CLs to figure out if token handles are
being checked against the latest token / LST. We have received reports
from Gaia that ChromeOS checks tokens for older LSTs.
Bug: b/297349237
Change-Id: I7c7e98600a71bc6422e6deafbb727c983cb508b9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4812204
Reviewed-by: Roman Sorokin <[email protected]>
Reviewed-by: Anastasiia N <[email protected]>
Commit-Queue: Kush Sinha <[email protected]>
Reviewed-by: David Roger <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1192070}
diff --git a/chrome/browser/ash/login/session/user_session_manager.cc b/chrome/browser/ash/login/session/user_session_manager.cc
index ac4b956..b89a9ac1 100644
--- a/chrome/browser/ash/login/session/user_session_manager.cc
+++ b/chrome/browser/ash/login/session/user_session_manager.cc
@@ -25,6 +25,7 @@
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
+#include "base/hash/sha1.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
@@ -565,6 +566,13 @@
}
}
+// Returns a Base16 encoded SHA1 digest of `data`.
+std::string Sha1Digest(const std::string& data) {
+ const base::SHA1Digest hash =
+ base::SHA1HashSpan(base::as_bytes(base::make_span(data)));
+ return base::HexEncode(hash);
+}
+
} // namespace
UserSessionManagerDelegate::~UserSessionManagerDelegate() {}
@@ -2095,6 +2103,7 @@
profile, token_handle_util_.get(), user_context_.GetAccountId());
token_handle_fetcher_->FillForNewUser(
user_context_.GetAccessToken(),
+ Sha1Digest(user_context_.GetRefreshToken()),
base::BindOnce(&UserSessionManager::OnTokenHandleObtained,
GetUserSessionManagerAsWeakPtr()));
} else {
diff --git a/chrome/browser/ash/login/signin/token_handle_fetcher.cc b/chrome/browser/ash/login/signin/token_handle_fetcher.cc
index 8c39458..611a563b 100644
--- a/chrome/browser/ash/login/signin/token_handle_fetcher.cc
+++ b/chrome/browser/ash/login/signin/token_handle_fetcher.cc
@@ -6,13 +6,24 @@
#include <memory>
+#include "base/check.h"
#include "base/functional/bind.h"
#include "base/metrics/histogram_functions.h"
+#include "base/values.h"
#include "chrome/browser/ash/login/signin/token_handle_util.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part_ash.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/ui/webui/signin/ash/signin_helper.h"
+#include "chromeos/ash/components/account_manager/account_manager_factory.h"
+#include "components/account_id/account_id.h"
+#include "components/account_manager_core/chromeos/account_manager.h"
#include "components/keyed_service/content/browser_context_keyed_service_shutdown_notifier_factory.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/scoped_user_pref_update.h"
#include "components/signin/public/base/consent_level.h"
#include "components/signin/public/identity_manager/access_token_info.h"
#include "components/signin/public/identity_manager/identity_manager.h"
@@ -27,6 +38,10 @@
const int kMaxRetries = 3;
const char kAccessTokenFetchId[] = "token_handle_fetcher";
+// A dictionary pref that stores the mapping from (access) token handles to a
+// hash of the OAuth refresh token from which the token handle was derived.
+constexpr char kTokenHandleMap[] = "ash.token_handle_map";
+
class TokenHandleFetcherShutdownNotifierFactory
: public BrowserContextKeyedServiceShutdownNotifierFactory {
public:
@@ -51,6 +66,12 @@
~TokenHandleFetcherShutdownNotifierFactory() override {}
};
+account_manager::AccountManager* GetAccountManager(Profile* profile) {
+ return g_browser_process->platform_part()
+ ->GetAccountManagerFactory()
+ ->GetAccountManager(profile->GetPath().value());
+}
+
} // namespace
TokenHandleFetcher::TokenHandleFetcher(Profile* profile,
@@ -66,6 +87,10 @@
void TokenHandleFetcher::BackfillToken(TokenFetchingCallback callback) {
callback_ = std::move(callback);
+ if (account_id_.GetAccountType() != AccountType::GOOGLE) {
+ return;
+ }
+
identity_manager_ = IdentityManagerFactory::GetForProfile(profile_);
// This class doesn't care about browser sync consent.
if (!identity_manager_->HasAccountWithRefreshToken(
@@ -110,19 +135,34 @@
return;
}
- FillForAccessToken(token_info.token);
+ GetAccountManager(profile_)->GetTokenHash(
+ account_manager::AccountKey(account_id_.GetGaiaId(),
+ account_manager::AccountType::kGaia),
+ base::BindOnce(&TokenHandleFetcher::FillForAccessToken,
+ weak_factory_.GetWeakPtr(),
+ /*access_token=*/token_info.token));
+}
+
+// static
+void TokenHandleFetcher::RegisterPrefs(PrefRegistrySimple* registry) {
+ registry->RegisterDictionaryPref(/*path=*/kTokenHandleMap);
}
void TokenHandleFetcher::FillForNewUser(const std::string& access_token,
+ const std::string& refresh_token_hash,
TokenFetchingCallback callback) {
callback_ = std::move(callback);
- FillForAccessToken(access_token);
+ FillForAccessToken(access_token, refresh_token_hash);
}
-void TokenHandleFetcher::FillForAccessToken(const std::string& access_token) {
- if (!gaia_client_.get())
+void TokenHandleFetcher::FillForAccessToken(
+ const std::string& access_token,
+ const std::string& refresh_token_hash) {
+ refresh_token_hash_ = refresh_token_hash;
+ if (!gaia_client_.get()) {
gaia_client_ = std::make_unique<gaia::GaiaOAuthClient>(
profile_->GetURLLoaderFactory());
+ }
tokeninfo_response_start_time_ = base::TimeTicks::Now();
gaia_client_->GetTokenInfo(access_token, kMaxRetries, this);
}
@@ -143,6 +183,7 @@
if (handle) {
success = true;
token_handle_util_->StoreTokenHandle(account_id_, *handle);
+ StoreTokenHandleMapping(*handle);
}
}
const base::TimeDelta duration =
@@ -151,6 +192,14 @@
std::move(callback_).Run(account_id_, success);
}
+void TokenHandleFetcher::StoreTokenHandleMapping(
+ const std::string& token_handle) {
+ PrefService* prefs = profile_->GetPrefs();
+ ScopedDictPrefUpdate update(prefs, kTokenHandleMap);
+ CHECK(!refresh_token_hash_.empty());
+ update->Set(token_handle, refresh_token_hash_);
+}
+
void TokenHandleFetcher::OnProfileDestroyed() {
std::move(callback_).Run(account_id_, false);
}
diff --git a/chrome/browser/ash/login/signin/token_handle_fetcher.h b/chrome/browser/ash/login/signin/token_handle_fetcher.h
index 02961f6..650ff2d 100644
--- a/chrome/browser/ash/login/signin/token_handle_fetcher.h
+++ b/chrome/browser/ash/login/signin/token_handle_fetcher.h
@@ -16,6 +16,7 @@
#include "google_apis/gaia/gaia_oauth_client.h"
class Profile;
+class PrefRegistrySimple;
namespace signin {
class IdentityManager;
@@ -42,8 +43,11 @@
using TokenFetchingCallback =
base::OnceCallback<void(const AccountId&, bool success)>;
+ static void RegisterPrefs(PrefRegistrySimple* registry);
+
// Fetch token handle for a user who has just signed in via Gaia online auth.
void FillForNewUser(const std::string& access_token,
+ const std::string& refresh_token_hash,
TokenFetchingCallback callback);
// Fetch token handle for an existing user.
@@ -61,7 +65,9 @@
void OnNetworkError(int response_code) override;
void OnGetTokenInfoResponse(const base::Value::Dict& token_info) override;
- void FillForAccessToken(const std::string& access_token);
+ void FillForAccessToken(const std::string& access_token,
+ const std::string& refresh_token_hash);
+ void StoreTokenHandleMapping(const std::string& token_handle);
// This is called before profile is detroyed.
void OnProfileDestroyed();
@@ -72,11 +78,14 @@
raw_ptr<signin::IdentityManager, ExperimentalAsh> identity_manager_ = nullptr;
base::TimeTicks tokeninfo_response_start_time_ = base::TimeTicks();
+ std::string refresh_token_hash_;
TokenFetchingCallback callback_;
std::unique_ptr<gaia::GaiaOAuthClient> gaia_client_;
std::unique_ptr<signin::PrimaryAccountAccessTokenFetcher>
access_token_fetcher_;
base::CallbackListSubscription profile_shutdown_subscription_;
+
+ base::WeakPtrFactory<TokenHandleFetcher> weak_factory_{this};
};
} // namespace ash
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 1b5ab228..327282b 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -378,6 +378,7 @@
#include "chrome/browser/ash/login/security_token_session_controller.h"
#include "chrome/browser/ash/login/session/user_session_manager.h"
#include "chrome/browser/ash/login/signin/signin_error_notifier.h"
+#include "chrome/browser/ash/login/signin/token_handle_fetcher.h"
#include "chrome/browser/ash/login/startup_utils.h"
#include "chrome/browser/ash/login/users/avatar/user_image_manager.h"
#include "chrome/browser/ash/login/users/avatar/user_image_prefs.h"
@@ -1949,6 +1950,7 @@
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
ash::RegisterUserProfilePrefs(registry, locale);
+ ash::TokenHandleFetcher::RegisterPrefs(registry);
#endif
}