gaia_authenticator.h revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2009 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// Use this class to authenticate users with Gaia and access cookies sent
6// by the Gaia servers. This class cannot be used on its own becaue it relies
7// on a subclass to provide the virtual Post and GetBackoffDelaySeconds methods.
8//
9// Sample usage:
10// class ActualGaiaAuthenticator : public gaia::GaiaAuthenticator {
11//   Provides actual implementation of Post and GetBackoffDelaySeconds.
12// };
13// ActualGaiaAuthenticator gaia_auth("User-Agent", SERVICE_NAME, kGaiaUrl);
14// if (gaia_auth.Authenticate("email", "passwd", SAVE_IN_MEMORY_ONLY,
15//                            true)) { // Synchronous
16//   // Do something with: gaia_auth.auth_token(), or gaia_auth.sid(),
17//   // or gaia_auth.lsid()
18// }
19//
20// Credentials can also be preserved for subsequent requests, though these are
21// saved in plain-text in memory, and not very secure on client systems. The
22// email address associated with the Gaia account can be read; the password is
23// write-only.
24
25// TODO(sanjeevr): This class has been moved here from the bookmarks sync code.
26// While it is a generic class that handles GAIA authentication, there are some
27// artifacts of the sync code which needs to be cleaned up.
28#ifndef CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR_H_
29#define CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR_H_
30#pragma once
31
32#include <string>
33
34#include "base/basictypes.h"
35#include "base/gtest_prod_util.h"
36#include "base/message_loop.h"
37#include "chrome/common/deprecated/event_sys.h"
38#include "googleurl/src/gurl.h"
39
40namespace gaia {
41
42static const char kGaiaUrl[] =
43    "https://www.google.com:443/accounts/ClientLogin";
44
45// Error codes from Gaia. These will be set correctly for both Gaia V1
46// (/ClientAuth) and V2 (/ClientLogin)
47enum AuthenticationError {
48  None                      = 0,
49  BadAuthentication         = 1,
50  NotVerified               = 2,
51  TermsNotAgreed            = 3,
52  Unknown                   = 4,
53  AccountDeleted            = 5,
54  AccountDisabled           = 6,
55  CaptchaRequired           = 7,
56  ServiceUnavailable        = 8,
57  // Errors generated by this class not Gaia.
58  CredentialsNotSet         = 9,
59  ConnectionUnavailable     = 10
60};
61
62class GaiaAuthenticator;
63
64struct GaiaAuthEvent {
65  enum {
66    GAIA_AUTH_FAILED,
67    GAIA_AUTH_SUCCEEDED,
68    GAIA_AUTHENTICATOR_DESTROYED
69  }
70  what_happened;
71  AuthenticationError error;
72  const GaiaAuthenticator* authenticator;
73
74  // Lets us use GaiaAuthEvent as its own traits type in hookups.
75  typedef GaiaAuthEvent EventType;
76  static inline bool IsChannelShutdownEvent(const GaiaAuthEvent& event) {
77    return event.what_happened == GAIA_AUTHENTICATOR_DESTROYED;
78  }
79};
80
81// GaiaAuthenticator can be used to pass user credentials to Gaia and obtain
82// cookies set by the Gaia servers.
83class GaiaAuthenticator {
84  FRIEND_TEST_ALL_PREFIXES(GaiaAuthenticatorTest,
85                           TestNewlineAtEndOfAuthTokenRemoved);
86 public:
87
88  // Since GaiaAuthenticator can be used for any service, or by any client, you
89  // must include a user-agent and a service-id when creating one. The
90  // user_agent is a short string used for simple log analysis. gaia_url is used
91  // to choose the server to authenticate with (e.g.
92  // http://www.google.com/accounts/ClientLogin).
93  GaiaAuthenticator(const std::string& user_agent,
94                    const std::string& service_id,
95                    const std::string& gaia_url);
96
97  virtual ~GaiaAuthenticator();
98
99  // This object should only be invoked from the AuthWatcherThread message
100  // loop, which is injected here.
101  void set_message_loop(const MessageLoop* loop) {
102    message_loop_ = loop;
103  }
104
105  // Pass credentials to authenticate with, or use saved credentials via an
106  // overload. If authentication succeeds, you can retrieve the authentication
107  // token via the respective accessors. Returns a boolean indicating whether
108  // authentication succeeded or not.
109  bool Authenticate(const std::string& user_name, const std::string& password,
110                    const std::string& captcha_token,
111                    const std::string& captcha_value);
112
113  bool Authenticate(const std::string& user_name, const std::string& password);
114
115  // Pass the LSID to authenticate with. If the authentication succeeds, you can
116  // retrieve the authetication token via the respective accessors. Returns a
117  // boolean indicating whether authentication succeeded or not.
118  // Always returns a long lived token.
119  bool AuthenticateWithLsid(const std::string& lsid);
120
121  // Resets all stored cookies to their default values.
122  void ResetCredentials();
123
124  void SetUsernamePassword(const std::string& username,
125                           const std::string& password);
126
127  void SetUsername(const std::string& username);
128
129  // Virtual for testing
130  virtual void RenewAuthToken(const std::string& auth_token);
131  void SetAuthToken(const std::string& auth_token);
132
133  struct AuthResults {
134    std::string email;
135    std::string password;
136
137    // Fields that store various cookies.
138    std::string sid;
139    std::string lsid;
140    std::string auth_token;
141
142    std::string primary_email;
143
144    // Fields for items returned when authentication fails.
145    std::string error_msg;
146    enum AuthenticationError auth_error;
147    std::string auth_error_url;
148    std::string captcha_token;
149    std::string captcha_url;
150
151    AuthResults() : auth_error(None) {}
152  };
153
154 protected:
155
156  struct AuthParams {
157    GaiaAuthenticator* authenticator;
158    uint32 request_id;
159    std::string email;
160    std::string password;
161    std::string captcha_token;
162    std::string captcha_value;
163  };
164
165  // mutex_ must be entered before calling this function.
166  AuthParams MakeParams(const std::string& user_name,
167                        const std::string& password,
168                        const std::string& captcha_token,
169                        const std::string& captcha_value);
170
171  // The real Authenticate implementations.
172  bool AuthenticateImpl(const AuthParams& params);
173  bool AuthenticateImpl(const AuthParams& params, AuthResults* results);
174
175  // virtual for testing purposes.
176  virtual bool PerformGaiaRequest(const AuthParams& params,
177                                  AuthResults* results);
178  virtual bool Post(const GURL& url, const std::string& post_body,
179                    unsigned long* response_code, std::string* response_body) {
180    return false;
181  }
182
183  // Caller should fill in results->LSID before calling. Result in
184  // results->primary_email.
185  virtual bool LookupEmail(AuthResults* results);
186
187  // Subclasses must override to provide a backoff delay. It is virtual instead
188  // of pure virtual for testing purposes.
189  // TODO(sanjeevr): This should be made pure virtual. But this class is
190  // currently directly being used in sync/engine/authenticator.cc, which is
191  // wrong.
192  virtual int GetBackoffDelaySeconds(int current_backoff_delay) {
193    NOTREACHED();
194    return current_backoff_delay;
195  }
196
197 public:
198  // Retrieve email.
199  inline std::string email() const {
200    DCHECK_EQ(MessageLoop::current(), message_loop_);
201    return auth_results_.email;
202  }
203
204  // Retrieve password.
205  inline std::string password() const {
206    DCHECK_EQ(MessageLoop::current(), message_loop_);
207    return auth_results_.password;
208  }
209
210  // Retrieve AuthToken, if previously authenticated; otherwise returns "".
211  inline std::string auth_token() const {
212    DCHECK_EQ(MessageLoop::current(), message_loop_);
213    return auth_results_.auth_token;
214  }
215
216  // Retrieve SID cookie. For details, see the Google Accounts documentation.
217  inline std::string sid() const {
218    DCHECK_EQ(MessageLoop::current(), message_loop_);
219    return auth_results_.sid;
220  }
221
222  // Retrieve LSID cookie. For details, see the Google Accounts documentation.
223  inline std::string lsid() const {
224    DCHECK_EQ(MessageLoop::current(), message_loop_);
225    return auth_results_.lsid;
226  }
227
228  // Get last authentication error.
229  inline enum AuthenticationError auth_error() const {
230    DCHECK_EQ(MessageLoop::current(), message_loop_);
231    return auth_results_.auth_error;
232  }
233
234  inline std::string auth_error_url() const {
235    DCHECK_EQ(MessageLoop::current(), message_loop_);
236    return auth_results_.auth_error_url;
237  }
238
239  inline std::string captcha_token() const {
240    DCHECK_EQ(MessageLoop::current(), message_loop_);
241    return auth_results_.captcha_token;
242  }
243
244  inline std::string captcha_url() const {
245    DCHECK_EQ(MessageLoop::current(), message_loop_);
246    return auth_results_.captcha_url;
247  }
248
249  inline AuthResults results() const {
250    DCHECK_EQ(MessageLoop::current(), message_loop_);
251    return auth_results_;
252  }
253
254  typedef EventChannel<GaiaAuthEvent, Lock> Channel;
255
256  inline Channel* channel() const {
257    return channel_;
258  }
259
260 private:
261  bool IssueAuthToken(AuthResults* results, const std::string& service_id);
262
263  // Helper method to parse response when authentication succeeds.
264  void ExtractTokensFrom(const std::string& response, AuthResults* results);
265  // Helper method to parse response when authentication fails.
266  void ExtractAuthErrorFrom(const std::string& response, AuthResults* results);
267
268  // Fields for the obvious data items.
269  const std::string user_agent_;
270  const std::string service_id_;
271  const std::string gaia_url_;
272
273  AuthResults auth_results_;
274
275  // When multiple async requests are running, only the one that started most
276  // recently updates the values.
277  //
278  // Note that even though this code was written to handle multiple requests
279  // simultaneously, the sync code issues auth requests one at a time.
280  uint32 request_count_;
281
282  Channel* channel_;
283
284  // Used to compute backoff time for next allowed authentication.
285  int delay_;  // In seconds.
286  // On Windows, time_t is 64-bit by default. Even though we have defined the
287  // _USE_32BIT_TIME_T preprocessor flag, other libraries including this header
288  // may not have that preprocessor flag defined resulting in mismatched class
289  // sizes. So we explicitly define it as 32-bit on Windows.
290  // TODO(sanjeevr): Change this to to use base::Time
291#if defined(OS_WIN)
292  __time32_t next_allowed_auth_attempt_time_;
293#else  // defined(OS_WIN)
294  time_t next_allowed_auth_attempt_time_;
295#endif  // defined(OS_WIN)
296  int early_auth_attempt_count_;
297
298  // The message loop all our methods are invoked on.
299  const MessageLoop* message_loop_;
300};
301
302}  // namespace gaia
303#endif  // CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR_H_
304
305