diff options
3 files changed, 64 insertions, 24 deletions
diff --git a/chrome/browser/chromeos/login/google_authenticator.cc b/chrome/browser/chromeos/login/google_authenticator.cc index 19a6231..3215769 100644 --- a/chrome/browser/chromeos/login/google_authenticator.cc +++ b/chrome/browser/chromeos/login/google_authenticator.cc @@ -4,13 +4,12 @@ #include "chrome/browser/chromeos/login/google_authenticator.h" -#include <errno.h> #include <string> #include <vector> -#include "base/logging.h" #include "base/file_path.h" #include "base/file_util.h" +#include "base/logging.h" #include "base/path_service.h" #include "base/sha2.h" #include "base/string_util.h" @@ -29,6 +28,7 @@ #include "chrome/common/net/url_fetcher.h" #include "chrome/common/notification_service.h" #include "net/base/load_flags.h" +#include "net/base/net_errors.h" #include "net/url_request/url_request_status.h" #include "third_party/libjingle/files/talk/base/urlencode.h" @@ -70,7 +70,8 @@ GoogleAuthenticator::GoogleAuthenticator(LoginStatusConsumer* consumer) fetcher_(NULL), getter_(NULL), checked_for_localaccount_(false), - unlock_(false) { + unlock_(false), + try_again_(true) { CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded()); } @@ -78,32 +79,42 @@ GoogleAuthenticator::~GoogleAuthenticator() { ChromeThread::DeleteSoon(ChromeThread::FILE, FROM_HERE, fetcher_); } +// static +URLFetcher* GoogleAuthenticator::CreateClientLoginFetcher( + URLRequestContextGetter* getter, + const std::string& body, + URLFetcher::Delegate* delegate) { + URLFetcher* to_return = + URLFetcher::Create(0, + GURL(AuthResponseHandler::kClientLoginUrl), + URLFetcher::POST, + delegate); + to_return->set_request_context(getter); + to_return->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES); + to_return->set_upload_data("application/x-www-form-urlencoded", body); + return to_return; +} + bool GoogleAuthenticator::AuthenticateToLogin(Profile* profile, const std::string& username, const std::string& password) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); unlock_ = false; getter_ = profile->GetRequestContext(); - fetcher_ = URLFetcher::Create(0, - GURL(AuthResponseHandler::kClientLoginUrl), - URLFetcher::POST, - this); - fetcher_->set_request_context(getter_); - fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES); + // TODO(cmasone): be more careful about zeroing memory that stores // the user's password. - std::string body = StringPrintf(kFormat, - UrlEncodeString(username).c_str(), - UrlEncodeString(password).c_str(), - kCookiePersistence, - kAccountType, - kSource); - fetcher_->set_upload_data("application/x-www-form-urlencoded", body); + request_body_ = StringPrintf(kFormat, + UrlEncodeString(username).c_str(), + UrlEncodeString(password).c_str(), + kCookiePersistence, + kAccountType, + kSource); // TODO(cmasone): Figure out how to parallelize fetch, username/password // processing without impacting testability. username_.assign(Canonicalize(username)); StoreHashedPassword(password); - fetcher_->Start(); + TryClientLogin(); return true; } @@ -131,13 +142,23 @@ void GoogleAuthenticator::OnURLFetchComplete(const URLFetcher* source, ChromeThread::UI, FROM_HERE, NewRunnableMethod(this, &GoogleAuthenticator::OnLoginSuccess, data)); } else if (!status.is_success()) { - LOG(INFO) << "Network fail"; + if (status.status() == URLRequestStatus::CANCELED) { + if (try_again_) { + try_again_ = false; + LOG(ERROR) << "Login attempt canceled!?!? Trying again."; + TryClientLogin(); + return; + } + LOG(ERROR) << "Login attempt canceled again? Already retried..."; + } + LOG(WARNING) << "Could not reach Google Accounts servers: errno " + << status.os_error(); // The fetch failed for network reasons, try offline login. LoadLocalaccount(kLocalaccountFile); ChromeThread::PostTask( ChromeThread::UI, FROM_HERE, NewRunnableMethod(this, &GoogleAuthenticator::CheckOffline, - strerror(status.os_error()))); + net::ErrorToString(status.os_error()))); } else { if (IsSecondFactorSuccess(data)) { ChromeThread::PostTask( @@ -282,6 +303,13 @@ std::string GoogleAuthenticator::SaltAsAscii() { } } +void GoogleAuthenticator::TryClientLogin() { + if (fetcher_) + delete fetcher_; + fetcher_ = CreateClientLoginFetcher(getter_, request_body_, this); + fetcher_->Start(); +} + // static bool GoogleAuthenticator::IsSecondFactorSuccess( const std::string& alleged_error) { diff --git a/chrome/browser/chromeos/login/google_authenticator.h b/chrome/browser/chromeos/login/google_authenticator.h index ab3dadd..94d725c 100644 --- a/chrome/browser/chromeos/login/google_authenticator.h +++ b/chrome/browser/chromeos/login/google_authenticator.h @@ -107,6 +107,10 @@ class GoogleAuthenticator : public Authenticator, // Returns the ascii encoding of the system salt. std::string SaltAsAscii(); + // Kicks off a new ClientLogin attempt, canceling any existing attempts. + // It is an error to call this before populating |getter_| and |request_body_| + void TryClientLogin(); + // To support internal two-factor authentication, check to see if // |alleged_error| is actually indicating the successful completion // of the first half of a two-factor login. @@ -126,6 +130,12 @@ class GoogleAuthenticator : public Authenticator, // http://mail.google.com/support/bin/answer.py?hl=en&ctx=mail&answer=10313# static std::string Canonicalize(const std::string& email_address); + // Create and return a URLFetcher that is set up to perform a ClientLogin + // authentication attempt. Caller takes ownership. + static URLFetcher* CreateClientLoginFetcher(URLRequestContextGetter* getter, + const std::string& body, + URLFetcher::Delegate* delegate); + // Constants to use in the ClientLogin request POST body. static const char kCookiePersistence[]; static const char kAccountType[]; @@ -150,10 +160,12 @@ class GoogleAuthenticator : public Authenticator, URLRequestContextGetter* getter_; std::string username_; std::string ascii_hash_; + std::string request_body_; std::vector<unsigned char> system_salt_; std::string localaccount_; bool checked_for_localaccount_; // needed becasuse empty localaccount_ is ok. bool unlock_; // True if authenticating to unlock the computer. + bool try_again_; // True if we're willing to retry the login attempt. friend class GoogleAuthenticatorTest; FRIEND_TEST(GoogleAuthenticatorTest, SaltToAsciiTest); diff --git a/chrome/browser/chromeos/login/google_authenticator_unittest.cc b/chrome/browser/chromeos/login/google_authenticator_unittest.cc index 4705673..f9b75b6 100644 --- a/chrome/browser/chromeos/login/google_authenticator_unittest.cc +++ b/chrome/browser/chromeos/login/google_authenticator_unittest.cc @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <errno.h> #include <string> #include <vector> @@ -24,6 +23,7 @@ #include "chrome/common/net/url_fetcher.h" #include "chrome/test/testing_profile.h" #include "googleurl/src/gurl.h" +#include "net/base/net_errors.h" #include "net/url_request/url_request_status.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/gmock/include/gmock/gmock.h" @@ -258,8 +258,8 @@ TEST_F(GoogleAuthenticatorTest, LoginNetFailureTest) { MessageLoopForUI message_loop; ChromeThread ui_thread(ChromeThread::UI, &message_loop); - int error_no = ECONNRESET; - std::string data(strerror(error_no)); + int error_no = net::ERR_CONNECTION_RESET; + std::string data(net::ErrorToString(error_no)); GURL source; URLRequestStatus status(URLRequestStatus::FAILED, error_no); @@ -301,8 +301,8 @@ TEST_F(GoogleAuthenticatorTest, OfflineLoginTest) { MessageLoopForUI message_loop; ChromeThread ui_thread(ChromeThread::UI, &message_loop); - int error_no = ECONNRESET; - std::string data(strerror(error_no)); + int error_no = net::ERR_CONNECTION_RESET; + std::string data(net::ErrorToString(error_no)); GURL source; URLRequestStatus status(URLRequestStatus::FAILED, error_no); |