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