oauth2_token_service.h revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef GOOGLE_APIS_GAIA_OAUTH2_TOKEN_SERVICE_H_ 6#define GOOGLE_APIS_GAIA_OAUTH2_TOKEN_SERVICE_H_ 7 8#include <map> 9#include <set> 10#include <string> 11 12#include "base/basictypes.h" 13#include "base/gtest_prod_util.h" 14#include "base/memory/scoped_ptr.h" 15#include "base/memory/weak_ptr.h" 16#include "base/observer_list.h" 17#include "base/threading/non_thread_safe.h" 18#include "base/time/time.h" 19#include "base/timer/timer.h" 20#include "google_apis/gaia/google_service_auth_error.h" 21#include "google_apis/gaia/oauth2_access_token_consumer.h" 22#include "google_apis/gaia/oauth2_access_token_fetcher.h" 23 24namespace net { 25class URLRequestContextGetter; 26} 27 28class GoogleServiceAuthError; 29 30// Abstract base class for a service that fetches and caches OAuth2 access 31// tokens. Concrete subclasses should implement GetRefreshToken to return 32// the appropriate refresh token. Derived services might maintain refresh tokens 33// for multiple accounts. 34// 35// All calls are expected from the UI thread. 36// 37// To use this service, call StartRequest() with a given set of scopes and a 38// consumer of the request results. The consumer is required to outlive the 39// request. The request can be deleted. The consumer may be called back 40// asynchronously with the fetch results. 41// 42// - If the consumer is not called back before the request is deleted, it will 43// never be called back. 44// Note in this case, the actual network requests are not canceled and the 45// cache will be populated with the fetched results; it is just the consumer 46// callback that is aborted. 47// 48// - Otherwise the consumer will be called back with the request and the fetch 49// results. 50// 51// The caller of StartRequest() owns the returned request and is responsible to 52// delete the request even once the callback has been invoked. 53class OAuth2TokenService : public base::NonThreadSafe { 54 public: 55 // Class representing a request that fetches an OAuth2 access token. 56 class Request { 57 public: 58 virtual ~Request(); 59 protected: 60 Request(); 61 }; 62 63 // Class representing the consumer of a Request passed to |StartRequest|, 64 // which will be called back when the request completes. 65 class Consumer { 66 public: 67 Consumer(); 68 virtual ~Consumer(); 69 // |request| is a Request that is started by this consumer and has 70 // completed. 71 virtual void OnGetTokenSuccess(const Request* request, 72 const std::string& access_token, 73 const base::Time& expiration_time) = 0; 74 virtual void OnGetTokenFailure(const Request* request, 75 const GoogleServiceAuthError& error) = 0; 76 }; 77 78 // Classes that want to listen for token availability should implement this 79 // interface and register with the AddObserver() call. 80 class Observer { 81 public: 82 // Called whenever a new login-scoped refresh token is available for 83 // account |account_id|. Once available, access tokens can be retrieved for 84 // this account. This is called during initial startup for each token 85 // loaded. 86 virtual void OnRefreshTokenAvailable(const std::string& account_id) {} 87 // Called whenever the login-scoped refresh token becomes unavailable for 88 // account |account_id|. 89 virtual void OnRefreshTokenRevoked(const std::string& account_id) {} 90 // Called after all refresh tokens are loaded during OAuth2TokenService 91 // startup. 92 virtual void OnRefreshTokensLoaded() {} 93 protected: 94 virtual ~Observer() {} 95 }; 96 97 // A set of scopes in OAuth2 authentication. 98 typedef std::set<std::string> ScopeSet; 99 100 OAuth2TokenService(); 101 virtual ~OAuth2TokenService(); 102 103 // Add or remove observers of this token service. 104 void AddObserver(Observer* observer); 105 void RemoveObserver(Observer* observer); 106 107 // Checks in the cache for a valid access token for a specified |account_id| 108 // and |scopes|, and if not found starts a request for an OAuth2 access token 109 // using the OAuth2 refresh token maintained by this instance for that 110 // |account_id|. The caller owns the returned Request. 111 // |scopes| is the set of scopes to get an access token for, |consumer| is 112 // the object that will be called back with results if the returned request 113 // is not deleted. 114 scoped_ptr<Request> StartRequest(const std::string& account_id, 115 const ScopeSet& scopes, 116 Consumer* consumer); 117 118 // This method does the same as |StartRequest| except it uses |client_id| and 119 // |client_secret| to identify OAuth client app instead of using 120 // Chrome's default values. 121 scoped_ptr<Request> StartRequestForClient( 122 const std::string& account_id, 123 const std::string& client_id, 124 const std::string& client_secret, 125 const ScopeSet& scopes, 126 Consumer* consumer); 127 128 // This method does the same as |StartRequest| except it uses the request 129 // context given by |getter| instead of using the one returned by 130 // |GetRequestContext| implemented by derived classes. 131 scoped_ptr<Request> StartRequestWithContext( 132 const std::string& account_id, 133 net::URLRequestContextGetter* getter, 134 const ScopeSet& scopes, 135 Consumer* consumer); 136 137 // Lists account IDs of all accounts with a refresh token maintained by this 138 // instance. 139 virtual std::vector<std::string> GetAccounts(); 140 141 // Returns true if a refresh token exists for |account_id|. If false, calls to 142 // |StartRequest| will result in a Consumer::OnGetTokenFailure callback. 143 virtual bool RefreshTokenIsAvailable(const std::string& account_id); 144 145 // Mark an OAuth2 |access_token| issued for |account_id| and |scopes| as 146 // invalid. This should be done if the token was received from this class, 147 // but was not accepted by the server (e.g., the server returned 148 // 401 Unauthorized). The token will be removed from the cache for the given 149 // scopes. 150 void InvalidateToken(const std::string& account_id, 151 const ScopeSet& scopes, 152 const std::string& access_token); 153 154 // Like |InvalidateToken| except is uses |client_id| to identity OAuth2 client 155 // app that issued the request instead of Chrome's default values. 156 void InvalidateTokenForClient(const std::string& account_id, 157 const std::string& client_id, 158 const ScopeSet& scopes, 159 const std::string& access_token); 160 161 162 // Return the current number of entries in the cache. 163 int cache_size_for_testing() const; 164 void set_max_authorization_token_fetch_retries_for_testing(int max_retries); 165 // Returns the current number of pending fetchers matching given params. 166 size_t GetNumPendingRequestsForTesting( 167 const std::string& client_id, 168 const std::string& account_id, 169 const ScopeSet& scopes) const; 170 171 protected: 172 // Implements a cancelable |OAuth2TokenService::Request|, which should be 173 // operated on the UI thread. 174 // TODO(davidroche): move this out of header file. 175 class RequestImpl : public base::SupportsWeakPtr<RequestImpl>, 176 public base::NonThreadSafe, 177 public Request { 178 public: 179 // |consumer| is required to outlive this. 180 explicit RequestImpl(Consumer* consumer); 181 virtual ~RequestImpl(); 182 183 // Informs |consumer_| that this request is completed. 184 void InformConsumer(const GoogleServiceAuthError& error, 185 const std::string& access_token, 186 const base::Time& expiration_date); 187 188 private: 189 // |consumer_| to call back when this request completes. 190 Consumer* const consumer_; 191 }; 192 193 // Subclasses should return the maintained refresh token for |account_id|. 194 // If no token is available, return an empty string. 195 virtual std::string GetRefreshToken(const std::string& account_id) = 0; 196 197 // Subclasses can override if they want to report errors to the user. 198 virtual void UpdateAuthError( 199 const std::string& account_id, 200 const GoogleServiceAuthError& error); 201 202 // Add a new entry to the cache. 203 // Subclasses can override if there are implementation-specific reasons 204 // that an access token should ever not be cached. 205 virtual void RegisterCacheEntry(const std::string& client_id, 206 const std::string& account_id, 207 const ScopeSet& scopes, 208 const std::string& access_token, 209 const base::Time& expiration_date); 210 211 // Clears the internal token cache. 212 void ClearCache(); 213 214 // Clears all of the tokens belonging to |account_id| from the internal token 215 // cache. It does not matter what other parameters, like |client_id| were 216 // used to request the tokens. 217 void ClearCacheForAccount(const std::string& account_id); 218 219 // Cancels all requests that are currently in progress. 220 void CancelAllRequests(); 221 222 // Cancels all requests related to a given |account_id|. 223 void CancelRequestsForAccount(const std::string& account_id); 224 225 // Called by subclasses to notify observers. 226 virtual void FireRefreshTokenAvailable(const std::string& account_id); 227 virtual void FireRefreshTokenRevoked(const std::string& account_id); 228 virtual void FireRefreshTokensLoaded(); 229 230 // Creates a request implementation. Can be overriden by derived classes to 231 // provide additional control of token consumption. |consumer| will outlive 232 // the created request. 233 virtual scoped_ptr<RequestImpl> CreateRequest(Consumer* consumer); 234 235 // Fetches an OAuth token for the specified client/scopes. Virtual so it can 236 // be overridden for tests and for platform-specific behavior on Android. 237 virtual void FetchOAuth2Token(RequestImpl* request, 238 const std::string& account_id, 239 net::URLRequestContextGetter* getter, 240 const std::string& client_id, 241 const std::string& client_secret, 242 const ScopeSet& scopes); 243 244 // Invalidates the |access_token| issued for |account_id|, |client_id| and 245 // |scopes|. Virtual so it can be overriden for tests and for platform- 246 // specifc behavior. 247 virtual void InvalidateOAuth2Token(const std::string& account_id, 248 const std::string& client_id, 249 const ScopeSet& scopes, 250 const std::string& access_token); 251 252 private: 253 class Fetcher; 254 friend class Fetcher; 255 256 // The parameters used to fetch an OAuth2 access token. 257 struct RequestParameters { 258 RequestParameters(const std::string& client_id, 259 const std::string& account_id, 260 const ScopeSet& scopes); 261 ~RequestParameters(); 262 bool operator<(const RequestParameters& params) const; 263 264 // OAuth2 client id. 265 std::string client_id; 266 // Account id for which the request is made. 267 std::string account_id; 268 // URL scopes for the requested access token. 269 ScopeSet scopes; 270 }; 271 272 typedef std::map<RequestParameters, Fetcher*> PendingFetcherMap; 273 274 // Derived classes must provide a request context used for fetching access 275 // tokens with the |StartRequest| method. 276 virtual net::URLRequestContextGetter* GetRequestContext() = 0; 277 278 // Struct that contains the information of an OAuth2 access token. 279 struct CacheEntry { 280 std::string access_token; 281 base::Time expiration_date; 282 }; 283 284 // This method does the same as |StartRequestWithContext| except it 285 // uses |client_id| and |client_secret| to identify OAuth 286 // client app instead of using Chrome's default values. 287 scoped_ptr<Request> StartRequestForClientWithContext( 288 const std::string& account_id, 289 net::URLRequestContextGetter* getter, 290 const std::string& client_id, 291 const std::string& client_secret, 292 const ScopeSet& scopes, 293 Consumer* consumer); 294 295 // Returns true if GetCacheEntry would return a valid cache entry for the 296 // given scopes. 297 bool HasCacheEntry(const RequestParameters& client_scopes); 298 299 // Posts a task to fire the Consumer callback with the cached token. Must 300 // Must only be called if HasCacheEntry() returns true. 301 void StartCacheLookupRequest(RequestImpl* request, 302 const RequestParameters& client_scopes, 303 Consumer* consumer); 304 305 // Returns a currently valid OAuth2 access token for the given set of scopes, 306 // or NULL if none have been cached. Note the user of this method should 307 // ensure no entry with the same |client_scopes| is added before the usage of 308 // the returned entry is done. 309 const CacheEntry* GetCacheEntry(const RequestParameters& client_scopes); 310 311 // Removes an access token for the given set of scopes from the cache. 312 // Returns true if the entry was removed, otherwise false. 313 bool RemoveCacheEntry(const RequestParameters& client_scopes, 314 const std::string& token_to_remove); 315 316 // Called when |fetcher| finishes fetching. 317 void OnFetchComplete(Fetcher* fetcher); 318 319 // Called when a number of fetchers need to be canceled. 320 void CancelFetchers(std::vector<Fetcher*> fetchers_to_cancel); 321 322 // The cache of currently valid tokens. 323 typedef std::map<RequestParameters, CacheEntry> TokenCache; 324 TokenCache token_cache_; 325 326 // A map from fetch parameters to a fetcher that is fetching an OAuth2 access 327 // token using these parameters. 328 PendingFetcherMap pending_fetchers_; 329 330 // List of observers to notify when token availability changes. 331 // Makes sure list is empty on destruction. 332 ObserverList<Observer, true> observer_list_; 333 334 // Maximum number of retries in fetching an OAuth2 access token. 335 static int max_fetch_retry_num_; 336 337 FRIEND_TEST_ALL_PREFIXES(OAuth2TokenServiceTest, RequestParametersOrderTest); 338 FRIEND_TEST_ALL_PREFIXES(OAuth2TokenServiceTest, 339 SameScopesRequestedForDifferentClients); 340 341 DISALLOW_COPY_AND_ASSIGN(OAuth2TokenService); 342}; 343 344#endif // GOOGLE_APIS_GAIA_OAUTH2_TOKEN_SERVICE_H_ 345