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