1// Copyright 2013 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/setup/me2me_native_messaging_host.h" 6 7#include "base/basictypes.h" 8#include "base/compiler_specific.h" 9#include "base/json/json_reader.h" 10#include "base/json/json_writer.h" 11#include "base/message_loop/message_loop.h" 12#include "base/run_loop.h" 13#include "base/stl_util.h" 14#include "base/strings/stringize_macros.h" 15#include "base/values.h" 16#include "google_apis/gaia/gaia_oauth_client.h" 17#include "net/base/file_stream.h" 18#include "net/base/net_util.h" 19#include "remoting/base/auto_thread_task_runner.h" 20#include "remoting/host/native_messaging/pipe_messaging_channel.h" 21#include "remoting/host/pin_hash.h" 22#include "remoting/host/setup/test_util.h" 23#include "remoting/protocol/pairing_registry.h" 24#include "remoting/protocol/protocol_mock_objects.h" 25#include "testing/gtest/include/gtest/gtest.h" 26 27using remoting::protocol::MockPairingRegistryDelegate; 28using remoting::protocol::PairingRegistry; 29using remoting::protocol::SynchronousPairingRegistry; 30 31namespace { 32 33void VerifyHelloResponse(scoped_ptr<base::DictionaryValue> response) { 34 ASSERT_TRUE(response); 35 std::string value; 36 EXPECT_TRUE(response->GetString("type", &value)); 37 EXPECT_EQ("helloResponse", value); 38 EXPECT_TRUE(response->GetString("version", &value)); 39 EXPECT_EQ(STRINGIZE(VERSION), value); 40} 41 42void VerifyGetHostNameResponse(scoped_ptr<base::DictionaryValue> response) { 43 ASSERT_TRUE(response); 44 std::string value; 45 EXPECT_TRUE(response->GetString("type", &value)); 46 EXPECT_EQ("getHostNameResponse", value); 47 EXPECT_TRUE(response->GetString("hostname", &value)); 48 EXPECT_EQ(net::GetHostName(), value); 49} 50 51void VerifyGetPinHashResponse(scoped_ptr<base::DictionaryValue> response) { 52 ASSERT_TRUE(response); 53 std::string value; 54 EXPECT_TRUE(response->GetString("type", &value)); 55 EXPECT_EQ("getPinHashResponse", value); 56 EXPECT_TRUE(response->GetString("hash", &value)); 57 EXPECT_EQ(remoting::MakeHostPinHash("my_host", "1234"), value); 58} 59 60void VerifyGenerateKeyPairResponse(scoped_ptr<base::DictionaryValue> response) { 61 ASSERT_TRUE(response); 62 std::string value; 63 EXPECT_TRUE(response->GetString("type", &value)); 64 EXPECT_EQ("generateKeyPairResponse", value); 65 EXPECT_TRUE(response->GetString("privateKey", &value)); 66 EXPECT_TRUE(response->GetString("publicKey", &value)); 67} 68 69void VerifyGetDaemonConfigResponse(scoped_ptr<base::DictionaryValue> response) { 70 ASSERT_TRUE(response); 71 std::string value; 72 EXPECT_TRUE(response->GetString("type", &value)); 73 EXPECT_EQ("getDaemonConfigResponse", value); 74 const base::DictionaryValue* config = NULL; 75 EXPECT_TRUE(response->GetDictionary("config", &config)); 76 EXPECT_TRUE(base::DictionaryValue().Equals(config)); 77} 78 79void VerifyGetUsageStatsConsentResponse( 80 scoped_ptr<base::DictionaryValue> response) { 81 ASSERT_TRUE(response); 82 std::string value; 83 EXPECT_TRUE(response->GetString("type", &value)); 84 EXPECT_EQ("getUsageStatsConsentResponse", value); 85 bool supported, allowed, set_by_policy; 86 EXPECT_TRUE(response->GetBoolean("supported", &supported)); 87 EXPECT_TRUE(response->GetBoolean("allowed", &allowed)); 88 EXPECT_TRUE(response->GetBoolean("setByPolicy", &set_by_policy)); 89 EXPECT_TRUE(supported); 90 EXPECT_TRUE(allowed); 91 EXPECT_TRUE(set_by_policy); 92} 93 94void VerifyStopDaemonResponse(scoped_ptr<base::DictionaryValue> response) { 95 ASSERT_TRUE(response); 96 std::string value; 97 EXPECT_TRUE(response->GetString("type", &value)); 98 EXPECT_EQ("stopDaemonResponse", value); 99 EXPECT_TRUE(response->GetString("result", &value)); 100 EXPECT_EQ("OK", value); 101} 102 103void VerifyGetDaemonStateResponse(scoped_ptr<base::DictionaryValue> response) { 104 ASSERT_TRUE(response); 105 std::string value; 106 EXPECT_TRUE(response->GetString("type", &value)); 107 EXPECT_EQ("getDaemonStateResponse", value); 108 EXPECT_TRUE(response->GetString("state", &value)); 109 EXPECT_EQ("STARTED", value); 110} 111 112void VerifyUpdateDaemonConfigResponse( 113 scoped_ptr<base::DictionaryValue> response) { 114 ASSERT_TRUE(response); 115 std::string value; 116 EXPECT_TRUE(response->GetString("type", &value)); 117 EXPECT_EQ("updateDaemonConfigResponse", value); 118 EXPECT_TRUE(response->GetString("result", &value)); 119 EXPECT_EQ("OK", value); 120} 121 122void VerifyStartDaemonResponse(scoped_ptr<base::DictionaryValue> response) { 123 ASSERT_TRUE(response); 124 std::string value; 125 EXPECT_TRUE(response->GetString("type", &value)); 126 EXPECT_EQ("startDaemonResponse", value); 127 EXPECT_TRUE(response->GetString("result", &value)); 128 EXPECT_EQ("OK", value); 129} 130 131} // namespace 132 133namespace remoting { 134 135class MockDaemonControllerDelegate : public DaemonController::Delegate { 136 public: 137 MockDaemonControllerDelegate(); 138 virtual ~MockDaemonControllerDelegate(); 139 140 // DaemonController::Delegate interface. 141 virtual DaemonController::State GetState() OVERRIDE; 142 virtual scoped_ptr<base::DictionaryValue> GetConfig() OVERRIDE; 143 virtual void InstallHost( 144 const DaemonController::CompletionCallback& done) OVERRIDE; 145 virtual void SetConfigAndStart( 146 scoped_ptr<base::DictionaryValue> config, 147 bool consent, 148 const DaemonController::CompletionCallback& done) OVERRIDE; 149 virtual void UpdateConfig( 150 scoped_ptr<base::DictionaryValue> config, 151 const DaemonController::CompletionCallback& done) OVERRIDE; 152 virtual void Stop(const DaemonController::CompletionCallback& done) OVERRIDE; 153 virtual void SetWindow(void* window_handle) OVERRIDE; 154 virtual std::string GetVersion() OVERRIDE; 155 virtual DaemonController::UsageStatsConsent GetUsageStatsConsent() OVERRIDE; 156 157 private: 158 DISALLOW_COPY_AND_ASSIGN(MockDaemonControllerDelegate); 159}; 160 161MockDaemonControllerDelegate::MockDaemonControllerDelegate() {} 162 163MockDaemonControllerDelegate::~MockDaemonControllerDelegate() {} 164 165DaemonController::State MockDaemonControllerDelegate::GetState() { 166 return DaemonController::STATE_STARTED; 167} 168 169scoped_ptr<base::DictionaryValue> MockDaemonControllerDelegate::GetConfig() { 170 return scoped_ptr<base::DictionaryValue>(new base::DictionaryValue()); 171} 172 173void MockDaemonControllerDelegate::InstallHost( 174 const DaemonController::CompletionCallback& done) { 175 done.Run(DaemonController::RESULT_OK); 176} 177 178void MockDaemonControllerDelegate::SetConfigAndStart( 179 scoped_ptr<base::DictionaryValue> config, 180 bool consent, 181 const DaemonController::CompletionCallback& done) { 182 183 // Verify parameters passed in. 184 if (consent && config && config->HasKey("start")) { 185 done.Run(DaemonController::RESULT_OK); 186 } else { 187 done.Run(DaemonController::RESULT_FAILED); 188 } 189} 190 191void MockDaemonControllerDelegate::UpdateConfig( 192 scoped_ptr<base::DictionaryValue> config, 193 const DaemonController::CompletionCallback& done) { 194 if (config && config->HasKey("update")) { 195 done.Run(DaemonController::RESULT_OK); 196 } else { 197 done.Run(DaemonController::RESULT_FAILED); 198 } 199} 200 201void MockDaemonControllerDelegate::Stop( 202 const DaemonController::CompletionCallback& done) { 203 done.Run(DaemonController::RESULT_OK); 204} 205 206void MockDaemonControllerDelegate::SetWindow(void* window_handle) {} 207 208std::string MockDaemonControllerDelegate::GetVersion() { 209 // Unused - Me2MeNativeMessagingHost returns the compiled-in version string 210 // instead of calling this method. 211 NOTREACHED(); 212 return std::string(); 213} 214 215DaemonController::UsageStatsConsent 216MockDaemonControllerDelegate::GetUsageStatsConsent() { 217 DaemonController::UsageStatsConsent consent; 218 consent.supported = true; 219 consent.allowed = true; 220 consent.set_by_policy = true; 221 return consent; 222} 223 224class Me2MeNativeMessagingHostTest : public testing::Test { 225 public: 226 Me2MeNativeMessagingHostTest(); 227 virtual ~Me2MeNativeMessagingHostTest(); 228 229 virtual void SetUp() OVERRIDE; 230 virtual void TearDown() OVERRIDE; 231 232 scoped_ptr<base::DictionaryValue> ReadMessageFromOutputPipe(); 233 234 void WriteMessageToInputPipe(const base::Value& message); 235 236 // The Host process should shut down when it receives a malformed request. 237 // This is tested by sending a known-good request, followed by |message|, 238 // followed by the known-good request again. The response file should only 239 // contain a single response from the first good request. 240 void TestBadRequest(const base::Value& message); 241 242 protected: 243 // Reference to the MockDaemonControllerDelegate, which is owned by 244 // |channel_|. 245 MockDaemonControllerDelegate* daemon_controller_delegate_; 246 247 private: 248 void StartHost(); 249 void StopHost(); 250 void ExitTest(); 251 252 // Each test creates two unidirectional pipes: "input" and "output". 253 // Me2MeNativeMessagingHost reads from input_read_handle and writes to 254 // output_write_file. The unittest supplies data to input_write_handle, and 255 // verifies output from output_read_handle. 256 // 257 // unittest -> [input] -> Me2MeNativeMessagingHost -> [output] -> unittest 258 base::File input_write_file_; 259 base::File output_read_file_; 260 261 // Message loop of the test thread. 262 scoped_ptr<base::MessageLoop> test_message_loop_; 263 scoped_ptr<base::RunLoop> test_run_loop_; 264 265 scoped_ptr<base::Thread> host_thread_; 266 scoped_ptr<base::RunLoop> host_run_loop_; 267 268 // Task runner of the host thread. 269 scoped_refptr<AutoThreadTaskRunner> host_task_runner_; 270 scoped_ptr<remoting::Me2MeNativeMessagingHost> host_; 271 272 DISALLOW_COPY_AND_ASSIGN(Me2MeNativeMessagingHostTest); 273}; 274 275Me2MeNativeMessagingHostTest::Me2MeNativeMessagingHostTest() {} 276 277Me2MeNativeMessagingHostTest::~Me2MeNativeMessagingHostTest() {} 278 279void Me2MeNativeMessagingHostTest::SetUp() { 280 base::File input_read_file; 281 base::File output_write_file; 282 283 ASSERT_TRUE(MakePipe(&input_read_file, &input_write_file_)); 284 ASSERT_TRUE(MakePipe(&output_read_file_, &output_write_file)); 285 286 test_message_loop_.reset(new base::MessageLoop()); 287 test_run_loop_.reset(new base::RunLoop()); 288 289 // Run the host on a dedicated thread. 290 host_thread_.reset(new base::Thread("host_thread")); 291 host_thread_->Start(); 292 293 // Arrange to run |test_message_loop_| until no components depend on it. 294 host_task_runner_ = new AutoThreadTaskRunner( 295 host_thread_->message_loop_proxy(), 296 base::Bind(&Me2MeNativeMessagingHostTest::ExitTest, 297 base::Unretained(this))); 298 299 host_task_runner_->PostTask( 300 FROM_HERE, 301 base::Bind(&Me2MeNativeMessagingHostTest::StartHost, 302 base::Unretained(this))); 303 304 // Wait until the host finishes starting. 305 test_run_loop_->Run(); 306} 307 308void Me2MeNativeMessagingHostTest::StartHost() { 309 DCHECK(host_task_runner_->RunsTasksOnCurrentThread()); 310 311 base::File input_read_file; 312 base::File output_write_file; 313 314 ASSERT_TRUE(MakePipe(&input_read_file, &input_write_file_)); 315 ASSERT_TRUE(MakePipe(&output_read_file_, &output_write_file)); 316 317 daemon_controller_delegate_ = new MockDaemonControllerDelegate(); 318 scoped_refptr<DaemonController> daemon_controller( 319 new DaemonController( 320 scoped_ptr<DaemonController::Delegate>(daemon_controller_delegate_))); 321 322 scoped_refptr<PairingRegistry> pairing_registry = 323 new SynchronousPairingRegistry(scoped_ptr<PairingRegistry::Delegate>( 324 new MockPairingRegistryDelegate())); 325 326 scoped_ptr<extensions::NativeMessagingChannel> channel( 327 new PipeMessagingChannel(input_read_file.Pass(), 328 output_write_file.Pass())); 329 330 host_.reset(new Me2MeNativeMessagingHost( 331 false, 332 0, 333 channel.Pass(), 334 daemon_controller, 335 pairing_registry, 336 scoped_ptr<remoting::OAuthClient>())); 337 host_->Start(base::Bind(&Me2MeNativeMessagingHostTest::StopHost, 338 base::Unretained(this))); 339 340 // Notify the test that the host has finished starting up. 341 test_message_loop_->message_loop_proxy()->PostTask( 342 FROM_HERE, test_run_loop_->QuitClosure()); 343} 344 345void Me2MeNativeMessagingHostTest::StopHost() { 346 DCHECK(host_task_runner_->RunsTasksOnCurrentThread()); 347 348 host_.reset(); 349 350 // Wait till all shutdown tasks have completed. 351 base::RunLoop().RunUntilIdle(); 352 353 // Trigger a test shutdown via ExitTest(). 354 host_task_runner_ = NULL; 355} 356 357void Me2MeNativeMessagingHostTest::ExitTest() { 358 if (!test_message_loop_->message_loop_proxy()->RunsTasksOnCurrentThread()) { 359 test_message_loop_->message_loop_proxy()->PostTask( 360 FROM_HERE, 361 base::Bind(&Me2MeNativeMessagingHostTest::ExitTest, 362 base::Unretained(this))); 363 return; 364 } 365 test_run_loop_->Quit(); 366} 367 368void Me2MeNativeMessagingHostTest::TearDown() { 369 // Closing the write-end of the input will send an EOF to the native 370 // messaging reader. This will trigger a host shutdown. 371 input_write_file_.Close(); 372 373 // Start a new RunLoop and Wait until the host finishes shutting down. 374 test_run_loop_.reset(new base::RunLoop()); 375 test_run_loop_->Run(); 376 377 // Verify there are no more message in the output pipe. 378 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe(); 379 EXPECT_FALSE(response); 380 381 // The It2MeMe2MeNativeMessagingHost dtor closes the handles that are passed 382 // to it. So the only handle left to close is |output_read_file_|. 383 output_read_file_.Close(); 384} 385 386scoped_ptr<base::DictionaryValue> 387Me2MeNativeMessagingHostTest::ReadMessageFromOutputPipe() { 388 uint32 length; 389 int read_result = output_read_file_.ReadAtCurrentPos( 390 reinterpret_cast<char*>(&length), sizeof(length)); 391 if (read_result != sizeof(length)) { 392 return scoped_ptr<base::DictionaryValue>(); 393 } 394 395 std::string message_json(length, '\0'); 396 read_result = output_read_file_.ReadAtCurrentPos( 397 string_as_array(&message_json), length); 398 if (read_result != static_cast<int>(length)) { 399 return scoped_ptr<base::DictionaryValue>(); 400 } 401 402 scoped_ptr<base::Value> message(base::JSONReader::Read(message_json)); 403 if (!message || !message->IsType(base::Value::TYPE_DICTIONARY)) { 404 return scoped_ptr<base::DictionaryValue>(); 405 } 406 407 return scoped_ptr<base::DictionaryValue>( 408 static_cast<base::DictionaryValue*>(message.release())); 409} 410 411void Me2MeNativeMessagingHostTest::WriteMessageToInputPipe( 412 const base::Value& message) { 413 std::string message_json; 414 base::JSONWriter::Write(&message, &message_json); 415 416 uint32 length = message_json.length(); 417 input_write_file_.WriteAtCurrentPos(reinterpret_cast<char*>(&length), 418 sizeof(length)); 419 input_write_file_.WriteAtCurrentPos(message_json.data(), length); 420} 421 422void Me2MeNativeMessagingHostTest::TestBadRequest(const base::Value& message) { 423 base::DictionaryValue good_message; 424 good_message.SetString("type", "hello"); 425 426 // This test currently relies on synchronous processing of hello messages and 427 // message parameters verification. 428 WriteMessageToInputPipe(good_message); 429 WriteMessageToInputPipe(message); 430 WriteMessageToInputPipe(good_message); 431 432 // Read from output pipe, and verify responses. 433 scoped_ptr<base::DictionaryValue> response = 434 ReadMessageFromOutputPipe(); 435 VerifyHelloResponse(response.Pass()); 436 437 response = ReadMessageFromOutputPipe(); 438 EXPECT_FALSE(response); 439} 440 441// TODO (weitaosu): crbug.com/323306. Re-enable these tests. 442// Test all valid request-types. 443TEST_F(Me2MeNativeMessagingHostTest, All) { 444 int next_id = 0; 445 base::DictionaryValue message; 446 message.SetInteger("id", next_id++); 447 message.SetString("type", "hello"); 448 WriteMessageToInputPipe(message); 449 450 message.SetInteger("id", next_id++); 451 message.SetString("type", "getHostName"); 452 WriteMessageToInputPipe(message); 453 454 message.SetInteger("id", next_id++); 455 message.SetString("type", "getPinHash"); 456 message.SetString("hostId", "my_host"); 457 message.SetString("pin", "1234"); 458 WriteMessageToInputPipe(message); 459 460 message.Clear(); 461 message.SetInteger("id", next_id++); 462 message.SetString("type", "generateKeyPair"); 463 WriteMessageToInputPipe(message); 464 465 message.SetInteger("id", next_id++); 466 message.SetString("type", "getDaemonConfig"); 467 WriteMessageToInputPipe(message); 468 469 message.SetInteger("id", next_id++); 470 message.SetString("type", "getUsageStatsConsent"); 471 WriteMessageToInputPipe(message); 472 473 message.SetInteger("id", next_id++); 474 message.SetString("type", "stopDaemon"); 475 WriteMessageToInputPipe(message); 476 477 message.SetInteger("id", next_id++); 478 message.SetString("type", "getDaemonState"); 479 WriteMessageToInputPipe(message); 480 481 // Following messages require a "config" dictionary. 482 base::DictionaryValue config; 483 config.SetBoolean("update", true); 484 message.Set("config", config.DeepCopy()); 485 message.SetInteger("id", next_id++); 486 message.SetString("type", "updateDaemonConfig"); 487 WriteMessageToInputPipe(message); 488 489 config.Clear(); 490 config.SetBoolean("start", true); 491 message.Set("config", config.DeepCopy()); 492 message.SetBoolean("consent", true); 493 message.SetInteger("id", next_id++); 494 message.SetString("type", "startDaemon"); 495 WriteMessageToInputPipe(message); 496 497 void (*verify_routines[])(scoped_ptr<base::DictionaryValue>) = { 498 &VerifyHelloResponse, 499 &VerifyGetHostNameResponse, 500 &VerifyGetPinHashResponse, 501 &VerifyGenerateKeyPairResponse, 502 &VerifyGetDaemonConfigResponse, 503 &VerifyGetUsageStatsConsentResponse, 504 &VerifyStopDaemonResponse, 505 &VerifyGetDaemonStateResponse, 506 &VerifyUpdateDaemonConfigResponse, 507 &VerifyStartDaemonResponse, 508 }; 509 ASSERT_EQ(arraysize(verify_routines), static_cast<size_t>(next_id)); 510 511 // Read all responses from output pipe, and verify them. 512 for (int i = 0; i < next_id; ++i) { 513 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe(); 514 515 // Make sure that id is available and is in the range. 516 int id; 517 ASSERT_TRUE(response->GetInteger("id", &id)); 518 ASSERT_TRUE(0 <= id && id < next_id); 519 520 // Call the verification routine corresponding to the message id. 521 ASSERT_TRUE(verify_routines[id]); 522 verify_routines[id](response.Pass()); 523 524 // Clear the pointer so that the routine cannot be called the second time. 525 verify_routines[id] = NULL; 526 } 527} 528 529// Verify that response ID matches request ID. 530TEST_F(Me2MeNativeMessagingHostTest, Id) { 531 base::DictionaryValue message; 532 message.SetString("type", "hello"); 533 WriteMessageToInputPipe(message); 534 message.SetString("id", "42"); 535 WriteMessageToInputPipe(message); 536 537 scoped_ptr<base::DictionaryValue> response = 538 ReadMessageFromOutputPipe(); 539 EXPECT_TRUE(response); 540 std::string value; 541 EXPECT_FALSE(response->GetString("id", &value)); 542 543 response = ReadMessageFromOutputPipe(); 544 EXPECT_TRUE(response); 545 EXPECT_TRUE(response->GetString("id", &value)); 546 EXPECT_EQ("42", value); 547} 548 549// Verify non-Dictionary requests are rejected. 550TEST_F(Me2MeNativeMessagingHostTest, WrongFormat) { 551 base::ListValue message; 552 TestBadRequest(message); 553} 554 555// Verify requests with no type are rejected. 556TEST_F(Me2MeNativeMessagingHostTest, MissingType) { 557 base::DictionaryValue message; 558 TestBadRequest(message); 559} 560 561// Verify rejection if type is unrecognized. 562TEST_F(Me2MeNativeMessagingHostTest, InvalidType) { 563 base::DictionaryValue message; 564 message.SetString("type", "xxx"); 565 TestBadRequest(message); 566} 567 568// Verify rejection if getPinHash request has no hostId. 569TEST_F(Me2MeNativeMessagingHostTest, GetPinHashNoHostId) { 570 base::DictionaryValue message; 571 message.SetString("type", "getPinHash"); 572 message.SetString("pin", "1234"); 573 TestBadRequest(message); 574} 575 576// Verify rejection if getPinHash request has no pin. 577TEST_F(Me2MeNativeMessagingHostTest, GetPinHashNoPin) { 578 base::DictionaryValue message; 579 message.SetString("type", "getPinHash"); 580 message.SetString("hostId", "my_host"); 581 TestBadRequest(message); 582} 583 584// Verify rejection if updateDaemonConfig request has invalid config. 585TEST_F(Me2MeNativeMessagingHostTest, UpdateDaemonConfigInvalidConfig) { 586 base::DictionaryValue message; 587 message.SetString("type", "updateDaemonConfig"); 588 message.SetString("config", "xxx"); 589 TestBadRequest(message); 590} 591 592// Verify rejection if startDaemon request has invalid config. 593TEST_F(Me2MeNativeMessagingHostTest, StartDaemonInvalidConfig) { 594 base::DictionaryValue message; 595 message.SetString("type", "startDaemon"); 596 message.SetString("config", "xxx"); 597 message.SetBoolean("consent", true); 598 TestBadRequest(message); 599} 600 601// Verify rejection if startDaemon request has no "consent" parameter. 602TEST_F(Me2MeNativeMessagingHostTest, StartDaemonNoConsent) { 603 base::DictionaryValue message; 604 message.SetString("type", "startDaemon"); 605 message.Set("config", base::DictionaryValue().DeepCopy()); 606 TestBadRequest(message); 607} 608 609} // namespace remoting 610