summaryrefslogtreecommitdiffstats
path: root/remoting/host/security_key
diff options
context:
space:
mode:
authorjoedow <joedow@chromium.org>2016-03-14 13:12:43 -0700
committerCommit bot <commit-bot@chromium.org>2016-03-14 20:14:08 +0000
commit99d59d48f1f9c205388657ba465bac11b8f9d747 (patch)
tree7f2fc6c8052b3c7c795e2151a2a3fd2cdd3bec71 /remoting/host/security_key
parentce3c4cbf6353f9953cc71edfc9f5e49ea4ecd248 (diff)
downloadchromium_src-99d59d48f1f9c205388657ba465bac11b8f9d747.zip
chromium_src-99d59d48f1f9c205388657ba465bac11b8f9d747.tar.gz
chromium_src-99d59d48f1f9c205388657ba465bac11b8f9d747.tar.bz2
Implementing RemoteSecurityKeyIpcServer class and tests.
This change introduces the IPC Server class used to communicate with the remote_security_key process for SK forwarding. It also includes unit tests and some facilities that will be used in the subsequent change which will implement the GnubbyAuthHandlerWin class. BUG=584463 Review URL: https://codereview.chromium.org/1757873003 Cr-Commit-Position: refs/heads/master@{#381054}
Diffstat (limited to 'remoting/host/security_key')
-rw-r--r--remoting/host/security_key/fake_remote_security_key_ipc_client.cc94
-rw-r--r--remoting/host/security_key/fake_remote_security_key_ipc_client.h70
-rw-r--r--remoting/host/security_key/gnubby_auth_handler.h6
-rw-r--r--remoting/host/security_key/gnubby_auth_handler_linux.cc6
-rw-r--r--remoting/host/security_key/gnubby_extension_session_unittest.cc2
-rw-r--r--remoting/host/security_key/gnubby_socket.cc2
-rw-r--r--remoting/host/security_key/gnubby_socket.h2
-rw-r--r--remoting/host/security_key/remote_security_key_ipc_server.cc50
-rw-r--r--remoting/host/security_key/remote_security_key_ipc_server.h58
-rw-r--r--remoting/host/security_key/remote_security_key_ipc_server_impl.cc130
-rw-r--r--remoting/host/security_key/remote_security_key_ipc_server_impl.h87
-rw-r--r--remoting/host/security_key/remote_security_key_ipc_server_unittest.cc297
12 files changed, 795 insertions, 9 deletions
diff --git a/remoting/host/security_key/fake_remote_security_key_ipc_client.cc b/remoting/host/security_key/fake_remote_security_key_ipc_client.cc
new file mode 100644
index 0000000..ba5219f
--- /dev/null
+++ b/remoting/host/security_key/fake_remote_security_key_ipc_client.cc
@@ -0,0 +1,94 @@
+// Copyright 2016 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/security_key/fake_remote_security_key_ipc_client.h"
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
+#include "ipc/ipc_channel.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_macros.h"
+#include "remoting/host/chromoting_messages.h"
+#include "remoting/host/security_key/gnubby_auth_handler.h"
+
+namespace remoting {
+
+FakeRemoteSecurityKeyIpcClient::FakeRemoteSecurityKeyIpcClient(
+ base::Closure channel_event_callback)
+ : channel_event_callback_(channel_event_callback) {
+ DCHECK(!channel_event_callback_.is_null());
+}
+
+FakeRemoteSecurityKeyIpcClient::~FakeRemoteSecurityKeyIpcClient() {}
+
+bool FakeRemoteSecurityKeyIpcClient::Connect(const std::string& channel_name) {
+ // The retry loop is needed as the IPC Servers we connect to are reset (torn
+ // down and recreated) in some tests and we should be resilient in that case.
+ IPC::ChannelHandle channel_handle(channel_name);
+ for (int i = 0; i < 5; i++) {
+ client_channel_ = IPC::Channel::CreateClient(channel_handle, this);
+ if (client_channel_->Connect()) {
+ return true;
+ }
+
+ base::RunLoop run_loop;
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(),
+ base::TimeDelta::FromMilliseconds(100));
+ run_loop.Run();
+ }
+
+ return false;
+}
+
+void FakeRemoteSecurityKeyIpcClient::CloseChannel() {
+ client_channel_.reset();
+ channel_event_callback_.Run();
+}
+
+void FakeRemoteSecurityKeyIpcClient::SendRequest(
+ const std::string& request_payload) {
+ client_channel_->Send(
+ new ChromotingRemoteSecurityKeyToNetworkMsg_Request(request_payload));
+}
+
+bool FakeRemoteSecurityKeyIpcClient::OnMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(FakeRemoteSecurityKeyIpcClient, message)
+ IPC_MESSAGE_HANDLER(
+ ChromotingNetworkToRemoteSecurityKeyMsg_ConnectionDetails,
+ OnConnectionDetails)
+ IPC_MESSAGE_HANDLER(ChromotingNetworkToRemoteSecurityKeyMsg_Response,
+ OnSecurityKeyResponse)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ CHECK(handled) << "Received unexpected IPC type: " << message.type();
+ return handled;
+}
+
+void FakeRemoteSecurityKeyIpcClient::OnChannelConnected(int32_t peer_pid) {
+ channel_event_callback_.Run();
+}
+
+void FakeRemoteSecurityKeyIpcClient::OnChannelError() {
+ channel_event_callback_.Run();
+}
+
+void FakeRemoteSecurityKeyIpcClient::OnConnectionDetails(
+ const std::string& channel_name) {
+ last_message_received_ = channel_name;
+ channel_event_callback_.Run();
+}
+
+void FakeRemoteSecurityKeyIpcClient::OnSecurityKeyResponse(
+ const std::string& request_data) {
+ last_message_received_ = request_data;
+ channel_event_callback_.Run();
+}
+
+} // namespace remoting
diff --git a/remoting/host/security_key/fake_remote_security_key_ipc_client.h b/remoting/host/security_key/fake_remote_security_key_ipc_client.h
new file mode 100644
index 0000000..24305ea
--- /dev/null
+++ b/remoting/host/security_key/fake_remote_security_key_ipc_client.h
@@ -0,0 +1,70 @@
+// Copyright 2016 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_SECURITY_KEY_FAKE_SECURITY_KEY_IPC_CLIENT_H_
+#define REMOTING_HOST_SECURITY_KEY_FAKE_SECURITY_KEY_IPC_CLIENT_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "ipc/ipc_listener.h"
+
+namespace IPC {
+class Channel;
+class Message;
+}
+
+namespace remoting {
+
+// Simulates the RemoteSecurityKeyIpcClient and provides access to data members
+// for testing.
+class FakeRemoteSecurityKeyIpcClient : public IPC::Listener {
+ public:
+ explicit FakeRemoteSecurityKeyIpcClient(base::Closure channel_event_callback);
+ ~FakeRemoteSecurityKeyIpcClient() override;
+
+ // Connects as a client to the |channel_name| IPC Channel.
+ bool Connect(const std::string& channel_name);
+
+ // Closes the |client_channel_| IPC channel.
+ void CloseChannel();
+
+ // Sends a security key request message via IPC through |client_channel_|.
+ void SendRequest(const std::string& request_data);
+
+ // Provides access to |last_message_received_| for testing.
+ const std::string& last_message_received() const {
+ return last_message_received_;
+ }
+
+ private:
+ // IPC::Listener implementation.
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OnChannelConnected(int32_t peer_pid) override;
+ void OnChannelError() override;
+
+ // Handles the initial IPC message used to establish a side channel with this
+ // IPC Client instance.
+ void OnConnectionDetails(const std::string& request_data);
+
+ // Handles security key response IPC messages.
+ void OnSecurityKeyResponse(const std::string& request_data);
+
+ // Called when a change in the IPC channel state has occurred.
+ base::Closure channel_event_callback_;
+
+ // Used for sending/receiving security key messages between processes.
+ scoped_ptr<IPC::Channel> client_channel_;
+
+ // Provides the contents of the last IPC message received.
+ std::string last_message_received_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeRemoteSecurityKeyIpcClient);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_HOST_SECURITY_KEY_FAKE_SECURITY_KEY_IPC_CLIENT_H_ \ No newline at end of file
diff --git a/remoting/host/security_key/gnubby_auth_handler.h b/remoting/host/security_key/gnubby_auth_handler.h
index 4c7ed25..fe6dff0 100644
--- a/remoting/host/security_key/gnubby_auth_handler.h
+++ b/remoting/host/security_key/gnubby_auth_handler.h
@@ -7,12 +7,12 @@
#include <string>
-#include "base/callback_forward.h"
+#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
namespace base {
class FilePath;
-class TimeDelta;
} // namespace base
namespace remoting {
@@ -59,7 +59,7 @@ class GnubbyAuthHandler {
virtual size_t GetActiveConnectionCountForTest() const = 0;
// Sets the timeout used when waiting for a gnubby response.
- virtual void SetRequestTimeoutForTest(const base::TimeDelta& timeout) = 0;
+ virtual void SetRequestTimeoutForTest(base::TimeDelta timeout) = 0;
};
} // namespace remoting
diff --git a/remoting/host/security_key/gnubby_auth_handler_linux.cc b/remoting/host/security_key/gnubby_auth_handler_linux.cc
index f036434..fdde958 100644
--- a/remoting/host/security_key/gnubby_auth_handler_linux.cc
+++ b/remoting/host/security_key/gnubby_auth_handler_linux.cc
@@ -1,6 +1,7 @@
// Copyright 2016 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 <stdint.h>
#include <unistd.h>
@@ -64,7 +65,7 @@ class GnubbyAuthHandlerLinux : public GnubbyAuthHandler {
void SendErrorAndCloseConnection(int gnubby_connection_id) override;
void SetSendMessageCallback(const SendMessageCallback& callback) override;
size_t GetActiveConnectionCountForTest() const override;
- void SetRequestTimeoutForTest(const base::TimeDelta& timeout) override;
+ void SetRequestTimeoutForTest(base::TimeDelta timeout) override;
// Starts listening for connection.
void DoAccept();
@@ -200,8 +201,7 @@ size_t GnubbyAuthHandlerLinux::GetActiveConnectionCountForTest() const {
return active_sockets_.size();
}
-void GnubbyAuthHandlerLinux::SetRequestTimeoutForTest(
- const base::TimeDelta& timeout) {
+void GnubbyAuthHandlerLinux::SetRequestTimeoutForTest(base::TimeDelta timeout) {
request_timeout_ = timeout;
}
diff --git a/remoting/host/security_key/gnubby_extension_session_unittest.cc b/remoting/host/security_key/gnubby_extension_session_unittest.cc
index f763670..ceb76e1 100644
--- a/remoting/host/security_key/gnubby_extension_session_unittest.cc
+++ b/remoting/host/security_key/gnubby_extension_session_unittest.cc
@@ -71,7 +71,7 @@ class TestClientStub : public protocol::ClientStub {
// protocol::CursorShapeStub implementation.
void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape) override {}
- void WaitForDeliverHostMessage(const base::TimeDelta& max_timeout) {
+ void WaitForDeliverHostMessage(base::TimeDelta max_timeout) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, run_loop_->QuitClosure(), max_timeout);
run_loop_->Run();
diff --git a/remoting/host/security_key/gnubby_socket.cc b/remoting/host/security_key/gnubby_socket.cc
index 0a24688..371a352 100644
--- a/remoting/host/security_key/gnubby_socket.cc
+++ b/remoting/host/security_key/gnubby_socket.cc
@@ -27,7 +27,7 @@ const char kSshError[] = {0x05};
} // namespace
GnubbySocket::GnubbySocket(scoped_ptr<net::StreamSocket> socket,
- const base::TimeDelta& timeout,
+ base::TimeDelta timeout,
const base::Closure& timeout_callback)
: socket_(std::move(socket)),
read_completed_(false),
diff --git a/remoting/host/security_key/gnubby_socket.h b/remoting/host/security_key/gnubby_socket.h
index 39d5d05..f56bf33 100644
--- a/remoting/host/security_key/gnubby_socket.h
+++ b/remoting/host/security_key/gnubby_socket.h
@@ -34,7 +34,7 @@ namespace remoting {
class GnubbySocket {
public:
GnubbySocket(scoped_ptr<net::StreamSocket> socket,
- const base::TimeDelta& timeout,
+ base::TimeDelta timeout,
const base::Closure& timeout_callback);
~GnubbySocket();
diff --git a/remoting/host/security_key/remote_security_key_ipc_server.cc b/remoting/host/security_key/remote_security_key_ipc_server.cc
new file mode 100644
index 0000000..62d54c8
--- /dev/null
+++ b/remoting/host/security_key/remote_security_key_ipc_server.cc
@@ -0,0 +1,50 @@
+// Copyright 2016 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/security_key/remote_security_key_ipc_server.h"
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/timer/timer.h"
+#include "ipc/ipc_channel.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_macros.h"
+#include "remoting/base/logging.h"
+#include "remoting/host/chromoting_messages.h"
+#include "remoting/host/security_key/remote_security_key_ipc_server_impl.h"
+
+namespace {
+
+// Not thread safe, tests which set this value must do so on the same thread.
+static remoting::RemoteSecurityKeyIpcServerFactory* g_factory = nullptr;
+
+} // namespace
+
+namespace remoting {
+
+void RemoteSecurityKeyIpcServer::SetFactoryForTest(
+ RemoteSecurityKeyIpcServerFactory* factory) {
+ g_factory = factory;
+}
+
+scoped_ptr<RemoteSecurityKeyIpcServer> RemoteSecurityKeyIpcServer::Create(
+ int connection_id,
+ base::TimeDelta initial_connect_timeout,
+ const GnubbyAuthHandler::SendMessageCallback& message_callback,
+ const base::Closure& done_callback) {
+ scoped_ptr<RemoteSecurityKeyIpcServer> ipc_server =
+ g_factory
+ ? g_factory->Create(connection_id, initial_connect_timeout,
+ message_callback, done_callback)
+ : make_scoped_ptr(new RemoteSecurityKeyIpcServerImpl(
+ connection_id, initial_connect_timeout, message_callback,
+ done_callback));
+
+ return ipc_server;
+}
+
+} // namespace remoting
diff --git a/remoting/host/security_key/remote_security_key_ipc_server.h b/remoting/host/security_key/remote_security_key_ipc_server.h
new file mode 100644
index 0000000..cd85541
--- /dev/null
+++ b/remoting/host/security_key/remote_security_key_ipc_server.h
@@ -0,0 +1,58 @@
+// Copyright 2016 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_SECURITY_KEY_REMOTE_SECURITY_KEY_IPC_SERVER_H_
+#define REMOTING_HOST_SECURITY_KEY_REMOTE_SECURITY_KEY_IPC_SERVER_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "remoting/host/security_key/gnubby_auth_handler.h"
+
+namespace remoting {
+
+class RemoteSecurityKeyIpcServerFactory;
+
+// Responsible for handing the server end of the IPC channel between the
+// network process (server) and the remote_security_key process (client).
+class RemoteSecurityKeyIpcServer {
+ public:
+ virtual ~RemoteSecurityKeyIpcServer() {}
+
+ // Creates a new RemoteSecurityKeyIpcServer instance.
+ static scoped_ptr<RemoteSecurityKeyIpcServer> Create(
+ int connection_id,
+ base::TimeDelta initial_connect_timeout,
+ const GnubbyAuthHandler::SendMessageCallback& message_callback,
+ const base::Closure& done_callback);
+
+ // Used to set a Factory to generate fake/mock RemoteSecurityKeyIpcServer
+ // instances for testing.
+ static void SetFactoryForTest(RemoteSecurityKeyIpcServerFactory* factory);
+
+ // Creates and starts listening on an IPC channel with the given name.
+ virtual bool CreateChannel(const std::string& channel_name,
+ base::TimeDelta request_timeout) = 0;
+
+ // Sends a security key response IPC message via the IPC channel.
+ virtual bool SendResponse(const std::string& message_data) = 0;
+};
+
+// Used to allow for creating Fake/Mock RemoteSecurityKeyIpcServer for testing.
+class RemoteSecurityKeyIpcServerFactory {
+ public:
+ virtual ~RemoteSecurityKeyIpcServerFactory() {}
+
+ virtual scoped_ptr<RemoteSecurityKeyIpcServer> Create(
+ int connection_id,
+ base::TimeDelta connect_timeout,
+ const GnubbyAuthHandler::SendMessageCallback& message_callback,
+ const base::Closure& done_callback) = 0;
+};
+
+} // namespace remoting
+
+#endif // REMOTING_HOST_SECURITY_KEY_REMOTE_SECURITY_KEY_IPC_SERVER_H_
diff --git a/remoting/host/security_key/remote_security_key_ipc_server_impl.cc b/remoting/host/security_key/remote_security_key_ipc_server_impl.cc
new file mode 100644
index 0000000..3d9aaff
--- /dev/null
+++ b/remoting/host/security_key/remote_security_key_ipc_server_impl.cc
@@ -0,0 +1,130 @@
+// Copyright 2016 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/security_key/remote_security_key_ipc_server_impl.h"
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/timer/timer.h"
+#include "ipc/ipc_channel.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_macros.h"
+#include "remoting/base/logging.h"
+#include "remoting/host/chromoting_messages.h"
+
+namespace {
+
+// Returns the command code (the first byte of the data) if it exists, or -1 if
+// the data is empty.
+unsigned int GetCommandCode(const std::string& data) {
+ return data.empty() ? -1 : static_cast<unsigned int>(data[0]);
+}
+
+} // namespace
+
+namespace remoting {
+
+RemoteSecurityKeyIpcServerImpl::RemoteSecurityKeyIpcServerImpl(
+ int connection_id,
+ base::TimeDelta initial_connect_timeout,
+ const GnubbyAuthHandler::SendMessageCallback& message_callback,
+ const base::Closure& done_callback)
+ : connection_id_(connection_id),
+ initial_connect_timeout_(initial_connect_timeout),
+ done_callback_(done_callback),
+ message_callback_(message_callback) {
+ DCHECK_GT(connection_id_, 0);
+ DCHECK(!done_callback_.is_null());
+ DCHECK(!message_callback_.is_null());
+}
+
+RemoteSecurityKeyIpcServerImpl::~RemoteSecurityKeyIpcServerImpl() {}
+
+bool RemoteSecurityKeyIpcServerImpl::CreateChannel(
+ const std::string& channel_name,
+ base::TimeDelta request_timeout) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!ipc_channel_);
+ security_key_request_timeout_ = request_timeout;
+
+ ipc_channel_ =
+ IPC::Channel::CreateServer(IPC::ChannelHandle(channel_name), this);
+ if (!ipc_channel_->Connect()) {
+ ipc_channel_.reset();
+ return false;
+ }
+
+ // It is safe to use base::Unretained here as |timer_| will be stopped and
+ // this task will be removed when this instance is being destroyed. All
+ // methods must execute on the same thread (due to |thread_Checker_| so
+ // the posted task and D'Tor can not execute concurrently.
+ timer_.Start(FROM_HERE, initial_connect_timeout_,
+ base::Bind(&RemoteSecurityKeyIpcServerImpl::OnChannelError,
+ base::Unretained(this)));
+ return true;
+}
+
+bool RemoteSecurityKeyIpcServerImpl::SendResponse(const std::string& response) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // Since we have received a response, we update the timer and wait
+ // for a subsequent request.
+ timer_.Start(FROM_HERE, initial_connect_timeout_,
+ base::Bind(&RemoteSecurityKeyIpcServerImpl::OnChannelError,
+ base::Unretained(this)));
+
+ return ipc_channel_->Send(
+ new ChromotingNetworkToRemoteSecurityKeyMsg_Response(response));
+}
+
+bool RemoteSecurityKeyIpcServerImpl::OnMessageReceived(
+ const IPC::Message& message) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(RemoteSecurityKeyIpcServerImpl, message)
+ IPC_MESSAGE_HANDLER(ChromotingRemoteSecurityKeyToNetworkMsg_Request,
+ OnSecurityKeyRequest)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ CHECK(handled) << "Received unexpected IPC type: " << message.type();
+ return handled;
+}
+
+void RemoteSecurityKeyIpcServerImpl::OnChannelConnected(int32_t peer_pid) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // Reset the timer to give the client a chance to send the request.
+ timer_.Start(FROM_HERE, initial_connect_timeout_,
+ base::Bind(&RemoteSecurityKeyIpcServerImpl::OnChannelError,
+ base::Unretained(this)));
+}
+
+void RemoteSecurityKeyIpcServerImpl::OnChannelError() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!done_callback_.is_null()) {
+ // Note: This callback may result in this object being torn down.
+ base::ResetAndReturn(&done_callback_).Run();
+ }
+}
+
+void RemoteSecurityKeyIpcServerImpl::OnSecurityKeyRequest(
+ const std::string& request_data) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // Reset the timer to give the client a chance to send the response.
+ timer_.Start(FROM_HERE, security_key_request_timeout_,
+ base::Bind(&RemoteSecurityKeyIpcServerImpl::OnChannelError,
+ base::Unretained(this)));
+
+ HOST_LOG << "Received gnubby request: " << GetCommandCode(request_data);
+ message_callback_.Run(connection_id_, request_data);
+}
+
+} // namespace remoting
diff --git a/remoting/host/security_key/remote_security_key_ipc_server_impl.h b/remoting/host/security_key/remote_security_key_ipc_server_impl.h
new file mode 100644
index 0000000..6810114
--- /dev/null
+++ b/remoting/host/security_key/remote_security_key_ipc_server_impl.h
@@ -0,0 +1,87 @@
+// Copyright 2016 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_SECURITY_KEY_REMOTE_SECURITY_KEY_IPC_SERVER_IMPL_H_
+#define REMOTING_HOST_SECURITY_KEY_REMOTE_SECURITY_KEY_IPC_SERVER_IMPL_H_
+
+#include "remoting/host/security_key/remote_security_key_ipc_server.h"
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "ipc/ipc_listener.h"
+
+namespace base {
+class TimeDelta;
+} // base
+
+namespace IPC {
+class Channel;
+class Message;
+} // IPC
+
+namespace remoting {
+
+// Responsible for handing the server end of the IPC channel between the
+// the network process and the local remote_security_key process.
+class RemoteSecurityKeyIpcServerImpl : public RemoteSecurityKeyIpcServer,
+ public IPC::Listener {
+ public:
+ RemoteSecurityKeyIpcServerImpl(
+ int connection_id,
+ base::TimeDelta initial_connect_timeout,
+ const GnubbyAuthHandler::SendMessageCallback& message_callback,
+ const base::Closure& done_callback);
+ ~RemoteSecurityKeyIpcServerImpl() override;
+
+ // RemoteSecurityKeyIpcServer implementation.
+ bool CreateChannel(const std::string& channel_name,
+ base::TimeDelta request_timeout) override;
+ bool SendResponse(const std::string& message_data) override;
+
+ private:
+ // IPC::Listener implementation.
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OnChannelConnected(int32_t peer_pid) override;
+ void OnChannelError() override;
+
+ // Handles security key resquest IPC messages.
+ void OnSecurityKeyRequest(const std::string& request);
+
+ // The value assigned to identify the current IPC channel.
+ int connection_id_;
+
+ // Timeout for disconnecting the IPC channel if there is no client activity.
+ base::TimeDelta initial_connect_timeout_;
+
+ // Timeout for disconnecting the IPC channel if there is no response from
+ // the remote client after a security key request.
+ base::TimeDelta security_key_request_timeout_;
+
+ // Used to detect timeouts and disconnect the IPC channel.
+ base::OneShotTimer timer_;
+
+ // Used to signal that the IPC channel should be disconnected.
+ base::Closure done_callback_;
+
+ // Used to pass a security key request on to the remote client.
+ GnubbyAuthHandler::SendMessageCallback message_callback_;
+
+ // Used for sending/receiving security key messages between processes.
+ scoped_ptr<IPC::Channel> ipc_channel_;
+
+ // Ensures RemoteSecurityKeyIpcServerImpl methods are called on the same
+ // thread.
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteSecurityKeyIpcServerImpl);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_HOST_SECURITY_KEY_REMOTE_SECURITY_KEY_IPC_SERVER_IMPL_H_ \ No newline at end of file
diff --git a/remoting/host/security_key/remote_security_key_ipc_server_unittest.cc b/remoting/host/security_key/remote_security_key_ipc_server_unittest.cc
new file mode 100644
index 0000000..8afd68d
--- /dev/null
+++ b/remoting/host/security_key/remote_security_key_ipc_server_unittest.cc
@@ -0,0 +1,297 @@
+// Copyright 2016 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/security_key/remote_security_key_ipc_server.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "ipc/ipc_channel.h"
+#include "remoting/host/security_key/fake_remote_security_key_ipc_client.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+const int kTestConnectionId = 42;
+const int kInitialConnectTimeoutMs = 250;
+const int kConnectionTimeoutErrorDeltaMs = 100;
+} // namespace
+
+namespace remoting {
+
+class RemoteSecurityKeyIpcServerTest : public testing::Test {
+ public:
+ RemoteSecurityKeyIpcServerTest();
+ ~RemoteSecurityKeyIpcServerTest() override;
+
+ // Passed to the object used for testing to be called back to signal
+ // completion of an IPC channel state change or reception of an IPC message.
+ void OperationComplete();
+
+ protected:
+ // Returns a unique IPC channel name which prevents conflicts when running
+ // tests concurrently.
+ std::string GetUniqueTestChannelName();
+
+ // Waits until the current |run_loop_| instance is signaled, then resets it.
+ void WaitForOperationComplete();
+
+ // Used as a callback to signal receipt of a security key request message.
+ void SendRequestToClient(int connection_id, const std::string& data);
+
+ // IPC tests require a valid MessageLoop to run.
+ base::MessageLoopForIO message_loop_;
+
+ // Used to allow |message_loop_| to run during tests. The instance is reset
+ // after each stage of the tests has been completed.
+ scoped_ptr<base::RunLoop> run_loop_;
+
+ // The object under test.
+ scoped_ptr<RemoteSecurityKeyIpcServer> remote_security_key_ipc_server_;
+
+ // Used to validate the object under test uses the correct ID when
+ // communicating over the IPC channel.
+ int last_connection_id_received_ = -1;
+
+ // Stores the contents of the last IPC message received for validation.
+ std::string last_message_received_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RemoteSecurityKeyIpcServerTest);
+};
+
+RemoteSecurityKeyIpcServerTest::RemoteSecurityKeyIpcServerTest()
+ : run_loop_(new base::RunLoop()) {
+ remote_security_key_ipc_server_ =
+ remoting::RemoteSecurityKeyIpcServer::Create(
+ kTestConnectionId,
+ base::TimeDelta::FromMilliseconds(kInitialConnectTimeoutMs),
+ base::Bind(&RemoteSecurityKeyIpcServerTest::SendRequestToClient,
+ base::Unretained(this)),
+ base::Bind(&RemoteSecurityKeyIpcServerTest::OperationComplete,
+ base::Unretained(this)));
+}
+
+RemoteSecurityKeyIpcServerTest::~RemoteSecurityKeyIpcServerTest() {}
+
+void RemoteSecurityKeyIpcServerTest::OperationComplete() {
+ run_loop_->Quit();
+}
+
+void RemoteSecurityKeyIpcServerTest::WaitForOperationComplete() {
+ run_loop_->Run();
+ run_loop_.reset(new base::RunLoop());
+}
+
+void RemoteSecurityKeyIpcServerTest::SendRequestToClient(
+ int connection_id,
+ const std::string& data) {
+ last_connection_id_received_ = connection_id;
+ last_message_received_ = data;
+ OperationComplete();
+}
+
+std::string RemoteSecurityKeyIpcServerTest::GetUniqueTestChannelName() {
+ std::string channel_name("Super_Awesome_Test_Channel.");
+ channel_name.append(IPC::Channel::GenerateUniqueRandomChannelID());
+
+ return channel_name;
+}
+
+TEST_F(RemoteSecurityKeyIpcServerTest, HandleSingleGnubbyRequest) {
+ std::string channel_name(GetUniqueTestChannelName());
+ ASSERT_TRUE(remote_security_key_ipc_server_->CreateChannel(
+ channel_name,
+ /*request_timeout=*/base::TimeDelta::FromMilliseconds(500)));
+
+ // Create a fake client and connect to the IPC server channel.
+ FakeRemoteSecurityKeyIpcClient fake_ipc_client(
+ base::Bind(&RemoteSecurityKeyIpcServerTest::OperationComplete,
+ base::Unretained(this)));
+ ASSERT_TRUE(fake_ipc_client.Connect(channel_name));
+ WaitForOperationComplete();
+
+ // Send a request from the IPC client to the IPC server.
+ std::string request_data("Blergh!");
+ fake_ipc_client.SendRequest(request_data);
+ WaitForOperationComplete();
+
+ // Verify the request was received.
+ ASSERT_EQ(kTestConnectionId, last_connection_id_received_);
+ ASSERT_EQ(request_data, last_message_received_);
+
+ // Send a response from the IPC server to the IPC client.
+ std::string response_data("Blargh!");
+ ASSERT_TRUE(remote_security_key_ipc_server_->SendResponse(response_data));
+ WaitForOperationComplete();
+
+ // Verify the request was received.
+ ASSERT_EQ(response_data, fake_ipc_client.last_message_received());
+
+ // Typically the client will be the one to close the connection.
+ fake_ipc_client.CloseChannel();
+}
+
+TEST_F(RemoteSecurityKeyIpcServerTest, HandleMultipleGnubbyRequests) {
+ std::string channel_name(GetUniqueTestChannelName());
+ ASSERT_TRUE(remote_security_key_ipc_server_->CreateChannel(
+ channel_name,
+ /*request_timeout=*/base::TimeDelta::FromMilliseconds(500)));
+
+ // Create a fake client and connect to the IPC server channel.
+ FakeRemoteSecurityKeyIpcClient fake_ipc_client(
+ base::Bind(&RemoteSecurityKeyIpcServerTest::OperationComplete,
+ base::Unretained(this)));
+ ASSERT_TRUE(fake_ipc_client.Connect(channel_name));
+ WaitForOperationComplete();
+
+ // Send a request from the IPC client to the IPC server.
+ std::string request_data_1("Blergh!");
+ fake_ipc_client.SendRequest(request_data_1);
+ WaitForOperationComplete();
+
+ // Verify the request was received.
+ ASSERT_EQ(kTestConnectionId, last_connection_id_received_);
+ ASSERT_EQ(request_data_1, last_message_received_);
+
+ // Send a response from the IPC server to the IPC client.
+ std::string response_data_1("Blargh!");
+ ASSERT_TRUE(remote_security_key_ipc_server_->SendResponse(response_data_1));
+ WaitForOperationComplete();
+
+ // Verify the response was received.
+ ASSERT_EQ(response_data_1, fake_ipc_client.last_message_received());
+
+ // Send a request from the IPC client to the IPC server.
+ std::string request_data_2("Bleh!");
+ fake_ipc_client.SendRequest(request_data_2);
+ WaitForOperationComplete();
+
+ // Verify the request was received.
+ ASSERT_EQ(kTestConnectionId, last_connection_id_received_);
+ ASSERT_EQ(request_data_2, last_message_received_);
+
+ // Send a response from the IPC server to the IPC client.
+ std::string response_data_2("Meh!");
+ ASSERT_TRUE(remote_security_key_ipc_server_->SendResponse(response_data_2));
+ WaitForOperationComplete();
+
+ // Verify the response was received.
+ ASSERT_EQ(response_data_2, fake_ipc_client.last_message_received());
+
+ // Typically the client will be the one to close the connection.
+ fake_ipc_client.CloseChannel();
+}
+
+TEST_F(RemoteSecurityKeyIpcServerTest, InitialIpcConnectionTimeout) {
+ // Create a channel, then wait for the done callback to be called indicating
+ // the connection was closed. This test simulates the IPC Server being
+ // created but the client failing to connect to it.
+ std::string channel_name(GetUniqueTestChannelName());
+ ASSERT_TRUE(remote_security_key_ipc_server_->CreateChannel(
+ channel_name,
+ /*request_timeout=*/base::TimeDelta::FromMilliseconds(500)));
+ base::Time start_time(base::Time::NowFromSystemTime());
+ WaitForOperationComplete();
+ base::TimeDelta elapsed_time = base::Time::NowFromSystemTime() - start_time;
+
+ ASSERT_NEAR(elapsed_time.InMilliseconds(), kInitialConnectTimeoutMs,
+ kConnectionTimeoutErrorDeltaMs);
+}
+
+TEST_F(RemoteSecurityKeyIpcServerTest, NoGnubbyRequestTimeout) {
+ // Create a channel and connect to it via IPC but do not send a request.
+ // The channel should be closed and cleaned up if the IPC client does not
+ // issue a request within the specified timeout period.
+ std::string channel_name(GetUniqueTestChannelName());
+ ASSERT_TRUE(remote_security_key_ipc_server_->CreateChannel(
+ channel_name,
+ /*request_timeout=*/base::TimeDelta::FromMilliseconds(500)));
+
+ // Create a fake client and connect to the IPC server channel.
+ FakeRemoteSecurityKeyIpcClient fake_ipc_client(
+ base::Bind(&RemoteSecurityKeyIpcServerTest::OperationComplete,
+ base::Unretained(this)));
+ ASSERT_TRUE(fake_ipc_client.Connect(channel_name));
+ WaitForOperationComplete();
+
+ // Now that a connection has been established, we wait for the timeout.
+ base::Time start_time(base::Time::NowFromSystemTime());
+ WaitForOperationComplete();
+ base::TimeDelta elapsed_time = base::Time::NowFromSystemTime() - start_time;
+
+ ASSERT_NEAR(elapsed_time.InMilliseconds(), kInitialConnectTimeoutMs,
+ kConnectionTimeoutErrorDeltaMs);
+}
+
+TEST_F(RemoteSecurityKeyIpcServerTest, GnubbyResponseTimeout) {
+ // Create a channel, connect to it via IPC, and issue a request, but do
+ // not send a response. This simulates a client-side timeout.
+ base::TimeDelta request_timeout(base::TimeDelta::FromMilliseconds(50));
+ std::string channel_name(GetUniqueTestChannelName());
+ ASSERT_TRUE(remote_security_key_ipc_server_->CreateChannel(channel_name,
+ request_timeout));
+
+ // Create a fake client and connect to the IPC server channel.
+ FakeRemoteSecurityKeyIpcClient fake_ipc_client(
+ base::Bind(&RemoteSecurityKeyIpcServerTest::OperationComplete,
+ base::Unretained(this)));
+ ASSERT_TRUE(fake_ipc_client.Connect(channel_name));
+ WaitForOperationComplete();
+
+ // Now that a connection has been established, we issue a request and
+ // then wait for the timeout.
+ std::string request_data("I can haz Auth?");
+ fake_ipc_client.SendRequest(request_data);
+ WaitForOperationComplete();
+
+ // Leave the request hanging until it times out...
+ base::Time start_time(base::Time::NowFromSystemTime());
+ WaitForOperationComplete();
+ base::TimeDelta elapsed_time = base::Time::NowFromSystemTime() - start_time;
+
+ ASSERT_NEAR(elapsed_time.InMilliseconds(), request_timeout.InMilliseconds(),
+ kConnectionTimeoutErrorDeltaMs);
+}
+
+TEST_F(RemoteSecurityKeyIpcServerTest, SendResponseTimeout) {
+ // Create a channel, connect to it via IPC, issue a request, and send
+ // a response, but do not close the channel after that. The connection
+ // should be terminated after the initial timeout period has elapsed.
+ std::string channel_name(GetUniqueTestChannelName());
+ ASSERT_TRUE(remote_security_key_ipc_server_->CreateChannel(
+ channel_name,
+ /*request_timeout=*/base::TimeDelta::FromMilliseconds(500)));
+
+ // Create a fake client and connect to the IPC server channel.
+ FakeRemoteSecurityKeyIpcClient fake_ipc_client(
+ base::Bind(&RemoteSecurityKeyIpcServerTest::OperationComplete,
+ base::Unretained(this)));
+ ASSERT_TRUE(fake_ipc_client.Connect(channel_name));
+ WaitForOperationComplete();
+
+ // Issue a request.
+ std::string request_data("Auth me yo!");
+ fake_ipc_client.SendRequest(request_data);
+ WaitForOperationComplete();
+
+ // Send a response from the IPC server to the IPC client.
+ std::string response_data("OK, the secret code is 1-2-3-4-5");
+ ASSERT_TRUE(remote_security_key_ipc_server_->SendResponse(response_data));
+ WaitForOperationComplete();
+
+ // Now wait for the timeout period for the connection to be torn down.
+ base::Time start_time(base::Time::NowFromSystemTime());
+ WaitForOperationComplete();
+ base::TimeDelta elapsed_time = base::Time::NowFromSystemTime() - start_time;
+
+ ASSERT_NEAR(elapsed_time.InMilliseconds(), kInitialConnectTimeoutMs,
+ kConnectionTimeoutErrorDeltaMs);
+}
+
+} // namespace remoting