| OLD | NEW |
| (Empty) |
| 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_server.h" | |
| 6 | |
| 7 #include <memory> | |
| 8 #include <string> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/bind_helpers.h" | |
| 12 #include "base/callback.h" | |
| 13 #include "base/macros.h" | |
| 14 #include "base/message_loop/message_loop.h" | |
| 15 #include "base/run_loop.h" | |
| 16 #include "ipc/ipc_channel.h" | |
| 17 #include "remoting/host/security_key/fake_security_key_ipc_client.h" | |
| 18 #include "remoting/host/security_key/security_key_ipc_constants.h" | |
| 19 #include "testing/gtest/include/gtest/gtest.h" | |
| 20 | |
| 21 namespace { | |
| 22 const int kTestConnectionId = 42; | |
| 23 const int kInitialConnectTimeoutMs = 250; | |
| 24 const int kConnectionTimeoutErrorDeltaMs = 100; | |
| 25 const int kLargeMessageSizeBytes = 256 * 1024; | |
| 26 } // namespace | |
| 27 | |
| 28 namespace remoting { | |
| 29 | |
| 30 class SecurityKeyIpcServerTest : public testing::Test { | |
| 31 public: | |
| 32 SecurityKeyIpcServerTest(); | |
| 33 ~SecurityKeyIpcServerTest() override; | |
| 34 | |
| 35 // Passed to the object used for testing to be called back to signal | |
| 36 // completion of an IPC channel state change or reception of an IPC message. | |
| 37 void OperationComplete(); | |
| 38 | |
| 39 // Used as a callback to signal receipt of a security key request message. | |
| 40 void SendRequestToClient(int connection_id, const std::string& data); | |
| 41 | |
| 42 protected: | |
| 43 // Returns a unique IPC channel name which prevents conflicts when running | |
| 44 // tests concurrently. | |
| 45 std::string GetUniqueTestChannelName(); | |
| 46 | |
| 47 // Waits until the current |run_loop_| instance is signaled, then resets it. | |
| 48 void WaitForOperationComplete(); | |
| 49 | |
| 50 // IPC tests require a valid MessageLoop to run. | |
| 51 base::MessageLoopForIO message_loop_; | |
| 52 | |
| 53 // Used to allow |message_loop_| to run during tests. The instance is reset | |
| 54 // after each stage of the tests has been completed. | |
| 55 std::unique_ptr<base::RunLoop> run_loop_; | |
| 56 | |
| 57 // The object under test. | |
| 58 std::unique_ptr<SecurityKeyIpcServer> security_key_ipc_server_; | |
| 59 | |
| 60 // Used to validate the object under test uses the correct ID when | |
| 61 // communicating over the IPC channel. | |
| 62 int last_connection_id_received_ = -1; | |
| 63 | |
| 64 // Stores the contents of the last IPC message received for validation. | |
| 65 std::string last_message_received_; | |
| 66 | |
| 67 private: | |
| 68 DISALLOW_COPY_AND_ASSIGN(SecurityKeyIpcServerTest); | |
| 69 }; | |
| 70 | |
| 71 SecurityKeyIpcServerTest::SecurityKeyIpcServerTest() | |
| 72 : run_loop_(new base::RunLoop()) { | |
| 73 uint32_t peer_session_id = UINT32_MAX; | |
| 74 #if defined(OS_WIN) | |
| 75 EXPECT_TRUE(ProcessIdToSessionId(GetCurrentProcessId(), | |
| 76 reinterpret_cast<DWORD*>(&peer_session_id))); | |
| 77 #endif // defined(OS_WIN) | |
| 78 | |
| 79 security_key_ipc_server_ = remoting::SecurityKeyIpcServer::Create( | |
| 80 kTestConnectionId, peer_session_id, | |
| 81 base::TimeDelta::FromMilliseconds(kInitialConnectTimeoutMs), | |
| 82 base::Bind(&SecurityKeyIpcServerTest::SendRequestToClient, | |
| 83 base::Unretained(this)), | |
| 84 base::Bind(&SecurityKeyIpcServerTest::OperationComplete, | |
| 85 base::Unretained(this))); | |
| 86 } | |
| 87 | |
| 88 SecurityKeyIpcServerTest::~SecurityKeyIpcServerTest() {} | |
| 89 | |
| 90 void SecurityKeyIpcServerTest::OperationComplete() { | |
| 91 run_loop_->Quit(); | |
| 92 } | |
| 93 | |
| 94 void SecurityKeyIpcServerTest::WaitForOperationComplete() { | |
| 95 run_loop_->Run(); | |
| 96 run_loop_.reset(new base::RunLoop()); | |
| 97 } | |
| 98 | |
| 99 void SecurityKeyIpcServerTest::SendRequestToClient(int connection_id, | |
| 100 const std::string& data) { | |
| 101 last_connection_id_received_ = connection_id; | |
| 102 last_message_received_ = data; | |
| 103 OperationComplete(); | |
| 104 } | |
| 105 | |
| 106 std::string SecurityKeyIpcServerTest::GetUniqueTestChannelName() { | |
| 107 return GetChannelNamePathPrefixForTest() + "Super_Awesome_Test_Channel." + | |
| 108 IPC::Channel::GenerateUniqueRandomChannelID(); | |
| 109 } | |
| 110 | |
| 111 TEST_F(SecurityKeyIpcServerTest, HandleSingleSecurityKeyRequest) { | |
| 112 std::string channel_name(GetUniqueTestChannelName()); | |
| 113 ASSERT_TRUE(security_key_ipc_server_->CreateChannel( | |
| 114 channel_name, | |
| 115 /*request_timeout=*/base::TimeDelta::FromMilliseconds(500))); | |
| 116 | |
| 117 // Create a fake client and connect to the IPC server channel. | |
| 118 FakeSecurityKeyIpcClient fake_ipc_client(base::Bind( | |
| 119 &SecurityKeyIpcServerTest::OperationComplete, base::Unretained(this))); | |
| 120 ASSERT_TRUE(fake_ipc_client.ConnectViaIpc(channel_name)); | |
| 121 WaitForOperationComplete(); | |
| 122 | |
| 123 ASSERT_TRUE(fake_ipc_client.ipc_channel_connected()); | |
| 124 | |
| 125 // Send a request from the IPC client to the IPC server. | |
| 126 std::string request_data("Blergh!"); | |
| 127 fake_ipc_client.SendSecurityKeyRequestViaIpc(request_data); | |
| 128 WaitForOperationComplete(); | |
| 129 | |
| 130 // Verify the request was received. | |
| 131 ASSERT_EQ(kTestConnectionId, last_connection_id_received_); | |
| 132 ASSERT_EQ(request_data, last_message_received_); | |
| 133 | |
| 134 // Send a response from the IPC server to the IPC client. | |
| 135 std::string response_data("Blargh!"); | |
| 136 ASSERT_TRUE(security_key_ipc_server_->SendResponse(response_data)); | |
| 137 WaitForOperationComplete(); | |
| 138 | |
| 139 // Verify the request was received. | |
| 140 ASSERT_EQ(response_data, fake_ipc_client.last_message_received()); | |
| 141 | |
| 142 // Typically the client will be the one to close the connection. | |
| 143 fake_ipc_client.CloseIpcConnection(); | |
| 144 } | |
| 145 | |
| 146 TEST_F(SecurityKeyIpcServerTest, HandleLargeSecurityKeyRequest) { | |
| 147 std::string channel_name(GetUniqueTestChannelName()); | |
| 148 ASSERT_TRUE(security_key_ipc_server_->CreateChannel( | |
| 149 channel_name, | |
| 150 /*request_timeout=*/base::TimeDelta::FromMilliseconds(500))); | |
| 151 | |
| 152 // Create a fake client and connect to the IPC server channel. | |
| 153 FakeSecurityKeyIpcClient fake_ipc_client(base::Bind( | |
| 154 &SecurityKeyIpcServerTest::OperationComplete, base::Unretained(this))); | |
| 155 ASSERT_TRUE(fake_ipc_client.ConnectViaIpc(channel_name)); | |
| 156 WaitForOperationComplete(); | |
| 157 | |
| 158 ASSERT_TRUE(fake_ipc_client.ipc_channel_connected()); | |
| 159 | |
| 160 // Send a request from the IPC client to the IPC server. | |
| 161 std::string request_data(kLargeMessageSizeBytes, 'Y'); | |
| 162 fake_ipc_client.SendSecurityKeyRequestViaIpc(request_data); | |
| 163 WaitForOperationComplete(); | |
| 164 | |
| 165 // Verify the request was received. | |
| 166 ASSERT_EQ(kTestConnectionId, last_connection_id_received_); | |
| 167 ASSERT_EQ(request_data, last_message_received_); | |
| 168 | |
| 169 // Send a response from the IPC server to the IPC client. | |
| 170 std::string response_data(kLargeMessageSizeBytes, 'Z'); | |
| 171 ASSERT_TRUE(security_key_ipc_server_->SendResponse(response_data)); | |
| 172 WaitForOperationComplete(); | |
| 173 | |
| 174 // Verify the request was received. | |
| 175 ASSERT_EQ(response_data, fake_ipc_client.last_message_received()); | |
| 176 | |
| 177 // Typically the client will be the one to close the connection. | |
| 178 fake_ipc_client.CloseIpcConnection(); | |
| 179 } | |
| 180 | |
| 181 TEST_F(SecurityKeyIpcServerTest, HandleReallyLargeSecurityKeyRequest) { | |
| 182 std::string channel_name(GetUniqueTestChannelName()); | |
| 183 ASSERT_TRUE(security_key_ipc_server_->CreateChannel( | |
| 184 channel_name, | |
| 185 /*request_timeout=*/base::TimeDelta::FromMilliseconds(500))); | |
| 186 | |
| 187 // Create a fake client and connect to the IPC server channel. | |
| 188 FakeSecurityKeyIpcClient fake_ipc_client(base::Bind( | |
| 189 &SecurityKeyIpcServerTest::OperationComplete, base::Unretained(this))); | |
| 190 ASSERT_TRUE(fake_ipc_client.ConnectViaIpc(channel_name)); | |
| 191 WaitForOperationComplete(); | |
| 192 | |
| 193 ASSERT_TRUE(fake_ipc_client.ipc_channel_connected()); | |
| 194 | |
| 195 // Send a request from the IPC client to the IPC server. | |
| 196 std::string request_data(kLargeMessageSizeBytes * 2, 'Y'); | |
| 197 fake_ipc_client.SendSecurityKeyRequestViaIpc(request_data); | |
| 198 WaitForOperationComplete(); | |
| 199 | |
| 200 // Verify the request was received. | |
| 201 ASSERT_EQ(kTestConnectionId, last_connection_id_received_); | |
| 202 ASSERT_EQ(request_data, last_message_received_); | |
| 203 | |
| 204 // Send a response from the IPC server to the IPC client. | |
| 205 std::string response_data(kLargeMessageSizeBytes * 2, 'Z'); | |
| 206 ASSERT_TRUE(security_key_ipc_server_->SendResponse(response_data)); | |
| 207 WaitForOperationComplete(); | |
| 208 | |
| 209 // Verify the request was received. | |
| 210 ASSERT_EQ(response_data, fake_ipc_client.last_message_received()); | |
| 211 | |
| 212 // Typically the client will be the one to close the connection. | |
| 213 fake_ipc_client.CloseIpcConnection(); | |
| 214 } | |
| 215 | |
| 216 TEST_F(SecurityKeyIpcServerTest, HandleMultipleSecurityKeyRequests) { | |
| 217 std::string channel_name(GetUniqueTestChannelName()); | |
| 218 ASSERT_TRUE(security_key_ipc_server_->CreateChannel( | |
| 219 channel_name, | |
| 220 /*request_timeout=*/base::TimeDelta::FromMilliseconds(500))); | |
| 221 | |
| 222 // Create a fake client and connect to the IPC server channel. | |
| 223 FakeSecurityKeyIpcClient fake_ipc_client(base::Bind( | |
| 224 &SecurityKeyIpcServerTest::OperationComplete, base::Unretained(this))); | |
| 225 ASSERT_TRUE(fake_ipc_client.ConnectViaIpc(channel_name)); | |
| 226 WaitForOperationComplete(); | |
| 227 | |
| 228 ASSERT_TRUE(fake_ipc_client.ipc_channel_connected()); | |
| 229 | |
| 230 // Send a request from the IPC client to the IPC server. | |
| 231 std::string request_data_1("Blergh!"); | |
| 232 fake_ipc_client.SendSecurityKeyRequestViaIpc(request_data_1); | |
| 233 WaitForOperationComplete(); | |
| 234 | |
| 235 // Verify the request was received. | |
| 236 ASSERT_EQ(kTestConnectionId, last_connection_id_received_); | |
| 237 ASSERT_EQ(request_data_1, last_message_received_); | |
| 238 | |
| 239 // Send a response from the IPC server to the IPC client. | |
| 240 std::string response_data_1("Blargh!"); | |
| 241 ASSERT_TRUE(security_key_ipc_server_->SendResponse(response_data_1)); | |
| 242 WaitForOperationComplete(); | |
| 243 | |
| 244 // Verify the response was received. | |
| 245 ASSERT_EQ(response_data_1, fake_ipc_client.last_message_received()); | |
| 246 | |
| 247 // Send a request from the IPC client to the IPC server. | |
| 248 std::string request_data_2("Bleh!"); | |
| 249 fake_ipc_client.SendSecurityKeyRequestViaIpc(request_data_2); | |
| 250 WaitForOperationComplete(); | |
| 251 | |
| 252 // Verify the request was received. | |
| 253 ASSERT_EQ(kTestConnectionId, last_connection_id_received_); | |
| 254 ASSERT_EQ(request_data_2, last_message_received_); | |
| 255 | |
| 256 // Send a response from the IPC server to the IPC client. | |
| 257 std::string response_data_2("Meh!"); | |
| 258 ASSERT_TRUE(security_key_ipc_server_->SendResponse(response_data_2)); | |
| 259 WaitForOperationComplete(); | |
| 260 | |
| 261 // Verify the response was received. | |
| 262 ASSERT_EQ(response_data_2, fake_ipc_client.last_message_received()); | |
| 263 | |
| 264 // Typically the client will be the one to close the connection. | |
| 265 fake_ipc_client.CloseIpcConnection(); | |
| 266 } | |
| 267 | |
| 268 TEST_F(SecurityKeyIpcServerTest, InitialIpcConnectionTimeout) { | |
| 269 // Create a channel, then wait for the done callback to be called indicating | |
| 270 // the connection was closed. This test simulates the IPC Server being | |
| 271 // created but the client failing to connect to it. | |
| 272 std::string channel_name(GetUniqueTestChannelName()); | |
| 273 ASSERT_TRUE(security_key_ipc_server_->CreateChannel( | |
| 274 channel_name, | |
| 275 /*request_timeout=*/base::TimeDelta::FromMilliseconds(500))); | |
| 276 base::Time start_time(base::Time::NowFromSystemTime()); | |
| 277 WaitForOperationComplete(); | |
| 278 base::TimeDelta elapsed_time = base::Time::NowFromSystemTime() - start_time; | |
| 279 | |
| 280 ASSERT_NEAR(elapsed_time.InMilliseconds(), kInitialConnectTimeoutMs, | |
| 281 kConnectionTimeoutErrorDeltaMs); | |
| 282 } | |
| 283 | |
| 284 TEST_F(SecurityKeyIpcServerTest, NoSecurityKeyRequestTimeout) { | |
| 285 // Create a channel and connect to it via IPC but do not send a request. | |
| 286 // The channel should be closed and cleaned up if the IPC client does not | |
| 287 // issue a request within the specified timeout period. | |
| 288 std::string channel_name(GetUniqueTestChannelName()); | |
| 289 ASSERT_TRUE(security_key_ipc_server_->CreateChannel( | |
| 290 channel_name, | |
| 291 /*request_timeout=*/base::TimeDelta::FromMilliseconds(500))); | |
| 292 | |
| 293 // Create a fake client and connect to the IPC server channel. | |
| 294 FakeSecurityKeyIpcClient fake_ipc_client(base::Bind( | |
| 295 &SecurityKeyIpcServerTest::OperationComplete, base::Unretained(this))); | |
| 296 ASSERT_TRUE(fake_ipc_client.ConnectViaIpc(channel_name)); | |
| 297 WaitForOperationComplete(); | |
| 298 | |
| 299 ASSERT_TRUE(fake_ipc_client.ipc_channel_connected()); | |
| 300 | |
| 301 // Now that a connection has been established, we wait for the timeout. | |
| 302 base::Time start_time(base::Time::NowFromSystemTime()); | |
| 303 WaitForOperationComplete(); | |
| 304 base::TimeDelta elapsed_time = base::Time::NowFromSystemTime() - start_time; | |
| 305 | |
| 306 ASSERT_NEAR(elapsed_time.InMilliseconds(), kInitialConnectTimeoutMs, | |
| 307 kConnectionTimeoutErrorDeltaMs); | |
| 308 } | |
| 309 | |
| 310 TEST_F(SecurityKeyIpcServerTest, SecurityKeyResponseTimeout) { | |
| 311 // Create a channel, connect to it via IPC, and issue a request, but do | |
| 312 // not send a response. This simulates a client-side timeout. | |
| 313 base::TimeDelta request_timeout(base::TimeDelta::FromMilliseconds(50)); | |
| 314 std::string channel_name(GetUniqueTestChannelName()); | |
| 315 ASSERT_TRUE( | |
| 316 security_key_ipc_server_->CreateChannel(channel_name, request_timeout)); | |
| 317 | |
| 318 // Create a fake client and connect to the IPC server channel. | |
| 319 FakeSecurityKeyIpcClient fake_ipc_client(base::Bind( | |
| 320 &SecurityKeyIpcServerTest::OperationComplete, base::Unretained(this))); | |
| 321 ASSERT_TRUE(fake_ipc_client.ConnectViaIpc(channel_name)); | |
| 322 WaitForOperationComplete(); | |
| 323 | |
| 324 ASSERT_TRUE(fake_ipc_client.ipc_channel_connected()); | |
| 325 | |
| 326 // Now that a connection has been established, we issue a request and | |
| 327 // then wait for the timeout. | |
| 328 std::string request_data("I can haz Auth?"); | |
| 329 fake_ipc_client.SendSecurityKeyRequestViaIpc(request_data); | |
| 330 WaitForOperationComplete(); | |
| 331 | |
| 332 // Leave the request hanging until it times out... | |
| 333 base::Time start_time(base::Time::NowFromSystemTime()); | |
| 334 WaitForOperationComplete(); | |
| 335 base::TimeDelta elapsed_time = base::Time::NowFromSystemTime() - start_time; | |
| 336 | |
| 337 ASSERT_NEAR(elapsed_time.InMilliseconds(), request_timeout.InMilliseconds(), | |
| 338 kConnectionTimeoutErrorDeltaMs); | |
| 339 } | |
| 340 | |
| 341 TEST_F(SecurityKeyIpcServerTest, SendResponseTimeout) { | |
| 342 // Create a channel, connect to it via IPC, issue a request, and send | |
| 343 // a response, but do not close the channel after that. The connection | |
| 344 // should be terminated after the initial timeout period has elapsed. | |
| 345 base::TimeDelta request_timeout(base::TimeDelta::FromMilliseconds(500)); | |
| 346 std::string channel_name(GetUniqueTestChannelName()); | |
| 347 ASSERT_TRUE( | |
| 348 security_key_ipc_server_->CreateChannel(channel_name, request_timeout)); | |
| 349 | |
| 350 // Create a fake client and connect to the IPC server channel. | |
| 351 FakeSecurityKeyIpcClient fake_ipc_client(base::Bind( | |
| 352 &SecurityKeyIpcServerTest::OperationComplete, base::Unretained(this))); | |
| 353 ASSERT_TRUE(fake_ipc_client.ConnectViaIpc(channel_name)); | |
| 354 WaitForOperationComplete(); | |
| 355 | |
| 356 ASSERT_TRUE(fake_ipc_client.ipc_channel_connected()); | |
| 357 | |
| 358 // Issue a request. | |
| 359 std::string request_data("Auth me yo!"); | |
| 360 fake_ipc_client.SendSecurityKeyRequestViaIpc(request_data); | |
| 361 WaitForOperationComplete(); | |
| 362 | |
| 363 // Send a response from the IPC server to the IPC client. | |
| 364 std::string response_data("OK, the secret code is 1-2-3-4-5"); | |
| 365 ASSERT_TRUE(security_key_ipc_server_->SendResponse(response_data)); | |
| 366 WaitForOperationComplete(); | |
| 367 | |
| 368 // Now wait for the timeout period for the connection to be torn down. | |
| 369 base::Time start_time(base::Time::NowFromSystemTime()); | |
| 370 WaitForOperationComplete(); | |
| 371 base::TimeDelta elapsed_time = base::Time::NowFromSystemTime() - start_time; | |
| 372 | |
| 373 ASSERT_NEAR(elapsed_time.InMilliseconds(), request_timeout.InMilliseconds(), | |
| 374 kConnectionTimeoutErrorDeltaMs); | |
| 375 } | |
| 376 | |
| 377 #if defined(OS_WIN) | |
| 378 TEST_F(SecurityKeyIpcServerTest, IpcConnectionFailsFromInvalidSession) { | |
| 379 uint32_t peer_session_id = UINT32_MAX; | |
| 380 ASSERT_TRUE(ProcessIdToSessionId(GetCurrentProcessId(), | |
| 381 reinterpret_cast<DWORD*>(&peer_session_id))); | |
| 382 peer_session_id++; | |
| 383 | |
| 384 // Reinitialize the object under test. | |
| 385 security_key_ipc_server_ = remoting::SecurityKeyIpcServer::Create( | |
| 386 kTestConnectionId, peer_session_id, | |
| 387 base::TimeDelta::FromMilliseconds(kInitialConnectTimeoutMs), | |
| 388 base::Bind(&SecurityKeyIpcServerTest::SendRequestToClient, | |
| 389 base::Unretained(this)), | |
| 390 base::Bind(&base::DoNothing)); | |
| 391 | |
| 392 base::TimeDelta request_timeout(base::TimeDelta::FromMilliseconds(500)); | |
| 393 std::string channel_name(GetUniqueTestChannelName()); | |
| 394 ASSERT_TRUE( | |
| 395 security_key_ipc_server_->CreateChannel(channel_name, request_timeout)); | |
| 396 | |
| 397 // Create a fake client and attempt to connect to the IPC server channel. | |
| 398 FakeSecurityKeyIpcClient fake_ipc_client(base::Bind( | |
| 399 &SecurityKeyIpcServerTest::OperationComplete, base::Unretained(this))); | |
| 400 ASSERT_TRUE(fake_ipc_client.ConnectViaIpc(channel_name)); | |
| 401 WaitForOperationComplete(); | |
| 402 WaitForOperationComplete(); | |
| 403 | |
| 404 // Verify the connection failed. | |
| 405 ASSERT_FALSE(fake_ipc_client.ipc_channel_connected()); | |
| 406 } | |
| 407 #endif // defined(OS_WIN) | |
| 408 | |
| 409 } // namespace remoting | |
| OLD | NEW |