#ifndef GOOGLE_APIS_GAIA_OAUTH2_ACCESS_TOKEN_MANAGER_H_
#define GOOGLE_APIS_GAIA_OAUTH2_ACCESS_TOKEN_MANAGER_H_
#include <map>
#include <set>
#include "base/component_export.h"
#include "base/functional/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "google_apis/gaia/core_account_id.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "google_apis/gaia/oauth2_access_token_consumer.h"
namespace network {
class SharedURLLoaderFactory;
}
class OAuth2AccessTokenFetcher;
class COMPONENT_EXPORT(GOOGLE_APIS) OAuth2AccessTokenManager {
public:
typedef std::set<std::string> ScopeSet;
class RequestImpl;
class COMPONENT_EXPORT(GOOGLE_APIS) Delegate {
public:
Delegate();
virtual ~Delegate();
[[nodiscard]] virtual std::unique_ptr<OAuth2AccessTokenFetcher>
CreateAccessTokenFetcher(
const CoreAccountId& account_id,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
OAuth2AccessTokenConsumer* consumer,
const std::string& token_binding_challenge) = 0;
virtual bool HasRefreshToken(const CoreAccountId& account_id) const = 0;
virtual scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory()
const;
virtual bool HandleAccessTokenFetch(
RequestImpl* request,
const CoreAccountId& account_id,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const std::string& client_id,
const std::string& client_secret,
const ScopeSet& scopes);
virtual void OnAccessTokenInvalidated(const CoreAccountId& account_id,
const std::string& client_id,
const ScopeSet& scopes,
const std::string& access_token) {}
virtual void OnAccessTokenFetched(const CoreAccountId& account_id,
const GoogleServiceAuthError& error) {}
};
class COMPONENT_EXPORT(GOOGLE_APIS) Request {
public:
virtual ~Request();
virtual CoreAccountId GetAccountId() const = 0;
protected:
Request();
};
class COMPONENT_EXPORT(GOOGLE_APIS) Consumer {
public:
explicit Consumer(const std::string& id);
virtual ~Consumer();
std::string id() const { return id_; }
virtual void OnGetTokenSuccess(
const Request* request,
const OAuth2AccessTokenConsumer::TokenResponse& token_response) = 0;
virtual void OnGetTokenFailure(const Request* request,
const GoogleServiceAuthError& error) = 0;
private:
std::string id_;
};
class COMPONENT_EXPORT(GOOGLE_APIS) RequestImpl final : public Request {
public:
RequestImpl(const CoreAccountId& account_id, Consumer* consumer);
~RequestImpl() override;
CoreAccountId GetAccountId() const override;
std::string GetConsumerId() const;
void InformConsumer(
const GoogleServiceAuthError& error,
const OAuth2AccessTokenConsumer::TokenResponse& token_response);
base::WeakPtr<RequestImpl> AsWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
private:
const CoreAccountId account_id_;
const raw_ptr<Consumer, DanglingUntriaged> consumer_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<RequestImpl> weak_ptr_factory_{this};
};
class COMPONENT_EXPORT(GOOGLE_APIS) DiagnosticsObserver {
public:
virtual void OnAccessTokenRequested(const CoreAccountId& account_id,
const std::string& consumer_id,
const ScopeSet& scopes) {}
virtual void OnFetchAccessTokenComplete(const CoreAccountId& account_id,
const std::string& consumer_id,
const ScopeSet& scopes,
const GoogleServiceAuthError& error,
base::Time expiration_time) {}
virtual void OnAccessTokenRemoved(const CoreAccountId& account_id,
const ScopeSet& scopes) {}
};
struct COMPONENT_EXPORT(GOOGLE_APIS) RequestParameters {
RequestParameters(const std::string& client_id,
const CoreAccountId& account_id,
const ScopeSet& scopes);
RequestParameters(const RequestParameters& other);
~RequestParameters();
bool operator<(const RequestParameters& params) const;
std::string client_id;
CoreAccountId account_id;
ScopeSet scopes;
};
typedef std::map<RequestParameters, OAuth2AccessTokenConsumer::TokenResponse>
TokenCache;
explicit OAuth2AccessTokenManager(
OAuth2AccessTokenManager::Delegate* delegate);
OAuth2AccessTokenManager(const OAuth2AccessTokenManager&) = delete;
OAuth2AccessTokenManager& operator=(const OAuth2AccessTokenManager&) = delete;
virtual ~OAuth2AccessTokenManager();
OAuth2AccessTokenManager::Delegate* GetDelegate();
const OAuth2AccessTokenManager::Delegate* GetDelegate() const;
void AddDiagnosticsObserver(DiagnosticsObserver* observer);
void RemoveDiagnosticsObserver(DiagnosticsObserver* observer);
std::unique_ptr<Request> StartRequest(const CoreAccountId& account_id,
const ScopeSet& scopes,
Consumer* consumer);
std::unique_ptr<Request> StartRequestForClient(
const CoreAccountId& account_id,
const std::string& client_id,
const std::string& client_secret,
const ScopeSet& scopes,
Consumer* consumer);
std::unique_ptr<Request> StartRequestWithContext(
const CoreAccountId& account_id,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const ScopeSet& scopes,
Consumer* consumer);
virtual void FetchOAuth2Token(
RequestImpl* request,
const CoreAccountId& account_id,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const std::string& client_id,
const std::string& client_secret,
const std::string& consumer_name,
const ScopeSet& scopes);
const OAuth2AccessTokenConsumer::TokenResponse* GetCachedTokenResponse(
const RequestParameters& client_scopes);
void ClearCacheForAccount(const CoreAccountId& account_id);
virtual void CancelRequestsForAccount(const CoreAccountId& account_id,
const GoogleServiceAuthError& error);
void InvalidateAccessToken(const CoreAccountId& account_id,
const ScopeSet& scopes,
const std::string& access_token);
void set_max_authorization_token_fetch_retries_for_testing(int max_retries);
size_t GetNumPendingRequestsForTesting(const std::string& client_id,
const CoreAccountId& account_id,
const ScopeSet& scopes) const;
const base::ObserverList<DiagnosticsObserver, true>::Unchecked&
GetDiagnosticsObserversForTesting();
protected:
virtual void InvalidateAccessTokenImpl(const CoreAccountId& account_id,
const std::string& client_id,
const ScopeSet& scopes,
const std::string& access_token);
private:
class Fetcher;
friend class Fetcher;
TokenCache& token_cache() { return token_cache_; }
std::unique_ptr<OAuth2AccessTokenFetcher> CreateAccessTokenFetcher(
const CoreAccountId& account_id,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
OAuth2AccessTokenConsumer* consumer,
const std::string& token_binding_challenge);
std::unique_ptr<Request> StartRequestForClientWithContext(
const CoreAccountId& account_id,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const std::string& client_id,
const std::string& client_secret,
const ScopeSet& scopes,
Consumer* consumer);
void InformConsumerWithCachedTokenResponse(
const OAuth2AccessTokenConsumer::TokenResponse* token_response,
RequestImpl* request,
const RequestParameters& client_scopes);
bool RemoveCachedTokenResponse(const RequestParameters& client_scopes,
const std::string& token_to_remove);
void OnFetchComplete(const std::string& client_id,
const CoreAccountId& account_id,
const ScopeSet& scopes,
base::expected<OAuth2AccessTokenConsumer::TokenResponse,
GoogleServiceAuthError> response);
void ProcessOnFetchComplete(
const RequestParameters& request_parameters,
base::expected<OAuth2AccessTokenConsumer::TokenResponse,
GoogleServiceAuthError> response,
const std::vector<base::WeakPtr<OAuth2AccessTokenManager::RequestImpl>>&
waiting_requests);
void CancelAllRequests(const GoogleServiceAuthError& error);
void CancelRequestIfMatch(
const GoogleServiceAuthError& error,
base::RepeatingCallback<bool(const RequestParameters&)> match_request);
TokenCache token_cache_;
base::ObserverList<DiagnosticsObserver, true>::Unchecked
diagnostics_observer_list_;
raw_ptr<Delegate> delegate_;
std::map<RequestParameters, std::unique_ptr<Fetcher>> pending_fetchers_;
static int max_fetch_retry_num_;
SEQUENCE_CHECKER(sequence_checker_);
FRIEND_TEST_ALL_PREFIXES(OAuth2AccessTokenManagerTest, ClearCache);
FRIEND_TEST_ALL_PREFIXES(OAuth2AccessTokenManagerTest, ClearCacheForAccount);
FRIEND_TEST_ALL_PREFIXES(OAuth2AccessTokenManagerTest, OnAccessTokenRemoved);
};
#endif