summaryrefslogtreecommitdiffstats
path: root/google_apis/gaia/gaia_authenticator.h
blob: c9bf3bcba8cd0d429fcc3a5c56f68837f2b2f128 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Use this class to authenticate users with Gaia and access cookies sent
// by the Gaia servers. This class cannot be used on its own becaue it relies
// on a subclass to provide the virtual Post and GetBackoffDelaySeconds methods.
//
// Sample usage:
// class ActualGaiaAuthenticator : public gaia::GaiaAuthenticator {
//   Provides actual implementation of Post and GetBackoffDelaySeconds.
// };
// ActualGaiaAuthenticator gaia_auth("User-Agent", SERVICE_NAME, kGaiaUrl);
// if (gaia_auth.Authenticate("email", "passwd", SAVE_IN_MEMORY_ONLY,
//                            true)) { // Synchronous
//   // Do something with: gaia_auth.auth_token(), or gaia_auth.sid(),
//   // or gaia_auth.lsid()
// }
//
// Credentials can also be preserved for subsequent requests, though these are
// saved in plain-text in memory, and not very secure on client systems. The
// email address associated with the Gaia account can be read; the password is
// write-only.

// TODO(sanjeevr): This class has been moved here from the bookmarks sync code.
// While it is a generic class that handles GAIA authentication, there are some
// artifacts of the sync code which needs to be cleaned up.
#ifndef GOOGLE_APIS_GAIA_GAIA_AUTHENTICATOR_H_
#define GOOGLE_APIS_GAIA_GAIA_AUTHENTICATOR_H_

#include <string>

#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/message_loop.h"
#include "googleurl/src/gurl.h"

namespace gaia {

// Error codes from Gaia. These will be set correctly for both Gaia V1
// (/ClientAuth) and V2 (/ClientLogin)
enum AuthenticationError {
  None                      = 0,
  BadAuthentication         = 1,
  NotVerified               = 2,
  TermsNotAgreed            = 3,
  Unknown                   = 4,
  AccountDeleted            = 5,
  AccountDisabled           = 6,
  CaptchaRequired           = 7,
  ServiceUnavailable        = 8,
  // Errors generated by this class not Gaia.
  CredentialsNotSet         = 9,
  ConnectionUnavailable     = 10
};

class GaiaAuthenticator;

// GaiaAuthenticator can be used to pass user credentials to Gaia and obtain
// cookies set by the Gaia servers.
class GaiaAuthenticator {
  FRIEND_TEST_ALL_PREFIXES(GaiaAuthenticatorTest,
                           TestNewlineAtEndOfAuthTokenRemoved);
 public:

  // Since GaiaAuthenticator can be used for any service, or by any client, you
  // must include a user-agent and a service-id when creating one. The
  // user_agent is a short string used for simple log analysis. gaia_url is used
  // to choose the server to authenticate with (e.g.
  // http://accounts.google.com/ClientLogin).
  GaiaAuthenticator(const std::string& user_agent,
                    const std::string& service_id,
                    const std::string& gaia_url);

  virtual ~GaiaAuthenticator();

  // This object should only be invoked from the AuthWatcherThread message
  // loop, which is injected here.
  void set_message_loop(const base::MessageLoop* loop) { message_loop_ = loop; }

  // Pass credentials to authenticate with, or use saved credentials via an
  // overload. If authentication succeeds, you can retrieve the authentication
  // token via the respective accessors. Returns a boolean indicating whether
  // authentication succeeded or not.
  bool Authenticate(const std::string& user_name, const std::string& password,
                    const std::string& captcha_token,
                    const std::string& captcha_value);

  bool Authenticate(const std::string& user_name, const std::string& password);

  // Pass the LSID to authenticate with. If the authentication succeeds, you can
  // retrieve the authetication token via the respective accessors. Returns a
  // boolean indicating whether authentication succeeded or not.
  // Always returns a long lived token.
  bool AuthenticateWithLsid(const std::string& lsid);

  // Resets all stored cookies to their default values.
  void ResetCredentials();

  void SetUsernamePassword(const std::string& username,
                           const std::string& password);

  void SetUsername(const std::string& username);

  // Virtual for testing
  virtual void RenewAuthToken(const std::string& auth_token);
  void SetAuthToken(const std::string& auth_token);

  struct AuthResults {
    AuthResults();
    AuthResults(const AuthResults& other);
    ~AuthResults();

    std::string email;
    std::string password;

    // Fields that store various cookies.
    std::string sid;
    std::string lsid;
    std::string auth_token;

    std::string primary_email;

    // Fields for items returned when authentication fails.
    std::string error_msg;
    enum AuthenticationError auth_error;
    std::string auth_error_url;
    std::string captcha_token;
    std::string captcha_url;
  };

 protected:

  struct AuthParams {
    AuthParams();
    ~AuthParams();

    GaiaAuthenticator* authenticator;
    uint32 request_id;
    std::string email;
    std::string password;
    std::string captcha_token;
    std::string captcha_value;
  };

  // mutex_ must be entered before calling this function.
  AuthParams MakeParams(const std::string& user_name,
                        const std::string& password,
                        const std::string& captcha_token,
                        const std::string& captcha_value);

  // The real Authenticate implementations.
  bool AuthenticateImpl(const AuthParams& params);
  bool AuthenticateImpl(const AuthParams& params, AuthResults* results);

  // virtual for testing purposes.
  virtual bool PerformGaiaRequest(const AuthParams& params,
                                  AuthResults* results);
  virtual bool Post(const GURL& url, const std::string& post_body,
                    unsigned long* response_code, std::string* response_body);

  // Caller should fill in results->LSID before calling. Result in
  // results->primary_email.
  virtual bool LookupEmail(AuthResults* results);

  // Subclasses must override to provide a backoff delay. It is virtual instead
  // of pure virtual for testing purposes.
  // TODO(sanjeevr): This should be made pure virtual. But this class is
  // currently directly being used in sync/engine/authenticator.cc, which is
  // wrong.
  virtual int GetBackoffDelaySeconds(int current_backoff_delay);

 public:
  // Retrieve email.
  inline std::string email() const {
    DCHECK_EQ(base::MessageLoop::current(), message_loop_);
    return auth_results_.email;
  }

  // Retrieve password.
  inline std::string password() const {
    DCHECK_EQ(base::MessageLoop::current(), message_loop_);
    return auth_results_.password;
  }

  // Retrieve AuthToken, if previously authenticated; otherwise returns "".
  inline std::string auth_token() const {
    DCHECK_EQ(base::MessageLoop::current(), message_loop_);
    return auth_results_.auth_token;
  }

  // Retrieve SID cookie. For details, see the Google Accounts documentation.
  inline std::string sid() const {
    DCHECK_EQ(base::MessageLoop::current(), message_loop_);
    return auth_results_.sid;
  }

  // Retrieve LSID cookie. For details, see the Google Accounts documentation.
  inline std::string lsid() const {
    DCHECK_EQ(base::MessageLoop::current(), message_loop_);
    return auth_results_.lsid;
  }

  // Get last authentication error.
  inline enum AuthenticationError auth_error() const {
    DCHECK_EQ(base::MessageLoop::current(), message_loop_);
    return auth_results_.auth_error;
  }

  inline std::string auth_error_url() const {
    DCHECK_EQ(base::MessageLoop::current(), message_loop_);
    return auth_results_.auth_error_url;
  }

  inline std::string captcha_token() const {
    DCHECK_EQ(base::MessageLoop::current(), message_loop_);
    return auth_results_.captcha_token;
  }

  inline std::string captcha_url() const {
    DCHECK_EQ(base::MessageLoop::current(), message_loop_);
    return auth_results_.captcha_url;
  }

  inline AuthResults results() const {
    DCHECK_EQ(base::MessageLoop::current(), message_loop_);
    return auth_results_;
  }

 private:
  bool IssueAuthToken(AuthResults* results, const std::string& service_id);

  // Helper method to parse response when authentication succeeds.
  void ExtractTokensFrom(const std::string& response, AuthResults* results);
  // Helper method to parse response when authentication fails.
  void ExtractAuthErrorFrom(const std::string& response, AuthResults* results);

  // Fields for the obvious data items.
  const std::string user_agent_;
  const std::string service_id_;
  const std::string gaia_url_;

  AuthResults auth_results_;

  // When multiple async requests are running, only the one that started most
  // recently updates the values.
  //
  // Note that even though this code was written to handle multiple requests
  // simultaneously, the sync code issues auth requests one at a time.
  uint32 request_count_;

  // Used to compute backoff time for next allowed authentication.
  int delay_;  // In seconds.
  // On Windows, time_t is 64-bit by default. Even though we have defined the
  // _USE_32BIT_TIME_T preprocessor flag, other libraries including this header
  // may not have that preprocessor flag defined resulting in mismatched class
  // sizes. So we explicitly define it as 32-bit on Windows.
  // TODO(sanjeevr): Change this to to use base::Time
#if defined(OS_WIN)
  __time32_t next_allowed_auth_attempt_time_;
#else  // defined(OS_WIN)
  time_t next_allowed_auth_attempt_time_;
#endif  // defined(OS_WIN)
  int early_auth_attempt_count_;

  // The message loop all our methods are invoked on.
  const base::MessageLoop* message_loop_;
};

}  // namespace gaia
#endif  // GOOGLE_APIS_GAIA_GAIA_AUTHENTICATOR_H_