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