diff options
author | cmasone@google.com <cmasone@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-11 00:05:02 +0000 |
---|---|---|
committer | cmasone@google.com <cmasone@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-11 00:05:02 +0000 |
commit | ad8a6ea045cdaf65c4a61e1ededb67f8c4d0534e (patch) | |
tree | 24b04f27a331de0170aeed7e1e533c2b9959e9cf | |
parent | ae437cff5b2fd0abc2b9980aaa0d451597652d43 (diff) | |
download | chromium_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.cc | 26 | ||||
-rw-r--r-- | chrome/browser/chromeos/cros/cryptohome_library.h | 46 | ||||
-rw-r--r-- | chrome/browser/chromeos/cros/mock_cryptohome_library.h | 27 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/google_authenticator.cc | 159 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/google_authenticator.h | 57 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/google_authenticator_unittest.cc | 185 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/login_manager_view.cc | 9 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/login_manager_view.h | 4 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/login_status_consumer.h | 7 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/pam_google_authenticator.cc | 2 | ||||
-rwxr-xr-x | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 1 |
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 |