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.
5 #include "remoting/host/setup/me2me_native_messaging_host.h"
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"
27 using remoting::protocol::MockPairingRegistryDelegate
;
28 using remoting::protocol::PairingRegistry
;
29 using remoting::protocol::SynchronousPairingRegistry
;
33 void VerifyHelloResponse(scoped_ptr
<base::DictionaryValue
> response
) {
34 ASSERT_TRUE(response
);
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
);
42 void VerifyGetHostNameResponse(scoped_ptr
<base::DictionaryValue
> response
) {
43 ASSERT_TRUE(response
);
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
);
51 void VerifyGetPinHashResponse(scoped_ptr
<base::DictionaryValue
> response
) {
52 ASSERT_TRUE(response
);
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
);
60 void VerifyGenerateKeyPairResponse(scoped_ptr
<base::DictionaryValue
> response
) {
61 ASSERT_TRUE(response
);
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
));
69 void VerifyGetDaemonConfigResponse(scoped_ptr
<base::DictionaryValue
> response
) {
70 ASSERT_TRUE(response
);
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
));
79 void VerifyGetUsageStatsConsentResponse(
80 scoped_ptr
<base::DictionaryValue
> response
) {
81 ASSERT_TRUE(response
);
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
);
91 EXPECT_TRUE(set_by_policy
);
94 void VerifyStopDaemonResponse(scoped_ptr
<base::DictionaryValue
> response
) {
95 ASSERT_TRUE(response
);
97 EXPECT_TRUE(response
->GetString("type", &value
));
98 EXPECT_EQ("stopDaemonResponse", value
);
99 EXPECT_TRUE(response
->GetString("result", &value
));
100 EXPECT_EQ("OK", value
);
103 void VerifyGetDaemonStateResponse(scoped_ptr
<base::DictionaryValue
> response
) {
104 ASSERT_TRUE(response
);
106 EXPECT_TRUE(response
->GetString("type", &value
));
107 EXPECT_EQ("getDaemonStateResponse", value
);
108 EXPECT_TRUE(response
->GetString("state", &value
));
109 EXPECT_EQ("STARTED", value
);
112 void VerifyUpdateDaemonConfigResponse(
113 scoped_ptr
<base::DictionaryValue
> response
) {
114 ASSERT_TRUE(response
);
116 EXPECT_TRUE(response
->GetString("type", &value
));
117 EXPECT_EQ("updateDaemonConfigResponse", value
);
118 EXPECT_TRUE(response
->GetString("result", &value
));
119 EXPECT_EQ("OK", value
);
122 void VerifyStartDaemonResponse(scoped_ptr
<base::DictionaryValue
> response
) {
123 ASSERT_TRUE(response
);
125 EXPECT_TRUE(response
->GetString("type", &value
));
126 EXPECT_EQ("startDaemonResponse", value
);
127 EXPECT_TRUE(response
->GetString("result", &value
));
128 EXPECT_EQ("OK", value
);
135 class MockDaemonControllerDelegate
: public DaemonController::Delegate
{
137 MockDaemonControllerDelegate();
138 ~MockDaemonControllerDelegate() override
;
140 // DaemonController::Delegate interface.
141 DaemonController::State
GetState() override
;
142 scoped_ptr
<base::DictionaryValue
> GetConfig() override
;
143 void InstallHost(const DaemonController::CompletionCallback
& done
) override
;
144 void SetConfigAndStart(
145 scoped_ptr
<base::DictionaryValue
> config
,
147 const DaemonController::CompletionCallback
& done
) override
;
148 void UpdateConfig(scoped_ptr
<base::DictionaryValue
> config
,
149 const DaemonController::CompletionCallback
& done
) override
;
150 void Stop(const DaemonController::CompletionCallback
& done
) override
;
151 void SetWindow(void* window_handle
) override
;
152 std::string
GetVersion() override
;
153 DaemonController::UsageStatsConsent
GetUsageStatsConsent() override
;
156 DISALLOW_COPY_AND_ASSIGN(MockDaemonControllerDelegate
);
159 MockDaemonControllerDelegate::MockDaemonControllerDelegate() {}
161 MockDaemonControllerDelegate::~MockDaemonControllerDelegate() {}
163 DaemonController::State
MockDaemonControllerDelegate::GetState() {
164 return DaemonController::STATE_STARTED
;
167 scoped_ptr
<base::DictionaryValue
> MockDaemonControllerDelegate::GetConfig() {
168 return make_scoped_ptr(new base::DictionaryValue());
171 void MockDaemonControllerDelegate::InstallHost(
172 const DaemonController::CompletionCallback
& done
) {
173 done
.Run(DaemonController::RESULT_OK
);
176 void MockDaemonControllerDelegate::SetConfigAndStart(
177 scoped_ptr
<base::DictionaryValue
> config
,
179 const DaemonController::CompletionCallback
& done
) {
181 // Verify parameters passed in.
182 if (consent
&& config
&& config
->HasKey("start")) {
183 done
.Run(DaemonController::RESULT_OK
);
185 done
.Run(DaemonController::RESULT_FAILED
);
189 void MockDaemonControllerDelegate::UpdateConfig(
190 scoped_ptr
<base::DictionaryValue
> config
,
191 const DaemonController::CompletionCallback
& done
) {
192 if (config
&& config
->HasKey("update")) {
193 done
.Run(DaemonController::RESULT_OK
);
195 done
.Run(DaemonController::RESULT_FAILED
);
199 void MockDaemonControllerDelegate::Stop(
200 const DaemonController::CompletionCallback
& done
) {
201 done
.Run(DaemonController::RESULT_OK
);
204 void MockDaemonControllerDelegate::SetWindow(void* window_handle
) {}
206 std::string
MockDaemonControllerDelegate::GetVersion() {
207 // Unused - Me2MeNativeMessagingHost returns the compiled-in version string
208 // instead of calling this method.
210 return std::string();
213 DaemonController::UsageStatsConsent
214 MockDaemonControllerDelegate::GetUsageStatsConsent() {
215 DaemonController::UsageStatsConsent consent
;
216 consent
.supported
= true;
217 consent
.allowed
= true;
218 consent
.set_by_policy
= true;
222 class Me2MeNativeMessagingHostTest
: public testing::Test
{
224 Me2MeNativeMessagingHostTest();
225 ~Me2MeNativeMessagingHostTest() override
;
227 void SetUp() override
;
228 void TearDown() override
;
230 scoped_ptr
<base::DictionaryValue
> ReadMessageFromOutputPipe();
232 void WriteMessageToInputPipe(const base::Value
& message
);
234 // The Host process should shut down when it receives a malformed request.
235 // This is tested by sending a known-good request, followed by |message|,
236 // followed by the known-good request again. The response file should only
237 // contain a single response from the first good request.
238 void TestBadRequest(const base::Value
& message
);
241 // Reference to the MockDaemonControllerDelegate, which is owned by
243 MockDaemonControllerDelegate
* daemon_controller_delegate_
;
250 // Each test creates two unidirectional pipes: "input" and "output".
251 // Me2MeNativeMessagingHost reads from input_read_handle and writes to
252 // output_write_file. The unittest supplies data to input_write_handle, and
253 // verifies output from output_read_handle.
255 // unittest -> [input] -> Me2MeNativeMessagingHost -> [output] -> unittest
256 base::File input_write_file_
;
257 base::File output_read_file_
;
259 // Message loop of the test thread.
260 scoped_ptr
<base::MessageLoop
> test_message_loop_
;
261 scoped_ptr
<base::RunLoop
> test_run_loop_
;
263 scoped_ptr
<base::Thread
> host_thread_
;
264 scoped_ptr
<base::RunLoop
> host_run_loop_
;
266 // Task runner of the host thread.
267 scoped_refptr
<AutoThreadTaskRunner
> host_task_runner_
;
268 scoped_ptr
<remoting::Me2MeNativeMessagingHost
> host_
;
270 DISALLOW_COPY_AND_ASSIGN(Me2MeNativeMessagingHostTest
);
273 Me2MeNativeMessagingHostTest::Me2MeNativeMessagingHostTest() {}
275 Me2MeNativeMessagingHostTest::~Me2MeNativeMessagingHostTest() {}
277 void Me2MeNativeMessagingHostTest::SetUp() {
278 base::File input_read_file
;
279 base::File output_write_file
;
281 ASSERT_TRUE(MakePipe(&input_read_file
, &input_write_file_
));
282 ASSERT_TRUE(MakePipe(&output_read_file_
, &output_write_file
));
284 test_message_loop_
.reset(new base::MessageLoop());
285 test_run_loop_
.reset(new base::RunLoop());
287 // Run the host on a dedicated thread.
288 host_thread_
.reset(new base::Thread("host_thread"));
289 host_thread_
->Start();
291 // Arrange to run |test_message_loop_| until no components depend on it.
292 host_task_runner_
= new AutoThreadTaskRunner(
293 host_thread_
->message_loop_proxy(),
294 base::Bind(&Me2MeNativeMessagingHostTest::ExitTest
,
295 base::Unretained(this)));
297 host_task_runner_
->PostTask(
299 base::Bind(&Me2MeNativeMessagingHostTest::StartHost
,
300 base::Unretained(this)));
302 // Wait until the host finishes starting.
303 test_run_loop_
->Run();
306 void Me2MeNativeMessagingHostTest::StartHost() {
307 DCHECK(host_task_runner_
->RunsTasksOnCurrentThread());
309 base::File input_read_file
;
310 base::File output_write_file
;
312 ASSERT_TRUE(MakePipe(&input_read_file
, &input_write_file_
));
313 ASSERT_TRUE(MakePipe(&output_read_file_
, &output_write_file
));
315 daemon_controller_delegate_
= new MockDaemonControllerDelegate();
316 scoped_refptr
<DaemonController
> daemon_controller(
317 new DaemonController(make_scoped_ptr(daemon_controller_delegate_
)));
319 scoped_refptr
<PairingRegistry
> pairing_registry
=
320 new SynchronousPairingRegistry(
321 make_scoped_ptr(new MockPairingRegistryDelegate()));
323 scoped_ptr
<extensions::NativeMessagingChannel
> channel(
324 new PipeMessagingChannel(input_read_file
.Pass(),
325 output_write_file
.Pass()));
327 host_
.reset(new Me2MeNativeMessagingHost(
328 false, 0, channel
.Pass(), daemon_controller
, pairing_registry
, nullptr));
329 host_
->Start(base::Bind(&Me2MeNativeMessagingHostTest::StopHost
,
330 base::Unretained(this)));
332 // Notify the test that the host has finished starting up.
333 test_message_loop_
->message_loop_proxy()->PostTask(
334 FROM_HERE
, test_run_loop_
->QuitClosure());
337 void Me2MeNativeMessagingHostTest::StopHost() {
338 DCHECK(host_task_runner_
->RunsTasksOnCurrentThread());
342 // Wait till all shutdown tasks have completed.
343 base::RunLoop().RunUntilIdle();
345 // Trigger a test shutdown via ExitTest().
346 host_task_runner_
= NULL
;
349 void Me2MeNativeMessagingHostTest::ExitTest() {
350 if (!test_message_loop_
->message_loop_proxy()->RunsTasksOnCurrentThread()) {
351 test_message_loop_
->message_loop_proxy()->PostTask(
353 base::Bind(&Me2MeNativeMessagingHostTest::ExitTest
,
354 base::Unretained(this)));
357 test_run_loop_
->Quit();
360 void Me2MeNativeMessagingHostTest::TearDown() {
361 // Closing the write-end of the input will send an EOF to the native
362 // messaging reader. This will trigger a host shutdown.
363 input_write_file_
.Close();
365 // Start a new RunLoop and Wait until the host finishes shutting down.
366 test_run_loop_
.reset(new base::RunLoop());
367 test_run_loop_
->Run();
369 // Verify there are no more message in the output pipe.
370 scoped_ptr
<base::DictionaryValue
> response
= ReadMessageFromOutputPipe();
371 EXPECT_FALSE(response
);
373 // The It2MeMe2MeNativeMessagingHost dtor closes the handles that are passed
374 // to it. So the only handle left to close is |output_read_file_|.
375 output_read_file_
.Close();
378 scoped_ptr
<base::DictionaryValue
>
379 Me2MeNativeMessagingHostTest::ReadMessageFromOutputPipe() {
381 int read_result
= output_read_file_
.ReadAtCurrentPos(
382 reinterpret_cast<char*>(&length
), sizeof(length
));
383 if (read_result
!= sizeof(length
)) {
387 std::string
message_json(length
, '\0');
388 read_result
= output_read_file_
.ReadAtCurrentPos(
389 string_as_array(&message_json
), length
);
390 if (read_result
!= static_cast<int>(length
)) {
394 scoped_ptr
<base::Value
> message(base::JSONReader::Read(message_json
));
395 if (!message
|| !message
->IsType(base::Value::TYPE_DICTIONARY
)) {
399 return make_scoped_ptr(
400 static_cast<base::DictionaryValue
*>(message
.release()));
403 void Me2MeNativeMessagingHostTest::WriteMessageToInputPipe(
404 const base::Value
& message
) {
405 std::string message_json
;
406 base::JSONWriter::Write(&message
, &message_json
);
408 uint32 length
= message_json
.length();
409 input_write_file_
.WriteAtCurrentPos(reinterpret_cast<char*>(&length
),
411 input_write_file_
.WriteAtCurrentPos(message_json
.data(), length
);
414 void Me2MeNativeMessagingHostTest::TestBadRequest(const base::Value
& message
) {
415 base::DictionaryValue good_message
;
416 good_message
.SetString("type", "hello");
418 // This test currently relies on synchronous processing of hello messages and
419 // message parameters verification.
420 WriteMessageToInputPipe(good_message
);
421 WriteMessageToInputPipe(message
);
422 WriteMessageToInputPipe(good_message
);
424 // Read from output pipe, and verify responses.
425 scoped_ptr
<base::DictionaryValue
> response
= ReadMessageFromOutputPipe();
426 VerifyHelloResponse(response
.Pass());
428 response
= ReadMessageFromOutputPipe();
429 EXPECT_FALSE(response
);
432 // TODO (weitaosu): crbug.com/323306. Re-enable these tests.
433 // Test all valid request-types.
434 TEST_F(Me2MeNativeMessagingHostTest
, All
) {
436 base::DictionaryValue message
;
437 message
.SetInteger("id", next_id
++);
438 message
.SetString("type", "hello");
439 WriteMessageToInputPipe(message
);
441 message
.SetInteger("id", next_id
++);
442 message
.SetString("type", "getHostName");
443 WriteMessageToInputPipe(message
);
445 message
.SetInteger("id", next_id
++);
446 message
.SetString("type", "getPinHash");
447 message
.SetString("hostId", "my_host");
448 message
.SetString("pin", "1234");
449 WriteMessageToInputPipe(message
);
452 message
.SetInteger("id", next_id
++);
453 message
.SetString("type", "generateKeyPair");
454 WriteMessageToInputPipe(message
);
456 message
.SetInteger("id", next_id
++);
457 message
.SetString("type", "getDaemonConfig");
458 WriteMessageToInputPipe(message
);
460 message
.SetInteger("id", next_id
++);
461 message
.SetString("type", "getUsageStatsConsent");
462 WriteMessageToInputPipe(message
);
464 message
.SetInteger("id", next_id
++);
465 message
.SetString("type", "stopDaemon");
466 WriteMessageToInputPipe(message
);
468 message
.SetInteger("id", next_id
++);
469 message
.SetString("type", "getDaemonState");
470 WriteMessageToInputPipe(message
);
472 // Following messages require a "config" dictionary.
473 base::DictionaryValue config
;
474 config
.SetBoolean("update", true);
475 message
.Set("config", config
.DeepCopy());
476 message
.SetInteger("id", next_id
++);
477 message
.SetString("type", "updateDaemonConfig");
478 WriteMessageToInputPipe(message
);
481 config
.SetBoolean("start", true);
482 message
.Set("config", config
.DeepCopy());
483 message
.SetBoolean("consent", true);
484 message
.SetInteger("id", next_id
++);
485 message
.SetString("type", "startDaemon");
486 WriteMessageToInputPipe(message
);
488 void (*verify_routines
[])(scoped_ptr
<base::DictionaryValue
>) = {
489 &VerifyHelloResponse
,
490 &VerifyGetHostNameResponse
,
491 &VerifyGetPinHashResponse
,
492 &VerifyGenerateKeyPairResponse
,
493 &VerifyGetDaemonConfigResponse
,
494 &VerifyGetUsageStatsConsentResponse
,
495 &VerifyStopDaemonResponse
,
496 &VerifyGetDaemonStateResponse
,
497 &VerifyUpdateDaemonConfigResponse
,
498 &VerifyStartDaemonResponse
,
500 ASSERT_EQ(arraysize(verify_routines
), static_cast<size_t>(next_id
));
502 // Read all responses from output pipe, and verify them.
503 for (int i
= 0; i
< next_id
; ++i
) {
504 scoped_ptr
<base::DictionaryValue
> response
= ReadMessageFromOutputPipe();
506 // Make sure that id is available and is in the range.
508 ASSERT_TRUE(response
->GetInteger("id", &id
));
509 ASSERT_TRUE(0 <= id
&& id
< next_id
);
511 // Call the verification routine corresponding to the message id.
512 ASSERT_TRUE(verify_routines
[id
]);
513 verify_routines
[id
](response
.Pass());
515 // Clear the pointer so that the routine cannot be called the second time.
516 verify_routines
[id
] = NULL
;
520 // Verify that response ID matches request ID.
521 TEST_F(Me2MeNativeMessagingHostTest
, Id
) {
522 base::DictionaryValue message
;
523 message
.SetString("type", "hello");
524 WriteMessageToInputPipe(message
);
525 message
.SetString("id", "42");
526 WriteMessageToInputPipe(message
);
528 scoped_ptr
<base::DictionaryValue
> response
= ReadMessageFromOutputPipe();
529 EXPECT_TRUE(response
);
531 EXPECT_FALSE(response
->GetString("id", &value
));
533 response
= ReadMessageFromOutputPipe();
534 EXPECT_TRUE(response
);
535 EXPECT_TRUE(response
->GetString("id", &value
));
536 EXPECT_EQ("42", value
);
539 // Verify non-Dictionary requests are rejected.
540 TEST_F(Me2MeNativeMessagingHostTest
, WrongFormat
) {
541 base::ListValue message
;
542 TestBadRequest(message
);
545 // Verify requests with no type are rejected.
546 TEST_F(Me2MeNativeMessagingHostTest
, MissingType
) {
547 base::DictionaryValue message
;
548 TestBadRequest(message
);
551 // Verify rejection if type is unrecognized.
552 TEST_F(Me2MeNativeMessagingHostTest
, InvalidType
) {
553 base::DictionaryValue message
;
554 message
.SetString("type", "xxx");
555 TestBadRequest(message
);
558 // Verify rejection if getPinHash request has no hostId.
559 TEST_F(Me2MeNativeMessagingHostTest
, GetPinHashNoHostId
) {
560 base::DictionaryValue message
;
561 message
.SetString("type", "getPinHash");
562 message
.SetString("pin", "1234");
563 TestBadRequest(message
);
566 // Verify rejection if getPinHash request has no pin.
567 TEST_F(Me2MeNativeMessagingHostTest
, GetPinHashNoPin
) {
568 base::DictionaryValue message
;
569 message
.SetString("type", "getPinHash");
570 message
.SetString("hostId", "my_host");
571 TestBadRequest(message
);
574 // Verify rejection if updateDaemonConfig request has invalid config.
575 TEST_F(Me2MeNativeMessagingHostTest
, UpdateDaemonConfigInvalidConfig
) {
576 base::DictionaryValue message
;
577 message
.SetString("type", "updateDaemonConfig");
578 message
.SetString("config", "xxx");
579 TestBadRequest(message
);
582 // Verify rejection if startDaemon request has invalid config.
583 TEST_F(Me2MeNativeMessagingHostTest
, StartDaemonInvalidConfig
) {
584 base::DictionaryValue message
;
585 message
.SetString("type", "startDaemon");
586 message
.SetString("config", "xxx");
587 message
.SetBoolean("consent", true);
588 TestBadRequest(message
);
591 // Verify rejection if startDaemon request has no "consent" parameter.
592 TEST_F(Me2MeNativeMessagingHostTest
, StartDaemonNoConsent
) {
593 base::DictionaryValue message
;
594 message
.SetString("type", "startDaemon");
595 message
.Set("config", base::DictionaryValue().DeepCopy());
596 TestBadRequest(message
);
599 } // namespace remoting