• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
40 namespace gaia {
41 
42 static 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)
47 enum 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 
62 class GaiaAuthenticator;
63 
64 struct 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;
IsChannelShutdownEventGaiaAuthEvent76   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.
83 class 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.
set_message_loop(const MessageLoop * loop)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     AuthResults();
135     ~AuthResults();
136 
137     std::string email;
138     std::string password;
139 
140     // Fields that store various cookies.
141     std::string sid;
142     std::string lsid;
143     std::string auth_token;
144 
145     std::string primary_email;
146 
147     // Fields for items returned when authentication fails.
148     std::string error_msg;
149     enum AuthenticationError auth_error;
150     std::string auth_error_url;
151     std::string captcha_token;
152     std::string captcha_url;
153   };
154 
155  protected:
156 
157   struct AuthParams {
158     AuthParams();
159     ~AuthParams();
160 
161     GaiaAuthenticator* authenticator;
162     uint32 request_id;
163     std::string email;
164     std::string password;
165     std::string captcha_token;
166     std::string captcha_value;
167   };
168 
169   // mutex_ must be entered before calling this function.
170   AuthParams MakeParams(const std::string& user_name,
171                         const std::string& password,
172                         const std::string& captcha_token,
173                         const std::string& captcha_value);
174 
175   // The real Authenticate implementations.
176   bool AuthenticateImpl(const AuthParams& params);
177   bool AuthenticateImpl(const AuthParams& params, AuthResults* results);
178 
179   // virtual for testing purposes.
180   virtual bool PerformGaiaRequest(const AuthParams& params,
181                                   AuthResults* results);
182   virtual bool Post(const GURL& url, const std::string& post_body,
183                     unsigned long* response_code, std::string* response_body);
184 
185   // Caller should fill in results->LSID before calling. Result in
186   // results->primary_email.
187   virtual bool LookupEmail(AuthResults* results);
188 
189   // Subclasses must override to provide a backoff delay. It is virtual instead
190   // of pure virtual for testing purposes.
191   // TODO(sanjeevr): This should be made pure virtual. But this class is
192   // currently directly being used in sync/engine/authenticator.cc, which is
193   // wrong.
194   virtual int GetBackoffDelaySeconds(int current_backoff_delay);
195 
196  public:
197   // Retrieve email.
email()198   inline std::string email() const {
199     DCHECK_EQ(MessageLoop::current(), message_loop_);
200     return auth_results_.email;
201   }
202 
203   // Retrieve password.
password()204   inline std::string password() const {
205     DCHECK_EQ(MessageLoop::current(), message_loop_);
206     return auth_results_.password;
207   }
208 
209   // Retrieve AuthToken, if previously authenticated; otherwise returns "".
auth_token()210   inline std::string auth_token() const {
211     DCHECK_EQ(MessageLoop::current(), message_loop_);
212     return auth_results_.auth_token;
213   }
214 
215   // Retrieve SID cookie. For details, see the Google Accounts documentation.
sid()216   inline std::string sid() const {
217     DCHECK_EQ(MessageLoop::current(), message_loop_);
218     return auth_results_.sid;
219   }
220 
221   // Retrieve LSID cookie. For details, see the Google Accounts documentation.
lsid()222   inline std::string lsid() const {
223     DCHECK_EQ(MessageLoop::current(), message_loop_);
224     return auth_results_.lsid;
225   }
226 
227   // Get last authentication error.
auth_error()228   inline enum AuthenticationError auth_error() const {
229     DCHECK_EQ(MessageLoop::current(), message_loop_);
230     return auth_results_.auth_error;
231   }
232 
auth_error_url()233   inline std::string auth_error_url() const {
234     DCHECK_EQ(MessageLoop::current(), message_loop_);
235     return auth_results_.auth_error_url;
236   }
237 
captcha_token()238   inline std::string captcha_token() const {
239     DCHECK_EQ(MessageLoop::current(), message_loop_);
240     return auth_results_.captcha_token;
241   }
242 
captcha_url()243   inline std::string captcha_url() const {
244     DCHECK_EQ(MessageLoop::current(), message_loop_);
245     return auth_results_.captcha_url;
246   }
247 
results()248   inline AuthResults results() const {
249     DCHECK_EQ(MessageLoop::current(), message_loop_);
250     return auth_results_;
251   }
252 
253   typedef EventChannel<GaiaAuthEvent, base::Lock> Channel;
254 
channel()255   inline Channel* channel() const {
256     return channel_;
257   }
258 
259  private:
260   bool IssueAuthToken(AuthResults* results, const std::string& service_id);
261 
262   // Helper method to parse response when authentication succeeds.
263   void ExtractTokensFrom(const std::string& response, AuthResults* results);
264   // Helper method to parse response when authentication fails.
265   void ExtractAuthErrorFrom(const std::string& response, AuthResults* results);
266 
267   // Fields for the obvious data items.
268   const std::string user_agent_;
269   const std::string service_id_;
270   const std::string gaia_url_;
271 
272   AuthResults auth_results_;
273 
274   // When multiple async requests are running, only the one that started most
275   // recently updates the values.
276   //
277   // Note that even though this code was written to handle multiple requests
278   // simultaneously, the sync code issues auth requests one at a time.
279   uint32 request_count_;
280 
281   Channel* channel_;
282 
283   // Used to compute backoff time for next allowed authentication.
284   int delay_;  // In seconds.
285   // On Windows, time_t is 64-bit by default. Even though we have defined the
286   // _USE_32BIT_TIME_T preprocessor flag, other libraries including this header
287   // may not have that preprocessor flag defined resulting in mismatched class
288   // sizes. So we explicitly define it as 32-bit on Windows.
289   // TODO(sanjeevr): Change this to to use base::Time
290 #if defined(OS_WIN)
291   __time32_t next_allowed_auth_attempt_time_;
292 #else  // defined(OS_WIN)
293   time_t next_allowed_auth_attempt_time_;
294 #endif  // defined(OS_WIN)
295   int early_auth_attempt_count_;
296 
297   // The message loop all our methods are invoked on.
298   const MessageLoop* message_loop_;
299 };
300 
301 }  // namespace gaia
302 #endif  // CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR_H_
303 
304