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