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/log_message_handler.h"
21 #include "remoting/host/native_messaging/pipe_messaging_channel.h"
22 #include "remoting/host/pin_hash.h"
23 #include "remoting/host/setup/mock_oauth_client.h"
24 #include "remoting/host/setup/test_util.h"
25 #include "remoting/protocol/pairing_registry.h"
26 #include "remoting/protocol/protocol_mock_objects.h"
27 #include "testing/gtest/include/gtest/gtest.h"
29 using remoting::protocol::MockPairingRegistryDelegate
;
30 using remoting::protocol::PairingRegistry
;
31 using remoting::protocol::SynchronousPairingRegistry
;
35 void VerifyHelloResponse(scoped_ptr
<base::DictionaryValue
> response
) {
36 ASSERT_TRUE(response
);
38 EXPECT_TRUE(response
->GetString("type", &value
));
39 EXPECT_EQ("helloResponse", value
);
40 EXPECT_TRUE(response
->GetString("version", &value
));
42 // The check below will compile but fail if VERSION isn't defined (STRINGIZE
43 // silently converts undefined values).
45 #error VERSION must be defined
47 EXPECT_EQ(STRINGIZE(VERSION
), value
);
50 void VerifyGetHostNameResponse(scoped_ptr
<base::DictionaryValue
> response
) {
51 ASSERT_TRUE(response
);
53 EXPECT_TRUE(response
->GetString("type", &value
));
54 EXPECT_EQ("getHostNameResponse", value
);
55 EXPECT_TRUE(response
->GetString("hostname", &value
));
56 EXPECT_EQ(net::GetHostName(), value
);
59 void VerifyGetPinHashResponse(scoped_ptr
<base::DictionaryValue
> response
) {
60 ASSERT_TRUE(response
);
62 EXPECT_TRUE(response
->GetString("type", &value
));
63 EXPECT_EQ("getPinHashResponse", value
);
64 EXPECT_TRUE(response
->GetString("hash", &value
));
65 EXPECT_EQ(remoting::MakeHostPinHash("my_host", "1234"), value
);
68 void VerifyGenerateKeyPairResponse(scoped_ptr
<base::DictionaryValue
> response
) {
69 ASSERT_TRUE(response
);
71 EXPECT_TRUE(response
->GetString("type", &value
));
72 EXPECT_EQ("generateKeyPairResponse", value
);
73 EXPECT_TRUE(response
->GetString("privateKey", &value
));
74 EXPECT_TRUE(response
->GetString("publicKey", &value
));
77 void VerifyGetDaemonConfigResponse(scoped_ptr
<base::DictionaryValue
> response
) {
78 ASSERT_TRUE(response
);
80 EXPECT_TRUE(response
->GetString("type", &value
));
81 EXPECT_EQ("getDaemonConfigResponse", value
);
82 const base::DictionaryValue
* config
= nullptr;
83 EXPECT_TRUE(response
->GetDictionary("config", &config
));
84 EXPECT_TRUE(base::DictionaryValue().Equals(config
));
87 void VerifyGetUsageStatsConsentResponse(
88 scoped_ptr
<base::DictionaryValue
> response
) {
89 ASSERT_TRUE(response
);
91 EXPECT_TRUE(response
->GetString("type", &value
));
92 EXPECT_EQ("getUsageStatsConsentResponse", value
);
93 bool supported
, allowed
, set_by_policy
;
94 EXPECT_TRUE(response
->GetBoolean("supported", &supported
));
95 EXPECT_TRUE(response
->GetBoolean("allowed", &allowed
));
96 EXPECT_TRUE(response
->GetBoolean("setByPolicy", &set_by_policy
));
97 EXPECT_TRUE(supported
);
99 EXPECT_TRUE(set_by_policy
);
102 void VerifyStopDaemonResponse(scoped_ptr
<base::DictionaryValue
> response
) {
103 ASSERT_TRUE(response
);
105 EXPECT_TRUE(response
->GetString("type", &value
));
106 EXPECT_EQ("stopDaemonResponse", value
);
107 EXPECT_TRUE(response
->GetString("result", &value
));
108 EXPECT_EQ("OK", value
);
111 void VerifyGetDaemonStateResponse(scoped_ptr
<base::DictionaryValue
> response
) {
112 ASSERT_TRUE(response
);
114 EXPECT_TRUE(response
->GetString("type", &value
));
115 EXPECT_EQ("getDaemonStateResponse", value
);
116 EXPECT_TRUE(response
->GetString("state", &value
));
117 EXPECT_EQ("STARTED", value
);
120 void VerifyUpdateDaemonConfigResponse(
121 scoped_ptr
<base::DictionaryValue
> response
) {
122 ASSERT_TRUE(response
);
124 EXPECT_TRUE(response
->GetString("type", &value
));
125 EXPECT_EQ("updateDaemonConfigResponse", value
);
126 EXPECT_TRUE(response
->GetString("result", &value
));
127 EXPECT_EQ("OK", value
);
130 void VerifyStartDaemonResponse(scoped_ptr
<base::DictionaryValue
> response
) {
131 ASSERT_TRUE(response
);
133 EXPECT_TRUE(response
->GetString("type", &value
));
134 EXPECT_EQ("startDaemonResponse", value
);
135 EXPECT_TRUE(response
->GetString("result", &value
));
136 EXPECT_EQ("OK", value
);
139 void VerifyGetCredentialsFromAuthCodeResponse(
140 scoped_ptr
<base::DictionaryValue
> response
) {
141 ASSERT_TRUE(response
);
143 EXPECT_TRUE(response
->GetString("type", &value
));
144 EXPECT_EQ("getCredentialsFromAuthCodeResponse", value
);
145 EXPECT_TRUE(response
->GetString("userEmail", &value
));
146 EXPECT_EQ("fake_user_email", value
);
147 EXPECT_TRUE(response
->GetString("refreshToken", &value
));
148 EXPECT_EQ("fake_refresh_token", value
);
155 class MockDaemonControllerDelegate
: public DaemonController::Delegate
{
157 MockDaemonControllerDelegate();
158 ~MockDaemonControllerDelegate() override
;
160 // DaemonController::Delegate interface.
161 DaemonController::State
GetState() override
;
162 scoped_ptr
<base::DictionaryValue
> GetConfig() override
;
163 void SetConfigAndStart(
164 scoped_ptr
<base::DictionaryValue
> config
,
166 const DaemonController::CompletionCallback
& done
) override
;
167 void UpdateConfig(scoped_ptr
<base::DictionaryValue
> config
,
168 const DaemonController::CompletionCallback
& done
) override
;
169 void Stop(const DaemonController::CompletionCallback
& done
) override
;
170 DaemonController::UsageStatsConsent
GetUsageStatsConsent() override
;
173 DISALLOW_COPY_AND_ASSIGN(MockDaemonControllerDelegate
);
176 MockDaemonControllerDelegate::MockDaemonControllerDelegate() {}
178 MockDaemonControllerDelegate::~MockDaemonControllerDelegate() {}
180 DaemonController::State
MockDaemonControllerDelegate::GetState() {
181 return DaemonController::STATE_STARTED
;
184 scoped_ptr
<base::DictionaryValue
> MockDaemonControllerDelegate::GetConfig() {
185 return make_scoped_ptr(new base::DictionaryValue());
188 void MockDaemonControllerDelegate::SetConfigAndStart(
189 scoped_ptr
<base::DictionaryValue
> config
,
191 const DaemonController::CompletionCallback
& done
) {
193 // Verify parameters passed in.
194 if (consent
&& config
&& config
->HasKey("start")) {
195 done
.Run(DaemonController::RESULT_OK
);
197 done
.Run(DaemonController::RESULT_FAILED
);
201 void MockDaemonControllerDelegate::UpdateConfig(
202 scoped_ptr
<base::DictionaryValue
> config
,
203 const DaemonController::CompletionCallback
& done
) {
204 if (config
&& config
->HasKey("update")) {
205 done
.Run(DaemonController::RESULT_OK
);
207 done
.Run(DaemonController::RESULT_FAILED
);
211 void MockDaemonControllerDelegate::Stop(
212 const DaemonController::CompletionCallback
& done
) {
213 done
.Run(DaemonController::RESULT_OK
);
216 DaemonController::UsageStatsConsent
217 MockDaemonControllerDelegate::GetUsageStatsConsent() {
218 DaemonController::UsageStatsConsent consent
;
219 consent
.supported
= true;
220 consent
.allowed
= true;
221 consent
.set_by_policy
= true;
225 class Me2MeNativeMessagingHostTest
: public testing::Test
{
227 Me2MeNativeMessagingHostTest();
228 ~Me2MeNativeMessagingHostTest() override
;
230 void SetUp() override
;
231 void TearDown() override
;
233 scoped_ptr
<base::DictionaryValue
> ReadMessageFromOutputPipe();
235 void WriteMessageToInputPipe(const base::Value
& message
);
237 // The Host process should shut down when it receives a malformed request.
238 // This is tested by sending a known-good request, followed by |message|,
239 // followed by the known-good request again. The response file should only
240 // contain a single response from the first good request.
241 void TestBadRequest(const base::Value
& message
);
244 // Reference to the MockDaemonControllerDelegate, which is owned by
246 MockDaemonControllerDelegate
* daemon_controller_delegate_
;
253 // Each test creates two unidirectional pipes: "input" and "output".
254 // Me2MeNativeMessagingHost reads from input_read_handle and writes to
255 // output_write_file. The unittest supplies data to input_write_handle, and
256 // verifies output from output_read_handle.
258 // unittest -> [input] -> Me2MeNativeMessagingHost -> [output] -> unittest
259 base::File input_write_file_
;
260 base::File output_read_file_
;
262 // Message loop of the test thread.
263 scoped_ptr
<base::MessageLoop
> test_message_loop_
;
264 scoped_ptr
<base::RunLoop
> test_run_loop_
;
266 scoped_ptr
<base::Thread
> host_thread_
;
267 scoped_ptr
<base::RunLoop
> host_run_loop_
;
269 // Task runner of the host thread.
270 scoped_refptr
<AutoThreadTaskRunner
> host_task_runner_
;
271 scoped_ptr
<remoting::Me2MeNativeMessagingHost
> host_
;
273 DISALLOW_COPY_AND_ASSIGN(Me2MeNativeMessagingHostTest
);
276 Me2MeNativeMessagingHostTest::Me2MeNativeMessagingHostTest() {}
278 Me2MeNativeMessagingHostTest::~Me2MeNativeMessagingHostTest() {}
280 void Me2MeNativeMessagingHostTest::SetUp() {
281 base::File input_read_file
;
282 base::File output_write_file
;
284 ASSERT_TRUE(MakePipe(&input_read_file
, &input_write_file_
));
285 ASSERT_TRUE(MakePipe(&output_read_file_
, &output_write_file
));
287 test_message_loop_
.reset(new base::MessageLoop());
288 test_run_loop_
.reset(new base::RunLoop());
290 // Run the host on a dedicated thread.
291 host_thread_
.reset(new base::Thread("host_thread"));
292 host_thread_
->Start();
294 // Arrange to run |test_message_loop_| until no components depend on it.
295 host_task_runner_
= new AutoThreadTaskRunner(
296 host_thread_
->task_runner(),
297 base::Bind(&Me2MeNativeMessagingHostTest::ExitTest
,
298 base::Unretained(this)));
300 host_task_runner_
->PostTask(
302 base::Bind(&Me2MeNativeMessagingHostTest::StartHost
,
303 base::Unretained(this)));
305 // Wait until the host finishes starting.
306 test_run_loop_
->Run();
309 void Me2MeNativeMessagingHostTest::StartHost() {
310 DCHECK(host_task_runner_
->RunsTasksOnCurrentThread());
312 base::File input_read_file
;
313 base::File output_write_file
;
315 ASSERT_TRUE(MakePipe(&input_read_file
, &input_write_file_
));
316 ASSERT_TRUE(MakePipe(&output_read_file_
, &output_write_file
));
318 daemon_controller_delegate_
= new MockDaemonControllerDelegate();
319 scoped_refptr
<DaemonController
> daemon_controller(
320 new DaemonController(make_scoped_ptr(daemon_controller_delegate_
)));
322 scoped_refptr
<PairingRegistry
> pairing_registry
=
323 new SynchronousPairingRegistry(
324 make_scoped_ptr(new MockPairingRegistryDelegate()));
326 scoped_ptr
<extensions::NativeMessagingChannel
> channel(
327 new PipeMessagingChannel(input_read_file
.Pass(),
328 output_write_file
.Pass()));
330 scoped_ptr
<OAuthClient
> oauth_client(
331 new MockOAuthClient("fake_user_email", "fake_refresh_token"));
333 host_
.reset(new Me2MeNativeMessagingHost(false, 0, channel
.Pass(),
334 daemon_controller
, pairing_registry
,
335 oauth_client
.Pass()));
336 host_
->Start(base::Bind(&Me2MeNativeMessagingHostTest::StopHost
,
337 base::Unretained(this)));
339 // Notify the test that the host has finished starting up.
340 test_message_loop_
->task_runner()->PostTask(
341 FROM_HERE
, test_run_loop_
->QuitClosure());
344 void Me2MeNativeMessagingHostTest::StopHost() {
345 DCHECK(host_task_runner_
->RunsTasksOnCurrentThread());
349 // Wait till all shutdown tasks have completed.
350 base::RunLoop().RunUntilIdle();
352 // Trigger a test shutdown via ExitTest().
353 host_task_runner_
= nullptr;
356 void Me2MeNativeMessagingHostTest::ExitTest() {
357 if (!test_message_loop_
->task_runner()->RunsTasksOnCurrentThread()) {
358 test_message_loop_
->task_runner()->PostTask(
360 base::Bind(&Me2MeNativeMessagingHostTest::ExitTest
,
361 base::Unretained(this)));
364 test_run_loop_
->Quit();
367 void Me2MeNativeMessagingHostTest::TearDown() {
368 // Closing the write-end of the input will send an EOF to the native
369 // messaging reader. This will trigger a host shutdown.
370 input_write_file_
.Close();
372 // Start a new RunLoop and Wait until the host finishes shutting down.
373 test_run_loop_
.reset(new base::RunLoop());
374 test_run_loop_
->Run();
376 // Verify there are no more message in the output pipe.
377 scoped_ptr
<base::DictionaryValue
> response
= ReadMessageFromOutputPipe();
378 EXPECT_FALSE(response
);
380 // The It2MeMe2MeNativeMessagingHost dtor closes the handles that are passed
381 // to it. So the only handle left to close is |output_read_file_|.
382 output_read_file_
.Close();
385 scoped_ptr
<base::DictionaryValue
>
386 Me2MeNativeMessagingHostTest::ReadMessageFromOutputPipe() {
389 int read_result
= output_read_file_
.ReadAtCurrentPos(
390 reinterpret_cast<char*>(&length
), sizeof(length
));
391 if (read_result
!= sizeof(length
)) {
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
)) {
402 scoped_ptr
<base::Value
> message
= base::JSONReader::Read(message_json
);
403 if (!message
|| !message
->IsType(base::Value::TYPE_DICTIONARY
)) {
407 scoped_ptr
<base::DictionaryValue
> result
= make_scoped_ptr(
408 static_cast<base::DictionaryValue
*>(message
.release()));
410 // If this is a debug message log, ignore it, otherwise return it.
411 if (!result
->GetString("type", &type
) ||
412 type
!= LogMessageHandler::kDebugMessageTypeName
) {
418 void Me2MeNativeMessagingHostTest::WriteMessageToInputPipe(
419 const base::Value
& message
) {
420 std::string message_json
;
421 base::JSONWriter::Write(message
, &message_json
);
423 uint32 length
= message_json
.length();
424 input_write_file_
.WriteAtCurrentPos(reinterpret_cast<char*>(&length
),
426 input_write_file_
.WriteAtCurrentPos(message_json
.data(), length
);
429 void Me2MeNativeMessagingHostTest::TestBadRequest(const base::Value
& message
) {
430 base::DictionaryValue good_message
;
431 good_message
.SetString("type", "hello");
433 // This test currently relies on synchronous processing of hello messages and
434 // message parameters verification.
435 WriteMessageToInputPipe(good_message
);
436 WriteMessageToInputPipe(message
);
437 WriteMessageToInputPipe(good_message
);
439 // Read from output pipe, and verify responses.
440 scoped_ptr
<base::DictionaryValue
> response
= ReadMessageFromOutputPipe();
441 VerifyHelloResponse(response
.Pass());
443 response
= ReadMessageFromOutputPipe();
444 EXPECT_FALSE(response
);
447 // TODO (weitaosu): crbug.com/323306. Re-enable these tests.
448 // Test all valid request-types.
449 TEST_F(Me2MeNativeMessagingHostTest
, All
) {
451 base::DictionaryValue message
;
452 message
.SetInteger("id", next_id
++);
453 message
.SetString("type", "hello");
454 WriteMessageToInputPipe(message
);
456 message
.SetInteger("id", next_id
++);
457 message
.SetString("type", "getHostName");
458 WriteMessageToInputPipe(message
);
460 message
.SetInteger("id", next_id
++);
461 message
.SetString("type", "getPinHash");
462 message
.SetString("hostId", "my_host");
463 message
.SetString("pin", "1234");
464 WriteMessageToInputPipe(message
);
467 message
.SetInteger("id", next_id
++);
468 message
.SetString("type", "generateKeyPair");
469 WriteMessageToInputPipe(message
);
471 message
.SetInteger("id", next_id
++);
472 message
.SetString("type", "getDaemonConfig");
473 WriteMessageToInputPipe(message
);
475 message
.SetInteger("id", next_id
++);
476 message
.SetString("type", "getUsageStatsConsent");
477 WriteMessageToInputPipe(message
);
479 message
.SetInteger("id", next_id
++);
480 message
.SetString("type", "stopDaemon");
481 WriteMessageToInputPipe(message
);
483 message
.SetInteger("id", next_id
++);
484 message
.SetString("type", "getDaemonState");
485 WriteMessageToInputPipe(message
);
487 // Following messages require a "config" dictionary.
488 base::DictionaryValue config
;
489 config
.SetBoolean("update", true);
490 message
.Set("config", config
.DeepCopy());
491 message
.SetInteger("id", next_id
++);
492 message
.SetString("type", "updateDaemonConfig");
493 WriteMessageToInputPipe(message
);
496 config
.SetBoolean("start", true);
497 message
.Set("config", config
.DeepCopy());
498 message
.SetBoolean("consent", true);
499 message
.SetInteger("id", next_id
++);
500 message
.SetString("type", "startDaemon");
501 WriteMessageToInputPipe(message
);
503 message
.SetInteger("id", next_id
++);
504 message
.SetString("type", "getCredentialsFromAuthCode");
505 message
.SetString("authorizationCode", "fake_auth_code");
506 WriteMessageToInputPipe(message
);
508 void (*verify_routines
[])(scoped_ptr
<base::DictionaryValue
>) = {
509 &VerifyHelloResponse
,
510 &VerifyGetHostNameResponse
,
511 &VerifyGetPinHashResponse
,
512 &VerifyGenerateKeyPairResponse
,
513 &VerifyGetDaemonConfigResponse
,
514 &VerifyGetUsageStatsConsentResponse
,
515 &VerifyStopDaemonResponse
,
516 &VerifyGetDaemonStateResponse
,
517 &VerifyUpdateDaemonConfigResponse
,
518 &VerifyStartDaemonResponse
,
519 &VerifyGetCredentialsFromAuthCodeResponse
,
521 ASSERT_EQ(arraysize(verify_routines
), static_cast<size_t>(next_id
));
523 // Read all responses from output pipe, and verify them.
524 for (int i
= 0; i
< next_id
; ++i
) {
525 scoped_ptr
<base::DictionaryValue
> response
= ReadMessageFromOutputPipe();
527 // Make sure that id is available and is in the range.
529 ASSERT_TRUE(response
->GetInteger("id", &id
));
530 ASSERT_TRUE(0 <= id
&& id
< next_id
);
532 // Call the verification routine corresponding to the message id.
533 ASSERT_TRUE(verify_routines
[id
]);
534 verify_routines
[id
](response
.Pass());
536 // Clear the pointer so that the routine cannot be called the second time.
537 verify_routines
[id
] = nullptr;
541 // Verify that response ID matches request ID.
542 TEST_F(Me2MeNativeMessagingHostTest
, Id
) {
543 base::DictionaryValue message
;
544 message
.SetString("type", "hello");
545 WriteMessageToInputPipe(message
);
546 message
.SetString("id", "42");
547 WriteMessageToInputPipe(message
);
549 scoped_ptr
<base::DictionaryValue
> response
= ReadMessageFromOutputPipe();
550 EXPECT_TRUE(response
);
552 EXPECT_FALSE(response
->GetString("id", &value
));
554 response
= ReadMessageFromOutputPipe();
555 EXPECT_TRUE(response
);
556 EXPECT_TRUE(response
->GetString("id", &value
));
557 EXPECT_EQ("42", value
);
560 // Verify non-Dictionary requests are rejected.
561 TEST_F(Me2MeNativeMessagingHostTest
, WrongFormat
) {
562 base::ListValue message
;
563 TestBadRequest(message
);
566 // Verify requests with no type are rejected.
567 TEST_F(Me2MeNativeMessagingHostTest
, MissingType
) {
568 base::DictionaryValue message
;
569 TestBadRequest(message
);
572 // Verify rejection if type is unrecognized.
573 TEST_F(Me2MeNativeMessagingHostTest
, InvalidType
) {
574 base::DictionaryValue message
;
575 message
.SetString("type", "xxx");
576 TestBadRequest(message
);
579 // Verify rejection if getPinHash request has no hostId.
580 TEST_F(Me2MeNativeMessagingHostTest
, GetPinHashNoHostId
) {
581 base::DictionaryValue message
;
582 message
.SetString("type", "getPinHash");
583 message
.SetString("pin", "1234");
584 TestBadRequest(message
);
587 // Verify rejection if getPinHash request has no pin.
588 TEST_F(Me2MeNativeMessagingHostTest
, GetPinHashNoPin
) {
589 base::DictionaryValue message
;
590 message
.SetString("type", "getPinHash");
591 message
.SetString("hostId", "my_host");
592 TestBadRequest(message
);
595 // Verify rejection if updateDaemonConfig request has invalid config.
596 TEST_F(Me2MeNativeMessagingHostTest
, UpdateDaemonConfigInvalidConfig
) {
597 base::DictionaryValue message
;
598 message
.SetString("type", "updateDaemonConfig");
599 message
.SetString("config", "xxx");
600 TestBadRequest(message
);
603 // Verify rejection if startDaemon request has invalid config.
604 TEST_F(Me2MeNativeMessagingHostTest
, StartDaemonInvalidConfig
) {
605 base::DictionaryValue message
;
606 message
.SetString("type", "startDaemon");
607 message
.SetString("config", "xxx");
608 message
.SetBoolean("consent", true);
609 TestBadRequest(message
);
612 // Verify rejection if startDaemon request has no "consent" parameter.
613 TEST_F(Me2MeNativeMessagingHostTest
, StartDaemonNoConsent
) {
614 base::DictionaryValue message
;
615 message
.SetString("type", "startDaemon");
616 message
.Set("config", base::DictionaryValue().DeepCopy());
617 TestBadRequest(message
);
620 // Verify rejection if getCredentialsFromAuthCode has no auth code.
621 TEST_F(Me2MeNativeMessagingHostTest
, GetCredentialsFromAuthCodeNoAuthCode
) {
622 base::DictionaryValue message
;
623 message
.SetString("type", "getCredentialsFromAuthCode");
624 TestBadRequest(message
);
627 } // namespace remoting