1// Copyright 2014 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 "chromeos/cryptohome/homedir_methods.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/compiler_specific.h"
10#include "base/memory/scoped_ptr.h"
11#include "chromeos/dbus/cryptohome/rpc.pb.h"
12#include "chromeos/dbus/cryptohome_client.h"
13#include "chromeos/dbus/dbus_method_call_status.h"
14#include "chromeos/dbus/dbus_thread_manager.h"
15#include "chromeos/dbus/mock_cryptohome_client.h"
16#include "testing/gmock/include/gmock/gmock.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19using testing::_;
20using testing::Invoke;
21using testing::WithArg;
22
23namespace cryptohome {
24
25namespace {
26
27MATCHER_P(EqualsProto, expected_proto, "") {
28  std::string expected_value;
29  expected_proto.SerializeToString(&expected_value);
30  std::string actual_value;
31  arg.SerializeToString(&actual_value);
32  return actual_value == expected_value;
33}
34
35}  // namespace
36
37const char kUserID[] = "user@example.com";
38const char kKeyLabel[] = "key_label";
39
40const int64 kKeyRevision = 123;
41const char kProviderData1Name[] = "data_1";
42const int64 kProviderData1Number = 12345;
43const char kProviderData2Name[] = "data_2";
44const char kProviderData2Bytes[] = "data_2 bytes";
45
46class HomedirMethodsTest : public testing::Test {
47 public:
48  HomedirMethodsTest();
49  virtual ~HomedirMethodsTest();
50
51  // testing::Test:
52  virtual void SetUp() OVERRIDE;
53  virtual void TearDown() OVERRIDE;
54
55  void RunProtobufMethodCallback(
56      const chromeos::CryptohomeClient::ProtobufMethodCallback& callback);
57
58  void StoreGetKeyDataExResult(
59      bool success,
60      MountError return_code,
61      const std::vector<KeyDefinition>& key_definitions);
62
63 protected:
64  chromeos::MockCryptohomeClient* cryptohome_client_;
65
66  // The reply that |cryptohome_client_| will make.
67  cryptohome::BaseReply cryptohome_reply_;
68
69  // The results of the most recent |HomedirMethods| method call.
70  bool success_;
71  MountError return_code_;
72  std::vector<KeyDefinition> key_definitions_;
73
74 private:
75  DISALLOW_COPY_AND_ASSIGN(HomedirMethodsTest);
76};
77
78HomedirMethodsTest::HomedirMethodsTest() : cryptohome_client_(NULL),
79                                           success_(false),
80                                           return_code_(MOUNT_ERROR_FATAL) {
81}
82
83HomedirMethodsTest::~HomedirMethodsTest() {
84}
85
86void HomedirMethodsTest::SetUp() {
87  scoped_ptr<chromeos::MockCryptohomeClient> cryptohome_client(
88      new chromeos::MockCryptohomeClient);
89  cryptohome_client_ = cryptohome_client.get();
90  chromeos::DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient(
91      cryptohome_client.PassAs<chromeos::CryptohomeClient>());
92  HomedirMethods::Initialize();
93}
94
95void HomedirMethodsTest::TearDown() {
96  HomedirMethods::Shutdown();
97  chromeos::DBusThreadManager::Shutdown();
98}
99
100void HomedirMethodsTest::RunProtobufMethodCallback(
101    const chromeos::CryptohomeClient::ProtobufMethodCallback& callback) {
102  callback.Run(chromeos::DBUS_METHOD_CALL_SUCCESS,
103               true,
104               cryptohome_reply_);
105}
106
107void HomedirMethodsTest::StoreGetKeyDataExResult(
108    bool success,
109    MountError return_code,
110    const std::vector<KeyDefinition>& key_definitions) {
111  success_ = success;
112  return_code_ = return_code;
113  key_definitions_ = key_definitions;
114}
115
116// Verifies that the result of a GetKeyDataEx() call is correctly parsed.
117TEST_F(HomedirMethodsTest, GetKeyDataEx) {
118  AccountIdentifier expected_id;
119  expected_id.set_email(kUserID);
120  const cryptohome::AuthorizationRequest expected_auth;
121  cryptohome::GetKeyDataRequest expected_request;
122      expected_request.mutable_key()->mutable_data()->set_label(kKeyLabel);
123
124  EXPECT_CALL(*cryptohome_client_,
125              GetKeyDataEx(EqualsProto(expected_id),
126                           EqualsProto(expected_auth),
127                           EqualsProto(expected_request),
128                           _))
129      .Times(1)
130      .WillOnce(WithArg<3>(Invoke(
131          this,
132          &HomedirMethodsTest::RunProtobufMethodCallback)));
133
134  // Set up the reply that |cryptohome_client_| will make.
135  cryptohome::GetKeyDataReply* reply =
136      cryptohome_reply_.MutableExtension(cryptohome::GetKeyDataReply::reply);
137  KeyData* key_data = reply->add_key_data();
138  key_data->set_type(KeyData::KEY_TYPE_PASSWORD);
139  key_data->set_label(kKeyLabel);
140  key_data->mutable_privileges()->set_update(false);
141  key_data->set_revision(kKeyRevision);
142  key_data->add_authorization_data()->set_type(
143      KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256);
144  KeyProviderData* data = key_data->mutable_provider_data();
145  KeyProviderData::Entry* entry = data->add_entry();
146  entry->set_name(kProviderData1Name);
147  entry->set_number(kProviderData1Number);
148  entry = data->add_entry();
149  entry->set_name(kProviderData2Name);
150  entry->set_bytes(kProviderData2Bytes);
151
152  // Call GetKeyDataEx().
153  HomedirMethods::GetInstance()->GetKeyDataEx(
154    Identification(kUserID),
155    kKeyLabel,
156    base::Bind(&HomedirMethodsTest::StoreGetKeyDataExResult,
157               base::Unretained(this)));
158
159  // Verify that the call was successful and the result was correctly parsed.
160  EXPECT_TRUE(success_);
161  EXPECT_EQ(MOUNT_ERROR_NONE, return_code_);
162  ASSERT_EQ(1u, key_definitions_.size());
163  const KeyDefinition& key_definition = key_definitions_.front();
164  EXPECT_EQ(KeyDefinition::TYPE_PASSWORD, key_definition.type);
165  EXPECT_EQ(PRIV_MOUNT | PRIV_ADD | PRIV_REMOVE,
166            key_definition.privileges);
167  EXPECT_EQ(kKeyRevision, key_definition.revision);
168  ASSERT_EQ(1u, key_definition.authorization_data.size());
169  EXPECT_EQ(KeyDefinition::AuthorizationData::TYPE_HMACSHA256,
170            key_definition.authorization_data.front().type);
171  ASSERT_EQ(2u, key_definition.provider_data.size());
172  const KeyDefinition::ProviderData* provider_data =
173      &key_definition.provider_data[0];
174  EXPECT_EQ(kProviderData1Name, provider_data->name);
175  ASSERT_TRUE(provider_data->number);
176  EXPECT_EQ(kProviderData1Number, *provider_data->number.get());
177  EXPECT_FALSE(provider_data->bytes);
178  provider_data = &key_definition.provider_data[1];
179  EXPECT_EQ(kProviderData2Name, provider_data->name);
180  EXPECT_FALSE(provider_data->number);
181  ASSERT_TRUE(provider_data->bytes);
182  EXPECT_EQ(kProviderData2Bytes, *provider_data->bytes.get());
183}
184
185}  // namespace cryptohome
186