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
20namespace base {
21class Time;
22}
23
24namespace net {
25class URLRequestContextGetter;
26}
27
28class 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.
52class 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