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 
    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