summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcmasone@google.com <cmasone@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-11 00:05:02 +0000
committercmasone@google.com <cmasone@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-11 00:05:02 +0000
commitad8a6ea045cdaf65c4a61e1ededb67f8c4d0534e (patch)
tree24b04f27a331de0170aeed7e1e533c2b9959e9cf
parentae437cff5b2fd0abc2b9980aaa0d451597652d43 (diff)
downloadchromium_src-ad8a6ea045cdaf65c4a61e1ededb67f8c4d0534e.zip
chromium_src-ad8a6ea045cdaf65c4a61e1ededb67f8c4d0534e.tar.gz
chromium_src-ad8a6ea045cdaf65c4a61e1ededb67f8c4d0534e.tar.bz2
Enable chrome to mount cryptohomes on its own as a part of auth, as well as handle offline login.
TEST=Unittests, and also run on chromium OS device with --in-chrome-auth Review URL: http://codereview.chromium.org/822006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@41223 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chromeos/cros/cryptohome_library.cc26
-rw-r--r--chrome/browser/chromeos/cros/cryptohome_library.h46
-rw-r--r--chrome/browser/chromeos/cros/mock_cryptohome_library.h27
-rw-r--r--chrome/browser/chromeos/login/google_authenticator.cc159
-rw-r--r--chrome/browser/chromeos/login/google_authenticator.h57
-rw-r--r--chrome/browser/chromeos/login/google_authenticator_unittest.cc185
-rw-r--r--chrome/browser/chromeos/login/login_manager_view.cc9
-rw-r--r--chrome/browser/chromeos/login/login_manager_view.h4
-rw-r--r--chrome/browser/chromeos/login/login_status_consumer.h7
-rw-r--r--chrome/browser/chromeos/login/pam_google_authenticator.cc2
-rwxr-xr-xchrome/chrome_browser.gypi2
-rw-r--r--chrome/chrome_tests.gypi1
12 files changed, 496 insertions, 29 deletions
diff --git a/chrome/browser/chromeos/cros/cryptohome_library.cc b/chrome/browser/chromeos/cros/cryptohome_library.cc
new file mode 100644
index 0000000..4be406c
--- /dev/null
+++ b/chrome/browser/chromeos/cros/cryptohome_library.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/cros/cryptohome_library.h"
+
+#include "base/message_loop.h"
+#include "chrome/browser/chrome_thread.h"
+
+namespace chromeos {
+// static
+CryptohomeLibrary* CryptohomeLibrary::Get() {
+ return Singleton<CryptohomeLibrary>::get();
+}
+
+bool CryptohomeLibrary::CheckKey(const std::string& user_email,
+ const std::string& passhash) {
+ return chromeos::CryptohomeCheckKey(user_email.c_str(), passhash.c_str());
+}
+
+bool CryptohomeLibrary::Mount(const std::string& user_email,
+ const std::string& passhash) {
+ return chromeos::CryptohomeMount(user_email.c_str(), passhash.c_str());
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/cryptohome_library.h b/chrome/browser/chromeos/cros/cryptohome_library.h
new file mode 100644
index 0000000..1bec9fa
--- /dev/null
+++ b/chrome/browser/chromeos/cros/cryptohome_library.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_CROS_CRYPTOHOME_LIBRARY_H_
+#define CHROME_BROWSER_CHROMEOS_CROS_CRYPTOHOME_LIBRARY_H_
+
+#include <string>
+
+#include "base/singleton.h"
+#include "third_party/cros/chromeos_cryptohome.h"
+
+namespace chromeos {
+class MockCryptohomeLibrary;
+
+// This class handles the interaction with the ChromeOS cryptohome library APIs.
+// Users can get an instance of this library class like this:
+// CryptohomeLibrary::Get()
+class CryptohomeLibrary {
+ public:
+ // This gets the singleton CryptohomeLibrary.
+ static CryptohomeLibrary* Get();
+
+ // Asks cryptohomed to try to find the cryptohome for |user_email| and then
+ // mount it using |passhash| to unlock the key.
+ virtual bool Mount(const std::string& user_email,
+ const std::string& passhash);
+
+ // Asks cryptohomed to try to find the cryptohome for |user_email| and then
+ // use |passhash| to unlock the key.
+ virtual bool CheckKey(const std::string& user_email,
+ const std::string& passhash);
+
+ private:
+ friend struct DefaultSingletonTraits<CryptohomeLibrary>;
+ friend class MockCryptohomeLibrary;
+
+ CryptohomeLibrary() {}
+ ~CryptohomeLibrary() {}
+
+ DISALLOW_COPY_AND_ASSIGN(CryptohomeLibrary);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_CROS_CRYPTOHOME_LIBRARY_H_
diff --git a/chrome/browser/chromeos/cros/mock_cryptohome_library.h b/chrome/browser/chromeos/cros/mock_cryptohome_library.h
new file mode 100644
index 0000000..4ef8e8d
--- /dev/null
+++ b/chrome/browser/chromeos/cros/mock_cryptohome_library.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_CROS_MOCK_CRYPTOHOME_LIBRARY_H_
+#define CHROME_BROWSER_CHROMEOS_CROS_MOCK_CRYPTOHOME_LIBRARY_H_
+
+#include "chrome/browser/chromeos/cros/cryptohome_library.h"
+
+#include <string>
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace chromeos {
+
+class MockCryptohomeLibrary : public CryptohomeLibrary {
+ public:
+ MockCryptohomeLibrary() {}
+ ~MockCryptohomeLibrary() {}
+ MOCK_METHOD2(Mount, bool(const std::string& user_email,
+ const std::string& passhash));
+ MOCK_METHOD2(CheckKey, bool(const std::string& user_email,
+ const std::string& passhash));
+};
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_CROS_MOCK_CRYPTOHOME_LIBRARY_H_
diff --git a/chrome/browser/chromeos/login/google_authenticator.cc b/chrome/browser/chromeos/login/google_authenticator.cc
index 9bd5a30..0cb2ae4 100644
--- a/chrome/browser/chromeos/login/google_authenticator.cc
+++ b/chrome/browser/chromeos/login/google_authenticator.cc
@@ -2,14 +2,21 @@
// 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>
#include "base/logging.h"
#include "base/file_path.h"
+#include "base/file_util.h"
#include "base/path_service.h"
+#include "base/sha2.h"
#include "base/string_util.h"
+#include "base/third_party/nss/blapi.h"
+#include "base/third_party/nss/sha256.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/chromeos/cros/cryptohome_library.h"
#include "chrome/browser/chromeos/login/google_authenticator.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/browser/net/chrome_url_request_context.h"
@@ -18,8 +25,12 @@
#include "chrome/browser/profile_manager.h"
#include "chrome/common/chrome_paths.h"
#include "net/base/load_flags.h"
+#include "net/url_request/url_request_status.h"
#include "third_party/libjingle/files/talk/base/urlencode.h"
+using namespace chromeos;
+using namespace file_util;
+
const char GoogleAuthenticator::kClientLoginUrl[] =
"https://www.google.com/accounts/ClientLogin";
const char GoogleAuthenticator::kFormat[] =
@@ -32,6 +43,12 @@ const char GoogleAuthenticator::kCookiePersistence[] = "true";
const char GoogleAuthenticator::kAccountType[] = "HOSTED_OR_GOOGLE";
const char GoogleAuthenticator::kSource[] = "chromeos";
+// Chromium OS system salt stored here
+const char GoogleAuthenticator::kSystemSalt[] = "/home/.shadow/salt";
+
+// String that appears at the start of OpenSSL cipher text with embedded salt
+const char GoogleAuthenticator::kOpenSSLMagic[] = "Salted__";
+
bool GoogleAuthenticator::Authenticate(const std::string& username,
const std::string& password) {
FilePath user_data_dir;
@@ -56,6 +73,7 @@ bool GoogleAuthenticator::Authenticate(const std::string& username,
fetcher_->set_upload_data("application/x-www-form-urlencoded", body);
fetcher_->Start();
username_.assign(username);
+ StoreHashedPassword(password);
return true;
}
@@ -65,33 +83,140 @@ void GoogleAuthenticator::OnURLFetchComplete(const URLFetcher* source,
int response_code,
const ResponseCookies& cookies,
const std::string& data) {
- // TODO(cmasone):
- // If successful, post a task to the UI thread with the cookies.
- // That task will mount cryptohome (has to be on the UI thread, as
- // it talks to dbus...eww) and then tell the UserManager that the
- // user logged in, get the new profile, and then inject cookies.
- // Then, do all the BrowserInit stuff.
-
- LOG(INFO) << "ClientLogin response code: " << response_code;
- if (200 == response_code) {
+ if (status.is_success() && response_code == 200) {
+ LOG(INFO) << "ClientLogin successful!";
ChromeThread::PostTask(
ChromeThread::UI, FROM_HERE,
- NewRunnableFunction(
- GoogleAuthenticator::OnLoginSuccess, consumer_, username_));
+ NewRunnableFunction(GoogleAuthenticator::OnLoginSuccess,
+ consumer_,
+ library_,
+ username_,
+ ascii_hash_,
+ data));
+ } else if (!status.is_success() &&
+ library_->CheckKey(username_.c_str(), ascii_hash_.c_str())) {
+ // The fetch didn't succeed, but offline login did.
+ LOG(INFO) << "Offline login successful!";
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(GoogleAuthenticator::OnLoginSuccess,
+ consumer_,
+ library_,
+ username_,
+ ascii_hash_,
+ data));
} else {
+ std::string error;
+ if (status.is_success()) {
+ // The fetch succeeded, but ClientLogin said no.
+ error.assign(data);
+ } else {
+ // We couldn't hit the network, and offline login failed.
+ error.assign(strerror(status.os_error()));
+ }
ChromeThread::PostTask(
ChromeThread::UI, FROM_HERE,
- NewRunnableFunction(GoogleAuthenticator::OnLoginFailure, consumer_));
+ NewRunnableFunction(
+ GoogleAuthenticator::OnLoginFailure, consumer_, error));
}
+ fetcher_.reset(NULL);
}
// static
-void GoogleAuthenticator::OnLoginSuccess(LoginStatusConsumer* consumer,
- const std::string& username) {
- consumer->OnLoginSuccess(username);
+void GoogleAuthenticator::OnLoginSuccess(
+ LoginStatusConsumer* consumer,
+ CryptohomeLibrary* library,
+ const std::string& username,
+ const std::string& passhash,
+ const std::string& client_login_data) {
+ bool success = library->Mount(username.c_str(), passhash.c_str());
+
+ // Also, convert client_login_data into legit cookies.
+
+ if (success) {
+ consumer->OnLoginSuccess(username);
+ } else {
+ GoogleAuthenticator::OnLoginFailure(consumer, client_login_data);
+ }
}
// static
-void GoogleAuthenticator::OnLoginFailure(LoginStatusConsumer* consumer) {
- consumer->OnLoginFailure();
+void GoogleAuthenticator::OnLoginFailure(LoginStatusConsumer* consumer,
+ const std::string& data) {
+ consumer->OnLoginFailure(data);
+}
+
+void GoogleAuthenticator::LoadSystemSalt(FilePath& path) {
+ if (!system_salt_.empty())
+ return;
+
+ CHECK(PathExists(path)) << path.value() << " does not exist!";
+
+ int64 file_size;
+ CHECK(GetFileSize(path, &file_size)) << "Could not get size of "
+ << path.value();
+
+ char salt[file_size];
+ int data_read = ReadFile(path, salt, file_size);
+
+ CHECK_EQ(data_read % 2, 0);
+ system_salt_.assign(salt, salt + data_read);
+}
+
+std::string GoogleAuthenticator::SaltAsAscii() {
+ FilePath salt_path(kSystemSalt);
+ LoadSystemSalt(salt_path);
+ unsigned int salt_len = system_salt_.size();
+ char ascii_salt[2 * salt_len];
+ if (GoogleAuthenticator::BinaryToHex(system_salt_,
+ salt_len,
+ ascii_salt,
+ sizeof(ascii_salt))) {
+ return std::string(ascii_salt, sizeof(ascii_salt));
+ } else {
+ return std::string();
+ }
+}
+
+void GoogleAuthenticator::StoreHashedPassword(const std::string& password) {
+ // Get salt, ascii encode, update sha with that, then update with ascii
+ // of password, then end.
+ std::string ascii_salt = SaltAsAscii();
+ unsigned char passhash_buf[32];
+ char ascii_buf[32];
+
+ // Hash salt and password
+ SHA256Context ctx;
+ SHA256_Begin(&ctx);
+ SHA256_Update(&ctx,
+ reinterpret_cast<const unsigned char*>(ascii_salt.data()),
+ static_cast<unsigned int>(ascii_salt.length()));
+ SHA256_Update(&ctx,
+ reinterpret_cast<const unsigned char*>(password.data()),
+ static_cast<unsigned int>(password.length()));
+ SHA256_End(&ctx,
+ passhash_buf,
+ NULL,
+ static_cast<unsigned int>(sizeof(passhash_buf)));
+
+ std::vector<unsigned char> passhash(passhash_buf,
+ passhash_buf + sizeof(passhash_buf));
+ BinaryToHex(passhash,
+ passhash.size() / 2, // only want top half, at least for now.
+ ascii_buf,
+ sizeof(ascii_buf));
+ ascii_hash_.assign(ascii_buf, sizeof(ascii_buf));
+}
+
+// static
+bool GoogleAuthenticator::BinaryToHex(const std::vector<unsigned char>& binary,
+ const unsigned int binary_len,
+ char* hex_string,
+ const unsigned int len) {
+ if (len < 2*binary_len)
+ return false;
+ memset(hex_string, 0, len);
+ for (uint i = 0, j = 0; i < binary_len; i++, j+=2)
+ sprintf(hex_string + j, "%02x", binary[i]);
+ return true;
}
diff --git a/chrome/browser/chromeos/login/google_authenticator.h b/chrome/browser/chromeos/login/google_authenticator.h
index b4da66a..ec1806b 100644
--- a/chrome/browser/chromeos/login/google_authenticator.h
+++ b/chrome/browser/chromeos/login/google_authenticator.h
@@ -6,7 +6,14 @@
#define CHROME_BROWSER_CHROMEOS_LOGIN_GOOGLE_AUTHENTICATOR_H_
#include <string>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
+#include "base/sha2.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/cryptohome_library.h"
#include "chrome/browser/chromeos/login/authenticator.h"
#include "chrome/browser/net/url_fetcher.h"
@@ -17,10 +24,22 @@ class LoginStatusConsumer;
class GoogleAuthenticator : public Authenticator,
public URLFetcher::Delegate {
public:
+ GoogleAuthenticator(LoginStatusConsumer* consumer,
+ chromeos::CryptohomeLibrary* library)
+ : Authenticator(consumer),
+ library_(library),
+ fetcher_(NULL) {
+ if (!library && chromeos::CrosLibrary::EnsureLoaded())
+ library_ = chromeos::CryptohomeLibrary::Get();
+ }
+
explicit GoogleAuthenticator(LoginStatusConsumer* consumer)
: Authenticator(consumer),
fetcher_(NULL) {
+ CHECK(chromeos::CrosLibrary::EnsureLoaded());
+ library_ = chromeos::CryptohomeLibrary::Get();
}
+
virtual ~GoogleAuthenticator() {}
// Given a |username| and |password|, this method attempts to authenticate to
@@ -46,18 +65,52 @@ class GoogleAuthenticator : public Authenticator,
// to the subclasses specifically, and I want to allow mocked out
// LoginStatusConsumers to be used here as well.
static void OnLoginSuccess(LoginStatusConsumer* consumer,
- const std::string& username);
- static void OnLoginFailure(LoginStatusConsumer* consumer);
+ chromeos::CryptohomeLibrary* library,
+ const std::string& username,
+ const std::string& passhash,
+ const std::string& client_login_data);
+ static void OnLoginFailure(LoginStatusConsumer* consumer,
+ const std::string& data);
+
+ // Meant for testing.
+ void set_system_salt(const std::vector<unsigned char>& fake_salt) {
+ system_salt_ = fake_salt;
+ }
+ void set_password_hash(const std::string& fake_hash) {
+ ascii_hash_ = fake_hash;
+ }
+ // Returns the ascii encoding of the system salt.
+ std::string SaltAsAscii();
private:
static const char kCookiePersistence[];
static const char kAccountType[];
static const char kSource[];
static const char kClientLoginUrl[];
static const char kFormat[];
+ static const char kSystemSalt[];
+ static const char kOpenSSLMagic[];
+ chromeos::CryptohomeLibrary* library_;
scoped_ptr<URLFetcher> fetcher_;
+ std::vector<unsigned char> system_salt_;
std::string username_;
+ std::string ascii_hash_;
+
+ // If we don't have the system salt yet, loads it from |path|.
+ void LoadSystemSalt(FilePath& path);
+
+ // Stores a hash of |password|, salted with the ascii of |system_salt_|.
+ void StoreHashedPassword(const std::string& password);
+
+ // Converts the binary data |binary| into an ascii hex string and stores
+ // it in |hex_string|. Not guaranteed to be NULL-terminated.
+ // Returns false if |hex_string| is too small, true otherwise.
+ static bool BinaryToHex(const std::vector<unsigned char>& binary,
+ const unsigned int binary_len,
+ char* hex_string,
+ const unsigned int len);
+
DISALLOW_COPY_AND_ASSIGN(GoogleAuthenticator);
};
diff --git a/chrome/browser/chromeos/login/google_authenticator_unittest.cc b/chrome/browser/chromeos/login/google_authenticator_unittest.cc
new file mode 100644
index 0000000..bfc4a19
--- /dev/null
+++ b/chrome/browser/chromeos/login/google_authenticator_unittest.cc
@@ -0,0 +1,185 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/google_authenticator.h"
+
+#include <errno.h>
+#include <string>
+#include <vector>
+
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/chromeos/cros/mock_cryptohome_library.h"
+#include "chrome/browser/chrome_thread.h"
+#include "googleurl/src/gurl.h"
+#include "net/url_request/url_request_status.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace chromeos {
+using ::testing::InvokeWithoutArgs;
+using ::testing::Return;
+using ::testing::_;
+
+class MockConsumer : public LoginStatusConsumer {
+ public:
+ MockConsumer() {}
+ ~MockConsumer() {}
+ MOCK_METHOD1(OnLoginFailure, void(const std::string error));
+ MOCK_METHOD1(OnLoginSuccess, void(const std::string username));
+};
+
+class GoogleAuthenticatorTest : public ::testing::Test {
+ public:
+ GoogleAuthenticatorTest() {
+ memset(fake_hash_, 0, sizeof(fake_hash_));
+ fake_hash_[0] = 10;
+ fake_hash_[1] = 1;
+ fake_hash_[7] = 10 << 4;
+ hash_ascii_.assign("0a010000000000a0");
+ hash_ascii_.append(std::string(16,'0'));
+ }
+ ~GoogleAuthenticatorTest() {}
+
+ unsigned char fake_hash_[32];
+ std::string hash_ascii_;
+ std::string username_;
+ std::string error_;
+};
+
+TEST_F(GoogleAuthenticatorTest, SaltToAsciiTest) {
+ unsigned char fake_salt[8] = { 0 };
+ fake_salt[0] = 10;
+ fake_salt[1] = 1;
+ fake_salt[7] = 10 << 4;
+ std::vector<unsigned char> salt_v(fake_salt, fake_salt + sizeof(fake_salt));
+
+ MockCryptohomeLibrary library;
+ GoogleAuthenticator auth(NULL, &library);
+ auth.set_system_salt(salt_v);
+
+ EXPECT_EQ("0a010000000000a0", auth.SaltAsAscii());
+}
+
+TEST_F(GoogleAuthenticatorTest, OnLoginSuccessTest) {
+ error_.assign("Unexpected error");
+
+ MockConsumer consumer;
+ EXPECT_CALL(consumer, OnLoginSuccess(username_));
+
+ MockCryptohomeLibrary library;
+ EXPECT_CALL(library, Mount(username_, hash_ascii_))
+ .WillOnce(Return(true));
+
+ GoogleAuthenticator auth(&consumer, &library);
+ auth.OnLoginSuccess(&consumer, &library, username_, hash_ascii_, error_);
+}
+
+TEST_F(GoogleAuthenticatorTest, MountFailureTest) {
+ error_.assign("Expected error");
+
+ MockConsumer consumer;
+ EXPECT_CALL(consumer, OnLoginFailure(error_));
+
+ MockCryptohomeLibrary library;
+ EXPECT_CALL(library, Mount(username_, hash_ascii_))
+ .WillOnce(Return(false));
+
+ GoogleAuthenticator auth(&consumer, &library);
+ auth.OnLoginSuccess(&consumer, &library, username_, hash_ascii_, error_);
+}
+
+static void Quit() { MessageLoop::current()->Quit(); }
+TEST_F(GoogleAuthenticatorTest, LoginNetFailureTest) {
+ MessageLoopForUI message_loop;
+ ChromeThread ui_thread(ChromeThread::UI, &message_loop);
+
+ int error_no = ECONNRESET;
+ error_.assign(strerror(error_no));
+ GURL source;
+ ResponseCookies cookies;
+
+ URLRequestStatus status(URLRequestStatus::FAILED, error_no);
+
+ MockConsumer consumer;
+ EXPECT_CALL(consumer, OnLoginFailure(error_))
+ .WillOnce(InvokeWithoutArgs(Quit));
+ MockCryptohomeLibrary library;
+ EXPECT_CALL(library, CheckKey(username_, hash_ascii_))
+ .WillOnce(Return(false));
+
+ GoogleAuthenticator auth(&consumer, &library);
+ auth.set_password_hash(hash_ascii_);
+ auth.OnURLFetchComplete(NULL, source, status, 0, cookies, std::string());
+ MessageLoop::current()->Run(); // So tasks can be posted.
+}
+
+TEST_F(GoogleAuthenticatorTest, LoginDeniedTest) {
+ MessageLoopForUI message_loop;
+ ChromeThread ui_thread(ChromeThread::UI, &message_loop);
+
+ error_.assign("Error: NO!");
+ GURL source;
+ ResponseCookies cookies;
+
+ URLRequestStatus status(URLRequestStatus::SUCCESS, 0);
+
+ MockConsumer consumer;
+ EXPECT_CALL(consumer, OnLoginFailure(error_))
+ .WillOnce(InvokeWithoutArgs(Quit));
+ MockCryptohomeLibrary library;
+
+ GoogleAuthenticator auth(&consumer, &library);
+ auth.OnURLFetchComplete(NULL, source, status, 403, cookies, error_);
+ MessageLoop::current()->Run(); // So tasks can be posted.
+}
+
+TEST_F(GoogleAuthenticatorTest, OfflineLoginTest) {
+ MessageLoopForUI message_loop;
+ ChromeThread ui_thread(ChromeThread::UI, &message_loop);
+
+ int error_no = ECONNRESET;
+ error_.assign(strerror(error_no));
+ GURL source;
+ ResponseCookies cookies;
+
+ URLRequestStatus status(URLRequestStatus::FAILED, error_no);
+
+ MockConsumer consumer;
+ EXPECT_CALL(consumer, OnLoginSuccess(username_))
+ .WillOnce(InvokeWithoutArgs(Quit));
+ MockCryptohomeLibrary library;
+ EXPECT_CALL(library, CheckKey(username_, hash_ascii_))
+ .WillOnce(Return(true));
+ EXPECT_CALL(library, Mount(username_, hash_ascii_))
+ .WillOnce(Return(true));
+
+ GoogleAuthenticator auth(&consumer, &library);
+ auth.set_password_hash(hash_ascii_);
+ auth.OnURLFetchComplete(NULL, source, status, 0, cookies, std::string());
+ MessageLoop::current()->Run(); // So tasks can be posted.
+}
+
+TEST_F(GoogleAuthenticatorTest, OnlineLoginTest) {
+ MessageLoopForUI message_loop;
+ ChromeThread ui_thread(ChromeThread::UI, &message_loop);
+
+ GURL source;
+ ResponseCookies cookies;
+ URLRequestStatus status(URLRequestStatus::SUCCESS, 0);
+
+ MockConsumer consumer;
+ EXPECT_CALL(consumer, OnLoginSuccess(username_))
+ .WillOnce(InvokeWithoutArgs(Quit));
+ MockCryptohomeLibrary library;
+ EXPECT_CALL(library, Mount(username_, hash_ascii_))
+ .WillOnce(Return(true));
+
+ GoogleAuthenticator auth(&consumer, &library);
+ auth.set_password_hash(hash_ascii_);
+ auth.OnURLFetchComplete(NULL, source, status, 200, cookies, std::string());
+ MessageLoop::current()->Run(); // So tasks can be posted.
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/login_manager_view.cc b/chrome/browser/chromeos/login/login_manager_view.cc
index d47a45b..cae59a5 100644
--- a/chrome/browser/chromeos/login/login_manager_view.cc
+++ b/chrome/browser/chromeos/login/login_manager_view.cc
@@ -304,8 +304,8 @@ void LoginManagerView::ButtonPressed(
Login();
}
-void LoginManagerView::OnLoginFailure() {
- LOG(INFO) << "LoginManagerView: OnLoginFailure()";
+void LoginManagerView::OnLoginFailure(const std::string error) {
+ LOG(INFO) << "LoginManagerView: OnLoginFailure() " << error;
NetworkLibrary* network = NetworkLibrary::Get();
// Send notification of failure
@@ -322,13 +322,12 @@ void LoginManagerView::OnLoginFailure() {
ShowError(IDS_LOGIN_ERROR_NETWORK_NOT_CONNECTED);
else
ShowError(IDS_LOGIN_ERROR_AUTHENTICATING);
+ // TODO(someone): get |error| onto the UI somehow?
}
-void LoginManagerView::OnLoginSuccess(const std::string& username) {
+void LoginManagerView::OnLoginSuccess(const std::string username) {
// TODO(cmasone): something sensible if errors occur.
-
SetupSession(username);
-
login_utils::CompleteLogin(username);
}
diff --git a/chrome/browser/chromeos/login/login_manager_view.h b/chrome/browser/chromeos/login/login_manager_view.h
index 6cbb76d..e208973 100644
--- a/chrome/browser/chromeos/login/login_manager_view.h
+++ b/chrome/browser/chromeos/login/login_manager_view.h
@@ -69,8 +69,8 @@ class LoginManagerView : public views::View,
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
// Overriden from LoginStatusConsumer.
- virtual void OnLoginFailure();
- virtual void OnLoginSuccess(const std::string& username);
+ virtual void OnLoginFailure(const std::string error);
+ virtual void OnLoginSuccess(const std::string username);
protected:
// views::View overrides:
diff --git a/chrome/browser/chromeos/login/login_status_consumer.h b/chrome/browser/chromeos/login/login_status_consumer.h
index 0b2a658..5e3b07a 100644
--- a/chrome/browser/chromeos/login/login_status_consumer.h
+++ b/chrome/browser/chromeos/login/login_status_consumer.h
@@ -13,8 +13,11 @@
class LoginStatusConsumer {
public:
virtual ~LoginStatusConsumer() {}
- virtual void OnLoginFailure() = 0;
- virtual void OnLoginSuccess(const std::string& username) = 0;
+ // These copy data in, so as to avoid potential object lifetime problems.
+ virtual void OnLoginFailure(const std::string error) = 0;
+ virtual void OnLoginSuccess(const std::string username) = 0;
};
+
+
#endif // CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_STATUS_CONSUMER_H_
diff --git a/chrome/browser/chromeos/login/pam_google_authenticator.cc b/chrome/browser/chromeos/login/pam_google_authenticator.cc
index fd32c2a..2bd6ae0 100644
--- a/chrome/browser/chromeos/login/pam_google_authenticator.cc
+++ b/chrome/browser/chromeos/login/pam_google_authenticator.cc
@@ -29,6 +29,6 @@ bool PamGoogleAuthenticator::Authenticate(const std::string& username,
if (ret)
consumer_->OnLoginSuccess(username);
else
- consumer_->OnLoginFailure();
+ consumer_->OnLoginFailure("");
return ret;
}
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 1a98773..ddf754b 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -315,6 +315,8 @@
'browser/chromeos/compact_navigation_bar.h',
'browser/chromeos/cros/cros_library.cc',
'browser/chromeos/cros/cros_library.h',
+ 'browser/chromeos/cros/cryptohome_library.cc',
+ 'browser/chromeos/cros/cryptohome_library.h',
'browser/chromeos/cros/language_library.cc',
'browser/chromeos/cros/language_library.h',
'browser/chromeos/cros/login_library.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index eb066a2..6de361c 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -580,6 +580,7 @@
'browser/chromeos/external_cookie_handler_unittest.cc',
'browser/chromeos/external_metrics_unittest.cc',
'browser/chromeos/gview_request_interceptor_unittest.cc',
+ 'browser/chromeos/login/google_authenticator_unittest.cc',
'browser/chromeos/pipe_reader_unittest.cc',
'browser/chromeos/version_loader_unittest.cc',
# It is safe to list */cocoa/* files in the "common" file list