diff options
author | cmasone@google.com <cmasone@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-29 21:28:11 +0000 |
---|---|---|
committer | cmasone@google.com <cmasone@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-29 21:28:11 +0000 |
commit | 4ada238a76785ee78396cfb8e5992044c302de1e (patch) | |
tree | 5c6ad77fbf8b38164b18c987febe844e6a516177 /chrome | |
parent | 5066a78ce88613ce6f52e246ea22fb3cc772be05 (diff) | |
download | chromium_src-4ada238a76785ee78396cfb8e5992044c302de1e.zip chromium_src-4ada238a76785ee78396cfb8e5992044c302de1e.tar.gz chromium_src-4ada238a76785ee78396cfb8e5992044c302de1e.tar.bz2 |
OwnerManager, allows use of OwnerKeyUtils to take ownership of a device
BUG=chromium-os:4485
TEST=unit tests
Review URL: http://codereview.chromium.org/3058021
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@54199 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/chromeos/login/owner_manager.cc | 213 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/owner_manager.h | 155 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/owner_manager_unittest.cc | 352 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 1 | ||||
-rw-r--r-- | chrome/common/notification_type.h | 4 |
6 files changed, 727 insertions, 0 deletions
diff --git a/chrome/browser/chromeos/login/owner_manager.cc b/chrome/browser/chromeos/login/owner_manager.cc new file mode 100644 index 0000000..546952a3 --- /dev/null +++ b/chrome/browser/chromeos/login/owner_manager.cc @@ -0,0 +1,213 @@ +// 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/owner_manager.h" + +#include "base/file_path.h" +#include "base/file_util.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/notification_type.h" + +namespace chromeos { + +OwnerManager::OwnerManager() + : private_key_(NULL), + public_key_(NULL), + utils_(OwnerKeyUtils::Create()) { +} + +OwnerManager::~OwnerManager() {} + +bool OwnerManager::IsAlreadyOwned() { + return file_util::PathExists(utils_->GetOwnerKeyFilePath()); +} + +bool OwnerManager::StartLoadOwnerKeyAttempt() { + if (!IsAlreadyOwned()) { + LOG(ERROR) << "Device not yet owned"; + return false; + } + ChromeThread::PostTask( + ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, &OwnerManager::LoadOwnerKey)); + return true; +} + +bool OwnerManager::StartTakeOwnershipAttempt() { + if (IsAlreadyOwned()) { + LOG(ERROR) << "Device is already owned"; + return false; + } + ChromeThread::PostTask( + ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, &OwnerManager::GenerateKeysAndExportPublic)); + return true; +} + +bool OwnerManager::StartSigningAttempt(const std::string& data, Delegate* d) { + if (!IsAlreadyOwned()) { + LOG(ERROR) << "Device not yet owned"; + return false; + } + ChromeThread::ID thread_id; + if (!ChromeThread::GetCurrentThreadIdentifier(&thread_id)) + thread_id = ChromeThread::UI; + ChromeThread::PostTask( + ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, &OwnerManager::Sign, thread_id, data, d)); + return true; +} + +bool OwnerManager::StartVerifyAttempt(const std::string& data, + const std::string& signature, + Delegate* d) { + if (!IsAlreadyOwned()) { + LOG(ERROR) << "Device not yet owned"; + return false; + } + ChromeThread::ID thread_id; + if (!ChromeThread::GetCurrentThreadIdentifier(&thread_id)) + thread_id = ChromeThread::UI; + ChromeThread::PostTask( + ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, + &OwnerManager::Verify, + thread_id, + data, + signature, + d)); + return true; +} + +void OwnerManager::LoadOwnerKey() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + public_key_ = utils_->ImportPublicKey(utils_->GetOwnerKeyFilePath()); + + // Whether we loaded the public key or not, send a notification indicating + // that we're done with this attempt. We send along the key if we + // got it, NULL if not. + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, + &OwnerManager::SendNotification, + NotificationType::OWNER_KEY_FETCH_ATTEMPT_COMPLETE, + Details<SECKEYPublicKey*>(&public_key_))); +} + +void OwnerManager::GenerateKeysAndExportPublic() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + public_key_ = NULL; + private_key_ = NULL; + + if (utils_->GenerateKeyPair(&private_key_, &public_key_)) { + // If we generated the keys successfully, export them. + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &OwnerManager::ExportKey)); + } else { + // If we didn't generate the key, send along NULL with the notification + // that we're done with this attempt. + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, + &OwnerManager::SendNotification, + NotificationType::OWNER_KEY_FETCH_ATTEMPT_COMPLETE, + Details<SECKEYPublicKey*>(&public_key_))); + } +} + +void OwnerManager::ExportKey() { + if (!utils_->ExportPublicKeyViaDbus(public_key_)) { + utils_->DestroyKeys(private_key_, public_key_); + private_key_ = NULL; + public_key_ = NULL; + } + + // Whether we generated the keys or not, send a notification indicating + // that we're done with this attempt. We send along the public key if we + // got it, NULL if not. + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, + &OwnerManager::SendNotification, + NotificationType::OWNER_KEY_FETCH_ATTEMPT_COMPLETE, + Details<SECKEYPublicKey*>(&public_key_))); +} + +bool OwnerManager::EnsurePublicKey() { + if (!public_key_) + LoadOwnerKey(); + + return public_key_ != NULL; +} + +bool OwnerManager::EnsurePrivateKey() { + if (!EnsurePublicKey()) + return false; + + if (!private_key_) + private_key_ = utils_->FindPrivateKey(public_key_); + + return private_key_ != NULL; +} + +void OwnerManager::Sign(const ChromeThread::ID thread_id, + const std::string& data, + Delegate* d) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + + // If it's not the case that we can get both keys... + if (!(EnsurePublicKey() && EnsurePrivateKey())) { + ChromeThread::PostTask( + thread_id, FROM_HERE, + NewRunnableMethod(this, + &OwnerManager::CallDelegate, + d, KEY_UNAVAILABLE, std::string())); + return; + } + + // TODO(cmasone): Sign |data| with |private_key_|, return + // appropriate errors via CallDelegate. + ChromeThread::PostTask( + thread_id, FROM_HERE, + NewRunnableMethod(this, + &OwnerManager::CallDelegate, + d, SUCCESS, data)); +} + +void OwnerManager::Verify(const ChromeThread::ID thread_id, + const std::string& data, + const std::string& signature, + Delegate* d) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + + if (!EnsurePublicKey()) { + ChromeThread::PostTask( + thread_id, FROM_HERE, + NewRunnableMethod(this, + &OwnerManager::CallDelegate, + d, KEY_UNAVAILABLE, std::string())); + return; + } + + LOG(INFO) << "Starting verify attempt"; + // TODO(cmasone): Verify |signature| over |data| with |public_key_|, return + // appropriate errors via CallDelegate. + ChromeThread::PostTask( + thread_id, FROM_HERE, + NewRunnableMethod(this, + &OwnerManager::CallDelegate, + d, SUCCESS, std::string())); +} + +void OwnerManager::SendNotification(NotificationType type, + const NotificationDetails& details) { + NotificationService::current()->Notify( + type, + NotificationService::AllSources(), + details); +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/login/owner_manager.h b/chrome/browser/chromeos/login/owner_manager.h new file mode 100644 index 0000000..6ce7fc9 --- /dev/null +++ b/chrome/browser/chromeos/login/owner_manager.h @@ -0,0 +1,155 @@ +// 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_LOGIN_OWNER_MANAGER_H_ +#define CHROME_BROWSER_CHROMEOS_LOGIN_OWNER_MANAGER_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "chrome/browser/chromeos/login/owner_key_utils.h" +#include "chrome/browser/chrome_thread.h" + +class FilePath; +class NotificationDetails; +class NotificationType; + +namespace chromeos { + +// This class allows the registration of an Owner of a Chromium OS device. +// It handles generating the appropriate keys and storing them in the +// appropriate locations. +class OwnerManager : public base::RefCountedThreadSafe<OwnerManager> { + public: + // Return codes for public/private key operations. + enum KeyOpCode { + SUCCESS, + KEY_UNAVAILABLE, // The necessary key isn't available yet. + OPERATION_FAILED // The crypto operation failed. + }; + + class Delegate { + public: + // Upon completion of a key operation, this method will be called. + // |return_code| indicates what happened, |payload| will be used to pass + // back any artifacts of the operation. For example, if the operation + // was a signature attempt, the signature blob would come back in |payload|. + virtual void OnKeyOpComplete(const KeyOpCode return_code, + const std::string& payload) = 0; + }; + + OwnerManager(); + virtual ~OwnerManager(); + + bool IsAlreadyOwned(); + + // If the device has been owned already, posts a task to the FILE thread to + // fetch the public key off disk. + // Returns true if the attempt was initiated, false otherwise. + // + // Sends out a OWNER_KEY_FETCH_ATTEMPT_COMPLETE notification on completion. + // Notification comes with a Details<SECKEYPublicKey*> that contains a pointer + // to the public key, or NULL if the fetch attempt failed. + bool StartLoadOwnerKeyAttempt(); + + // If the device has not yet been owned, posts a task to the FILE + // thread to generate the owner's keys and put them in the right + // places. Keeps them in memory as well, for later use. + // Returns true if the attempt was initiated, false otherwise. + // + // Sends out a OWNER_KEY_FETCH_ATTEMPT_COMPLETE notification on completion. + // Notification comes with a Details<SECKEYPublicKey*> that contains a pointer + // to the public key, or NULL if the fetch attempt failed. + bool StartTakeOwnershipAttempt(); + + // Initiate an attempt to sign |data| with |private_key_|. Will call + // d->OnKeyOpComplete() when done. Upon success, the signature will be passed + // as the |payload| argument to d->OnKeyOpComplete(). + // Returns true if the attempt was initiated, false otherwise. + // + // If you call this on a well-known thread, you'll be called back on that + // thread. Otherwise, you'll get called back on the UI thread. + bool StartSigningAttempt(const std::string& data, Delegate* d); + + // Initiate an attempt to verify that |signature| is valid over |data| with + // |public_key_|. When the attempt is completed, an appropriate KeyOpCode + // will be passed to d->OnKeyOpComplete(). + // Returns true if the attempt was initiated, false otherwise. + // + // If you call this on a well-known thread, you'll be called back on that + // thread. Otherwise, you'll get called back on the UI thread. + bool StartVerifyAttempt(const std::string& data, + const std::string& signature, + Delegate* d); + + private: + // Pulls the owner's public key off disk and into memory. + // + // Call this on the FILE thread. + void LoadOwnerKey(); + + // Generates the owner's keys in the default NSS token. Also stores + // them in |public_key_| and |private_key_|. When done, causes the + // public key to get exported via DBus. + // + // Call this on the FILE thread. + void GenerateKeysAndExportPublic(); + + // Exports |public_key_| via DBus. + // + // Call this on the UI thread (because of DBus usage). + void ExportKey(); + + bool EnsurePublicKey(); + bool EnsurePrivateKey(); + + // Do the actual work of signing |data| with |private_key_|. First, + // ensures that we have the keys we need. Then, computes the signature. + // + // On success, calls d->OnKeyOpComplete() on |thread_id| with a + // successful return code, passing the signaure blob in |payload|. + // On failure, calls d->OnKeyOpComplete() on |thread_id| with an appropriate + // error and passes an empty string for |payload|. + void Sign(const ChromeThread::ID thread_id, + const std::string& data, + Delegate* d); + + // Do the actual work of verifying that |signature| is valid over + // |data| with |public_key_|. First, ensures we have the key we + // need, then does the verify. + // + // On success, calls d->OnKeyOpComplete() on |thread_id| with a + // successful return code, passing an empty string for |payload|. + // On failure, calls d->OnKeyOpComplete() on |thread_id| with an appropriate + // error code, passing an empty string for |payload|. + void Verify(const ChromeThread::ID thread_id, + const std::string& data, + const std::string& signature, + Delegate* d); + + // A helper method to send a notification on another thread. + void SendNotification(NotificationType type, + const NotificationDetails& details); + + // A helper method to call back a delegte on another thread. + void CallDelegate(Delegate* d, + const KeyOpCode return_code, + const std::string& payload) { + d->OnKeyOpComplete(return_code, payload); + } + + SECKEYPrivateKey* private_key_; + SECKEYPublicKey* public_key_; + + scoped_ptr<OwnerKeyUtils> utils_; + + friend class OwnerManagerTest; + + DISALLOW_COPY_AND_ASSIGN(OwnerManager); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_LOGIN_OWNER_MANAGER_H_ diff --git a/chrome/browser/chromeos/login/owner_manager_unittest.cc b/chrome/browser/chromeos/login/owner_manager_unittest.cc new file mode 100644 index 0000000..1db81e9 --- /dev/null +++ b/chrome/browser/chromeos/login/owner_manager_unittest.cc @@ -0,0 +1,352 @@ +// 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/owner_manager.h" + +#include <cert.h> +#include <keyhi.h> +#include <keythi.h> // KeyType enum +#include <pk11pub.h> +#include <stdlib.h> + +#include <string> + +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/nss_util_internal.h" +#include "base/nss_util.h" +#include "base/scoped_temp_dir.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/notification_type.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::DoAll; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::SetArgumentPointee; +using ::testing::_; + +namespace chromeos { + +namespace { + +class MockKeyUtils : public OwnerKeyUtils { + public: + MockKeyUtils() {} + ~MockKeyUtils() {} + MOCK_METHOD2(GenerateKeyPair, bool(SECKEYPrivateKey** private_key_out, + SECKEYPublicKey** public_key_out)); + MOCK_METHOD1(ExportPublicKeyViaDbus, bool(SECKEYPublicKey* key)); + MOCK_METHOD2(ExportPublicKeyToFile, bool(SECKEYPublicKey* key, + const FilePath& key_file)); + MOCK_METHOD1(ImportPublicKey, SECKEYPublicKey*(const FilePath& key_file)); + MOCK_METHOD1(FindPrivateKey, SECKEYPrivateKey*(SECKEYPublicKey* key)); + MOCK_METHOD2(DestroyKeys, void(SECKEYPrivateKey* private_key, + SECKEYPublicKey* public_key)); + MOCK_METHOD0(GetOwnerKeyFilePath, FilePath()); +}; + +class MockInjector : public OwnerKeyUtils::Factory { + public: + // Takes ownership of |mock|. + explicit MockInjector(MockKeyUtils* mock) : + transient_(mock), + delete_transient_(true) { + } + + virtual ~MockInjector() { + if (delete_transient_) + delete transient_; + } + + // If this is called, its caller takes ownership of |transient_|. + // If it's never called, |transient_| remains our problem. + OwnerKeyUtils* CreateOwnerKeyUtils() { + delete_transient_ = false; + return transient_; + } + + private: + MockKeyUtils* transient_; + bool delete_transient_; +}; + +class KeyUser : public OwnerManager::Delegate { + public: + explicit KeyUser(const OwnerManager::KeyOpCode expected) + : expected_(expected) { + } + + virtual ~KeyUser() {} + + void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, + const std::string& payload) { + MessageLoop::current()->Quit(); + EXPECT_EQ(expected_, return_code); + } + + const OwnerManager::KeyOpCode expected_; +}; + +static bool Win(SECKEYPublicKey* key) { + MessageLoop::current()->Quit(); + return true; +} + +static bool Fail(SECKEYPublicKey* key) { + MessageLoop::current()->Quit(); + return false; +} + +} // anonymous namespace + +class OwnerManagerTest : public ::testing::Test, + public NotificationObserver { + public: + OwnerManagerTest() + : message_loop_(MessageLoop::TYPE_UI), + ui_thread_(ChromeThread::UI, &message_loop_), + file_thread_(ChromeThread::FILE), + fake_public_key_(reinterpret_cast<SECKEYPublicKey*>(7)), + fake_private_key_(reinterpret_cast<SECKEYPrivateKey*>(7)), + success_expected_(false), + quit_on_observe_(true), + mock_(new MockKeyUtils), + injector_(mock_) /* injector_ takes ownership of mock_ */ { + registrar_.Add( + this, + NotificationType::OWNER_KEY_FETCH_ATTEMPT_COMPLETE, + NotificationService::AllSources()); + } + virtual ~OwnerManagerTest() {} + + virtual void SetUp() { + // Mimic ownership. + ASSERT_TRUE(tmpdir_.CreateUniqueTempDir()); + ASSERT_TRUE(file_util::CreateTemporaryFileInDir(tmpdir_.path(), &tmpfile_)); + + file_thread_.Start(); + OwnerKeyUtils::set_factory(&injector_); + } + + virtual void TearDown() { + OwnerKeyUtils::set_factory(NULL); + } + + void StartUnowned() { + file_util::Delete(tmpfile_, false); + } + + void InjectKeys(OwnerManager* manager) { + manager->public_key_ = fake_public_key_; + manager->private_key_ = fake_private_key_; + } + + // NotificationObserver implementation. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type == NotificationType::OWNER_KEY_FETCH_ATTEMPT_COMPLETE) { + EXPECT_EQ(success_expected_, + NULL != *Details<SECKEYPublicKey*>(details).ptr()); + if (quit_on_observe_) + MessageLoop::current()->Quit(); + } + } + + void ExpectKeyFetchSuccess(bool should_succeed) { + success_expected_ = should_succeed; + } + void SetQuitOnKeyFetch(bool should_quit) { quit_on_observe_ = should_quit; } + + ScopedTempDir tmpdir_; + FilePath tmpfile_; + + MessageLoop message_loop_; + ChromeThread ui_thread_; + ChromeThread file_thread_; + + SECKEYPublicKey* fake_public_key_; + SECKEYPrivateKey* fake_private_key_; + + NotificationRegistrar registrar_; + bool success_expected_; + bool quit_on_observe_; + + MockKeyUtils* mock_; + MockInjector injector_; +}; + +TEST_F(OwnerManagerTest, LoadKeyUnowned) { + StartUnowned(); + + EXPECT_CALL(*mock_, GetOwnerKeyFilePath()) + .WillRepeatedly(Return(tmpfile_)); + + scoped_refptr<OwnerManager> manager(new OwnerManager); + EXPECT_FALSE(manager->StartLoadOwnerKeyAttempt()); +} + +TEST_F(OwnerManagerTest, LoadOwnerKeyFail) { + SECKEYPublicKey* to_return = NULL; + + EXPECT_CALL(*mock_, GetOwnerKeyFilePath()) + .WillRepeatedly(Return(tmpfile_)); + EXPECT_CALL(*mock_, ImportPublicKey(tmpfile_)) + .WillOnce(Return(to_return)) + .RetiresOnSaturation(); + + scoped_refptr<OwnerManager> manager(new OwnerManager); + EXPECT_TRUE(manager->StartLoadOwnerKeyAttempt()); + + // Run remaining events, until ExportPublicKeyViaDbus(). + message_loop_.Run(); +} + +TEST_F(OwnerManagerTest, LoadOwnerKey) { + ExpectKeyFetchSuccess(true); + + EXPECT_CALL(*mock_, GetOwnerKeyFilePath()) + .WillRepeatedly(Return(tmpfile_)); + EXPECT_CALL(*mock_, ImportPublicKey(tmpfile_)) + .WillOnce(Return(fake_public_key_)) + .RetiresOnSaturation(); + + scoped_refptr<OwnerManager> manager(new OwnerManager); + EXPECT_TRUE(manager->StartLoadOwnerKeyAttempt()); + + // Run remaining events, until ExportPublicKeyViaDbus(). + message_loop_.Run(); +} + +TEST_F(OwnerManagerTest, TakeOwnershipAlreadyOwned) { + + EXPECT_CALL(*mock_, GetOwnerKeyFilePath()) + .WillRepeatedly(Return(tmpfile_)); + + scoped_refptr<OwnerManager> manager(new OwnerManager); + EXPECT_FALSE(manager->StartTakeOwnershipAttempt()); +} + +TEST_F(OwnerManagerTest, KeyGenerationFail) { + StartUnowned(); + + EXPECT_CALL(*mock_, GenerateKeyPair(_, _)) + .WillOnce(Return(false)) + .RetiresOnSaturation(); + EXPECT_CALL(*mock_, GetOwnerKeyFilePath()) + .WillRepeatedly(Return(tmpfile_)); + + scoped_refptr<OwnerManager> manager(new OwnerManager); + EXPECT_TRUE(manager->StartTakeOwnershipAttempt()); + + message_loop_.Run(); +} + +TEST_F(OwnerManagerTest, KeyExportFail) { + StartUnowned(); + + EXPECT_CALL(*mock_, GenerateKeyPair(_, _)) + .WillOnce(Return(true)) + .RetiresOnSaturation(); + EXPECT_CALL(*mock_, ExportPublicKeyViaDbus(_)) + .WillOnce(Invoke(Fail)) + .RetiresOnSaturation(); + EXPECT_CALL(*mock_, DestroyKeys(_, _)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*mock_, GetOwnerKeyFilePath()) + .WillRepeatedly(Return(tmpfile_)); + + scoped_refptr<OwnerManager> manager(new OwnerManager); + EXPECT_TRUE(manager->StartTakeOwnershipAttempt()); + + message_loop_.Run(); +} + +TEST_F(OwnerManagerTest, TakeOwnership) { + StartUnowned(); + ExpectKeyFetchSuccess(true); + + EXPECT_CALL(*mock_, GenerateKeyPair(_, _)) + .WillOnce(DoAll(SetArgumentPointee<1>(fake_public_key_), + Return(true))) + .RetiresOnSaturation(); + EXPECT_CALL(*mock_, ExportPublicKeyViaDbus(_)) + .WillOnce(Invoke(Win)) + .RetiresOnSaturation(); + EXPECT_CALL(*mock_, GetOwnerKeyFilePath()) + .WillRepeatedly(Return(tmpfile_)); + + scoped_refptr<OwnerManager> manager(new OwnerManager); + EXPECT_TRUE(manager->StartTakeOwnershipAttempt()); + + message_loop_.Run(); +} + +TEST_F(OwnerManagerTest, NotYetOwnedVerify) { + StartUnowned(); + + // Since this shouldn't happen, don't want it to end the test if it does. + SetQuitOnKeyFetch(false); + + EXPECT_CALL(*mock_, GetOwnerKeyFilePath()) + .WillRepeatedly(Return(tmpfile_)); + + scoped_refptr<OwnerManager> manager(new OwnerManager); + KeyUser delegate(OwnerManager::KEY_UNAVAILABLE); + EXPECT_FALSE(manager->StartVerifyAttempt("", "", &delegate)); +} + +TEST_F(OwnerManagerTest, AlreadyHaveKeysVerify) { + EXPECT_CALL(*mock_, GetOwnerKeyFilePath()) + .WillRepeatedly(Return(tmpfile_)); + + scoped_refptr<OwnerManager> manager(new OwnerManager); + InjectKeys(manager.get()); + KeyUser delegate(OwnerManager::SUCCESS); + EXPECT_TRUE(manager->StartVerifyAttempt("", "", &delegate)); + + message_loop_.Run(); +} + +TEST_F(OwnerManagerTest, GetKeyFailDuringVerify) { + ExpectKeyFetchSuccess(false); + SECKEYPublicKey* to_return = NULL; + + EXPECT_CALL(*mock_, GetOwnerKeyFilePath()) + .WillRepeatedly(Return(tmpfile_)); + EXPECT_CALL(*mock_, ImportPublicKey(tmpfile_)) + .WillOnce(Return(to_return)) + .RetiresOnSaturation(); + + scoped_refptr<OwnerManager> manager(new OwnerManager); + KeyUser delegate(OwnerManager::KEY_UNAVAILABLE); + EXPECT_TRUE(manager->StartVerifyAttempt("", "", &delegate)); + + message_loop_.Run(); +} + +TEST_F(OwnerManagerTest, GetKeyAndVerify) { + ExpectKeyFetchSuccess(true); + SetQuitOnKeyFetch(false); + + EXPECT_CALL(*mock_, GetOwnerKeyFilePath()) + .WillRepeatedly(Return(tmpfile_)); + EXPECT_CALL(*mock_, ImportPublicKey(tmpfile_)) + .WillOnce(Return(fake_public_key_)) + .RetiresOnSaturation(); + + scoped_refptr<OwnerManager> manager(new OwnerManager); + KeyUser delegate(OwnerManager::SUCCESS); + EXPECT_TRUE(manager->StartVerifyAttempt("", "", &delegate)); + + message_loop_.Run(); +} + +} // namespace chromeos diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index b2bd6c5..021028e 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -492,6 +492,8 @@ 'browser/chromeos/login/oobe_progress_bar.h', 'browser/chromeos/login/owner_key_utils.cc', 'browser/chromeos/login/owner_key_utils.h', + 'browser/chromeos/login/owner_manager.cc', + 'browser/chromeos/login/owner_manager.h', 'browser/chromeos/login/password_changed_view.cc', 'browser/chromeos/login/password_changed_view.h', 'browser/chromeos/login/registration_screen.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index f35e03a..b61efcf 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -739,6 +739,7 @@ 'browser/chromeos/login/google_authenticator_unittest.cc', 'browser/chromeos/login/mock_auth_response_handler.cc', 'browser/chromeos/login/owner_key_utils_unittest.cc', + 'browser/chromeos/login/owner_manager_unittest.cc', 'browser/chromeos/notifications/desktop_notifications_unittest.cc', 'browser/chromeos/offline/offline_load_page_unittest.cc', 'browser/chromeos/options/language_config_model_unittest.cc', diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h index 36aca8b..188f3b9 100644 --- a/chrome/common/notification_type.h +++ b/chrome/common/notification_type.h @@ -1068,6 +1068,10 @@ class NotificationType { // in chrome/browser/chromeos/network_state_notifier.h. // TODO(oshima): Port this to all platforms. NETWORK_STATE_CHANGED, + + // Sent when an attempt to acquire the public key of the owner of a chromium + // os device has completed. Details are a boolean value indicating success. + OWNER_KEY_FETCH_ATTEMPT_COMPLETE, #endif // Sent before the repost form warning is brought up. |