blob: 153b34e421f4f8dc259e3824ba8490c3d8480eda [file] [log] [blame]
Junxiao Shid7631272016-08-17 04:16:31 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev635bf202017-03-09 21:57:34 +00003 * Copyright (c) 2014-2017, Regents of the University of California,
Junxiao Shid7631272016-08-17 04:16:31 +00004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26#include "mgmt/command-authenticator.hpp"
Junxiao Shid7631272016-08-17 04:16:31 +000027#include <boost/filesystem.hpp>
28
29#include "tests/test-common.hpp"
Junxiao Shi8a1f1702017-07-03 00:05:08 +000030#include "tests/manager-common-fixture.hpp"
Junxiao Shid7631272016-08-17 04:16:31 +000031
32namespace nfd {
33namespace tests {
34
Junxiao Shi8a1f1702017-07-03 00:05:08 +000035class CommandAuthenticatorFixture : public CommandInterestSignerFixture
Junxiao Shid7631272016-08-17 04:16:31 +000036{
37protected:
38 CommandAuthenticatorFixture()
39 : authenticator(CommandAuthenticator::create())
40 {
41 }
42
43 void
44 makeModules(std::initializer_list<std::string> modules)
45 {
46 for (const std::string& module : modules) {
47 authorizations.emplace(module, authenticator->makeAuthorization(module, "verb"));
48 }
49 }
50
51 void
52 loadConfig(const std::string& config)
53 {
54 boost::filesystem::path configPath = boost::filesystem::current_path() /=
55 "command-authenticator-test.conf";
56 ConfigFile cf;
57 authenticator->setConfigFile(cf);
58 cf.parse(config, false, configPath.c_str());
59 }
60
61 bool
62 authorize(const std::string& module, const Name& identity,
63 const function<void(Interest&)>& modifyInterest = nullptr)
64 {
Junxiao Shi8a1f1702017-07-03 00:05:08 +000065 Interest interest = this->makeControlCommandRequest(Name("/prefix/" + module + "/verb"),
66 ControlParameters(), identity);
Junxiao Shid7631272016-08-17 04:16:31 +000067 if (modifyInterest != nullptr) {
Junxiao Shi8a1f1702017-07-03 00:05:08 +000068 modifyInterest(interest);
Junxiao Shid7631272016-08-17 04:16:31 +000069 }
70
71 ndn::mgmt::Authorization authorization = authorizations.at(module);
72
73 bool isAccepted = false;
74 bool isRejected = false;
Junxiao Shi8a1f1702017-07-03 00:05:08 +000075 authorization(Name("/prefix"), interest, nullptr,
Junxiao Shid7631272016-08-17 04:16:31 +000076 [this, &isAccepted, &isRejected] (const std::string& requester) {
77 BOOST_REQUIRE_MESSAGE(!isAccepted && !isRejected,
78 "authorization function should invoke only one continuation");
79 isAccepted = true;
80 lastRequester = requester;
81 },
82 [this, &isAccepted, &isRejected] (ndn::mgmt::RejectReply act) {
83 BOOST_REQUIRE_MESSAGE(!isAccepted && !isRejected,
84 "authorization function should invoke only one continuation");
85 isRejected = true;
86 lastRejectReply = act;
87 });
88
89 this->advanceClocks(time::milliseconds(1), 10);
90 BOOST_REQUIRE_MESSAGE(isAccepted || isRejected,
91 "authorization function should invoke one continuation");
92 return isAccepted;
93 }
94
95protected:
96 shared_ptr<CommandAuthenticator> authenticator;
97 std::unordered_map<std::string, ndn::mgmt::Authorization> authorizations;
98 std::string lastRequester;
99 ndn::mgmt::RejectReply lastRejectReply;
100};
101
102BOOST_AUTO_TEST_SUITE(Mgmt)
103BOOST_FIXTURE_TEST_SUITE(TestCommandAuthenticator, CommandAuthenticatorFixture)
104
105BOOST_AUTO_TEST_CASE(Certs)
106{
107 Name id0("/localhost/CommandAuthenticator/0");
108 Name id1("/localhost/CommandAuthenticator/1");
109 Name id2("/localhost/CommandAuthenticator/2");
110 BOOST_REQUIRE(addIdentity(id0));
111 BOOST_REQUIRE(saveIdentityCertificate(id1, "1.ndncert", true));
112 BOOST_REQUIRE(saveIdentityCertificate(id2, "2.ndncert", true));
113
114 makeModules({"module0", "module1", "module2", "module3", "module4", "module5", "module6", "module7"});
115 const std::string& config = R"CONFIG(
116 authorizations
117 {
118 authorize
119 {
120 certfile any
121 privileges
122 {
123 module1
124 module3
125 module5
126 module7
127 }
128 }
129 authorize
130 {
131 certfile "1.ndncert"
132 privileges
133 {
134 module2
135 module3
136 module6
137 module7
138 }
139 }
140 authorize
141 {
142 certfile "2.ndncert"
143 privileges
144 {
145 module4
146 module5
147 module6
148 module7
149 }
150 }
151 }
152 )CONFIG";
153 loadConfig(config);
154
155 // module0: none
156 BOOST_CHECK_EQUAL(authorize("module0", id0), false);
157 BOOST_CHECK_EQUAL(authorize("module0", id1), false);
158 BOOST_CHECK_EQUAL(authorize("module0", id2), false);
159
160 // module1: any
161 BOOST_CHECK_EQUAL(authorize("module1", id0), true);
162 BOOST_CHECK_EQUAL(authorize("module1", id1), true);
163 BOOST_CHECK_EQUAL(authorize("module1", id2), true);
164
165 // module2: id1
166 BOOST_CHECK_EQUAL(authorize("module2", id0), false);
167 BOOST_CHECK_EQUAL(authorize("module2", id1), true);
168 BOOST_CHECK_EQUAL(authorize("module2", id2), false);
169
170 // module3: any,id1
171 BOOST_CHECK_EQUAL(authorize("module3", id0), true);
172 BOOST_CHECK_EQUAL(authorize("module3", id1), true);
173 BOOST_CHECK_EQUAL(authorize("module3", id2), true);
174
175 // module4: id2
176 BOOST_CHECK_EQUAL(authorize("module4", id0), false);
177 BOOST_CHECK_EQUAL(authorize("module4", id1), false);
178 BOOST_CHECK_EQUAL(authorize("module4", id2), true);
179
180 // module5: any,id2
181 BOOST_CHECK_EQUAL(authorize("module5", id0), true);
182 BOOST_CHECK_EQUAL(authorize("module5", id1), true);
183 BOOST_CHECK_EQUAL(authorize("module5", id2), true);
184
185 // module6: id1,id2
186 BOOST_CHECK_EQUAL(authorize("module6", id0), false);
187 BOOST_CHECK_EQUAL(authorize("module6", id1), true);
188 BOOST_CHECK_EQUAL(authorize("module6", id2), true);
189
190 // module7: any,id1,id2
191 BOOST_CHECK_EQUAL(authorize("module7", id0), true);
192 BOOST_CHECK_EQUAL(authorize("module7", id1), true);
193 BOOST_CHECK_EQUAL(authorize("module7", id2), true);
194}
195
196BOOST_AUTO_TEST_CASE(Requester)
197{
198 Name id0("/localhost/CommandAuthenticator/0");
199 Name id1("/localhost/CommandAuthenticator/1");
200 BOOST_REQUIRE(addIdentity(id0));
201 BOOST_REQUIRE(saveIdentityCertificate(id1, "1.ndncert", true));
202
203 makeModules({"module0", "module1"});
204 const std::string& config = R"CONFIG(
205 authorizations
206 {
207 authorize
208 {
209 certfile any
210 privileges
211 {
212 module0
213 }
214 }
215 authorize
216 {
217 certfile "1.ndncert"
218 privileges
219 {
220 module1
221 }
222 }
223 }
224 )CONFIG";
225 loadConfig(config);
226
227 // module0: any
228 BOOST_CHECK_EQUAL(authorize("module0", id0), true);
229 BOOST_CHECK_EQUAL(lastRequester, "*");
230 BOOST_CHECK_EQUAL(authorize("module0", id1), true);
231 BOOST_CHECK_EQUAL(lastRequester, "*");
232
233 // module1: id1
234 BOOST_CHECK_EQUAL(authorize("module1", id0), false);
235 BOOST_CHECK_EQUAL(authorize("module1", id1), true);
236 BOOST_CHECK(id1.isPrefixOf(lastRequester));
237}
238
239class IdentityAuthorizedFixture : public CommandAuthenticatorFixture
240{
241protected:
242 IdentityAuthorizedFixture()
243 : id1("/localhost/CommandAuthenticator/1")
244 {
245 BOOST_REQUIRE(saveIdentityCertificate(id1, "1.ndncert", true));
246
247 makeModules({"module1"});
248 const std::string& config = R"CONFIG(
249 authorizations
250 {
251 authorize
252 {
253 certfile "1.ndncert"
254 privileges
255 {
256 module1
257 }
258 }
259 }
260 )CONFIG";
261 loadConfig(config);
262 }
263
264 bool
265 authorize1(const function<void(Interest&)>& modifyInterest)
266 {
267 return authorize("module1", id1, modifyInterest);
268 }
269
270protected:
271 Name id1;
272};
273
274BOOST_FIXTURE_TEST_SUITE(Rejects, IdentityAuthorizedFixture)
275
276BOOST_AUTO_TEST_CASE(BadKeyLocator_NameTooShort)
277{
278 BOOST_CHECK_EQUAL(authorize1(
279 [] (Interest& interest) {
280 interest.setName("/prefix");
281 }
282 ), false);
283 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
284}
285
286BOOST_AUTO_TEST_CASE(BadKeyLocator_BadSigInfo)
287{
288 BOOST_CHECK_EQUAL(authorize1(
289 [] (Interest& interest) {
290 setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO, "not-SignatureInfo");
291 }
292 ), false);
293 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
294}
295
296BOOST_AUTO_TEST_CASE(BadKeyLocator_MissingKeyLocator)
297{
298 BOOST_CHECK_EQUAL(authorize1(
299 [] (Interest& interest) {
300 ndn::SignatureInfo sigInfo;
301 setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO,
302 sigInfo.wireEncode().begin(), sigInfo.wireEncode().end());
303 }
304 ), false);
305 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
306}
307
308BOOST_AUTO_TEST_CASE(BadKeyLocator_BadKeyLocatorType)
309{
310 BOOST_CHECK_EQUAL(authorize1(
311 [] (Interest& interest) {
312 ndn::KeyLocator kl;
313 kl.setKeyDigest(ndn::encoding::makeBinaryBlock(tlv::KeyDigest, "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD", 8));
314 ndn::SignatureInfo sigInfo;
315 sigInfo.setKeyLocator(kl);
316 setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO,
317 sigInfo.wireEncode().begin(), sigInfo.wireEncode().end());
318 }
319 ), false);
320 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
321}
322
Junxiao Shid7631272016-08-17 04:16:31 +0000323BOOST_AUTO_TEST_CASE(NotAuthorized)
324{
325 Name id0("/localhost/CommandAuthenticator/0");
326 BOOST_REQUIRE(addIdentity(id0));
327
328 BOOST_CHECK_EQUAL(authorize("module1", id0), false);
329 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
330}
331
332BOOST_AUTO_TEST_CASE(BadSig)
333{
334 BOOST_CHECK_EQUAL(authorize1(
335 [] (Interest& interest) {
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000336 setNameComponent(interest, ndn::command_interest::POS_SIG_VALUE, "bad-signature-bits");
Junxiao Shid7631272016-08-17 04:16:31 +0000337 }
338 ), false);
339 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
340}
341
342BOOST_AUTO_TEST_CASE(InvalidTimestamp)
343{
344 name::Component timestampComp;
345 BOOST_CHECK_EQUAL(authorize1(
346 [&timestampComp] (const Interest& interest) {
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000347 timestampComp = interest.getName().at(ndn::command_interest::POS_TIMESTAMP);
Junxiao Shid7631272016-08-17 04:16:31 +0000348 }
349 ), true); // accept first command
350 BOOST_CHECK_EQUAL(authorize1(
351 [&timestampComp] (Interest& interest) {
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000352 setNameComponent(interest, ndn::command_interest::POS_TIMESTAMP, timestampComp);
Junxiao Shid7631272016-08-17 04:16:31 +0000353 }
354 ), false); // reject second command because timestamp equals first command
355 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
356}
357
358BOOST_AUTO_TEST_SUITE_END() // Rejects
359
360BOOST_AUTO_TEST_SUITE(BadConfig)
361
362BOOST_AUTO_TEST_CASE(EmptyAuthorizationsSection)
363{
364 const std::string& config = R"CONFIG(
365 authorizations
366 {
367 }
368 )CONFIG";
369
370 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
371}
372
373BOOST_AUTO_TEST_CASE(UnrecognizedKey)
374{
375 const std::string& config = R"CONFIG(
376 authorizations
377 {
378 unrecognized_key
379 {
380 }
381 }
382 )CONFIG";
383
384 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
385}
386
387BOOST_AUTO_TEST_CASE(CertfileMissing)
388{
389 const std::string& config = R"CONFIG(
390 authorizations
391 {
392 authorize
393 {
394 privileges
395 {
396 }
397 }
398 }
399 )CONFIG";
400
401 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
402}
403
404BOOST_AUTO_TEST_CASE(CertUnreadable)
405{
406 const std::string& config = R"CONFIG(
407 authorizations
408 {
409 authorize
410 {
411 certfile "1.ndncert"
412 privileges
413 {
414 }
415 }
416 }
417 )CONFIG";
418
419 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
420}
421
422BOOST_AUTO_TEST_CASE(PrivilegesMissing)
423{
424 const std::string& config = R"CONFIG(
425 authorizations
426 {
427 authorize
428 {
429 certfile any
430 }
431 }
432 )CONFIG";
433
434 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
435}
436
437BOOST_AUTO_TEST_CASE(UnregisteredModule)
438{
439 const std::string& config = R"CONFIG(
440 authorizations
441 {
442 authorize
443 {
444 certfile any
445 privileges
446 {
447 nosuchmodule
448 }
449 }
450 }
451 )CONFIG";
452
453 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
454}
455
456BOOST_AUTO_TEST_SUITE_END() // BadConfig
457
458BOOST_AUTO_TEST_SUITE_END() // TestCommandAuthenticator
459BOOST_AUTO_TEST_SUITE_END() // Mgmt
460
461} // namespace tests
462} // namespace nfd