summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/chromeos/login/google_authenticator.cc66
-rw-r--r--chrome/browser/chromeos/login/google_authenticator.h12
-rw-r--r--chrome/browser/chromeos/login/google_authenticator_unittest.cc10
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);