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