Home | History | Annotate | Download | only in signin
      1 // Copyright 2012 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 CHROME_BROWSER_SIGNIN_OAUTH2_TOKEN_SERVICE_H_
      6 #define CHROME_BROWSER_SIGNIN_OAUTH2_TOKEN_SERVICE_H_
      7 
      8 #include <map>
      9 #include <set>
     10 #include <string>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/memory/ref_counted.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "base/memory/weak_ptr.h"
     16 #include "base/observer_list.h"
     17 #include "base/time/time.h"
     18 #include "google_apis/gaia/google_service_auth_error.h"
     19 
     20 namespace base {
     21 class Time;
     22 }
     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.
     33 //
     34 // All calls are expected from the UI thread.
     35 //
     36 // To use this service, call StartRequest() with a given set of scopes and a
     37 // consumer of the request results. The consumer is required to outlive the
     38 // request. The request can be deleted. The consumer may be called back
     39 // asynchronously with the fetch results.
     40 //
     41 // - If the consumer is not called back before the request is deleted, it will
     42 //   never be called back.
     43 //   Note in this case, the actual network requests are not canceled and the
     44 //   cache will be populated with the fetched results; it is just the consumer
     45 //   callback that is aborted.
     46 //
     47 // - Otherwise the consumer will be called back with the request and the fetch
     48 //   results.
     49 //
     50 // The caller of StartRequest() owns the returned request and is responsible to
     51 // delete the request even once the callback has been invoked.
     52 class OAuth2TokenService {
     53  public:
     54   // Class representing a request that fetches an OAuth2 access token.
     55   class Request {
     56    public:
     57     virtual ~Request();
     58    protected:
     59     Request();
     60   };
     61 
     62   // Class representing the consumer of a Request passed to |StartRequest|,
     63   // which will be called back when the request completes.
     64   class Consumer {
     65    public:
     66     Consumer();
     67     virtual ~Consumer();
     68     // |request| is a Request that is started by this consumer and has
     69     // completed.
     70     virtual void OnGetTokenSuccess(const Request* request,
     71                                    const std::string& access_token,
     72                                    const base::Time& expiration_time) = 0;
     73     virtual void OnGetTokenFailure(const Request* request,
     74                                    const GoogleServiceAuthError& error) = 0;
     75   };
     76 
     77   // Classes that want to listen for token availability should implement this
     78   // interface and register with the AddObserver() call.
     79   // TODO(rogerta): may get rid of |error| argument for OnRefreshTokenRevoked()
     80   // once we stop supporting ClientLogin.  Need to evaluate if its still useful.
     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                                        const GoogleServiceAuthError& error) {}
     92     // Called after all refresh tokens are loaded during OAuth2TokenService
     93     // startup.
     94     virtual void OnRefreshTokensLoaded() {}
     95     // Called after all refresh tokens are removed from OAuth2TokenService.
     96     virtual void OnRefreshTokensCleared() {}
     97    protected:
     98     virtual ~Observer() {}
     99   };
    100 
    101   // A set of scopes in OAuth2 authentication.
    102   typedef std::set<std::string> ScopeSet;
    103 
    104   OAuth2TokenService();
    105   virtual ~OAuth2TokenService();
    106 
    107   // Add or remove observers of this token service.
    108   void AddObserver(Observer* observer);
    109   void RemoveObserver(Observer* observer);
    110 
    111   // Checks in the cache for a valid access token, and if not found starts
    112   // a request for an OAuth2 access token using the OAuth2 refresh token
    113   // maintained by this instance. The caller owns the returned Request.
    114   // |scopes| is the set of scopes to get an access token for, |consumer| is
    115   // the object that will be called back with results if the returned request
    116   // is not deleted.
    117   virtual scoped_ptr<Request> StartRequest(const ScopeSet& scopes,
    118                                            Consumer* consumer);
    119 
    120   // This method does the same as |StartRequest| except it uses |client_id| and
    121   // |client_secret| to identify OAuth client app instead of using
    122   // Chrome's default values.
    123   virtual scoped_ptr<Request> StartRequestForClient(
    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   virtual scoped_ptr<Request> StartRequestWithContext(
    133       net::URLRequestContextGetter* getter,
    134       const ScopeSet& scopes,
    135       Consumer* consumer);
    136 
    137   // Returns true if a refresh token exists. If false, calls to
    138   // |StartRequest| will result in a Consumer::OnGetTokenFailure callback.
    139   virtual bool RefreshTokenIsAvailable();
    140 
    141   // Mark an OAuth2 access token as invalid. This should be done if the token
    142   // was received from this class, but was not accepted by the server (e.g.,
    143   // the server returned 401 Unauthorized). The token will be removed from the
    144   // cache for the given scopes.
    145   virtual void InvalidateToken(const ScopeSet& scopes,
    146                                const std::string& invalid_token);
    147 
    148   // Return the current number of entries in the cache.
    149   int cache_size_for_testing() const;
    150   void set_max_authorization_token_fetch_retries_for_testing(int max_retries);
    151 
    152  protected:
    153   // Implements a cancelable |OAuth2TokenService::Request|, which should be
    154   // operated on the UI thread.
    155   // TODO(davidroche): move this out of header file.
    156   class RequestImpl : public base::SupportsWeakPtr<RequestImpl>,
    157                       public Request {
    158    public:
    159     // |consumer| is required to outlive this.
    160     explicit RequestImpl(Consumer* consumer);
    161     virtual ~RequestImpl();
    162 
    163     // Informs |consumer_| that this request is completed.
    164     void InformConsumer(const GoogleServiceAuthError& error,
    165                         const std::string& access_token,
    166                         const base::Time& expiration_date);
    167 
    168    private:
    169     // |consumer_| to call back when this request completes.
    170     Consumer* const consumer_;
    171   };
    172 
    173   // Subclasses should return the refresh token maintained.
    174   // If no token is available, return an empty string.
    175   virtual std::string GetRefreshToken() = 0;
    176 
    177   // Subclasses can override if they want to report errors to the user.
    178   virtual void UpdateAuthError(const GoogleServiceAuthError& error);
    179 
    180   // Add a new entry to the cache.
    181   // Subclasses can override if there are implementation-specific reasons
    182   // that an access token should ever not be cached.
    183   virtual void RegisterCacheEntry(const std::string& refresh_token,
    184                                   const ScopeSet& scopes,
    185                                   const std::string& access_token,
    186                                   const base::Time& expiration_date);
    187 
    188   // Returns true if GetCacheEntry would return a valid cache entry for the
    189   // given scopes.
    190   bool HasCacheEntry(const ScopeSet& scopes);
    191 
    192   // Posts a task to fire the Consumer callback with the cached token.  Must
    193   // Must only be called if HasCacheEntry() returns true.
    194   scoped_ptr<Request> StartCacheLookupRequest(const ScopeSet& scopes,
    195                                               Consumer* consumer);
    196 
    197   // Clears the internal token cache.
    198   void ClearCache();
    199 
    200   // Cancels all requests that are currently in progress.
    201   void CancelAllRequests();
    202 
    203   // Cancels all requests related to a given refresh token.
    204   void CancelRequestsForToken(const std::string& refresh_token);
    205 
    206   // Called by subclasses to notify observers.
    207   void FireRefreshTokenAvailable(const std::string& account_id);
    208   void FireRefreshTokenRevoked(const std::string& account_id,
    209                                const GoogleServiceAuthError& error);
    210   void FireRefreshTokensLoaded();
    211   void FireRefreshTokensCleared();
    212 
    213  private:
    214   // Derived classes must provide a request context used for fetching access
    215   // tokens with the |StartRequest| method.
    216   virtual net::URLRequestContextGetter* GetRequestContext() = 0;
    217 
    218   // Class that fetches an OAuth2 access token for a given set of scopes and
    219   // OAuth2 refresh token.
    220   class Fetcher;
    221   friend class Fetcher;
    222 
    223   // Struct that contains the information of an OAuth2 access token.
    224   struct CacheEntry {
    225     std::string access_token;
    226     base::Time expiration_date;
    227   };
    228 
    229   // This method does the same as |StartRequestWithContext| except it
    230   // uses |client_id| and |client_secret| to identify OAuth
    231   // client app instead of using Chrome's default values.
    232   scoped_ptr<Request> StartRequestForClientWithContext(
    233       net::URLRequestContextGetter* getter,
    234       const std::string& client_id,
    235       const std::string& client_secret,
    236       const ScopeSet& scopes,
    237       Consumer* consumer);
    238 
    239   // Returns a currently valid OAuth2 access token for the given set of scopes,
    240   // or NULL if none have been cached. Note the user of this method should
    241   // ensure no entry with the same |scopes| is added before the usage of the
    242   // returned entry is done.
    243   const CacheEntry* GetCacheEntry(const ScopeSet& scopes);
    244 
    245 
    246   // Removes an access token for the given set of scopes from the cache.
    247   // Returns true if the entry was removed, otherwise false.
    248   bool RemoveCacheEntry(const OAuth2TokenService::ScopeSet& scopes,
    249                         const std::string& token_to_remove);
    250 
    251 
    252   // Called when |fetcher| finishes fetching.
    253   void OnFetchComplete(Fetcher* fetcher);
    254 
    255   // Called when a number of fetchers need to be canceled.
    256   void CancelFetchers(std::vector<Fetcher*> fetchers_to_cancel);
    257 
    258   // The cache of currently valid tokens.
    259   typedef std::map<ScopeSet, CacheEntry> TokenCache;
    260   TokenCache token_cache_;
    261 
    262   // The parameters (refresh token and scope set) used to fetch an OAuth2 access
    263   // token.
    264   typedef std::pair<std::string, ScopeSet> FetchParameters;
    265   // A map from fetch parameters to a fetcher that is fetching an OAuth2 access
    266   // token using these parameters.
    267   std::map<FetchParameters, Fetcher*> pending_fetchers_;
    268 
    269   // List of observers to notify when token availiability changes.
    270   // Makes sure list is empty on destruction.
    271   ObserverList<Observer, true> observer_list_;
    272 
    273   // Maximum number of retries in fetching an OAuth2 access token.
    274   static int max_fetch_retry_num_;
    275 
    276   DISALLOW_COPY_AND_ASSIGN(OAuth2TokenService);
    277 };
    278 
    279 #endif  // CHROME_BROWSER_SIGNIN_OAUTH2_TOKEN_SERVICE_H_
    280