| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/sync/engine/net/gaia_authenticator.h" | 5 #include "chrome/browser/sync/engine/net/gaia_authenticator.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <utility> | 8 #include <utility> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 early_auth_attempt_count_(0) { | 97 early_auth_attempt_count_(0) { |
| 98 GaiaAuthEvent done = { GaiaAuthEvent::GAIA_AUTHENTICATOR_DESTROYED, None, | 98 GaiaAuthEvent done = { GaiaAuthEvent::GAIA_AUTHENTICATOR_DESTROYED, None, |
| 99 this }; | 99 this }; |
| 100 channel_ = new Channel(done); | 100 channel_ = new Channel(done); |
| 101 } | 101 } |
| 102 | 102 |
| 103 GaiaAuthenticator::~GaiaAuthenticator() { | 103 GaiaAuthenticator::~GaiaAuthenticator() { |
| 104 delete channel_; | 104 delete channel_; |
| 105 } | 105 } |
| 106 | 106 |
| 107 bool GaiaAuthenticator::LaunchAuthenticate(const AuthParams& params, | |
| 108 bool synchronous) { | |
| 109 if (synchronous) | |
| 110 return AuthenticateImpl(params); | |
| 111 AuthParams* copy = new AuthParams; | |
| 112 *copy = params; | |
| 113 pthread_t thread_id; | |
| 114 int result = pthread_create(&thread_id, 0, &GaiaAuthenticator::ThreadMain, | |
| 115 copy); | |
| 116 if (result) | |
| 117 return false; | |
| 118 return true; | |
| 119 } | |
| 120 | |
| 121 | |
| 122 void* GaiaAuthenticator::ThreadMain(void* arg) { | |
| 123 NameCurrentThreadForDebugging("SyncEngine_GaiaAuthenticatorThread"); | |
| 124 AuthParams* const params = reinterpret_cast<AuthParams*>(arg); | |
| 125 params->authenticator->AuthenticateImpl(*params); | |
| 126 delete params; | |
| 127 return 0; | |
| 128 } | |
| 129 | |
| 130 // mutex_ must be entered before calling this function. | 107 // mutex_ must be entered before calling this function. |
| 131 GaiaAuthenticator::AuthParams GaiaAuthenticator::MakeParams( | 108 GaiaAuthenticator::AuthParams GaiaAuthenticator::MakeParams( |
| 132 const string& user_name, | 109 const string& user_name, |
| 133 const string& password, | 110 const string& password, |
| 134 SaveCredentials should_save_credentials, | 111 SaveCredentials should_save_credentials, |
| 135 const string& captcha_token, | 112 const string& captcha_token, |
| 136 const string& captcha_value, | 113 const string& captcha_value, |
| 137 SignIn try_first) { | 114 SignIn try_first) { |
| 138 AuthParams params; | 115 AuthParams params; |
| 139 params.request_id = ++request_count_; | 116 params.request_id = ++request_count_; |
| 140 params.email = user_name; | 117 params.email = user_name; |
| 141 params.password = password; | 118 params.password = password; |
| 142 params.should_save_credentials = should_save_credentials; | 119 params.should_save_credentials = should_save_credentials; |
| 143 params.captcha_token = captcha_token; | 120 params.captcha_token = captcha_token; |
| 144 params.captcha_value = captcha_value; | 121 params.captcha_value = captcha_value; |
| 145 params.authenticator = this; | 122 params.authenticator = this; |
| 146 params.try_first = try_first; | 123 params.try_first = try_first; |
| 147 return params; | 124 return params; |
| 148 } | 125 } |
| 149 | 126 |
| 150 bool GaiaAuthenticator::Authenticate(const string& user_name, | 127 bool GaiaAuthenticator::Authenticate(const string& user_name, |
| 151 const string& password, | 128 const string& password, |
| 152 SaveCredentials should_save_credentials, | 129 SaveCredentials should_save_credentials, |
| 153 bool synchronous, | |
| 154 const string& captcha_token, | 130 const string& captcha_token, |
| 155 const string& captcha_value, | 131 const string& captcha_value, |
| 156 SignIn try_first) { | 132 SignIn try_first) { |
| 157 mutex_.Lock(); | 133 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 134 |
| 158 AuthParams const params = | 135 AuthParams const params = |
| 159 MakeParams(user_name, password, should_save_credentials, captcha_token, | 136 MakeParams(user_name, password, should_save_credentials, captcha_token, |
| 160 captcha_value, try_first); | 137 captcha_value, try_first); |
| 161 mutex_.Unlock(); | 138 return AuthenticateImpl(params); |
| 162 return LaunchAuthenticate(params, synchronous); | |
| 163 } | 139 } |
| 164 | 140 |
| 165 bool GaiaAuthenticator::AuthenticateImpl(const AuthParams& params) { | 141 bool GaiaAuthenticator::AuthenticateImpl(const AuthParams& params) { |
| 142 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 166 AuthResults results; | 143 AuthResults results; |
| 167 const bool succeeded = AuthenticateImpl(params, &results); | 144 const bool succeeded = AuthenticateImpl(params, &results); |
| 168 mutex_.Lock(); | |
| 169 if (params.request_id == request_count_) { | 145 if (params.request_id == request_count_) { |
| 170 auth_results_ = results; | 146 auth_results_ = results; |
| 171 GaiaAuthEvent event = { succeeded ? GaiaAuthEvent::GAIA_AUTH_SUCCEEDED | 147 GaiaAuthEvent event = { succeeded ? GaiaAuthEvent::GAIA_AUTH_SUCCEEDED |
| 172 : GaiaAuthEvent::GAIA_AUTH_FAILED, | 148 : GaiaAuthEvent::GAIA_AUTH_FAILED, |
| 173 results.auth_error, this }; | 149 results.auth_error, this }; |
| 174 mutex_.Unlock(); | |
| 175 channel_->NotifyListeners(event); | 150 channel_->NotifyListeners(event); |
| 176 } else { | |
| 177 mutex_.Unlock(); | |
| 178 } | 151 } |
| 179 return succeeded; | 152 return succeeded; |
| 180 } | 153 } |
| 181 | 154 |
| 182 // This method makes an HTTP request to the Gaia server, and calls other | 155 // This method makes an HTTP request to the Gaia server, and calls other |
| 183 // methods to help parse the response. If authentication succeeded, then | 156 // methods to help parse the response. If authentication succeeded, then |
| 184 // Gaia-issued cookies are available in the respective variables; if | 157 // Gaia-issued cookies are available in the respective variables; if |
| 185 // authentication failed, then the exact error is available as an enum. If the | 158 // authentication failed, then the exact error is available as an enum. If the |
| 186 // client wishes to save the credentials, the last parameter must be true. | 159 // client wishes to save the credentials, the last parameter must be true. |
| 187 // If a subsequent request is made with fresh credentials, the saved credentials | 160 // If a subsequent request is made with fresh credentials, the saved credentials |
| 188 // are wiped out; any subsequent request to the zero-parameter overload of this | 161 // are wiped out; any subsequent request to the zero-parameter overload of this |
| 189 // method preserves the saved credentials. | 162 // method preserves the saved credentials. |
| 190 bool GaiaAuthenticator::AuthenticateImpl(const AuthParams& params, | 163 bool GaiaAuthenticator::AuthenticateImpl(const AuthParams& params, |
| 191 AuthResults* results) { | 164 AuthResults* results) { |
| 165 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 192 results->credentials_saved = params.should_save_credentials; | 166 results->credentials_saved = params.should_save_credentials; |
| 193 results->auth_error = ConnectionUnavailable; | 167 results->auth_error = ConnectionUnavailable; |
| 194 // Save credentials if so requested. | 168 // Save credentials if so requested. |
| 195 if (params.should_save_credentials != DONT_SAVE_CREDENTIALS) { | 169 if (params.should_save_credentials != DONT_SAVE_CREDENTIALS) { |
| 196 results->email = params.email.data(); | 170 results->email = params.email.data(); |
| 197 results->password = params.password; | 171 results->password = params.password; |
| 198 } else { // Explicitly clear previously-saved credentials. | 172 } else { // Explicitly clear previously-saved credentials. |
| 199 results->email = ""; | 173 results->email = ""; |
| 200 results->password = ""; | 174 results->password = ""; |
| 201 } | 175 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 219 next_allowed_auth_attempt_time_ = now + delay_; | 193 next_allowed_auth_attempt_time_ = now + delay_; |
| 220 return false; | 194 return false; |
| 221 } | 195 } |
| 222 } | 196 } |
| 223 | 197 |
| 224 return PerformGaiaRequest(params, results); | 198 return PerformGaiaRequest(params, results); |
| 225 } | 199 } |
| 226 | 200 |
| 227 bool GaiaAuthenticator::PerformGaiaRequest(const AuthParams& params, | 201 bool GaiaAuthenticator::PerformGaiaRequest(const AuthParams& params, |
| 228 AuthResults* results) { | 202 AuthResults* results) { |
| 203 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 229 GURL gaia_auth_url(gaia_url_); | 204 GURL gaia_auth_url(gaia_url_); |
| 230 | 205 |
| 231 string post_body; | 206 string post_body; |
| 232 post_body += "Email=" + CgiEscapeString(params.email); | 207 post_body += "Email=" + CgiEscapeString(params.email); |
| 233 post_body += "&Passwd=" + CgiEscapeString(params.password); | 208 post_body += "&Passwd=" + CgiEscapeString(params.password); |
| 234 post_body += "&source=" + CgiEscapeString(user_agent_); | 209 post_body += "&source=" + CgiEscapeString(user_agent_); |
| 235 post_body += "&service=" + service_id_; | 210 post_body += "&service=" + service_id_; |
| 236 if (!params.captcha_token.empty() && !params.captcha_value.empty()) { | 211 if (!params.captcha_token.empty() && !params.captcha_value.empty()) { |
| 237 post_body += "&logintoken=" + CgiEscapeString(params.captcha_token); | 212 post_body += "&logintoken=" + CgiEscapeString(params.captcha_token); |
| 238 post_body += "&logincaptcha=" + CgiEscapeString(params.captcha_value); | 213 post_body += "&logincaptcha=" + CgiEscapeString(params.captcha_value); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 265 return false; | 240 return false; |
| 266 | 241 |
| 267 return LookupEmail(results); | 242 return LookupEmail(results); |
| 268 } else { | 243 } else { |
| 269 results->auth_error = Unknown; | 244 results->auth_error = Unknown; |
| 270 return false; | 245 return false; |
| 271 } | 246 } |
| 272 } | 247 } |
| 273 | 248 |
| 274 bool GaiaAuthenticator::LookupEmail(AuthResults* results) { | 249 bool GaiaAuthenticator::LookupEmail(AuthResults* results) { |
| 250 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 275 // Use the provided Gaia server, but change the path to what V1 expects. | 251 // Use the provided Gaia server, but change the path to what V1 expects. |
| 276 GURL url(gaia_url_); // Gaia server. | 252 GURL url(gaia_url_); // Gaia server. |
| 277 GURL::Replacements repl; | 253 GURL::Replacements repl; |
| 278 // Needs to stay in scope till GURL is out of scope. | 254 // Needs to stay in scope till GURL is out of scope. |
| 279 string path(kGetUserInfoPath); | 255 string path(kGetUserInfoPath); |
| 280 repl.SetPathStr(path); | 256 repl.SetPathStr(path); |
| 281 url = url.ReplaceComponents(repl); | 257 url = url.ReplaceComponents(repl); |
| 282 | 258 |
| 283 string post_body; | 259 string post_body; |
| 284 post_body += "LSID="; | 260 post_body += "LSID="; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 311 return true; | 287 return true; |
| 312 } | 288 } |
| 313 return false; | 289 return false; |
| 314 } | 290 } |
| 315 | 291 |
| 316 // We need to call this explicitly when we need to obtain a long-lived session | 292 // We need to call this explicitly when we need to obtain a long-lived session |
| 317 // token. | 293 // token. |
| 318 bool GaiaAuthenticator::IssueAuthToken(AuthResults* results, | 294 bool GaiaAuthenticator::IssueAuthToken(AuthResults* results, |
| 319 const string& service_id, | 295 const string& service_id, |
| 320 bool long_lived) { | 296 bool long_lived) { |
| 297 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 321 // Use the provided Gaia server, but change the path to what V1 expects. | 298 // Use the provided Gaia server, but change the path to what V1 expects. |
| 322 GURL url(gaia_url_); // Gaia server. | 299 GURL url(gaia_url_); // Gaia server. |
| 323 GURL::Replacements repl; | 300 GURL::Replacements repl; |
| 324 // Needs to stay in scope till GURL is out of scope. | 301 // Needs to stay in scope till GURL is out of scope. |
| 325 string path(kGaiaV1IssueAuthTokenPath); | 302 string path(kGaiaV1IssueAuthTokenPath); |
| 326 repl.SetPathStr(path); | 303 repl.SetPathStr(path); |
| 327 url = url.ReplaceComponents(repl); | 304 url = url.ReplaceComponents(repl); |
| 328 | 305 |
| 329 string post_body; | 306 string post_body; |
| 330 post_body += "LSID="; | 307 post_body += "LSID="; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 353 // ExtractTokensFrom(...), but simply assign the token. | 330 // ExtractTokensFrom(...), but simply assign the token. |
| 354 int last_index = message_text.length() - 1; | 331 int last_index = message_text.length() - 1; |
| 355 if ('\n' == message_text[last_index]) | 332 if ('\n' == message_text[last_index]) |
| 356 message_text.erase(last_index); | 333 message_text.erase(last_index); |
| 357 results->auth_token = message_text; | 334 results->auth_token = message_text; |
| 358 return true; | 335 return true; |
| 359 } | 336 } |
| 360 return false; | 337 return false; |
| 361 } | 338 } |
| 362 | 339 |
| 363 // TOOD(sync): This passing around of AuthResults makes it really unclear who | |
| 364 // actually owns the authentication state and when it is valid, but this is | |
| 365 // endemic to this implementation. We should fix this. | |
| 366 bool GaiaAuthenticator::AuthenticateService(const string& service_id, | |
| 367 const string& sid, | |
| 368 const string& lsid, | |
| 369 string* other_service_cookie) { | |
| 370 // Copy the AuthResults structure and overload the auth_token field | |
| 371 // in the copy, local_results, to mean the auth_token for service_id. | |
| 372 AuthResults local_results; | |
| 373 local_results.sid = sid; | |
| 374 local_results.lsid = lsid; | |
| 375 | |
| 376 if (!IssueAuthToken(&local_results, service_id, true)) { | |
| 377 LOG(ERROR) << "[AUTH] Failed to obtain cookie for " << service_id; | |
| 378 return false; | |
| 379 } | |
| 380 | |
| 381 swap(*other_service_cookie, local_results.auth_token); | |
| 382 return true; | |
| 383 } | |
| 384 | |
| 385 // Helper method that extracts tokens from a successful reply, and saves them | 340 // Helper method that extracts tokens from a successful reply, and saves them |
| 386 // in the right fields. | 341 // in the right fields. |
| 387 void GaiaAuthenticator::ExtractTokensFrom(const string& response, | 342 void GaiaAuthenticator::ExtractTokensFrom(const string& response, |
| 388 AuthResults* results) { | 343 AuthResults* results) { |
| 389 vector<pair<string, string> > tokens; | 344 vector<pair<string, string> > tokens; |
| 390 SplitStringIntoKeyValuePairs(response, '=', '\n', &tokens); | 345 SplitStringIntoKeyValuePairs(response, '=', '\n', &tokens); |
| 391 for (vector<pair<string, string> >::iterator i = tokens.begin(); | 346 for (vector<pair<string, string> >::iterator i = tokens.begin(); |
| 392 i != tokens.end(); ++i) { | 347 i != tokens.end(); ++i) { |
| 393 if (i->first == "SID") { | 348 if (i->first == "SID") { |
| 394 results->sid = i->second; | 349 results->sid = i->second; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 438 } else if (error_msg == "CaptchaRequired" || error_msg == "cr") { | 393 } else if (error_msg == "CaptchaRequired" || error_msg == "cr") { |
| 439 results->auth_error = CaptchaRequired; | 394 results->auth_error = CaptchaRequired; |
| 440 } else if (error_msg == "ServiceUnavailable" || error_msg == "ire") { | 395 } else if (error_msg == "ServiceUnavailable" || error_msg == "ire") { |
| 441 results->auth_error = ServiceUnavailable; | 396 results->auth_error = ServiceUnavailable; |
| 442 } | 397 } |
| 443 } | 398 } |
| 444 | 399 |
| 445 // Reset all stored credentials, perhaps in preparation for letting a different | 400 // Reset all stored credentials, perhaps in preparation for letting a different |
| 446 // user sign in. | 401 // user sign in. |
| 447 void GaiaAuthenticator::ResetCredentials() { | 402 void GaiaAuthenticator::ResetCredentials() { |
| 448 PThreadScopedLock<PThreadMutex> enter(&mutex_); | 403 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 449 AuthResults blank; | 404 AuthResults blank; |
| 450 auth_results_ = blank; | 405 auth_results_ = blank; |
| 451 } | 406 } |
| 452 | 407 |
| 453 void GaiaAuthenticator::SetUsernamePassword(const string& username, | 408 void GaiaAuthenticator::SetUsernamePassword(const string& username, |
| 454 const string& password) { | 409 const string& password) { |
| 455 PThreadScopedLock<PThreadMutex> enter(&mutex_); | 410 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 456 auth_results_.password = password; | 411 auth_results_.password = password; |
| 457 auth_results_.email = username; | 412 auth_results_.email = username; |
| 458 } | 413 } |
| 459 | 414 |
| 460 void GaiaAuthenticator::SetUsername(const string& username) { | 415 void GaiaAuthenticator::SetUsername(const string& username) { |
| 461 PThreadScopedLock<PThreadMutex> enter(&mutex_); | 416 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 462 auth_results_.email = username; | 417 auth_results_.email = username; |
| 463 } | 418 } |
| 464 | 419 |
| 465 void GaiaAuthenticator::SetAuthToken(const string& auth_token, | 420 void GaiaAuthenticator::SetAuthToken(const string& auth_token, |
| 466 SaveCredentials save) { | 421 SaveCredentials save) { |
| 467 PThreadScopedLock<PThreadMutex> enter(&mutex_); | 422 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 468 auth_results_.auth_token = auth_token; | 423 auth_results_.auth_token = auth_token; |
| 469 auth_results_.credentials_saved = save; | 424 auth_results_.credentials_saved = save; |
| 470 } | 425 } |
| 471 | 426 |
| 472 bool GaiaAuthenticator::Authenticate(const string& user_name, | 427 bool GaiaAuthenticator::Authenticate(const string& user_name, |
| 473 const string& password, | 428 const string& password, |
| 474 SaveCredentials should_save_credentials, | 429 SaveCredentials should_save_credentials, |
| 475 bool synchronous, SignIn try_first) { | 430 SignIn try_first) { |
| 431 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 476 const string empty; | 432 const string empty; |
| 477 return Authenticate(user_name, password, should_save_credentials, synchronous, | 433 return Authenticate(user_name, password, should_save_credentials, empty, |
| 478 empty, empty, try_first); | 434 empty, try_first); |
| 479 } | 435 } |
| 480 | 436 |
| 481 } // namespace browser_sync | 437 } // namespace browser_sync |
| OLD | NEW |