token_service.h revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 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// The TokenService will supply authentication tokens for any service that
6// needs it, such as sync. Whenever the user logs in, a controller watching
7// the token service is expected either to call ClientLogin to derive a new
8// SID and LSID, or to use GAIA OAuth requests to derive an OAuth1 access
9// token for the OAuthLogin scope.  Whenever such credentials are available,
10// the TokenService should be updated with new credentials.  The controller
11// should then start fetching tokens, which will be written to the database
12// after retrieval, as well as provided to listeners.
13//
14// A token service controller like the ChromiumOS login is expected to:
15//
16// Initialize()  // Soon as you can
17// LoadTokensFromDB()  // When it's OK to talk to the database
18// UpdateCredentials()  // When user logs in
19// StartFetchingTokens()  // When it's safe to start fetching
20//
21// Typically a user of the TokenService is expected just to call:
22//
23// if (token_service.HasTokenForService(servicename)) {
24//   SetMyToken(token_service.GetTokenForService(servicename));
25// }
26// RegisterSomeObserver(token_service);
27//
28// Whenever a token update occurs:
29// OnTokenAvailable(...) {
30//   if (IsServiceICareAbout(notification.service())) {
31//     SetMyToken(notification.token())
32//   }
33// }
34//
35// There is currently no easy way to create a fake TokenService. Tests that want
36// to use TokenService to issue tokens without the use of fake GaiaAuthFetchers
37// or persisting the tokens to disk via WebDataService can do this by
38// creating a TokenService (skipping the Initialize() step to avoid interacting
39// with WebDataService) and calling IssueAuthTokenForTest() to issue new tokens.
40// This will result in the TokenService sending out the appropriate
41// TOKEN_AVAILABLE notification and returning the correct response to future
42// calls to Has/GetTokenForService().
43
44#ifndef CHROME_BROWSER_SIGNIN_TOKEN_SERVICE_H_
45#define CHROME_BROWSER_SIGNIN_TOKEN_SERVICE_H_
46
47#include <map>
48#include <string>
49#include <vector>
50
51#include "base/gtest_prod_util.h"
52#include "base/memory/scoped_ptr.h"
53#include "base/observer_list.h"
54#include "chrome/browser/profiles/profile_keyed_service.h"
55#include "chrome/browser/signin/signin_internals_util.h"
56#include "chrome/browser/webdata/web_data_service.h"
57#include "google_apis/gaia/gaia_auth_consumer.h"
58#include "google_apis/gaia/gaia_auth_fetcher.h"
59#include "google_apis/gaia/google_service_auth_error.h"
60
61class Profile;
62class TokenServiceTest;
63
64namespace net {
65class URLRequestContextGetter;
66}
67
68// The TokenService is a Profile member, so all calls are expected
69// from the UI thread.
70class TokenService : public GaiaAuthConsumer,
71                     public ProfileKeyedService,
72                     public WebDataServiceConsumer {
73 public:
74   TokenService();
75   virtual ~TokenService();
76
77  // Notification classes
78  class TokenAvailableDetails {
79   public:
80    TokenAvailableDetails() {}
81    TokenAvailableDetails(const std::string& service,
82                          const std::string& token)
83        : service_(service), token_(token) {}
84    const std::string& service() const { return service_; }
85    const std::string& token() const { return token_; }
86   private:
87    std::string service_;
88    std::string token_;
89  };
90
91  class TokenRequestFailedDetails {
92   public:
93    TokenRequestFailedDetails()
94        : error_(GoogleServiceAuthError::NONE) {}
95    TokenRequestFailedDetails(const std::string& service,
96                              const GoogleServiceAuthError& error)
97        : service_(service), error_(error) {}
98    const std::string& service() const { return service_; }
99    const GoogleServiceAuthError& error() const { return error_; }
100   private:
101    std::string service_;
102    GoogleServiceAuthError error_;
103  };
104
105  // Methods to register or remove SigninDiagnosticObservers
106  void AddSigninDiagnosticsObserver(
107      signin_internals_util::SigninDiagnosticsObserver* observer);
108  void RemoveSigninDiagnosticsObserver(
109      signin_internals_util::SigninDiagnosticsObserver* observer);
110
111  // Initialize this token service with a request source
112  // (usually from a GaiaAuthConsumer constant), and the profile.
113  // Typically you'd then update the credentials.
114  void Initialize(const char* const source, Profile* profile);
115
116  // Used to determine whether Initialize() has been called.
117  bool Initialized() const { return !source_.empty(); }
118
119  // Add a token not supported by a fetcher.
120  void AddAuthTokenManually(const std::string& service,
121                            const std::string& auth_token);
122
123  // Update ClientLogin credentials in the token service.
124  // Afterwards you can StartFetchingTokens.
125  void UpdateCredentials(
126      const GaiaAuthConsumer::ClientLoginResult& credentials);
127
128  // Update credentials in the token service with oauth2 tokens.
129  // Afterwards you can StartFetchingTokens.
130  void UpdateCredentialsWithOAuth2(
131      const GaiaAuthConsumer::ClientOAuthResult& credentials);
132
133  // Terminate any running requests and reset the TokenService to a clean
134  // slate. Resets in memory structures. Does not modify the DB.
135  // When this is done, no tokens will be left in memory and no
136  // user credentials will be left. Useful if a user is logging out.
137  // Initialize doesn't need to be called again but UpdateCredentials does.
138  void ResetCredentialsInMemory();
139
140  // Async load all tokens for services we know of from the DB.
141  // You should do this at startup. Optionally you can do it again
142  // after you reset in memory credentials.
143  virtual void LoadTokensFromDB();
144
145  // Clear all DB stored tokens for the current profile. Tokens may still be
146  // available in memory. If a DB load is pending it may still be serviced.
147  void EraseTokensFromDB();
148
149  // Returns true if tokens have been loaded from the DB. Set when
150  // LoadTokensFromDB() completes, unset when ResetCredentialsInMemory() is
151  // called.
152  bool TokensLoadedFromDB() const;
153
154  // Returns true if the token service has either GAIA credentials or OAuth2
155  // tokens needed to fetch other service tokens.
156  virtual bool AreCredentialsValid() const;
157
158  // Tokens will be fetched for all services(sync, talk) in the background.
159  // Results come back via event channel. Services can also poll before events
160  // are issued.
161  void StartFetchingTokens();
162  virtual bool HasTokenForService(const char* service) const;
163  const std::string& GetTokenForService(const char* const service) const;
164
165  // OAuth login token is an all-powerful token that allows creating OAuth2
166  // tokens for any other scope (i.e. down-scoping).
167  // Typical use is to create an OAuth2 token for appropriate scope and then
168  // use that token to call a Google API.
169  virtual bool HasOAuthLoginToken() const;
170  virtual const std::string& GetOAuth2LoginRefreshToken() const;
171
172  // For tests only. Doesn't save to the WebDB.
173  void IssueAuthTokenForTest(const std::string& service,
174                             const std::string& auth_token);
175
176  // GaiaAuthConsumer implementation.
177  virtual void OnIssueAuthTokenSuccess(const std::string& service,
178                                       const std::string& auth_token) OVERRIDE;
179  virtual void OnIssueAuthTokenFailure(
180      const std::string& service,
181      const GoogleServiceAuthError& error) OVERRIDE;
182  virtual void OnClientOAuthSuccess(const ClientOAuthResult& result) OVERRIDE;
183  virtual void OnClientOAuthFailure(
184      const GoogleServiceAuthError& error) OVERRIDE;
185
186  // WebDataServiceConsumer implementation.
187  virtual void OnWebDataServiceRequestDone(
188      WebDataService::Handle h,
189      const WDTypedResult* result) OVERRIDE;
190
191 protected:
192  // Saves OAuth2 credentials.
193  void SaveOAuth2Credentials(const ClientOAuthResult& result);
194
195  void set_tokens_loaded(bool loaded) {
196    tokens_loaded_ = loaded;
197  }
198
199 private:
200
201  // Gets the list of all service names for which tokens will be retrieved.
202  // This method is meant only for tests.
203  static void GetServiceNamesForTesting(std::vector<std::string>* names);
204
205  void FireTokenAvailableNotification(const std::string& service,
206                                      const std::string& auth_token);
207
208  void FireTokenRequestFailedNotification(const std::string& service,
209                                          const GoogleServiceAuthError& error);
210
211  void LoadTokensIntoMemory(
212      const std::map<std::string, std::string>& db_tokens,
213      std::map<std::string, std::string>* in_memory_tokens);
214  void LoadSingleTokenIntoMemory(
215      const std::map<std::string, std::string>& db_tokens,
216      std::map<std::string, std::string>* in_memory_tokens,
217      const std::string& service);
218
219  void SaveAuthTokenToDB(const std::string& service,
220                         const std::string& auth_token);
221
222  // Returns the index of the given service.
223  static int GetServiceIndex(const std::string& service);
224
225  // The profile with which this instance was initialized, or NULL.
226  Profile* profile_;
227
228  // Web data service to access tokens from.
229  scoped_refptr<WebDataService> web_data_service_;
230  // Getter to use for fetchers.
231  scoped_refptr<net::URLRequestContextGetter> getter_;
232  // Request handle to load Gaia tokens from DB.
233  WebDataService::Handle token_loading_query_;
234  // True if token loading has completed (regardless of success).
235  bool tokens_loaded_;
236
237  // Gaia request source for Gaia accounting.
238  std::string source_;
239  // Credentials from ClientLogin for Issuing auth tokens.
240  GaiaAuthConsumer::ClientLoginResult credentials_;
241
242  // A bunch of fetchers suitable for ClientLogin token issuing. We don't care
243  // about the ordering, nor do we care which is for which service.  The
244  // number of entries in this array must match the number of entries in the
245  // kServices array declared in the cc file.  If not, a compile time error
246  // will occur.
247  scoped_ptr<GaiaAuthFetcher> fetchers_[2];
248
249  // Map from service to token.
250  std::map<std::string, std::string> token_map_;
251
252  // The list of SigninDiagnosticObservers
253  ObserverList<signin_internals_util::SigninDiagnosticsObserver>
254      signin_diagnostics_observers_;
255
256  friend class TokenServiceTest;
257  FRIEND_TEST_ALL_PREFIXES(TokenServiceTest, LoadTokensIntoMemoryBasic);
258  FRIEND_TEST_ALL_PREFIXES(TokenServiceTest, LoadTokensIntoMemoryAdvanced);
259  FRIEND_TEST_ALL_PREFIXES(TokenServiceTest, FullIntegrationNewServicesAdded);
260
261  DISALLOW_COPY_AND_ASSIGN(TokenService);
262};
263
264#endif  // CHROME_BROWSER_SIGNIN_TOKEN_SERVICE_H_
265