summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/chromeos/login/signed_settings.cc308
-rw-r--r--chrome/browser/chromeos/login/signed_settings.h87
-rw-r--r--chrome/browser/chromeos/login/signed_settings_unittest.cc291
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/chrome_tests.gypi1
5 files changed, 689 insertions, 0 deletions
diff --git a/chrome/browser/chromeos/login/signed_settings.cc b/chrome/browser/chromeos/login/signed_settings.cc
new file mode 100644
index 0000000..03961c3
--- /dev/null
+++ b/chrome/browser/chromeos/login/signed_settings.cc
@@ -0,0 +1,308 @@
+// 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/signed_settings.h"
+
+#include <string>
+#include <vector>
+
+#include "base/ref_counted.h"
+#include "base/stringprintf.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/login_library.h"
+#include "chrome/browser/chromeos/login/ownership_service.h"
+
+namespace chromeos {
+
+SignedSettings::SignedSettings()
+ : service_(OwnershipService::GetSharedInstance()) {
+}
+
+SignedSettings::~SignedSettings() {}
+
+class CheckWhitelistOp : public SignedSettings {
+ public:
+ CheckWhitelistOp(const std::string& email,
+ SignedSettings::Delegate<bool>* d);
+ virtual ~CheckWhitelistOp();
+ bool Execute();
+ // Implementation of OwnerManager::Delegate::OnKeyOpComplete()
+ void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
+ const std::vector<uint8>& payload);
+
+ private:
+ const std::string email_;
+ SignedSettings::Delegate<bool>* d_;
+};
+
+class WhitelistOp : public SignedSettings,
+ public LoginLibrary::Delegate<bool> {
+ public:
+ WhitelistOp(const std::string& email,
+ bool add_to_whitelist,
+ SignedSettings::Delegate<bool>* d);
+ virtual ~WhitelistOp();
+ bool Execute();
+ // Implementation of OwnerManager::Delegate::OnKeyOpComplete()
+ void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
+ const std::vector<uint8>& payload);
+ // Implementation of LoginLibrary::Delegate::Run()
+ void Run(bool value);
+
+ private:
+ bool InitiateWhitelistOp(const std::vector<uint8>& signature);
+
+ const std::string email_;
+ const bool add_to_whitelist_;
+ SignedSettings::Delegate<bool>* d_;
+};
+
+class StorePropertyOp : public SignedSettings,
+ public LoginLibrary::Delegate<bool> {
+ public:
+ StorePropertyOp(const std::string& name,
+ const std::string& value,
+ SignedSettings::Delegate<bool>* d);
+ virtual ~StorePropertyOp();
+ bool Execute();
+ // Implementation of OwnerManager::Delegate::OnKeyOpComplete()
+ void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
+ const std::vector<uint8>& payload);
+ // Implementation of LoginLibrary::Delegate::Run()
+ void Run(bool value);
+
+ private:
+ std::string name_;
+ std::string value_;
+ SignedSettings::Delegate<bool>* d_;
+};
+
+class RetrievePropertyOp : public SignedSettings {
+ public:
+ RetrievePropertyOp(const std::string& name,
+ SignedSettings::Delegate<std::string>* d);
+ virtual ~RetrievePropertyOp();
+ bool Execute();
+ // Implementation of OwnerManager::Delegate::OnKeyOpComplete()
+ void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
+ const std::vector<uint8>& payload);
+
+ private:
+ std::string name_;
+ std::string value_;
+ SignedSettings::Delegate<std::string>* d_;
+};
+
+// static
+SignedSettings* SignedSettings::CreateCheckWhitelistOp(
+ const std::string& email,
+ SignedSettings::Delegate<bool>* d) {
+ return new CheckWhitelistOp(email, d);
+}
+
+// static
+SignedSettings* SignedSettings::CreateWhitelistOp(
+ const std::string& email,
+ bool add_to_whitelist,
+ SignedSettings::Delegate<bool>* d) {
+ return new WhitelistOp(email, add_to_whitelist, d);
+}
+
+// static
+SignedSettings* SignedSettings::CreateStorePropertyOp(
+ const std::string& name,
+ const std::string& value,
+ SignedSettings::Delegate<bool>* d) {
+ return new StorePropertyOp(name, value, d);
+}
+
+// static
+SignedSettings* SignedSettings::CreateRetrievePropertyOp(
+ const std::string& name,
+ SignedSettings::Delegate<std::string>* d) {
+ return new RetrievePropertyOp(name, d);
+}
+
+CheckWhitelistOp::CheckWhitelistOp(const std::string& email,
+ SignedSettings::Delegate<bool>* d)
+ : email_(email),
+ d_(d) {
+}
+
+CheckWhitelistOp::~CheckWhitelistOp() {}
+
+bool CheckWhitelistOp::Execute() {
+ CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded());
+ std::vector<uint8> sig;
+ if (!CrosLibrary::Get()->GetLoginLibrary()->CheckWhitelist(email_, &sig))
+ return false;
+
+ // Posts a task to the FILE thread to verify |sig|.
+ service_->StartVerifyAttempt(email_, sig, this);
+ return true;
+}
+
+void CheckWhitelistOp::OnKeyOpComplete(
+ const OwnerManager::KeyOpCode return_code,
+ const std::vector<uint8>& payload) {
+ // Ensure we're on the UI thread, due to the need to send DBus traffic.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this,
+ &CheckWhitelistOp::OnKeyOpComplete,
+ return_code, payload));
+ return;
+ }
+ if (return_code == OwnerManager::SUCCESS)
+ d_->OnSettingsOpSucceeded(true);
+ else
+ d_->OnSettingsOpFailed();
+}
+
+WhitelistOp::WhitelistOp(const std::string& email,
+ bool add_to_whitelist,
+ SignedSettings::Delegate<bool>* d)
+ : email_(email),
+ add_to_whitelist_(add_to_whitelist),
+ d_(d) {
+}
+
+WhitelistOp::~WhitelistOp() {}
+
+bool WhitelistOp::Execute() {
+ // Posts a task to the FILE thread to sign |email_|.
+ service_->StartSigningAttempt(email_, this);
+ return true;
+}
+
+void WhitelistOp::OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
+ const std::vector<uint8>& payload) {
+ // Ensure we're on the UI thread, due to the need to send DBus traffic.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this,
+ &WhitelistOp::OnKeyOpComplete,
+ return_code, payload));
+ return;
+ }
+ // Now, sure we're on the UI thread.
+ bool success = false;
+ if (return_code == OwnerManager::SUCCESS) {
+ // Run() will be called when this is done.
+ success = InitiateWhitelistOp(payload);
+ }
+ if (!success)
+ d_->OnSettingsOpFailed();
+}
+
+void WhitelistOp::Run(bool value) {
+ if (value)
+ d_->OnSettingsOpSucceeded(value);
+ else
+ d_->OnSettingsOpFailed();
+}
+
+bool WhitelistOp::InitiateWhitelistOp(const std::vector<uint8>& signature) {
+ LoginLibrary* library = CrosLibrary::Get()->GetLoginLibrary();
+ if (add_to_whitelist_)
+ return library->WhitelistAsync(email_, signature, this);
+ return library->UnwhitelistAsync(email_, signature, this);
+}
+
+StorePropertyOp::StorePropertyOp(const std::string& name,
+ const std::string& value,
+ SignedSettings::Delegate<bool>* d)
+ : name_(name),
+ value_(value),
+ d_(d) {
+}
+
+StorePropertyOp::~StorePropertyOp() {}
+
+bool StorePropertyOp::Execute() {
+ // Posts a task to the FILE thread to sign |name_|=|value_|.
+ std::string to_sign = base::StringPrintf("%s=%s",
+ name_.c_str(),
+ value_.c_str());
+ service_->StartSigningAttempt(to_sign, this);
+ return true;
+}
+
+void StorePropertyOp::OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
+ const std::vector<uint8>& payload) {
+ // Ensure we're on the UI thread, due to the need to send DBus traffic.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this,
+ &StorePropertyOp::OnKeyOpComplete,
+ return_code, payload));
+ return;
+ }
+ // Now, sure we're on the UI thread.
+ bool success = false;
+ if (return_code == OwnerManager::SUCCESS) {
+ // Run() will be called when this is done.
+ success = CrosLibrary::Get()->GetLoginLibrary()->StorePropertyAsync(name_,
+ value_,
+ payload,
+ this);
+ }
+ if (!success)
+ d_->OnSettingsOpFailed();
+}
+
+void StorePropertyOp::Run(bool value) {
+ if (value)
+ d_->OnSettingsOpSucceeded(value);
+ else
+ d_->OnSettingsOpFailed();
+}
+
+RetrievePropertyOp::RetrievePropertyOp(const std::string& name,
+ SignedSettings::Delegate<std::string>* d)
+ : name_(name),
+ d_(d) {
+}
+
+RetrievePropertyOp::~RetrievePropertyOp() {}
+
+bool RetrievePropertyOp::Execute() {
+ CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded());
+ std::vector<uint8> sig;
+ if (!CrosLibrary::Get()->GetLoginLibrary()->RetrieveProperty(name_,
+ &value_,
+ &sig)) {
+ return false;
+ }
+ std::string to_verify = base::StringPrintf("%s=%s",
+ name_.c_str(),
+ value_.c_str());
+ // Posts a task to the FILE thread to verify |sig|.
+ service_->StartVerifyAttempt(to_verify, sig, this);
+ return true;
+}
+
+void RetrievePropertyOp::OnKeyOpComplete(
+ const OwnerManager::KeyOpCode return_code,
+ const std::vector<uint8>& payload) {
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this,
+ &RetrievePropertyOp::OnKeyOpComplete,
+ return_code, payload));
+ return;
+ }
+ // Now, sure we're on the UI thread.
+ if (return_code == OwnerManager::SUCCESS)
+ d_->OnSettingsOpSucceeded(value_);
+ else
+ d_->OnSettingsOpFailed();
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/signed_settings.h b/chrome/browser/chromeos/login/signed_settings.h
new file mode 100644
index 0000000..d2c1049
--- /dev/null
+++ b/chrome/browser/chromeos/login/signed_settings.h
@@ -0,0 +1,87 @@
+// 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_SIGNED_SETTINGS_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SIGNED_SETTINGS_H_
+#pragma once
+
+#include <string>
+
+#include "base/ref_counted.h"
+#include "chrome/browser/chromeos/login/owner_manager.h"
+
+// There are two categories of operations that can be performed on the
+// Chrome OS owner-signed settings store:
+// 1) doing stuff to the whitelist (adding/removing/checking)
+// 2) Storing/Retrieving arbitrary name=value pairs
+//
+// Unfortunately, it is currently a limitation that only one of each
+// category can be in-flight at a time. You can be doing exactly one thing
+// to the whitelist, and exactly one thing to the property store at a time.
+// I've filed an issue on me to remove that restriction.
+// http://code.google.com/p/chromium-os/issues/detail?id=6415
+
+// The pattern of use here is that the caller instantiates some
+// subclass of SignedSettings by calling one of the create
+// methods. Then, call Execute() on this object from the UI
+// thread. It'll go off and do work (on the FILE thread and over DBus),
+// and then call the appropriate method of the Delegate you passed in
+// -- again, on the UI thread.
+
+namespace chromeos {
+class OwnershipService;
+
+class SignedSettings : public base::RefCountedThreadSafe<SignedSettings>,
+ public OwnerManager::Delegate {
+ public:
+ template <class T>
+ class Delegate {
+ public:
+ // These methods will be called on the UI thread.
+ virtual void OnSettingsOpSucceeded(T value) = 0;
+ virtual void OnSettingsOpFailed() = 0;
+ };
+
+ SignedSettings();
+ virtual ~SignedSettings();
+
+ // These are both "whitelist" operations, and only one instance of
+ // one type can be in flight at a time.
+ static SignedSettings* CreateCheckWhitelistOp(
+ const std::string& email,
+ SignedSettings::Delegate<bool>* d);
+
+ static SignedSettings* CreateWhitelistOp(const std::string& email,
+ bool add_to_whitelist,
+ SignedSettings::Delegate<bool>* d);
+
+ // These are both "property" operations, and only one instance of
+ // one type can be in flight at a time.
+ static SignedSettings* CreateStorePropertyOp(
+ const std::string& name,
+ const std::string& value,
+ SignedSettings::Delegate<bool>* d);
+
+ static SignedSettings* CreateRetrievePropertyOp(
+ const std::string& name,
+ SignedSettings::Delegate<std::string>* d);
+
+ virtual bool Execute() = 0;
+
+ // Implementation of OwnerManager::Delegate::OnKeyOpComplete()
+ void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
+ const std::vector<uint8>& payload) = 0;
+
+ protected:
+ OwnershipService* service_;
+
+ private:
+ friend class SignedSettingsTest;
+
+ void set_service(OwnershipService* service) { service_ = service; }
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SIGNED_SETTINGS_H_
diff --git a/chrome/browser/chromeos/login/signed_settings_unittest.cc b/chrome/browser/chromeos/login/signed_settings_unittest.cc
new file mode 100644
index 0000000..f56a393
--- /dev/null
+++ b/chrome/browser/chromeos/login/signed_settings_unittest.cc
@@ -0,0 +1,291 @@
+// 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/signed_settings.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/nss_util.h"
+#include "base/scoped_temp_dir.h"
+#include "base/stringprintf.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/chromeos/login/mock_owner_key_utils.h"
+#include "chrome/browser/chromeos/login/ownership_service.h"
+#include "chrome/browser/chromeos/login/owner_manager_unittest.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::_;
+
+namespace chromeos {
+
+namespace {
+template <class T>
+class DummyDelegate : public SignedSettings::Delegate<T> {
+ public:
+ explicit DummyDelegate(T to_expect)
+ : expect_success_(false),
+ expected_(to_expect),
+ run_(false) {}
+ virtual ~DummyDelegate() { EXPECT_TRUE(run_); }
+ virtual void OnSettingsOpSucceeded(T value) {
+ run_ = true;
+ EXPECT_TRUE(expect_success_);
+ EXPECT_EQ(expected_, value);
+ }
+ virtual void OnSettingsOpFailed() {
+ run_ = true;
+ EXPECT_FALSE(expect_success_);
+ }
+ virtual void expect_success() { expect_success_ = true; }
+ bool expect_success_;
+ T expected_;
+ bool run_;
+};
+
+class Quitter : public DummyDelegate<bool> {
+ public:
+ explicit Quitter(bool to_expect) : DummyDelegate<bool>(to_expect) {}
+ virtual ~Quitter() {}
+ void OnSettingsOpSucceeded(bool value) {
+ DummyDelegate<bool>::OnSettingsOpSucceeded(value);
+ MessageLoop::current()->Quit();
+ }
+ void OnSettingsOpFailed() {
+ DummyDelegate<bool>::OnSettingsOpFailed();
+ MessageLoop::current()->Quit();
+ }
+};
+} // anonymous namespace
+
+class MockService : public OwnershipService {
+ public:
+ MOCK_METHOD0(IsAlreadyOwned, bool(void));
+ MOCK_METHOD0(StartLoadOwnerKeyAttempt, bool(void));
+ MOCK_METHOD0(StartTakeOwnershipAttempt, bool(void));
+ MOCK_METHOD2(StartSigningAttempt, void(const std::string&,
+ OwnerManager::Delegate*));
+ MOCK_METHOD3(StartVerifyAttempt, void(const std::string&,
+ const std::vector<uint8>&,
+ OwnerManager::Delegate*));
+ MOCK_METHOD0(CurrentUserIsOwner, bool(void));
+};
+
+class SignedSettingsTest : public ::testing::Test {
+ public:
+ SignedSettingsTest()
+ : fake_email_("fakey"),
+ fake_prop_("prop_name"),
+ fake_value_("stub"),
+ message_loop_(MessageLoop::TYPE_UI),
+ ui_thread_(ChromeThread::UI, &message_loop_),
+ file_thread_(ChromeThread::FILE),
+ mock_(new MockKeyUtils),
+ injector_(mock_) /* injector_ takes ownership of mock_ */ {
+ }
+
+ virtual ~SignedSettingsTest() {}
+
+ virtual void SetUp() {
+ chromeos::CrosLibrary::Get()->GetTestApi()->SetUseStubImpl();
+ file_thread_.Start();
+ }
+
+ virtual void TearDown() {
+ OwnerKeyUtils::set_factory(NULL);
+ }
+
+ void mock_service(SignedSettings* s, MockService* m) {
+ s->set_service(m);
+ }
+
+ void FailingCheckWhitelist(const OwnerManager::KeyOpCode return_code) {
+ DummyDelegate<bool> d(false);
+ scoped_refptr<SignedSettings> s(
+ SignedSettings::CreateCheckWhitelistOp(fake_email_, &d));
+
+ mock_service(s.get(), &m_);
+ EXPECT_CALL(m_, StartVerifyAttempt(fake_email_, _, _))
+ .Times(1);
+
+ EXPECT_TRUE(s->Execute());
+ s->OnKeyOpComplete(return_code, std::vector<uint8>());
+ }
+
+ void FailingWhitelistOp(const OwnerManager::KeyOpCode return_code) {
+ DummyDelegate<bool> d(false);
+ scoped_refptr<SignedSettings> s(
+ SignedSettings::CreateWhitelistOp(fake_email_, true, &d));
+
+ mock_service(s.get(), &m_);
+ EXPECT_CALL(m_, StartSigningAttempt(fake_email_, _))
+ .Times(1);
+
+ EXPECT_TRUE(s->Execute());
+ s->OnKeyOpComplete(return_code, std::vector<uint8>());
+ }
+
+ void FailingStorePropertyOp(const OwnerManager::KeyOpCode return_code) {
+ DummyDelegate<bool> d(false);
+ scoped_refptr<SignedSettings> s(
+ SignedSettings::CreateStorePropertyOp(fake_prop_, fake_value_, &d));
+ std::string to_sign = base::StringPrintf("%s=%s",
+ fake_prop_.c_str(),
+ fake_value_.c_str());
+ mock_service(s.get(), &m_);
+ EXPECT_CALL(m_, StartSigningAttempt(to_sign, _))
+ .Times(1);
+
+ EXPECT_TRUE(s->Execute());
+ s->OnKeyOpComplete(return_code, std::vector<uint8>());
+ }
+
+ void FailingRetrievePropertyOp(const OwnerManager::KeyOpCode return_code) {
+ DummyDelegate<std::string> d(fake_value_);
+ scoped_refptr<SignedSettings> s(
+ SignedSettings::CreateRetrievePropertyOp(fake_prop_, &d));
+ std::string to_verify = base::StringPrintf("%s=%s",
+ fake_prop_.c_str(),
+ fake_value_.c_str());
+ mock_service(s.get(), &m_);
+ EXPECT_CALL(m_, StartVerifyAttempt(to_verify, _, _))
+ .Times(1);
+
+ EXPECT_TRUE(s->Execute());
+ s->OnKeyOpComplete(return_code, std::vector<uint8>());
+ }
+
+ const std::string fake_email_;
+ const std::string fake_prop_;
+ const std::string fake_value_;
+ MockService m_;
+
+ ScopedTempDir tmpdir_;
+ FilePath tmpfile_;
+
+ MessageLoop message_loop_;
+ ChromeThread ui_thread_;
+ ChromeThread file_thread_;
+
+ std::vector<uint8> fake_public_key_;
+ scoped_ptr<RSAPrivateKey> fake_private_key_;
+
+ MockKeyUtils* mock_;
+ MockInjector injector_;
+
+};
+
+TEST_F(SignedSettingsTest, CheckWhitelist) {
+ DummyDelegate<bool> d(true);
+ d.expect_success();
+ scoped_refptr<SignedSettings> s(
+ SignedSettings::CreateCheckWhitelistOp(fake_email_, &d));
+
+ mock_service(s.get(), &m_);
+ EXPECT_CALL(m_, StartVerifyAttempt(fake_email_, _, _))
+ .Times(1);
+
+ EXPECT_TRUE(s->Execute());
+ s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>());
+}
+
+TEST_F(SignedSettingsTest, CheckWhitelistNoKey) {
+ FailingCheckWhitelist(OwnerManager::KEY_UNAVAILABLE);
+}
+
+TEST_F(SignedSettingsTest, CheckWhitelistFailed) {
+ FailingCheckWhitelist(OwnerManager::OPERATION_FAILED);
+}
+
+TEST_F(SignedSettingsTest, Whitelist) {
+ Quitter d(true);
+ d.expect_success();
+ scoped_refptr<SignedSettings> s(
+ SignedSettings::CreateWhitelistOp(fake_email_, true, &d));
+
+ mock_service(s.get(), &m_);
+ EXPECT_CALL(m_, StartSigningAttempt(fake_email_, _))
+ .Times(1);
+
+ EXPECT_TRUE(s->Execute());
+ s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>());
+ message_loop_.Run();
+}
+
+TEST_F(SignedSettingsTest, Unwhitelist) {
+ Quitter d(true);
+ d.expect_success();
+ scoped_refptr<SignedSettings> s(
+ SignedSettings::CreateWhitelistOp(fake_email_, false, &d));
+
+ mock_service(s.get(), &m_);
+ EXPECT_CALL(m_, StartSigningAttempt(fake_email_, _))
+ .Times(1);
+
+ EXPECT_TRUE(s->Execute());
+ s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>());
+ message_loop_.Run();
+}
+
+TEST_F(SignedSettingsTest, WhitelistNoKey) {
+ FailingWhitelistOp(OwnerManager::KEY_UNAVAILABLE);
+}
+
+TEST_F(SignedSettingsTest, WhitelistFailed) {
+ FailingWhitelistOp(OwnerManager::OPERATION_FAILED);
+}
+
+TEST_F(SignedSettingsTest, StoreProperty) {
+ Quitter d(true);
+ d.expect_success();
+ scoped_refptr<SignedSettings> s(
+ SignedSettings::CreateStorePropertyOp(fake_prop_, fake_value_, &d));
+ std::string to_sign = base::StringPrintf("%s=%s",
+ fake_prop_.c_str(),
+ fake_value_.c_str());
+ mock_service(s.get(), &m_);
+ EXPECT_CALL(m_, StartSigningAttempt(to_sign, _))
+ .Times(1);
+
+ EXPECT_TRUE(s->Execute());
+ s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>());
+ message_loop_.Run();
+}
+
+TEST_F(SignedSettingsTest, StorePropertyNoKey) {
+ FailingStorePropertyOp(OwnerManager::KEY_UNAVAILABLE);
+}
+
+TEST_F(SignedSettingsTest, StorePropertyFailed) {
+ FailingStorePropertyOp(OwnerManager::OPERATION_FAILED);
+}
+
+TEST_F(SignedSettingsTest, RetrieveProperty) {
+ DummyDelegate<std::string> d(fake_value_);
+ d.expect_success();
+ scoped_refptr<SignedSettings> s(
+ SignedSettings::CreateRetrievePropertyOp(fake_prop_, &d));
+ std::string to_verify = base::StringPrintf("%s=%s",
+ fake_prop_.c_str(),
+ fake_value_.c_str());
+ mock_service(s.get(), &m_);
+ EXPECT_CALL(m_, StartVerifyAttempt(to_verify, _, _))
+ .Times(1);
+
+ EXPECT_TRUE(s->Execute());
+ s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>());
+}
+
+TEST_F(SignedSettingsTest, RetrievePropertyNoKey) {
+ FailingRetrievePropertyOp(OwnerManager::KEY_UNAVAILABLE);
+}
+
+TEST_F(SignedSettingsTest, RetrievePropertyFailed) {
+ FailingRetrievePropertyOp(OwnerManager::OPERATION_FAILED);
+}
+
+} // namespace chromeos
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 8e92f6f..9157a84 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -543,6 +543,8 @@
'browser/chromeos/login/screen_lock_view.cc',
'browser/chromeos/login/screen_lock_view.h',
'browser/chromeos/login/screen_observer.h',
+ 'browser/chromeos/login/signed_settings.cc',
+ 'browser/chromeos/login/signed_settings.h',
'browser/chromeos/login/update_screen.cc',
'browser/chromeos/login/update_screen.h',
'browser/chromeos/login/update_view.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index cd751e2..45ebc5d 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -870,6 +870,7 @@
'browser/chromeos/login/owner_key_utils_unittest.cc',
'browser/chromeos/login/owner_manager_unittest.cc',
'browser/chromeos/login/ownership_service_unittest.cc',
+ 'browser/chromeos/login/signed_settings_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',