1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "remoting/host/security_key/security_key_ipc_client.h"
6 
7 #include <memory>
8 #include <string>
9 
10 #include "base/bind.h"
11 #include "base/macros.h"
12 #include "base/run_loop.h"
13 #include "base/test/task_environment.h"
14 #include "build/build_config.h"
15 #include "ipc/ipc_channel.h"
16 #include "mojo/public/cpp/platform/named_platform_channel.h"
17 #include "remoting/host/security_key/fake_security_key_ipc_server.h"
18 #include "remoting/host/security_key/security_key_ipc_constants.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 
21 #if defined(OS_WIN)
22 #include <windows.h>
23 #endif
24 
25 namespace {
26 const int kTestConnectionId = 1;
27 const char kNonexistentIpcChannelName[] = "Nonexistent_IPC_Channel";
28 const char kValidIpcChannelName[] = "SecurityKeyIpcClientTest";
29 const int kLargeMessageSizeBytes = 256 * 1024;
30 }  // namespace
31 
32 namespace remoting {
33 
34 class SecurityKeyIpcClientTest : public testing::Test {
35  public:
36   SecurityKeyIpcClientTest();
37   ~SecurityKeyIpcClientTest() override;
38 
39   // Passed to the object used for testing to be called back to signal
40   // completion of an IPC channel state change or reception of an IPC message.
41   void OperationComplete(bool failed);
42 
43   // Callback used to signal when the IPC channel is ready for messages.
44   void ConnectionStateHandler(bool established);
45 
46   // Callback used to drive the |fake_ipc_server_| connection behavior.
47   void SendConnectionMessage();
48 
49   // Used as a callback given to the object under test, expected to be called
50   // back when a security key request is received by it.
51   void SendMessageToClient(int connection_id, const std::string& data);
52 
53   // Used as a callback given to the object under test, expected to be called
54   // back when a security key response is sent.
55   void ClientMessageReceived(const std::string& response_payload);
56 
57  protected:
58   // testing::Test interface.
59   void SetUp() override;
60 
61   // Waits until the current |run_loop_| instance is signaled, then resets it.
62   void WaitForOperationComplete();
63 
64   // Waits until all tasks have been run on the current message loop.
65   void RunPendingTasks();
66 
67   // Sets up an active IPC connection between |security_key_ipc_client_|
68   // and |fake_ipc_server_|.  |expect_connected| defines whether the operation
69   // is result in a usable IPC connection.  |expect_error| defines whether the
70   // the error callback should be invoked during the connection process.
71   void EstablishConnection(bool expect_connected, bool expect_error);
72 
73   // Sends a security key request from |security_key_ipc_client_| and
74   // a response from |fake_ipc_server_| and verifies the payloads for both.
75   void SendRequestAndResponse(const std::string& request_data,
76                               const std::string& response_data);
77 
78   // Creates a unique IPC channel name to use for testing.
79   mojo::NamedPlatformChannel::ServerName GenerateUniqueTestChannelName();
80 
81   // IPC tests require a valid MessageLoop to run.
82   base::test::SingleThreadTaskEnvironment task_environment_{
83       base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
84 
85   // Used to allow |message_loop_| to run during tests.  The instance is reset
86   // after each stage of the tests has been completed.
87   std::unique_ptr<base::RunLoop> run_loop_;
88 
89   // The object under test.
90   SecurityKeyIpcClient security_key_ipc_client_;
91 
92   // Used to send/receive security key IPC messages for testing.
93   FakeSecurityKeyIpcServer fake_ipc_server_;
94 
95   // Stores the current session ID on supported platforms.
96   uint32_t session_id_ = 0;
97 
98   // Tracks the success/failure of the last async operation.
99   bool operation_failed_ = false;
100 
101   // Tracks whether the IPC channel connection has been established.
102   bool connection_established_ = false;
103 
104   // Used to drive invalid session behavior for testing the client.
105   bool simulate_invalid_session_ = false;
106 
107   // Used to validate the object under test uses the correct ID when
108   // communicating over the IPC channel.
109   int last_connection_id_received_ = -1;
110 
111   // Stores the contents of the last IPC message received for validation.
112   std::string last_message_received_;
113 
114  private:
115   DISALLOW_COPY_AND_ASSIGN(SecurityKeyIpcClientTest);
116 };
117 
SecurityKeyIpcClientTest()118 SecurityKeyIpcClientTest::SecurityKeyIpcClientTest()
119     : run_loop_(new base::RunLoop()),
120       fake_ipc_server_(
121           kTestConnectionId,
122           /*client_session_details=*/nullptr,
123           /*initial_connect_timeout=*/base::TimeDelta::FromMilliseconds(500),
124           base::BindRepeating(&SecurityKeyIpcClientTest::SendMessageToClient,
125                               base::Unretained(this)),
126           base::BindOnce(&SecurityKeyIpcClientTest::SendConnectionMessage,
127                          base::Unretained(this)),
128           base::BindOnce(&SecurityKeyIpcClientTest::OperationComplete,
129                          base::Unretained(this),
130                          /*failed=*/false)) {}
131 
132 SecurityKeyIpcClientTest::~SecurityKeyIpcClientTest() = default;
133 
SetUp()134 void SecurityKeyIpcClientTest::SetUp() {
135 #if defined(OS_WIN)
136   DWORD session_id = 0;
137   // If we are on Windows, then we need to set the correct session ID or the
138   // IPC connection will not be created successfully.
139   ASSERT_TRUE(ProcessIdToSessionId(GetCurrentProcessId(), &session_id));
140   session_id_ = session_id;
141   security_key_ipc_client_.SetExpectedIpcServerSessionIdForTest(session_id_);
142 #endif  // defined(OS_WIN)
143 }
144 
OperationComplete(bool failed)145 void SecurityKeyIpcClientTest::OperationComplete(bool failed) {
146   operation_failed_ |= failed;
147   run_loop_->Quit();
148 }
149 
ConnectionStateHandler(bool established)150 void SecurityKeyIpcClientTest::ConnectionStateHandler(bool established) {
151   connection_established_ = established;
152   OperationComplete(/*failed=*/false);
153 }
154 
SendConnectionMessage()155 void SecurityKeyIpcClientTest::SendConnectionMessage() {
156   if (simulate_invalid_session_) {
157     fake_ipc_server_.SendInvalidSessionMessage();
158   } else {
159     fake_ipc_server_.SendConnectionReadyMessage();
160   }
161 }
162 
WaitForOperationComplete()163 void SecurityKeyIpcClientTest::WaitForOperationComplete() {
164   run_loop_->Run();
165   run_loop_.reset(new base::RunLoop());
166 }
167 
RunPendingTasks()168 void SecurityKeyIpcClientTest::RunPendingTasks() {
169   // Run until there are no pending work items in the queue.
170   base::RunLoop().RunUntilIdle();
171 }
172 
SendMessageToClient(int connection_id,const std::string & data)173 void SecurityKeyIpcClientTest::SendMessageToClient(int connection_id,
174                                                    const std::string& data) {
175   last_connection_id_received_ = connection_id;
176   last_message_received_ = data;
177   OperationComplete(/*failed=*/false);
178 }
179 
ClientMessageReceived(const std::string & response_payload)180 void SecurityKeyIpcClientTest::ClientMessageReceived(
181     const std::string& response_payload) {
182   last_message_received_ = response_payload;
183   OperationComplete(/*failed=*/false);
184 }
185 
186 mojo::NamedPlatformChannel::ServerName
GenerateUniqueTestChannelName()187 SecurityKeyIpcClientTest::GenerateUniqueTestChannelName() {
188   return mojo::NamedPlatformChannel::ServerNameFromUTF8(
189       GetChannelNamePathPrefixForTest() + kValidIpcChannelName +
190       IPC::Channel::GenerateUniqueRandomChannelID());
191 }
192 
EstablishConnection(bool expect_connected,bool expect_error)193 void SecurityKeyIpcClientTest::EstablishConnection(bool expect_connected,
194                                                    bool expect_error) {
195   // Start up the security key forwarding session IPC channel first, that way
196   // we can provide the channel using the fake SecurityKeyAuthHandler later on.
197   mojo::NamedPlatformChannel::ServerName server_name =
198       GenerateUniqueTestChannelName();
199   security_key_ipc_client_.SetIpcChannelHandleForTest(server_name);
200   ASSERT_TRUE(fake_ipc_server_.CreateChannel(
201       server_name,
202       /*request_timeout=*/base::TimeDelta::FromMilliseconds(500)));
203 
204   ASSERT_TRUE(security_key_ipc_client_.CheckForSecurityKeyIpcServerChannel());
205 
206   // Establish the IPC channel so we can begin sending and receiving security
207   // key messages.
208   security_key_ipc_client_.EstablishIpcConnection(
209       base::BindOnce(&SecurityKeyIpcClientTest::ConnectionStateHandler,
210                      base::Unretained(this)),
211       base::BindOnce(&SecurityKeyIpcClientTest::OperationComplete,
212                      base::Unretained(this), /*failed=*/true));
213   WaitForOperationComplete();
214   RunPendingTasks();
215 
216   ASSERT_EQ(expect_connected, connection_established_);
217   ASSERT_EQ(expect_error, operation_failed_);
218 }
219 
SendRequestAndResponse(const std::string & request_data,const std::string & response_data)220 void SecurityKeyIpcClientTest::SendRequestAndResponse(
221     const std::string& request_data,
222     const std::string& response_data) {
223   ASSERT_TRUE(security_key_ipc_client_.SendSecurityKeyRequest(
224       request_data,
225       base::BindRepeating(&SecurityKeyIpcClientTest::ClientMessageReceived,
226                           base::Unretained(this))));
227   WaitForOperationComplete();
228   ASSERT_FALSE(operation_failed_);
229   ASSERT_EQ(kTestConnectionId, last_connection_id_received_);
230   ASSERT_EQ(request_data, last_message_received_);
231 
232   ASSERT_TRUE(fake_ipc_server_.SendResponse(response_data));
233   WaitForOperationComplete();
234   ASSERT_FALSE(operation_failed_);
235   ASSERT_EQ(response_data, last_message_received_);
236 }
237 
TEST_F(SecurityKeyIpcClientTest,GenerateSingleSecurityKeyRequest)238 TEST_F(SecurityKeyIpcClientTest, GenerateSingleSecurityKeyRequest) {
239   EstablishConnection(/*expect_connected=*/true, /*expect_error=*/false);
240 
241   SendRequestAndResponse("Auth me!", "You've been authed!");
242 
243   security_key_ipc_client_.CloseIpcConnection();
244 }
245 
TEST_F(SecurityKeyIpcClientTest,GenerateLargeSecurityKeyRequest)246 TEST_F(SecurityKeyIpcClientTest, GenerateLargeSecurityKeyRequest) {
247   EstablishConnection(/*expect_connected=*/true, /*expect_error=*/false);
248 
249   SendRequestAndResponse(std::string(kLargeMessageSizeBytes, 'Y'),
250                          std::string(kLargeMessageSizeBytes, 'Z'));
251 
252   security_key_ipc_client_.CloseIpcConnection();
253 }
254 
TEST_F(SecurityKeyIpcClientTest,GenerateReallyLargeSecurityKeyRequest)255 TEST_F(SecurityKeyIpcClientTest, GenerateReallyLargeSecurityKeyRequest) {
256   EstablishConnection(/*expect_connected=*/true, /*expect_error=*/false);
257 
258   SendRequestAndResponse(std::string(kLargeMessageSizeBytes * 2, 'Y'),
259                          std::string(kLargeMessageSizeBytes * 2, 'Z'));
260 
261   security_key_ipc_client_.CloseIpcConnection();
262 }
263 
TEST_F(SecurityKeyIpcClientTest,GenerateMultipleSecurityKeyRequest)264 TEST_F(SecurityKeyIpcClientTest, GenerateMultipleSecurityKeyRequest) {
265   EstablishConnection(/*expect_connected=*/true, /*expect_error=*/false);
266 
267   SendRequestAndResponse("Auth me 1!", "You've been authed once!");
268   SendRequestAndResponse("Auth me 2!", "You've been authed twice!");
269   SendRequestAndResponse("Auth me 3!", "You've been authed thrice!");
270 
271   security_key_ipc_client_.CloseIpcConnection();
272 }
273 
TEST_F(SecurityKeyIpcClientTest,ServerClosesConnectionAfterRequestTimeout)274 TEST_F(SecurityKeyIpcClientTest, ServerClosesConnectionAfterRequestTimeout) {
275   EstablishConnection(/*expect_connected=*/true, /*expect_error=*/false);
276   fake_ipc_server_.CloseChannel();
277   WaitForOperationComplete();
278   ASSERT_FALSE(operation_failed_);
279 }
280 
TEST_F(SecurityKeyIpcClientTest,SecondSecurityKeyRequestBeforeFirstResponseReceived)281 TEST_F(SecurityKeyIpcClientTest,
282        SecondSecurityKeyRequestBeforeFirstResponseReceived) {
283   EstablishConnection(/*expect_connected=*/true, /*expect_error=*/false);
284 
285   ASSERT_TRUE(security_key_ipc_client_.SendSecurityKeyRequest(
286       "First Request",
287       base::BindRepeating(&SecurityKeyIpcClientTest::ClientMessageReceived,
288                           base::Unretained(this))));
289   WaitForOperationComplete();
290   ASSERT_FALSE(operation_failed_);
291 
292   ASSERT_FALSE(security_key_ipc_client_.SendSecurityKeyRequest(
293       "Second Request",
294       base::BindRepeating(&SecurityKeyIpcClientTest::ClientMessageReceived,
295                           base::Unretained(this))));
296 }
297 
TEST_F(SecurityKeyIpcClientTest,ReceiveSecurityKeyResponseWithEmptyPayload)298 TEST_F(SecurityKeyIpcClientTest, ReceiveSecurityKeyResponseWithEmptyPayload) {
299   EstablishConnection(/*expect_connected=*/true, /*expect_error=*/false);
300 
301   ASSERT_TRUE(security_key_ipc_client_.SendSecurityKeyRequest(
302       "Valid request",
303       base::BindRepeating(&SecurityKeyIpcClientTest::ClientMessageReceived,
304                           base::Unretained(this))));
305   WaitForOperationComplete();
306   ASSERT_FALSE(operation_failed_);
307 
308   ASSERT_TRUE(fake_ipc_server_.SendResponse(""));
309   WaitForOperationComplete();
310   ASSERT_TRUE(operation_failed_);
311 }
312 
TEST_F(SecurityKeyIpcClientTest,SendRequestBeforeEstablishingConnection)313 TEST_F(SecurityKeyIpcClientTest, SendRequestBeforeEstablishingConnection) {
314   // Sending a request will fail since the IPC connection has not been
315   // established.
316   ASSERT_FALSE(security_key_ipc_client_.SendSecurityKeyRequest(
317       "Too soon!!",
318       base::BindRepeating(&SecurityKeyIpcClientTest::ClientMessageReceived,
319                           base::Unretained(this))));
320 }
321 
TEST_F(SecurityKeyIpcClientTest,NonExistentIpcServerChannel)322 TEST_F(SecurityKeyIpcClientTest, NonExistentIpcServerChannel) {
323   security_key_ipc_client_.SetIpcChannelHandleForTest(
324       mojo::NamedPlatformChannel::ServerNameFromUTF8(
325           kNonexistentIpcChannelName));
326 
327   // Attempt to establish the conection (should fail since the IPC channel does
328   // not exist).
329   security_key_ipc_client_.EstablishIpcConnection(
330       base::BindOnce(&SecurityKeyIpcClientTest::ConnectionStateHandler,
331                      base::Unretained(this)),
332       base::BindOnce(&SecurityKeyIpcClientTest::OperationComplete,
333                      base::Unretained(this), /*failed=*/true));
334   WaitForOperationComplete();
335   ASSERT_TRUE(operation_failed_);
336 }
337 
TEST_F(SecurityKeyIpcClientTest,MultipleConnectionReadyMessagesReceived)338 TEST_F(SecurityKeyIpcClientTest, MultipleConnectionReadyMessagesReceived) {
339   EstablishConnection(/*expect_connected=*/true, /*expect_error=*/false);
340   ASSERT_FALSE(operation_failed_);
341 
342   // Send a second ConnectionReady message to trigger the error callback.
343   SendConnectionMessage();
344   WaitForOperationComplete();
345   ASSERT_TRUE(operation_failed_);
346 
347   // Send a third message to ensure no crash occurs both callbacks will have
348   // been called and cleared so we don't wait for the operation to complete.
349   SendConnectionMessage();
350   ASSERT_TRUE(operation_failed_);
351 }
352 
TEST_F(SecurityKeyIpcClientTest,UnexpectedInvalidSessionMessagesReceived)353 TEST_F(SecurityKeyIpcClientTest, UnexpectedInvalidSessionMessagesReceived) {
354   EstablishConnection(/*expect_connected=*/true, /*expect_error=*/false);
355   ASSERT_FALSE(operation_failed_);
356 
357   // Send an InvalidSession message to trigger the error callback.
358   simulate_invalid_session_ = true;
359   SendConnectionMessage();
360   WaitForOperationComplete();
361   ASSERT_TRUE(operation_failed_);
362 
363   // Send a third message to ensure no crash occurs both callbacks will have
364   // been called and cleared so we don't wait for the operation to complete.
365   SendConnectionMessage();
366   ASSERT_TRUE(operation_failed_);
367 }
368 
369 #if defined(OS_WIN)
TEST_F(SecurityKeyIpcClientTest,SecurityKeyIpcServerRunningInWrongSession)370 TEST_F(SecurityKeyIpcClientTest, SecurityKeyIpcServerRunningInWrongSession) {
371   // Set the expected session Id to a different session than we are running in.
372   security_key_ipc_client_.SetExpectedIpcServerSessionIdForTest(session_id_ +
373                                                                 1);
374 
375   // Attempting to establish a connection should fail here since the IPC Server
376   // is 'running' in a different session than expected.  The success callback
377   // will be called by the IPC server since it thinks the connection is valid,
378   // but we will have already started tearing down the connection since it
379   // failed at the client end.
380   EstablishConnection(/*expect_connected=*/true, /*expect_error=*/true);
381 }
382 
TEST_F(SecurityKeyIpcClientTest,SecurityKeyIpcClientRunningInWrongSession)383 TEST_F(SecurityKeyIpcClientTest, SecurityKeyIpcClientRunningInWrongSession) {
384   // Attempting to establish a connection should fail here since the IPC Client
385   // is 'running' in the non-remoted session.
386   simulate_invalid_session_ = true;
387   EstablishConnection(/*expect_connected=*/false, /*expect_error=*/false);
388 }
389 
TEST_F(SecurityKeyIpcClientTest,MultipleInvalidSessionMessagesReceived)390 TEST_F(SecurityKeyIpcClientTest, MultipleInvalidSessionMessagesReceived) {
391   // Attempting to establish a connection should fail here since the IPC Server
392   // is 'running' in a different session than expected.
393   simulate_invalid_session_ = true;
394   EstablishConnection(/*expect_connected=*/false, /*expect_error=*/false);
395 
396   SendConnectionMessage();
397   WaitForOperationComplete();
398   ASSERT_TRUE(operation_failed_);
399 
400   // Send a third message to ensure no crash occurs both callbacks will have
401   // been called and cleared so we don't wait for the operation to complete.
402   SendConnectionMessage();
403   ASSERT_TRUE(operation_failed_);
404 }
405 
TEST_F(SecurityKeyIpcClientTest,UnexpectedConnectionReadyMessagesReceived)406 TEST_F(SecurityKeyIpcClientTest, UnexpectedConnectionReadyMessagesReceived) {
407   // Attempting to establish a connection should fail here since the IPC Server
408   // is 'running' in a different session than expected.
409   simulate_invalid_session_ = true;
410   EstablishConnection(/*expect_connected=*/false, /*expect_error=*/false);
411 
412   // Send an InvalidSession message to trigger the error callback.
413   simulate_invalid_session_ = false;
414   SendConnectionMessage();
415   WaitForOperationComplete();
416   ASSERT_TRUE(operation_failed_);
417 
418   // Send a third message to ensure no crash occurs both callbacks will have
419   // been called and cleared so we don't wait for the operation to complete.
420   SendConnectionMessage();
421   ASSERT_TRUE(operation_failed_);
422 }
423 #endif  // defined(OS_WIN)
424 
425 }  // namespace remoting
426