Linux pairing registry delegate implementation

BUG=156182

Review URL: https://chromiumcodereview.appspot.com/15709005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@208123 0039d316-1c4b-4281-b951-d872f2087c98
parent 2885f9cb
// Copyright 2013 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 REMOTING_HOST_PAIRING_REGISTRY_DELEGATE_H_
#define REMOTING_HOST_PAIRING_REGISTRY_DELEGATE_H_
#include "base/memory/scoped_ptr.h"
#include "remoting/protocol/pairing_registry.h"
namespace base {
class TaskRunner;
} // namespace base
namespace remoting {
// Returns a platform-specific pairing registry delegate that will save to
// permanent storage using the specified TaskRunner. Returns NULL on platforms
// that don't support pairing.
scoped_ptr<protocol::PairingRegistry::Delegate>
CreatePairingRegistryDelegate(scoped_refptr<base::TaskRunner> task_runner);
} // namespace remoting
#endif // REMOTING_HOST_PAIRING_REGISTRY_DELEGATE_H_
// Copyright 2013 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 "remoting/host/pairing_registry_delegate_linux.h"
#include "base/bind.h"
#include "base/file_util.h"
#include "base/files/important_file_writer.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "remoting/host/branding.h"
namespace {
const char kRegistryFilename[] = "paired-clients.json";
} // namespace
namespace remoting {
using protocol::PairingRegistry;
PairingRegistryDelegateLinux::PairingRegistryDelegateLinux(
scoped_refptr<base::TaskRunner> task_runner)
: task_runner_(task_runner),
weak_factory_(this) {
}
PairingRegistryDelegateLinux::~PairingRegistryDelegateLinux() {
}
void PairingRegistryDelegateLinux::Save(
const std::string& pairings_json,
const PairingRegistry::SaveCallback& callback) {
// If a callback was supplied, wrap it in a helper function that will
// run it on this thread.
PairingRegistry::SaveCallback run_callback_on_this_thread;
if (!callback.is_null()) {
run_callback_on_this_thread =
base::Bind(&PairingRegistryDelegateLinux::RunSaveCallbackOnThread,
base::ThreadTaskRunnerHandle::Get(),
callback);
}
task_runner_->PostTask(
FROM_HERE,
base::Bind(&PairingRegistryDelegateLinux::DoSave,
weak_factory_.GetWeakPtr(),
pairings_json,
run_callback_on_this_thread));
}
void PairingRegistryDelegateLinux::Load(
const PairingRegistry::LoadCallback& callback) {
// Wrap the callback in a helper function that will run it on this thread.
// Note that, unlike AddPairing, the GetPairing callback is mandatory.
PairingRegistry::LoadCallback run_callback_on_this_thread =
base::Bind(&PairingRegistryDelegateLinux::RunLoadCallbackOnThread,
base::ThreadTaskRunnerHandle::Get(),
callback);
task_runner_->PostTask(
FROM_HERE,
base::Bind(&PairingRegistryDelegateLinux::DoLoad,
weak_factory_.GetWeakPtr(),
run_callback_on_this_thread));
}
void PairingRegistryDelegateLinux::RunSaveCallbackOnThread(
scoped_refptr<base::TaskRunner> task_runner,
const PairingRegistry::SaveCallback& callback,
bool success) {
task_runner->PostTask(FROM_HERE, base::Bind(callback, success));
}
void PairingRegistryDelegateLinux::RunLoadCallbackOnThread(
scoped_refptr<base::TaskRunner> task_runner,
const PairingRegistry::LoadCallback& callback,
const std::string& pairings_json) {
task_runner->PostTask(FROM_HERE, base::Bind(callback, pairings_json));
}
void PairingRegistryDelegateLinux::DoSave(
const std::string& pairings_json,
const PairingRegistry::SaveCallback& callback) {
base::FilePath registry_path = GetRegistryFilePath();
base::FilePath parent_directory = registry_path.DirName();
base::PlatformFileError error;
if (!file_util::CreateDirectoryAndGetError(parent_directory, &error)) {
LOG(ERROR) << "Could not create pairing registry directory: " << error;
return;
}
if (!base::ImportantFileWriter::WriteFileAtomically(registry_path,
pairings_json)) {
LOG(ERROR) << "Could not save pairing registry.";
}
if (!callback.is_null()) {
callback.Run(true);
}
}
void PairingRegistryDelegateLinux::DoLoad(
const PairingRegistry::LoadCallback& callback) {
base::FilePath registry_path = GetRegistryFilePath();
std::string result;
if (!file_util::ReadFileToString(registry_path, &result)) {
LOG(ERROR) << "Load failed.";
}
callback.Run(result);
}
base::FilePath PairingRegistryDelegateLinux::GetRegistryFilePath() {
if (!filename_for_testing_.empty()) {
return filename_for_testing_;
}
base::FilePath config_dir = remoting::GetConfigDir();
return config_dir.Append(kRegistryFilename);
}
void PairingRegistryDelegateLinux::SetFilenameForTesting(
const base::FilePath &filename) {
filename_for_testing_ = filename;
}
scoped_ptr<PairingRegistry::Delegate> CreatePairingRegistryDelegate(
scoped_refptr<base::TaskRunner> task_runner) {
return scoped_ptr<PairingRegistry::Delegate>(
new PairingRegistryDelegateLinux(task_runner));
}
} // namespace remoting
// Copyright 2013 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 REMOTING_PROTOCOL_PAIRING_REGISTRY_DELEGATE_LINUX_H_
#define REMOTING_PROTOCOL_PAIRING_REGISTRY_DELEGATE_LINUX_H_
#include "remoting/protocol/pairing_registry.h"
#include "base/files/file_path.h"
#include "base/memory/weak_ptr.h"
namespace base {
class ListValue;
class TaskRunner;
} // namespace base
namespace remoting {
class PairingRegistryDelegateLinux
: public protocol::PairingRegistry::Delegate {
public:
explicit PairingRegistryDelegateLinux(
scoped_refptr<base::TaskRunner> task_runner);
virtual ~PairingRegistryDelegateLinux();
// PairingRegistry::Delegate interface
virtual void Save(
const std::string& pairings_json,
const protocol::PairingRegistry::SaveCallback& callback) OVERRIDE;
virtual void Load(
const protocol::PairingRegistry::LoadCallback& callback) OVERRIDE;
private:
FRIEND_TEST_ALL_PREFIXES(PairingRegistryDelegateLinuxTest, SaveAndLoad);
// Blocking helper methods run using the TaskRunner passed to the ctor.
void DoSave(const std::string& pairings_json,
const protocol::PairingRegistry::SaveCallback& callback);
void DoLoad(const protocol::PairingRegistry::LoadCallback& callback);
// Run the delegate callbacks on their original thread.
static void RunSaveCallbackOnThread(
scoped_refptr<base::TaskRunner> task_runner,
const protocol::PairingRegistry::SaveCallback& callback,
bool success);
static void RunLoadCallbackOnThread(
scoped_refptr<base::TaskRunner> task_runner,
const protocol::PairingRegistry::LoadCallback& callback,
const std::string& pairings_json);
// Helper methods to load and save the pairing registry.
protocol::PairingRegistry::PairedClients LoadPairings();
void SavePairings(
const protocol::PairingRegistry::PairedClients& paired_clients);
// Return the path to the file to use for loading and saving paired clients.
base::FilePath GetRegistryFilePath();
// For testing purposes, set the path returned by |GetRegistryFilePath|.
void SetFilenameForTesting(const base::FilePath &filename);
scoped_refptr<base::TaskRunner> task_runner_;
base::FilePath filename_for_testing_;
base::WeakPtrFactory<PairingRegistryDelegateLinux> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PairingRegistryDelegateLinux);
};
} // namespace remoting
#endif // REMOTING_PROTOCOL_PAIRING_REGISTRY_DELEGATE_LINUX_H_
// Copyright 2013 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 "remoting/host/pairing_registry_delegate_linux.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/run_loop.h"
#include "base/task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "base/timer.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace remoting {
using protocol::PairingRegistry;
class PairingRegistryDelegateLinuxTest : public testing::Test {
public:
void SaveComplete(PairingRegistry::Delegate* delegate,
const std::string& expected_json,
bool success) {
EXPECT_TRUE(success);
// Load the pairings again to make sure we get what we've just written.
delegate->Load(
base::Bind(&PairingRegistryDelegateLinuxTest::VerifyLoad,
base::Unretained(this),
expected_json));
}
void VerifyLoad(const std::string& expected,
const std::string& actual) {
EXPECT_EQ(actual, expected);
base::MessageLoop::current()->Quit();
}
};
TEST_F(PairingRegistryDelegateLinuxTest, SaveAndLoad) {
base::MessageLoop message_loop;
base::RunLoop run_loop;
// Create a temporary directory in order to get a unique name and use a
// subdirectory to ensure that the AddPairing method creates the parent
// directory if it doesn't exist.
base::FilePath temp_dir;
file_util::CreateNewTempDirectory("chromoting-test", &temp_dir);
base::FilePath temp_file = temp_dir.Append("dir").Append("registry.json");
scoped_refptr<base::TaskRunner> task_runner =
base::ThreadTaskRunnerHandle::Get();
scoped_ptr<PairingRegistryDelegateLinux> save_delegate(
new PairingRegistryDelegateLinux(task_runner));
scoped_ptr<PairingRegistryDelegateLinux> load_delegate(
new PairingRegistryDelegateLinux(task_runner));
save_delegate->SetFilenameForTesting(temp_file);
load_delegate->SetFilenameForTesting(temp_file);
// Save the pairings, then load them using a different delegate to ensure
// that the test isn't passing due to cached values. Note that the delegate
// doesn't require that the strings it loads and saves are valid JSON, so
// we can simplify the test a bit.
std::string test_data = "test data";
save_delegate->Save(
test_data,
base::Bind(&PairingRegistryDelegateLinuxTest::SaveComplete,
base::Unretained(this),
load_delegate.get(),
test_data));
run_loop.Run();
file_util::Delete(temp_dir, true);
};
} // namespace remoting
// Copyright 2013 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 "remoting/host/pairing_registry_delegate.h"
#include "base/task_runner.h"
namespace remoting {
using protocol::PairingRegistry;
scoped_ptr<PairingRegistry::Delegate> CreatePairingRegistryDelegate(
scoped_refptr<base::TaskRunner> task_runner) {
return scoped_ptr<PairingRegistry::Delegate>();
}
} // namespace remoting
// Copyright 2013 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 "remoting/host/pairing_registry_delegate.h"
#include "base/task_runner.h"
namespace remoting {
using protocol::PairingRegistry;
scoped_ptr<PairingRegistry::Delegate> CreatePairingRegistryDelegate(
scoped_refptr<base::TaskRunner> task_runner) {
return scoped_ptr<PairingRegistry::Delegate>();
}
} // namespace remoting
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include "remoting/host/log_to_server.h" #include "remoting/host/log_to_server.h"
#include "remoting/host/logging.h" #include "remoting/host/logging.h"
#include "remoting/host/me2me_desktop_environment.h" #include "remoting/host/me2me_desktop_environment.h"
#include "remoting/host/pairing_registry_delegate.h"
#include "remoting/host/policy_hack/policy_watcher.h" #include "remoting/host/policy_hack/policy_watcher.h"
#include "remoting/host/service_urls.h" #include "remoting/host/service_urls.h"
#include "remoting/host/session_manager_factory.h" #include "remoting/host/session_manager_factory.h"
...@@ -478,12 +479,9 @@ void HostProcess::CreateAuthenticatorFactory() { ...@@ -478,12 +479,9 @@ void HostProcess::CreateAuthenticatorFactory() {
// TODO(jamiewalch): Add a pairing registry here once all the code // TODO(jamiewalch): Add a pairing registry here once all the code
// is committed. // is committed.
scoped_refptr<remoting::protocol::PairingRegistry> pairing_registry; scoped_refptr<remoting::protocol::PairingRegistry> pairing_registry(
//scoped_refptr<protocol::PairingRegistry> pairing_registry( new remoting::protocol::PairingRegistry(
// new protocol::PairingRegistry( CreatePairingRegistryDelegate(NULL)));
// scoped_ptr<protocol::PairingRegistry::Delegate>(
// new protocol::NotImplementedPairingRegistryDelegate),
// protocol::PairingRegistry::PairedClients()));
scoped_ptr<protocol::AuthenticatorFactory> factory; scoped_ptr<protocol::AuthenticatorFactory> factory;
......
...@@ -85,14 +85,14 @@ class NegotiatingAuthenticatorTest : public AuthenticatorTestBase { ...@@ -85,14 +85,14 @@ class NegotiatingAuthenticatorTest : public AuthenticatorTestBase {
void CreatePairingRegistry(bool with_paired_client) { void CreatePairingRegistry(bool with_paired_client) {
mock_delegate_ = new MockPairingRegistryDelegate; mock_delegate_ = new MockPairingRegistryDelegate;
pairing_registry_ = new PairingRegistry(
scoped_ptr<PairingRegistry::Delegate>(mock_delegate_));
if (with_paired_client) { if (with_paired_client) {
PairingRegistry::Pairing pairing( PairingRegistry::Pairing pairing(
base::Time(), kTestClientName, kTestClientId, kTestPairedSecret); base::Time(), kTestClientName, kTestClientId, kTestPairedSecret);
mock_delegate_->AddPairing(pairing, pairing_registry_->AddPairing(pairing);
PairingRegistry::AddPairingCallback()); mock_delegate_->RunCallback();
} }
pairing_registry_ = new PairingRegistry(
scoped_ptr<PairingRegistry::Delegate>(mock_delegate_));
} }
static void FetchSecret( static void FetchSecret(
......
...@@ -7,8 +7,18 @@ ...@@ -7,8 +7,18 @@
#include "base/base64.h" #include "base/base64.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/guid.h" #include "base/guid.h"
#include "base/json/json_string_value_serializer.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "crypto/random.h" #include "crypto/random.h"
namespace {
const char kCreatedTimeKey[] = "created-time";
const char kClientIdKey[] = "client-id";
const char kClientNameKey[] = "client-name";
const char kSharedSecretKey[] = "shared-secret";
} // namespace
namespace remoting { namespace remoting {
namespace protocol { namespace protocol {
...@@ -68,30 +78,101 @@ PairingRegistry::Pairing PairingRegistry::CreatePairing( ...@@ -68,30 +78,101 @@ PairingRegistry::Pairing PairingRegistry::CreatePairing(
const std::string& client_name) { const std::string& client_name) {
DCHECK(CalledOnValidThread()); DCHECK(CalledOnValidThread());
Pairing result = Pairing::Create(client_name); Pairing result = Pairing::Create(client_name);
delegate_->AddPairing(result, AddPairingCallback()); AddPairing(result);
return result; return result;
} }
void PairingRegistry::GetPairing(const std::string& client_id, void PairingRegistry::GetPairing(const std::string& client_id,
const GetPairingCallback& callback) { const GetPairingCallback& callback) {
DCHECK(CalledOnValidThread()); DCHECK(CalledOnValidThread());
delegate_->GetPairing(client_id, callback); delegate_->Load(
base::Bind(&PairingRegistry::DoGetPairing, this, client_id, callback));
}
void PairingRegistry::AddPairing(const Pairing& pairing) {
delegate_->Load(
base::Bind(&PairingRegistry::MergePairingAndSave, this, pairing));
}
void PairingRegistry::MergePairingAndSave(const Pairing& pairing,
const std::string& pairings_json) {
DCHECK(CalledOnValidThread());
PairedClients clients = DecodeJson(pairings_json);
clients[pairing.client_id()] = pairing;
std::string new_pairings_json = EncodeJson(clients);
delegate_->Save(new_pairings_json, SaveCallback());
} }
void NotImplementedPairingRegistryDelegate::AddPairing( void PairingRegistry::DoGetPairing(const std::string& client_id,
const PairingRegistry::Pairing& new_paired_client, const GetPairingCallback& callback,
const PairingRegistry::AddPairingCallback& callback) { const std::string& pairings_json) {
NOTIMPLEMENTED(); PairedClients clients = DecodeJson(pairings_json);
if (!callback.is_null()) { Pairing result = clients[client_id];
callback.Run(false); callback.Run(result);
}
PairingRegistry::PairedClients PairingRegistry::DecodeJson(
const std::string& pairings_json) {
PairedClients result;
if (pairings_json.empty()) {
return result;
}
JSONStringValueSerializer registry(pairings_json);
int error_code;
std::string error_message;
scoped_ptr<base::Value> root(
registry.Deserialize(&error_code, &error_message));
if (!root) {
LOG(ERROR) << "Failed to load paired clients: " << error_message
<< " (" << error_code << ").";
return result;
} }
base::ListValue* root_list = NULL;
if (!root->GetAsList(&root_list)) {
LOG(ERROR) << "Failed to load paired clients: root node is not a list.";
return result;
}
for (size_t i = 0; i < root_list->GetSize(); ++i) {
base::DictionaryValue* pairing = NULL;
std::string client_name, client_id, shared_secret;
double created_time_value;
if (root_list->GetDictionary(i, &pairing) &&
pairing->GetDouble(kCreatedTimeKey, &created_time_value) &&
pairing->GetString(kClientNameKey, &client_name) &&
pairing->GetString(kClientIdKey, &client_id) &&
pairing->GetString(kSharedSecretKey, &shared_secret)) {
base::Time created_time = base::Time::FromJsTime(created_time_value);
result[client_id] = Pairing(
created_time, client_name, client_id, shared_secret);
} else {
LOG(ERROR) << "Paired client " << i << " has unexpected format.";
}
}
return result;
} }
void NotImplementedPairingRegistryDelegate::GetPairing( std::string PairingRegistry::EncodeJson(const PairedClients& clients) {
const std::string& client_id, base::ListValue root;
const PairingRegistry::GetPairingCallback& callback) { for (PairedClients::const_iterator i = clients.begin();
NOTIMPLEMENTED(); i != clients.end(); ++i) {
callback.Run(PairingRegistry::Pairing()); base::DictionaryValue* pairing = new base::DictionaryValue();
pairing->SetDouble(kCreatedTimeKey, i->second.created_time().ToJsTime());
pairing->SetString(kClientNameKey, i->second.client_name());
pairing->SetString(kClientIdKey, i->second.client_id());
pairing->SetString(kSharedSecretKey, i->second.shared_secret());
root.Append(pairing);
}
std::string result;
JSONStringValueSerializer serializer(&result);
serializer.Serialize(root);
return result;
} }
} // namespace protocol } // namespace protocol
......
...@@ -17,9 +17,6 @@ ...@@ -17,9 +17,6 @@
namespace remoting { namespace remoting {
namespace protocol { namespace protocol {
// TODO(jamiewalch): This class is little more than a wrapper around the
// Pairing and Delegate classes. Refactor it away.
// PairingRegistry holds information about paired clients to support // PairingRegistry holds information about paired clients to support
// PIN-less authentication. For each paired client, the registry holds // PIN-less authentication. For each paired client, the registry holds
// the following information: // the following information:
...@@ -62,62 +59,63 @@ class PairingRegistry : public base::RefCountedThreadSafe<PairingRegistry>, ...@@ -62,62 +59,63 @@ class PairingRegistry : public base::RefCountedThreadSafe<PairingRegistry>,
typedef std::map<std::string, Pairing> PairedClients; typedef std::map<std::string, Pairing> PairedClients;
// Delegate callbacks. // Delegate callbacks.
typedef base::Callback<void(Pairing client_information)> GetPairingCallback; typedef base::Callback<void(const std::string& pairings_json)> LoadCallback;
typedef base::Callback<void(bool success)> AddPairingCallback; typedef base::Callback<void(bool success)> SaveCallback;
typedef base::Callback<void(Pairing pariring)> GetPairingCallback;
// Interface representing the persistent storage back-end. // Interface representing the persistent storage back-end.
class Delegate { class Delegate {
public: public:
virtual ~Delegate() {} virtual ~Delegate() {}
// Add pairing information to persistent storage. If a non-NULL callback // Save JSON-encoded pairing information to persistent storage. If
// is provided, invoke it on completion to indicate success or failure. // a non-NULL callback is provided, invoke it on completion to
// Must not block. // indicate success or failure. Must not block.
// virtual void Save(const std::string& pairings_json,
// TODO(jamiewalch): Plumb the callback into the RequestPairing flow so const SaveCallback& callback) = 0;
// that the client isn't sent the pairing information until it has been
// saved. // Retrieve the JSON-encoded pairing information from persistent
virtual void AddPairing(const Pairing& new_paired_client, // storage. Must not block.
const AddPairingCallback& callback) = 0; virtual void Load(const LoadCallback& callback) = 0;
// Retrieve the Pairing for the specified client id. If none is found,
// invoke the callback with a default pairing. Must not block.
virtual void GetPairing(const std::string& client_id,
const GetPairingCallback& callback) = 0;
}; };
explicit PairingRegistry(scoped_ptr<Delegate> delegate); explicit PairingRegistry(scoped_ptr<Delegate> delegate);
// Create a pairing for a new client and save it to disk. // Creates a pairing for a new client and saves it to disk.
//
// TODO(jamiewalch): Plumb the Save callback into the RequestPairing flow
// so that the client isn't sent the pairing information until it has been
// saved.
Pairing CreatePairing(const std::string& client_name); Pairing CreatePairing(const std::string& client_name);
// Get the pairing for the specified client id. See the corresponding // Gets the pairing for the specified client id. See the corresponding
// Delegate method for details. // Delegate method for details. If none is found, the callback is invoked
// with an invalid Pairing.
void GetPairing(const std::string& client_id, void GetPairing(const std::string& client_id,
const GetPairingCallback& callback); const GetPairingCallback& callback);
private: private:
FRIEND_TEST_ALL_PREFIXES(PairingRegistryTest, AddPairing);
friend class NegotiatingAuthenticatorTest;
friend class base::RefCountedThreadSafe<PairingRegistry>; friend class base::RefCountedThreadSafe<PairingRegistry>;
virtual ~PairingRegistry(); virtual ~PairingRegistry();
void AddPairing(const Pairing& pairing);;
void MergePairingAndSave(const Pairing& pairing,
const std::string& pairings_json);
void DoGetPairing(const std::string& client_id,
const GetPairingCallback& callback,
const std::string& pairings_json);
static PairedClients DecodeJson(const std::string& pairings_json);
static std::string EncodeJson(const PairedClients& clients);
scoped_ptr<Delegate> delegate_; scoped_ptr<Delegate> delegate_;
DISALLOW_COPY_AND_ASSIGN(PairingRegistry); DISALLOW_COPY_AND_ASSIGN(PairingRegistry);
}; };
// Temporary delegate that just logs NOTIMPLEMENTED for Load/Save.
// TODO(jamiewalch): Delete once Delegates are implemented for all platforms.
class NotImplementedPairingRegistryDelegate : public PairingRegistry::Delegate {
public:
virtual void AddPairing(
const PairingRegistry::Pairing& paired_clients,
const PairingRegistry::AddPairingCallback& callback) OVERRIDE;
virtual void GetPairing(
const std::string& client_id,
const PairingRegistry::GetPairingCallback& callback) OVERRIDE;
};
} // namespace protocol } // namespace protocol
} // namespace remoting } // namespace remoting
......
...@@ -17,57 +17,47 @@ namespace protocol { ...@@ -17,57 +17,47 @@ namespace protocol {
class PairingRegistryTest : public testing::Test { class PairingRegistryTest : public testing::Test {
public: public:
virtual void SetUp() OVERRIDE {
got_secret_ = false;
}
void CompareSecret(const std::string& expected, void CompareSecret(const std::string& expected,
PairingRegistry::Pairing actual) { PairingRegistry::Pairing actual) {
EXPECT_EQ(actual.shared_secret(), expected); EXPECT_EQ(expected, actual.shared_secret());
secret_ = actual.shared_secret();
got_secret_ = true; got_secret_ = true;
} }
protected: protected:
std::string secret_;
bool got_secret_; bool got_secret_;
}; };
TEST_F(PairingRegistryTest, GetPairing) { TEST_F(PairingRegistryTest, CreateAndGetPairings) {
PairingRegistry::Pairing client_info =
PairingRegistry::Pairing::Create("client_name");
MockPairingRegistryDelegate* mock_delegate = MockPairingRegistryDelegate* mock_delegate =
new MockPairingRegistryDelegate(); new MockPairingRegistryDelegate();
mock_delegate->AddPairing(client_info, PairingRegistry::AddPairingCallback());
scoped_ptr<PairingRegistry::Delegate> delegate(mock_delegate); scoped_ptr<PairingRegistry::Delegate> delegate(mock_delegate);
scoped_refptr<PairingRegistry> registry(new PairingRegistry(delegate.Pass())); scoped_refptr<PairingRegistry> registry(new PairingRegistry(delegate.Pass()));
PairingRegistry::Pairing pairing_1 = registry->CreatePairing("client_name");
mock_delegate->RunCallback();
PairingRegistry::Pairing pairing_2 = registry->CreatePairing("client_name");
mock_delegate->RunCallback();
registry->GetPairing(client_info.client_id(), registry->GetPairing(pairing_1.client_id(),
base::Bind(&PairingRegistryTest::CompareSecret, base::Bind(&PairingRegistryTest::CompareSecret,
base::Unretained(this), base::Unretained(this),
client_info.shared_secret())); pairing_1.shared_secret()));
got_secret_ = false;
mock_delegate->RunCallback(); mock_delegate->RunCallback();
EXPECT_TRUE(got_secret_); EXPECT_TRUE(got_secret_);
} std::string secret_1 = secret_;
TEST_F(PairingRegistryTest, AddPairing) {
MockPairingRegistryDelegate* mock_delegate =
new MockPairingRegistryDelegate();
scoped_ptr<PairingRegistry::Delegate> delegate(mock_delegate);
scoped_refptr<PairingRegistry> registry(new PairingRegistry(delegate.Pass()));
// Verify that we can create pairings from two clients with the same name, but
// that they aren't allocated the same client id.
PairingRegistry::Pairing pairing_1 = registry->CreatePairing("client_name");
PairingRegistry::Pairing pairing_2 = registry->CreatePairing("client_name");
const PairingRegistry::PairedClients& clients = // Check that the second client is paired with a different shared secret.
mock_delegate->paired_clients(); registry->GetPairing(pairing_2.client_id(),
ASSERT_EQ(clients.size(), 2u); base::Bind(&PairingRegistryTest::CompareSecret,
PairingRegistry::Pairing first = clients.begin()->second; base::Unretained(this),
PairingRegistry::Pairing second = (++clients.begin())->second; pairing_2.shared_secret()));
EXPECT_EQ(first.client_name(), second.client_name()); got_secret_ = false;
EXPECT_NE(first.client_id(), second.client_id()); mock_delegate->RunCallback();
EXPECT_TRUE(got_secret_);
EXPECT_NE(secret_, secret_1);
} }
} // namespace protocol } // namespace protocol
......
...@@ -54,31 +54,24 @@ MockPairingRegistryDelegate::MockPairingRegistryDelegate() { ...@@ -54,31 +54,24 @@ MockPairingRegistryDelegate::MockPairingRegistryDelegate() {
MockPairingRegistryDelegate::~MockPairingRegistryDelegate() { MockPairingRegistryDelegate::~MockPairingRegistryDelegate() {
} }
void MockPairingRegistryDelegate::AddPairing( void MockPairingRegistryDelegate::Save(
const PairingRegistry::Pairing& new_paired_client, const std::string& pairings_json,
const PairingRegistry::AddPairingCallback& callback) { const PairingRegistry::SaveCallback& callback) {
paired_clients_[new_paired_client.client_id()] = new_paired_client; pairings_json_ = pairings_json;
if (!callback.is_null()) { if (!callback.is_null()) {
callback.Run(true); callback.Run(true);
} }
} }
void MockPairingRegistryDelegate::GetPairing( void MockPairingRegistryDelegate::Load(
const std::string& client_id, const PairingRegistry::LoadCallback& callback) {
const PairingRegistry::GetPairingCallback& callback) { load_callback_ = base::Bind(base::Bind(callback), pairings_json_);
PairingRegistry::Pairing result;
PairingRegistry::PairedClients::const_iterator i =
paired_clients_.find(client_id);
if (i != paired_clients_.end()) {
result = i->second;
}
saved_callback_ = base::Bind(base::Bind(callback), result);
} }
void MockPairingRegistryDelegate::RunCallback() { void MockPairingRegistryDelegate::RunCallback() {
DCHECK(!saved_callback_.is_null()); DCHECK(!load_callback_.is_null());
saved_callback_.Run(); load_callback_.Run();
saved_callback_.Reset(); load_callback_.Reset();
} }
} // namespace protocol } // namespace protocol
......
...@@ -211,23 +211,22 @@ class MockPairingRegistryDelegate : public PairingRegistry::Delegate { ...@@ -211,23 +211,22 @@ class MockPairingRegistryDelegate : public PairingRegistry::Delegate {
MockPairingRegistryDelegate(); MockPairingRegistryDelegate();
virtual ~MockPairingRegistryDelegate(); virtual ~MockPairingRegistryDelegate();
const PairingRegistry::PairedClients& paired_clients() const { const std::string& pairings_json() const {
return paired_clients_; return pairings_json_;
} }
// PairingRegistry::Delegate implementation. // PairingRegistry::Delegate implementation.
virtual void AddPairing( virtual void Save(
const PairingRegistry::Pairing& new_paired_client, const std::string& pairings_json,
const PairingRegistry::AddPairingCallback& callback) OVERRIDE; const PairingRegistry::SaveCallback& callback) OVERRIDE;
virtual void GetPairing( virtual void Load(
const std::string& client_id, const PairingRegistry::LoadCallback& callback) OVERRIDE;
const PairingRegistry::GetPairingCallback& callback) OVERRIDE;
void RunCallback(); void RunCallback();
private: private:
base::Closure saved_callback_; base::Closure load_callback_;
PairingRegistry::PairedClients paired_clients_; std::string pairings_json_;
}; };
} // namespace protocol } // namespace protocol
......
...@@ -413,6 +413,11 @@ ...@@ -413,6 +413,11 @@
'host/me2me_desktop_environment.h', 'host/me2me_desktop_environment.h',
'host/mouse_clamping_filter.cc', 'host/mouse_clamping_filter.cc',
'host/mouse_clamping_filter.h', 'host/mouse_clamping_filter.h',
'host/pairing_registry_delegate.h',
'host/pairing_registry_delegate_linux.cc',
'host/pairing_registry_delegate_linux.h',
'host/pairing_registry_delegate_mac.cc',
'host/pairing_registry_delegate_win.cc',
'host/pam_authorization_factory_posix.cc', 'host/pam_authorization_factory_posix.cc',
'host/pam_authorization_factory_posix.h', 'host/pam_authorization_factory_posix.h',
'host/pin_hash.cc', 'host/pin_hash.cc',
...@@ -2647,6 +2652,7 @@ ...@@ -2647,6 +2652,7 @@
'host/linux/x_server_clipboard_unittest.cc', 'host/linux/x_server_clipboard_unittest.cc',
'host/local_input_monitor_unittest.cc', 'host/local_input_monitor_unittest.cc',
'host/log_to_server_unittest.cc', 'host/log_to_server_unittest.cc',
'host/pairing_registry_delegate_linux_unittest.cc',
'host/pin_hash_unittest.cc', 'host/pin_hash_unittest.cc',
'host/policy_hack/fake_policy_watcher.cc', 'host/policy_hack/fake_policy_watcher.cc',
'host/policy_hack/fake_policy_watcher.h', 'host/policy_hack/fake_policy_watcher.h',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment