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 24 namespace net { 25 class URLRequestContextGetter; 26 } 27 28 class GoogleServiceAuthError; 29 class 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. 54 class 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 104 protected: 105 virtual ~Observer() {} 106 }; 107 108 // Classes that want to monitor status of access token and access token 109 // request should implement this interface and register with the 110 // AddDiagnosticsObserver() call. 111 class DiagnosticsObserver { 112 public: 113 // Called when receiving request for access token. 114 virtual void OnAccessTokenRequested(const std::string& account_id, 115 const std::string& consumer_id, 116 const ScopeSet& scopes) = 0; 117 // Called when access token fetching finished successfully or 118 // unsuccessfully. |expiration_time| are only valid with 119 // successful completion. 120 virtual void OnFetchAccessTokenComplete(const std::string& account_id, 121 const std::string& consumer_id, 122 const ScopeSet& scopes, 123 GoogleServiceAuthError error, 124 base::Time expiration_time) = 0; 125 virtual void OnTokenRemoved(const std::string& account_id, 126 const ScopeSet& scopes) = 0; 127 }; 128 129 OAuth2TokenService(); 130 virtual ~OAuth2TokenService(); 131 132 // Add or remove observers of this token service. 133 void AddObserver(Observer* observer); 134 void RemoveObserver(Observer* observer); 135 136 // Add or remove observers of this token service. 137 void AddDiagnosticsObserver(DiagnosticsObserver* observer); 138 void RemoveDiagnosticsObserver(DiagnosticsObserver* observer); 139 140 // Checks in the cache for a valid access token for a specified |account_id| 141 // and |scopes|, and if not found starts a request for an OAuth2 access token 142 // using the OAuth2 refresh token maintained by this instance for that 143 // |account_id|. The caller owns the returned Request. 144 // |scopes| is the set of scopes to get an access token for, |consumer| is 145 // the object that will be called back with results if the returned request 146 // is not deleted. 147 scoped_ptr<Request> StartRequest(const std::string& account_id, 148 const ScopeSet& scopes, 149 Consumer* consumer); 150 151 // This method does the same as |StartRequest| except it uses |client_id| and 152 // |client_secret| to identify OAuth client app instead of using 153 // Chrome's default values. 154 scoped_ptr<Request> StartRequestForClient( 155 const std::string& account_id, 156 const std::string& client_id, 157 const std::string& client_secret, 158 const ScopeSet& scopes, 159 Consumer* consumer); 160 161 // This method does the same as |StartRequest| except it uses the request 162 // context given by |getter| instead of using the one returned by 163 // |GetRequestContext| implemented by derived classes. 164 scoped_ptr<Request> StartRequestWithContext( 165 const std::string& account_id, 166 net::URLRequestContextGetter* getter, 167 const ScopeSet& scopes, 168 Consumer* consumer); 169 170 // Lists account IDs of all accounts with a refresh token maintained by this 171 // instance. 172 virtual std::vector<std::string> GetAccounts(); 173 174 // Returns true if a refresh token exists for |account_id|. If false, calls to 175 // |StartRequest| will result in a Consumer::OnGetTokenFailure callback. 176 virtual bool RefreshTokenIsAvailable(const std::string& account_id) const = 0; 177 178 // Mark an OAuth2 |access_token| issued for |account_id| and |scopes| as 179 // invalid. This should be done if the token was received from this class, 180 // but was not accepted by the server (e.g., the server returned 181 // 401 Unauthorized). The token will be removed from the cache for the given 182 // scopes. 183 void InvalidateToken(const std::string& account_id, 184 const ScopeSet& scopes, 185 const std::string& access_token); 186 187 // Like |InvalidateToken| except is uses |client_id| to identity OAuth2 client 188 // app that issued the request instead of Chrome's default values. 189 void InvalidateTokenForClient(const std::string& account_id, 190 const std::string& client_id, 191 const ScopeSet& scopes, 192 const std::string& access_token); 193 194 195 // Return the current number of entries in the cache. 196 int cache_size_for_testing() const; 197 void set_max_authorization_token_fetch_retries_for_testing(int max_retries); 198 // Returns the current number of pending fetchers matching given params. 199 size_t GetNumPendingRequestsForTesting( 200 const std::string& client_id, 201 const std::string& account_id, 202 const ScopeSet& scopes) const; 203 204 protected: 205 // Implements a cancelable |OAuth2TokenService::Request|, which should be 206 // operated on the UI thread. 207 // TODO(davidroche): move this out of header file. 208 class RequestImpl : public base::SupportsWeakPtr<RequestImpl>, 209 public base::NonThreadSafe, 210 public Request { 211 public: 212 // |consumer| is required to outlive this. 213 explicit RequestImpl(const std::string& account_id, Consumer* consumer); 214 virtual ~RequestImpl(); 215 216 // Overridden from Request: 217 virtual std::string GetAccountId() const OVERRIDE; 218 219 std::string GetConsumerId() const; 220 221 // Informs |consumer_| that this request is completed. 222 void InformConsumer(const GoogleServiceAuthError& error, 223 const std::string& access_token, 224 const base::Time& expiration_date); 225 226 private: 227 // |consumer_| to call back when this request completes. 228 const std::string account_id_; 229 Consumer* const consumer_; 230 }; 231 232 // Subclasses can override if they want to report errors to the user. 233 virtual void UpdateAuthError( 234 const std::string& account_id, 235 const GoogleServiceAuthError& error); 236 237 // Add a new entry to the cache. 238 // Subclasses can override if there are implementation-specific reasons 239 // that an access token should ever not be cached. 240 virtual void RegisterCacheEntry(const std::string& client_id, 241 const std::string& account_id, 242 const ScopeSet& scopes, 243 const std::string& access_token, 244 const base::Time& expiration_date); 245 246 // Clears the internal token cache. 247 void ClearCache(); 248 249 // Clears all of the tokens belonging to |account_id| from the internal token 250 // cache. It does not matter what other parameters, like |client_id| were 251 // used to request the tokens. 252 void ClearCacheForAccount(const std::string& account_id); 253 254 // Cancels all requests that are currently in progress. 255 void CancelAllRequests(); 256 257 // Cancels all requests related to a given |account_id|. 258 void CancelRequestsForAccount(const std::string& account_id); 259 260 // Called by subclasses to notify observers. 261 virtual void FireRefreshTokenAvailable(const std::string& account_id); 262 virtual void FireRefreshTokenRevoked(const std::string& account_id); 263 virtual void FireRefreshTokensLoaded(); 264 265 // Fetches an OAuth token for the specified client/scopes. Virtual so it can 266 // be overridden for tests and for platform-specific behavior on Android. 267 virtual void FetchOAuth2Token(RequestImpl* request, 268 const std::string& account_id, 269 net::URLRequestContextGetter* getter, 270 const std::string& client_id, 271 const std::string& client_secret, 272 const ScopeSet& scopes); 273 274 // Creates an access token fetcher for the given account id. 275 // 276 // Subclasses should override to create an access token fetcher for the given 277 // |account_id|. This method is only called if subclasses use the default 278 // implementation of |FetchOAuth2Token|. 279 virtual OAuth2AccessTokenFetcher* CreateAccessTokenFetcher( 280 const std::string& account_id, 281 net::URLRequestContextGetter* getter, 282 OAuth2AccessTokenConsumer* consumer) = 0; 283 284 // Invalidates the |access_token| issued for |account_id|, |client_id| and 285 // |scopes|. Virtual so it can be overriden for tests and for platform- 286 // specifc behavior. 287 virtual void InvalidateOAuth2Token(const std::string& account_id, 288 const std::string& client_id, 289 const ScopeSet& scopes, 290 const std::string& access_token); 291 292 private: 293 class Fetcher; 294 friend class Fetcher; 295 296 // The parameters used to fetch an OAuth2 access token. 297 struct RequestParameters { 298 RequestParameters(const std::string& client_id, 299 const std::string& account_id, 300 const ScopeSet& scopes); 301 ~RequestParameters(); 302 bool operator<(const RequestParameters& params) const; 303 304 // OAuth2 client id. 305 std::string client_id; 306 // Account id for which the request is made. 307 std::string account_id; 308 // URL scopes for the requested access token. 309 ScopeSet scopes; 310 }; 311 312 typedef std::map<RequestParameters, Fetcher*> PendingFetcherMap; 313 314 // Derived classes must provide a request context used for fetching access 315 // tokens with the |StartRequest| method. 316 virtual net::URLRequestContextGetter* GetRequestContext() = 0; 317 318 // Struct that contains the information of an OAuth2 access token. 319 struct CacheEntry { 320 std::string access_token; 321 base::Time expiration_date; 322 }; 323 324 // This method does the same as |StartRequestWithContext| except it 325 // uses |client_id| and |client_secret| to identify OAuth 326 // client app instead of using Chrome's default values. 327 scoped_ptr<Request> StartRequestForClientWithContext( 328 const std::string& account_id, 329 net::URLRequestContextGetter* getter, 330 const std::string& client_id, 331 const std::string& client_secret, 332 const ScopeSet& scopes, 333 Consumer* consumer); 334 335 // Returns true if GetCacheEntry would return a valid cache entry for the 336 // given scopes. 337 bool HasCacheEntry(const RequestParameters& client_scopes); 338 339 // Posts a task to fire the Consumer callback with the cached token. Must 340 // Must only be called if HasCacheEntry() returns true. 341 void StartCacheLookupRequest(RequestImpl* request, 342 const RequestParameters& client_scopes, 343 Consumer* consumer); 344 345 // Returns a currently valid OAuth2 access token for the given set of scopes, 346 // or NULL if none have been cached. Note the user of this method should 347 // ensure no entry with the same |client_scopes| is added before the usage of 348 // the returned entry is done. 349 const CacheEntry* GetCacheEntry(const RequestParameters& client_scopes); 350 351 // Removes an access token for the given set of scopes from the cache. 352 // Returns true if the entry was removed, otherwise false. 353 bool RemoveCacheEntry(const RequestParameters& client_scopes, 354 const std::string& token_to_remove); 355 356 // Called when |fetcher| finishes fetching. 357 void OnFetchComplete(Fetcher* fetcher); 358 359 // Called when a number of fetchers need to be canceled. 360 void CancelFetchers(std::vector<Fetcher*> fetchers_to_cancel); 361 362 // The cache of currently valid tokens. 363 typedef std::map<RequestParameters, CacheEntry> TokenCache; 364 TokenCache token_cache_; 365 366 // A map from fetch parameters to a fetcher that is fetching an OAuth2 access 367 // token using these parameters. 368 PendingFetcherMap pending_fetchers_; 369 370 // List of observers to notify when refresh token availability changes. 371 // Makes sure list is empty on destruction. 372 ObserverList<Observer, true> observer_list_; 373 374 // List of observers to notify when access token status changes. 375 ObserverList<DiagnosticsObserver, true> diagnostics_observer_list_; 376 377 // Maximum number of retries in fetching an OAuth2 access token. 378 static int max_fetch_retry_num_; 379 380 FRIEND_TEST_ALL_PREFIXES(OAuth2TokenServiceTest, RequestParametersOrderTest); 381 FRIEND_TEST_ALL_PREFIXES(OAuth2TokenServiceTest, 382 SameScopesRequestedForDifferentClients); 383 384 DISALLOW_COPY_AND_ASSIGN(OAuth2TokenService); 385 }; 386 387 #endif // GOOGLE_APIS_GAIA_OAUTH2_TOKEN_SERVICE_H_ 388