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/native_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 virtual ~MockDaemonControllerDelegate();
140 // DaemonController::Delegate interface.
141 virtual DaemonController::State GetState() OVERRIDE;
142 virtual scoped_ptr<base::DictionaryValue> GetConfig() OVERRIDE;
143 virtual void SetConfigAndStart(
144 scoped_ptr<base::DictionaryValue> config,
146 const DaemonController::CompletionCallback& done) OVERRIDE;
147 virtual void UpdateConfig(
148 scoped_ptr<base::DictionaryValue> config,
149 const DaemonController::CompletionCallback& done) OVERRIDE;
150 virtual void Stop(const DaemonController::CompletionCallback& done) OVERRIDE;
151 virtual void SetWindow(void* window_handle) OVERRIDE;
152 virtual std::string GetVersion() OVERRIDE;
153 virtual 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 scoped_ptr<base::DictionaryValue>(new base::DictionaryValue());
171 void MockDaemonControllerDelegate::SetConfigAndStart(
172 scoped_ptr<base::DictionaryValue> config,
174 const DaemonController::CompletionCallback& done) {
176 // Verify parameters passed in.
177 if (consent && config && config->HasKey("start")) {
178 done.Run(DaemonController::RESULT_OK);
180 done.Run(DaemonController::RESULT_FAILED);
184 void MockDaemonControllerDelegate::UpdateConfig(
185 scoped_ptr<base::DictionaryValue> config,
186 const DaemonController::CompletionCallback& done) {
187 if (config && config->HasKey("update")) {
188 done.Run(DaemonController::RESULT_OK);
190 done.Run(DaemonController::RESULT_FAILED);
194 void MockDaemonControllerDelegate::Stop(
195 const DaemonController::CompletionCallback& done) {
196 done.Run(DaemonController::RESULT_OK);
199 void MockDaemonControllerDelegate::SetWindow(void* window_handle) {}
201 std::string MockDaemonControllerDelegate::GetVersion() {
202 // Unused - NativeMessagingHost returns the compiled-in version string
203 // instead of calling this method.
205 return std::string();
208 DaemonController::UsageStatsConsent
209 MockDaemonControllerDelegate::GetUsageStatsConsent() {
210 DaemonController::UsageStatsConsent consent;
211 consent.supported = true;
212 consent.allowed = true;
213 consent.set_by_policy = true;
217 class NativeMessagingHostTest : public testing::Test {
219 NativeMessagingHostTest();
220 virtual ~NativeMessagingHostTest();
222 virtual void SetUp() OVERRIDE;
223 virtual 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_;
246 // Each test creates two unidirectional pipes: "input" and "output".
247 // NativeMessagingHost reads from input_read_handle and writes to
248 // output_write_handle. The unittest supplies data to input_write_handle, and
249 // verifies output from output_read_handle.
251 // unittest -> [input] -> NativeMessagingHost -> [output] -> unittest
252 base::PlatformFile input_write_handle_;
253 base::PlatformFile output_read_handle_;
255 base::MessageLoop message_loop_;
256 base::RunLoop run_loop_;
257 scoped_refptr<AutoThreadTaskRunner> task_runner_;
258 scoped_ptr<remoting::NativeMessagingChannel> channel_;
260 DISALLOW_COPY_AND_ASSIGN(NativeMessagingHostTest);
263 NativeMessagingHostTest::NativeMessagingHostTest()
264 : message_loop_(base::MessageLoop::TYPE_IO) {}
266 NativeMessagingHostTest::~NativeMessagingHostTest() {}
268 void NativeMessagingHostTest::SetUp() {
269 base::PlatformFile input_read_handle;
270 base::PlatformFile output_write_handle;
272 ASSERT_TRUE(MakePipe(&input_read_handle, &input_write_handle_));
273 ASSERT_TRUE(MakePipe(&output_read_handle_, &output_write_handle));
275 // Arrange to run |message_loop_| until no components depend on it.
276 task_runner_ = new AutoThreadTaskRunner(
277 message_loop_.message_loop_proxy(), run_loop_.QuitClosure());
279 daemon_controller_delegate_ = new MockDaemonControllerDelegate();
280 scoped_refptr<DaemonController> daemon_controller(
281 new DaemonController(
282 scoped_ptr<DaemonController::Delegate>(daemon_controller_delegate_)));
284 scoped_refptr<PairingRegistry> pairing_registry =
285 new SynchronousPairingRegistry(scoped_ptr<PairingRegistry::Delegate>(
286 new MockPairingRegistryDelegate()));
287 scoped_ptr<NativeMessagingChannel::Delegate> host(
288 new NativeMessagingHost(daemon_controller,
290 scoped_ptr<remoting::OAuthClient>()));
292 new NativeMessagingChannel(host.Pass(),
294 output_write_handle));
297 void NativeMessagingHostTest::TearDown() {
298 // DaemonController destroys its internals asynchronously. Let these and any
299 // other pending tasks run to make sure we don't leak the memory owned by
301 message_loop_.RunUntilIdle();
303 // The NativeMessagingHost dtor closes the handles that are passed to it.
304 // |input_write_handle_| gets closed just before starting the host. So the
305 // only handle left to close is |output_read_handle_|.
306 base::ClosePlatformFile(output_read_handle_);
309 void NativeMessagingHostTest::Run() {
310 // Close the write-end of input, so that the host sees EOF after reading
311 // messages and won't block waiting for more input.
312 base::ClosePlatformFile(input_write_handle_);
313 channel_->Start(base::Bind(&NativeMessagingHostTest::DeleteHost,
314 base::Unretained(this)));
318 void NativeMessagingHostTest::DeleteHost() {
319 // Destroy |channel_| so that it closes its end of the output pipe, so that
320 // TestBadRequest() will see EOF and won't block waiting for more data.
325 scoped_ptr<base::DictionaryValue>
326 NativeMessagingHostTest::ReadMessageFromOutputPipe() {
328 int read_result = base::ReadPlatformFileAtCurrentPos(
329 output_read_handle_, reinterpret_cast<char*>(&length), sizeof(length));
330 if (read_result != sizeof(length)) {
331 return scoped_ptr<base::DictionaryValue>();
334 std::string message_json(length, '\0');
335 read_result = base::ReadPlatformFileAtCurrentPos(
336 output_read_handle_, string_as_array(&message_json), length);
337 if (read_result != static_cast<int>(length)) {
338 return scoped_ptr<base::DictionaryValue>();
341 scoped_ptr<base::Value> message(base::JSONReader::Read(message_json));
342 if (!message || !message->IsType(base::Value::TYPE_DICTIONARY)) {
343 return scoped_ptr<base::DictionaryValue>();
346 return scoped_ptr<base::DictionaryValue>(
347 static_cast<base::DictionaryValue*>(message.release()));
350 void NativeMessagingHostTest::WriteMessageToInputPipe(
351 const base::Value& message) {
352 std::string message_json;
353 base::JSONWriter::Write(&message, &message_json);
355 uint32 length = message_json.length();
356 base::WritePlatformFileAtCurrentPos(input_write_handle_,
357 reinterpret_cast<char*>(&length),
359 base::WritePlatformFileAtCurrentPos(input_write_handle_, message_json.data(),
363 void NativeMessagingHostTest::TestBadRequest(const base::Value& message) {
364 base::DictionaryValue good_message;
365 good_message.SetString("type", "hello");
367 // This test currently relies on synchronous processing of hello messages and
368 // message parameters verification.
369 WriteMessageToInputPipe(good_message);
370 WriteMessageToInputPipe(message);
371 WriteMessageToInputPipe(good_message);
375 // Read from output pipe, and verify responses.
376 scoped_ptr<base::DictionaryValue> response =
377 ReadMessageFromOutputPipe();
378 VerifyHelloResponse(response.Pass());
380 response = ReadMessageFromOutputPipe();
381 EXPECT_FALSE(response);
384 // Test all valid request-types.
385 TEST_F(NativeMessagingHostTest, All) {
387 base::DictionaryValue message;
388 message.SetInteger("id", next_id++);
389 message.SetString("type", "hello");
390 WriteMessageToInputPipe(message);
392 message.SetInteger("id", next_id++);
393 message.SetString("type", "getHostName");
394 WriteMessageToInputPipe(message);
396 message.SetInteger("id", next_id++);
397 message.SetString("type", "getPinHash");
398 message.SetString("hostId", "my_host");
399 message.SetString("pin", "1234");
400 WriteMessageToInputPipe(message);
403 message.SetInteger("id", next_id++);
404 message.SetString("type", "generateKeyPair");
405 WriteMessageToInputPipe(message);
407 message.SetInteger("id", next_id++);
408 message.SetString("type", "getDaemonConfig");
409 WriteMessageToInputPipe(message);
411 message.SetInteger("id", next_id++);
412 message.SetString("type", "getUsageStatsConsent");
413 WriteMessageToInputPipe(message);
415 message.SetInteger("id", next_id++);
416 message.SetString("type", "stopDaemon");
417 WriteMessageToInputPipe(message);
419 message.SetInteger("id", next_id++);
420 message.SetString("type", "getDaemonState");
421 WriteMessageToInputPipe(message);
423 // Following messages require a "config" dictionary.
424 base::DictionaryValue config;
425 config.SetBoolean("update", true);
426 message.Set("config", config.DeepCopy());
427 message.SetInteger("id", next_id++);
428 message.SetString("type", "updateDaemonConfig");
429 WriteMessageToInputPipe(message);
432 config.SetBoolean("start", true);
433 message.Set("config", config.DeepCopy());
434 message.SetBoolean("consent", true);
435 message.SetInteger("id", next_id++);
436 message.SetString("type", "startDaemon");
437 WriteMessageToInputPipe(message);
441 void (*verify_routines[])(scoped_ptr<base::DictionaryValue>) = {
442 &VerifyHelloResponse,
443 &VerifyGetHostNameResponse,
444 &VerifyGetPinHashResponse,
445 &VerifyGenerateKeyPairResponse,
446 &VerifyGetDaemonConfigResponse,
447 &VerifyGetUsageStatsConsentResponse,
448 &VerifyStopDaemonResponse,
449 &VerifyGetDaemonStateResponse,
450 &VerifyUpdateDaemonConfigResponse,
451 &VerifyStartDaemonResponse,
453 ASSERT_EQ(arraysize(verify_routines), static_cast<size_t>(next_id));
455 // Read all responses from output pipe, and verify them.
456 for (int i = 0; i < next_id; ++i) {
457 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
459 // Make sure that id is available and is in the range.
461 ASSERT_TRUE(response->GetInteger("id", &id));
462 ASSERT_TRUE(0 <= id && id < next_id);
464 // Call the verification routine corresponding to the message id.
465 ASSERT_TRUE(verify_routines[id]);
466 verify_routines[id](response.Pass());
468 // Clear the pointer so that the routine cannot be called the second time.
469 verify_routines[id] = NULL;
473 // Verify that response ID matches request ID.
474 TEST_F(NativeMessagingHostTest, Id) {
475 base::DictionaryValue message;
476 message.SetString("type", "hello");
477 WriteMessageToInputPipe(message);
478 message.SetString("id", "42");
479 WriteMessageToInputPipe(message);
483 scoped_ptr<base::DictionaryValue> response =
484 ReadMessageFromOutputPipe();
485 EXPECT_TRUE(response);
487 EXPECT_FALSE(response->GetString("id", &value));
489 response = ReadMessageFromOutputPipe();
490 EXPECT_TRUE(response);
491 EXPECT_TRUE(response->GetString("id", &value));
492 EXPECT_EQ("42", value);
495 // Verify non-Dictionary requests are rejected.
496 TEST_F(NativeMessagingHostTest, WrongFormat) {
497 base::ListValue message;
498 TestBadRequest(message);
501 // Verify requests with no type are rejected.
502 TEST_F(NativeMessagingHostTest, MissingType) {
503 base::DictionaryValue message;
504 TestBadRequest(message);
507 // Verify rejection if type is unrecognized.
508 TEST_F(NativeMessagingHostTest, InvalidType) {
509 base::DictionaryValue message;
510 message.SetString("type", "xxx");
511 TestBadRequest(message);
514 // Verify rejection if getPinHash request has no hostId.
515 TEST_F(NativeMessagingHostTest, GetPinHashNoHostId) {
516 base::DictionaryValue message;
517 message.SetString("type", "getPinHash");
518 message.SetString("pin", "1234");
519 TestBadRequest(message);
522 // Verify rejection if getPinHash request has no pin.
523 TEST_F(NativeMessagingHostTest, GetPinHashNoPin) {
524 base::DictionaryValue message;
525 message.SetString("type", "getPinHash");
526 message.SetString("hostId", "my_host");
527 TestBadRequest(message);
530 // Verify rejection if updateDaemonConfig request has invalid config.
531 TEST_F(NativeMessagingHostTest, UpdateDaemonConfigInvalidConfig) {
532 base::DictionaryValue message;
533 message.SetString("type", "updateDaemonConfig");
534 message.SetString("config", "xxx");
535 TestBadRequest(message);
538 // Verify rejection if startDaemon request has invalid config.
539 TEST_F(NativeMessagingHostTest, StartDaemonInvalidConfig) {
540 base::DictionaryValue message;
541 message.SetString("type", "startDaemon");
542 message.SetString("config", "xxx");
543 message.SetBoolean("consent", true);
544 TestBadRequest(message);
547 // Verify rejection if startDaemon request has no "consent" parameter.
548 TEST_F(NativeMessagingHostTest, StartDaemonNoConsent) {
549 base::DictionaryValue message;
550 message.SetString("type", "startDaemon");
551 message.Set("config", base::DictionaryValue().DeepCopy());
552 TestBadRequest(message);
555 } // namespace remoting