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