Home | History | Annotate | Download | only in gaia
      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     // 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