OLD | NEW |
(Empty) | |
| 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. |
| 7 // |
| 8 // Sample usage: |
| 9 // GaiaAuthenticator gaia_auth("User-Agent", SYNC_SERVICE_NAME, |
| 10 // browser_sync::kExternalGaiaUrl); |
| 11 // if (gaia_auth.Authenticate("email", "passwd", SAVE_IN_MEMORY_ONLY, |
| 12 // true)) { // Synchronous |
| 13 // // Do something with: gaia_auth.auth_token(), or gaia_auth.sid(), |
| 14 // // or gaia_auth.lsid() |
| 15 // } |
| 16 // |
| 17 // Sample asynchonous usage: |
| 18 // GaiaAuthenticator gaia_auth("User-Agent", SYNC_SERVICE_NAME, |
| 19 // browser_sync::kExternalGaiaUrl); |
| 20 // EventListenerHookup* hookup = NewListenerHookup(gaia_auth.channel(), |
| 21 // this, &OnAuthenticate); |
| 22 // gaia_auth.Authenticate("email", "passwd", true, false); |
| 23 // // OnAuthenticate() will get called with result; |
| 24 // |
| 25 // Credentials can also be preserved for subsequent requests, though these are |
| 26 // saved in plain-text in memory, and not very secure on client systems. The |
| 27 // email address associated with the Gaia account can be read; the password is |
| 28 // write-only. |
| 29 |
| 30 #ifndef CHROME_BROWSER_SYNC_ENGINE_NET_GAIA_AUTHENTICATOR_H_ |
| 31 #define CHROME_BROWSER_SYNC_ENGINE_NET_GAIA_AUTHENTICATOR_H_ |
| 32 |
| 33 #include <string> |
| 34 |
| 35 #include "base/basictypes.h" |
| 36 #include "chrome/browser/sync/engine/net/http_return.h" |
| 37 #include "chrome/browser/sync/util/event_sys.h" |
| 38 #include "chrome/browser/sync/util/pthread_helpers.h" |
| 39 #include "chrome/browser/sync/util/signin.h" |
| 40 #include "googleurl/src/gurl.h" |
| 41 #include "testing/gtest/include/gtest/gtest_prod.h" // For FRIEND_TEST |
| 42 |
| 43 namespace browser_sync { |
| 44 |
| 45 static const char kGaiaUrl[] = |
| 46 "https://www.google.com:443/accounts/ClientLogin"; |
| 47 |
| 48 // Use of the following enum is odd. GaiaAuthenticator only looks at |
| 49 // and DONT_SAVE_CREDENTIALS and SAVE_IN_MEMORY_ONLY (PERSIST_TO_DISK is == to |
| 50 // SAVE_IN_MEMORY_ONLY for GaiaAuthenticator). The sync engine never uses |
| 51 // DONT_SAVE_CREDENTIALS. AuthWatcher does look in GaiaAuthenticator's results |
| 52 // object to decide if it should save credentials to disk. This currently |
| 53 // works so I'm leaving the odd dance alone. |
| 54 |
| 55 enum SaveCredentials { |
| 56 DONT_SAVE_CREDENTIALS, |
| 57 SAVE_IN_MEMORY_ONLY, |
| 58 PERSIST_TO_DISK // Saved in both memory and disk |
| 59 }; |
| 60 |
| 61 // Error codes from Gaia. These will be set correctly for both Gaia V1 |
| 62 // (/ClientAuth) and V2 (/ClientLogin) |
| 63 enum AuthenticationError { |
| 64 None = 0, |
| 65 BadAuthentication = 1, |
| 66 NotVerified = 2, |
| 67 TermsNotAgreed = 3, |
| 68 Unknown = 4, |
| 69 AccountDeleted = 5, |
| 70 AccountDisabled = 6, |
| 71 CaptchaRequired = 7, |
| 72 ServiceUnavailable = 8, |
| 73 // Errors generated by this class not Gaia. |
| 74 CredentialsNotSet = 9, |
| 75 ConnectionUnavailable = 10 |
| 76 }; |
| 77 |
| 78 class GaiaAuthenticator; |
| 79 |
| 80 struct GaiaAuthEvent { |
| 81 enum { |
| 82 GAIA_AUTH_FAILED, |
| 83 GAIA_AUTH_SUCCEEDED, |
| 84 GAIA_AUTHENTICATOR_DESTROYED |
| 85 } |
| 86 what_happened; |
| 87 AuthenticationError error; |
| 88 const GaiaAuthenticator* authenticator; |
| 89 |
| 90 // Lets us use GaiaAuthEvent as its own traits type in hookups. |
| 91 typedef GaiaAuthEvent EventType; |
| 92 static inline bool IsChannelShutdownEvent(const GaiaAuthEvent& event) { |
| 93 return event.what_happened == GAIA_AUTHENTICATOR_DESTROYED; |
| 94 } |
| 95 }; |
| 96 |
| 97 // GaiaAuthenticator can be used to pass user credentials to Gaia and obtain |
| 98 // cookies set by the Gaia servers. |
| 99 class GaiaAuthenticator { |
| 100 FRIEND_TEST(GaiaAuthenticatorTest, TestNewlineAtEndOfAuthTokenRemoved); |
| 101 public: |
| 102 |
| 103 // Since GaiaAuthenticator can be used for any service, or by any client, you |
| 104 // must include a user-agent and a service-id when creating one. The |
| 105 // user_agent is a short string used for simple log analysis. gaia_url is used |
| 106 // to choose the server to authenticate with (e.g. |
| 107 // http://www.google.com/accounts/ClientLogin). |
| 108 GaiaAuthenticator(const std::string& user_agent, |
| 109 const std::string& service_id, |
| 110 const std::string& gaia_url); |
| 111 |
| 112 virtual ~GaiaAuthenticator(); |
| 113 |
| 114 // Pass credentials to authenticate with, or use saved credentials via an |
| 115 // overload. If authentication succeeds, you can retrieve the authentication |
| 116 // token via the respective accessors. Returns a boolean indicating whether |
| 117 // authentication succeeded or not. |
| 118 bool Authenticate(const std::string& user_name, const std::string& password, |
| 119 SaveCredentials should_save_credentials, bool synchronous, |
| 120 const std::string& captcha_token, |
| 121 const std::string& captcha_value, |
| 122 SignIn try_first); |
| 123 |
| 124 bool Authenticate(const std::string& user_name, const std::string& password, |
| 125 SaveCredentials should_save_credentials, bool synchronous, |
| 126 SignIn try_first); |
| 127 |
| 128 bool AuthenticateService(const std::string& service_id, |
| 129 const std::string& sid, |
| 130 const std::string& lsid, |
| 131 std::string* other_service_cookie); |
| 132 |
| 133 // Resets all stored cookies to their default values. |
| 134 void ResetCredentials(); |
| 135 |
| 136 void SetUsernamePassword(const std::string& username, |
| 137 const std::string& password); |
| 138 |
| 139 void SetUsername(const std::string& username); |
| 140 |
| 141 void SetAuthToken(const std::string& auth_token, SaveCredentials); |
| 142 |
| 143 struct AuthResults { |
| 144 SaveCredentials credentials_saved; |
| 145 std::string email; |
| 146 std::string password; |
| 147 |
| 148 // Fields that store various cookies. |
| 149 std::string sid; |
| 150 std::string lsid; |
| 151 std::string auth_token; |
| 152 |
| 153 std::string primary_email; |
| 154 |
| 155 // Fields for items returned when authentication fails. |
| 156 std::string error_msg; |
| 157 enum AuthenticationError auth_error; |
| 158 std::string auth_error_url; |
| 159 std::string captcha_token; |
| 160 std::string captcha_url; |
| 161 SignIn signin; |
| 162 |
| 163 AuthResults () : credentials_saved(DONT_SAVE_CREDENTIALS), |
| 164 auth_error(None) { } |
| 165 }; |
| 166 |
| 167 protected: |
| 168 |
| 169 struct AuthParams { |
| 170 GaiaAuthenticator* authenticator; |
| 171 uint32 request_id; |
| 172 SaveCredentials should_save_credentials; |
| 173 std::string email; |
| 174 std::string password; |
| 175 std::string captcha_token; |
| 176 std::string captcha_value; |
| 177 SignIn try_first; |
| 178 }; |
| 179 |
| 180 // mutex_ must be entered before calling this function. |
| 181 AuthParams MakeParams(const std::string& user_name, |
| 182 const std::string& password, |
| 183 SaveCredentials should_save_credentials, |
| 184 const std::string& captcha_token, |
| 185 const std::string& captcha_value, |
| 186 SignIn try_first); |
| 187 |
| 188 // The real Authenticate implementations. |
| 189 bool AuthenticateImpl(const AuthParams& params); |
| 190 bool AuthenticateImpl(const AuthParams& params, AuthResults* results); |
| 191 bool PerformGaiaRequest(const AuthParams& params, AuthResults* results); |
| 192 bool LaunchAuthenticate(const AuthParams& params, bool synchronous); |
| 193 static void *ThreadMain(void *arg); |
| 194 |
| 195 // virtual for testing purposes |
| 196 virtual bool Post(const GURL& url, const std::string& post_body, |
| 197 unsigned long* response_code, std::string* response_body) { |
| 198 return false; |
| 199 } |
| 200 |
| 201 // Caller should fill in results->LSID before calling. Result in |
| 202 // results->primary_email. |
| 203 bool LookupEmail(AuthResults* results); |
| 204 |
| 205 public: |
| 206 // Retrieve email |
| 207 inline std::string email() const { |
| 208 PThreadScopedLock<PThreadMutex> enter(&mutex_); |
| 209 return auth_results_.email; |
| 210 } |
| 211 |
| 212 // Retrieve password |
| 213 inline std::string password() const { |
| 214 PThreadScopedLock<PThreadMutex> enter(&mutex_); |
| 215 return auth_results_.password; |
| 216 } |
| 217 |
| 218 // Retrieve AuthToken, if previously authenticated; otherwise returns "". |
| 219 inline std::string auth_token() const { |
| 220 PThreadScopedLock<PThreadMutex> enter(&mutex_); |
| 221 return auth_results_.auth_token; |
| 222 } |
| 223 |
| 224 // Retrieve SID cookie. For details, see the Google Accounts documentation. |
| 225 inline std::string sid() const { |
| 226 PThreadScopedLock<PThreadMutex> enter(&mutex_); |
| 227 return auth_results_.sid; |
| 228 } |
| 229 |
| 230 // Retrieve LSID cookie. For details, see the Google Accounts documentation. |
| 231 inline std::string lsid() const { |
| 232 PThreadScopedLock<PThreadMutex> enter(&mutex_); |
| 233 return auth_results_.lsid; |
| 234 } |
| 235 |
| 236 // Get last authentication error. |
| 237 inline enum AuthenticationError auth_error() const { |
| 238 PThreadScopedLock<PThreadMutex> enter(&mutex_); |
| 239 return auth_results_.auth_error; |
| 240 } |
| 241 |
| 242 inline std::string auth_error_url() const { |
| 243 PThreadScopedLock<PThreadMutex> enter(&mutex_); |
| 244 return auth_results_.auth_error_url; |
| 245 } |
| 246 |
| 247 inline std::string captcha_token() const { |
| 248 PThreadScopedLock<PThreadMutex> enter(&mutex_); |
| 249 return auth_results_.captcha_token; |
| 250 } |
| 251 |
| 252 inline std::string captcha_url() const { |
| 253 PThreadScopedLock<PThreadMutex> enter(&mutex_); |
| 254 return auth_results_.captcha_url; |
| 255 } |
| 256 |
| 257 inline AuthResults results() const { |
| 258 PThreadScopedLock<PThreadMutex> enter(&mutex_); |
| 259 return auth_results_; |
| 260 } |
| 261 |
| 262 typedef EventChannel<GaiaAuthEvent, PThreadMutex> Channel; |
| 263 |
| 264 inline Channel* channel() const { |
| 265 return channel_; |
| 266 } |
| 267 |
| 268 private: |
| 269 bool IssueAuthToken(AuthResults* results, const std::string& service_id, |
| 270 bool long_lived_token); |
| 271 |
| 272 // Helper method to parse response when authentication succeeds. |
| 273 void ExtractTokensFrom(const std::string& response, AuthResults* results); |
| 274 // Helper method to parse response when authentication fails. |
| 275 void ExtractAuthErrorFrom(const std::string& response, AuthResults* results); |
| 276 |
| 277 // Fields for the obvious data items. |
| 278 const std::string user_agent_; |
| 279 const std::string service_id_; |
| 280 const std::string gaia_url_; |
| 281 |
| 282 AuthResults auth_results_; |
| 283 |
| 284 // When multiple async requests are running, only the one that started most |
| 285 // recently updates the values. |
| 286 // |
| 287 // Note that even though this code was written to handle multiple requests |
| 288 // simultaneously, the sync code issues auth requests one at a time. |
| 289 uint32 request_count_; |
| 290 |
| 291 Channel* channel_; |
| 292 |
| 293 // Used to compute backoff time for next allowed authentication. |
| 294 int delay_; // In seconds. |
| 295 time_t next_allowed_auth_attempt_time_; |
| 296 int early_auth_attempt_count_; |
| 297 |
| 298 // Protects auth_results_, and request_count_. |
| 299 mutable PThreadMutex mutex_; |
| 300 }; |
| 301 |
| 302 } // namespace browser_sync |
| 303 |
| 304 #endif // CHROME_BROWSER_SYNC_ENGINE_NET_GAIA_AUTHENTICATOR_H_ |
OLD | NEW |