blob: 7db02ca6c2b6322b4baaef096d1d116496be5528 [file] [log] [blame]
Junxiao Shid7631272016-08-17 04:16:31 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shia9079802017-08-26 14:12:30 +00002/*
Davide Pesaventoa599d2a2022-02-16 18:52:43 -05003 * Copyright (c) 2014-2022, 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
Davide Pesavento78ddcab2019-02-28 22:00:03 -050028#include "manager-common-fixture.hpp"
Junxiao Shid7631272016-08-17 04:16:31 +000029
Junxiao Shia9079802017-08-26 14:12:30 +000030#include <boost/filesystem.hpp>
31
Junxiao Shid7631272016-08-17 04:16:31 +000032namespace 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 {
Davide Pesaventod96744d2018-02-03 19:16:07 -050054 auto configPath = boost::filesystem::current_path() / "command-authenticator-test.conf";
Junxiao Shid7631272016-08-17 04:16:31 +000055 ConfigFile cf;
56 authenticator->setConfigFile(cf);
57 cf.parse(config, false, configPath.c_str());
58 }
59
60 bool
61 authorize(const std::string& module, const Name& identity,
Davide Pesavento87fc0f82018-04-11 23:43:51 -040062 const std::function<void(Interest&)>& modifyInterest = nullptr)
Junxiao Shid7631272016-08-17 04:16:31 +000063 {
Junxiao Shi8a1f1702017-07-03 00:05:08 +000064 Interest interest = this->makeControlCommandRequest(Name("/prefix/" + module + "/verb"),
Davide Pesaventod96744d2018-02-03 19:16:07 -050065 ControlParameters(), identity);
Junxiao Shid7631272016-08-17 04:16:31 +000066 if (modifyInterest != nullptr) {
Junxiao Shi8a1f1702017-07-03 00:05:08 +000067 modifyInterest(interest);
Junxiao Shid7631272016-08-17 04:16:31 +000068 }
69
70 ndn::mgmt::Authorization authorization = authorizations.at(module);
71
72 bool isAccepted = false;
73 bool isRejected = false;
Junxiao Shi8a1f1702017-07-03 00:05:08 +000074 authorization(Name("/prefix"), interest, nullptr,
Junxiao Shid7631272016-08-17 04:16:31 +000075 [this, &isAccepted, &isRejected] (const std::string& requester) {
76 BOOST_REQUIRE_MESSAGE(!isAccepted && !isRejected,
77 "authorization function should invoke only one continuation");
78 isAccepted = true;
79 lastRequester = requester;
80 },
81 [this, &isAccepted, &isRejected] (ndn::mgmt::RejectReply act) {
82 BOOST_REQUIRE_MESSAGE(!isAccepted && !isRejected,
83 "authorization function should invoke only one continuation");
84 isRejected = true;
85 lastRejectReply = act;
86 });
87
Davide Pesaventod96744d2018-02-03 19:16:07 -050088 this->advanceClocks(1_ms, 10);
Junxiao Shid7631272016-08-17 04:16:31 +000089 BOOST_REQUIRE_MESSAGE(isAccepted || isRejected,
90 "authorization function should invoke one continuation");
91 return isAccepted;
92 }
93
94protected:
95 shared_ptr<CommandAuthenticator> authenticator;
96 std::unordered_map<std::string, ndn::mgmt::Authorization> authorizations;
97 std::string lastRequester;
98 ndn::mgmt::RejectReply lastRejectReply;
99};
100
101BOOST_AUTO_TEST_SUITE(Mgmt)
102BOOST_FIXTURE_TEST_SUITE(TestCommandAuthenticator, CommandAuthenticatorFixture)
103
104BOOST_AUTO_TEST_CASE(Certs)
105{
106 Name id0("/localhost/CommandAuthenticator/0");
107 Name id1("/localhost/CommandAuthenticator/1");
108 Name id2("/localhost/CommandAuthenticator/2");
Davide Pesavento21353752020-11-20 00:43:44 -0500109 BOOST_REQUIRE(m_keyChain.createIdentity(id0));
110 BOOST_REQUIRE(saveIdentityCert(id1, "1.ndncert", true));
111 BOOST_REQUIRE(saveIdentityCert(id2, "2.ndncert", true));
Junxiao Shid7631272016-08-17 04:16:31 +0000112
113 makeModules({"module0", "module1", "module2", "module3", "module4", "module5", "module6", "module7"});
114 const std::string& config = R"CONFIG(
115 authorizations
116 {
117 authorize
118 {
119 certfile any
120 privileges
121 {
122 module1
123 module3
124 module5
125 module7
126 }
127 }
128 authorize
129 {
130 certfile "1.ndncert"
131 privileges
132 {
133 module2
134 module3
135 module6
136 module7
137 }
138 }
139 authorize
140 {
141 certfile "2.ndncert"
142 privileges
143 {
144 module4
145 module5
146 module6
147 module7
148 }
149 }
150 }
151 )CONFIG";
152 loadConfig(config);
153
154 // module0: none
155 BOOST_CHECK_EQUAL(authorize("module0", id0), false);
156 BOOST_CHECK_EQUAL(authorize("module0", id1), false);
157 BOOST_CHECK_EQUAL(authorize("module0", id2), false);
158
159 // module1: any
160 BOOST_CHECK_EQUAL(authorize("module1", id0), true);
161 BOOST_CHECK_EQUAL(authorize("module1", id1), true);
162 BOOST_CHECK_EQUAL(authorize("module1", id2), true);
163
164 // module2: id1
165 BOOST_CHECK_EQUAL(authorize("module2", id0), false);
166 BOOST_CHECK_EQUAL(authorize("module2", id1), true);
167 BOOST_CHECK_EQUAL(authorize("module2", id2), false);
168
169 // module3: any,id1
170 BOOST_CHECK_EQUAL(authorize("module3", id0), true);
171 BOOST_CHECK_EQUAL(authorize("module3", id1), true);
172 BOOST_CHECK_EQUAL(authorize("module3", id2), true);
173
174 // module4: id2
175 BOOST_CHECK_EQUAL(authorize("module4", id0), false);
176 BOOST_CHECK_EQUAL(authorize("module4", id1), false);
177 BOOST_CHECK_EQUAL(authorize("module4", id2), true);
178
179 // module5: any,id2
180 BOOST_CHECK_EQUAL(authorize("module5", id0), true);
181 BOOST_CHECK_EQUAL(authorize("module5", id1), true);
182 BOOST_CHECK_EQUAL(authorize("module5", id2), true);
183
184 // module6: id1,id2
185 BOOST_CHECK_EQUAL(authorize("module6", id0), false);
186 BOOST_CHECK_EQUAL(authorize("module6", id1), true);
187 BOOST_CHECK_EQUAL(authorize("module6", id2), true);
188
189 // module7: any,id1,id2
190 BOOST_CHECK_EQUAL(authorize("module7", id0), true);
191 BOOST_CHECK_EQUAL(authorize("module7", id1), true);
192 BOOST_CHECK_EQUAL(authorize("module7", id2), true);
193}
194
195BOOST_AUTO_TEST_CASE(Requester)
196{
197 Name id0("/localhost/CommandAuthenticator/0");
198 Name id1("/localhost/CommandAuthenticator/1");
Davide Pesavento21353752020-11-20 00:43:44 -0500199 BOOST_REQUIRE(m_keyChain.createIdentity(id0));
200 BOOST_REQUIRE(saveIdentityCert(id1, "1.ndncert", true));
Junxiao Shid7631272016-08-17 04:16:31 +0000201
202 makeModules({"module0", "module1"});
203 const std::string& config = R"CONFIG(
204 authorizations
205 {
206 authorize
207 {
208 certfile any
209 privileges
210 {
211 module0
212 }
213 }
214 authorize
215 {
216 certfile "1.ndncert"
217 privileges
218 {
219 module1
220 }
221 }
222 }
223 )CONFIG";
224 loadConfig(config);
225
226 // module0: any
227 BOOST_CHECK_EQUAL(authorize("module0", id0), true);
228 BOOST_CHECK_EQUAL(lastRequester, "*");
229 BOOST_CHECK_EQUAL(authorize("module0", id1), true);
230 BOOST_CHECK_EQUAL(lastRequester, "*");
231
232 // module1: id1
233 BOOST_CHECK_EQUAL(authorize("module1", id0), false);
234 BOOST_CHECK_EQUAL(authorize("module1", id1), true);
235 BOOST_CHECK(id1.isPrefixOf(lastRequester));
236}
237
238class IdentityAuthorizedFixture : public CommandAuthenticatorFixture
239{
240protected:
241 IdentityAuthorizedFixture()
242 : id1("/localhost/CommandAuthenticator/1")
243 {
Davide Pesavento21353752020-11-20 00:43:44 -0500244 BOOST_REQUIRE(saveIdentityCert(id1, "1.ndncert", true));
Junxiao Shid7631272016-08-17 04:16:31 +0000245
246 makeModules({"module1"});
247 const std::string& config = R"CONFIG(
248 authorizations
249 {
250 authorize
251 {
252 certfile "1.ndncert"
253 privileges
254 {
255 module1
256 }
257 }
258 }
259 )CONFIG";
260 loadConfig(config);
261 }
262
263 bool
Davide Pesavento87fc0f82018-04-11 23:43:51 -0400264 authorize1(const std::function<void(Interest&)>& modifyInterest)
Junxiao Shid7631272016-08-17 04:16:31 +0000265 {
266 return authorize("module1", id1, modifyInterest);
267 }
268
269protected:
270 Name id1;
271};
272
273BOOST_FIXTURE_TEST_SUITE(Rejects, IdentityAuthorizedFixture)
274
275BOOST_AUTO_TEST_CASE(BadKeyLocator_NameTooShort)
276{
277 BOOST_CHECK_EQUAL(authorize1(
278 [] (Interest& interest) {
279 interest.setName("/prefix");
280 }
281 ), false);
282 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
283}
284
285BOOST_AUTO_TEST_CASE(BadKeyLocator_BadSigInfo)
286{
287 BOOST_CHECK_EQUAL(authorize1(
288 [] (Interest& interest) {
289 setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO, "not-SignatureInfo");
290 }
291 ), false);
292 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
293}
294
295BOOST_AUTO_TEST_CASE(BadKeyLocator_MissingKeyLocator)
296{
297 BOOST_CHECK_EQUAL(authorize1(
298 [] (Interest& interest) {
Junxiao Shia9079802017-08-26 14:12:30 +0000299 ndn::SignatureInfo sigInfo(tlv::SignatureSha256WithRsa);
Davide Pesaventodeb54272022-03-11 18:51:05 -0500300 setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO, ndn::make_span(sigInfo.wireEncode()));
Junxiao Shid7631272016-08-17 04:16:31 +0000301 }
302 ), false);
303 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
304}
305
306BOOST_AUTO_TEST_CASE(BadKeyLocator_BadKeyLocatorType)
307{
308 BOOST_CHECK_EQUAL(authorize1(
309 [] (Interest& interest) {
310 ndn::KeyLocator kl;
Davide Pesaventoa599d2a2022-02-16 18:52:43 -0500311 kl.setKeyDigest(ndn::makeBinaryBlock(tlv::KeyDigest,
312 {0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD}));
Junxiao Shia9079802017-08-26 14:12:30 +0000313 ndn::SignatureInfo sigInfo(tlv::SignatureSha256WithRsa);
Junxiao Shid7631272016-08-17 04:16:31 +0000314 sigInfo.setKeyLocator(kl);
Davide Pesaventodeb54272022-03-11 18:51:05 -0500315 setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO, ndn::make_span(sigInfo.wireEncode()));
Junxiao Shid7631272016-08-17 04:16:31 +0000316 }
317 ), false);
318 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
319}
320
Junxiao Shid7631272016-08-17 04:16:31 +0000321BOOST_AUTO_TEST_CASE(NotAuthorized)
322{
323 Name id0("/localhost/CommandAuthenticator/0");
Davide Pesavento21353752020-11-20 00:43:44 -0500324 BOOST_REQUIRE(m_keyChain.createIdentity(id0));
Junxiao Shid7631272016-08-17 04:16:31 +0000325
326 BOOST_CHECK_EQUAL(authorize("module1", id0), false);
327 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
328}
329
330BOOST_AUTO_TEST_CASE(BadSig)
331{
332 BOOST_CHECK_EQUAL(authorize1(
333 [] (Interest& interest) {
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000334 setNameComponent(interest, ndn::command_interest::POS_SIG_VALUE, "bad-signature-bits");
Junxiao Shid7631272016-08-17 04:16:31 +0000335 }
336 ), false);
337 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
338}
339
340BOOST_AUTO_TEST_CASE(InvalidTimestamp)
341{
342 name::Component timestampComp;
343 BOOST_CHECK_EQUAL(authorize1(
344 [&timestampComp] (const Interest& interest) {
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000345 timestampComp = interest.getName().at(ndn::command_interest::POS_TIMESTAMP);
Junxiao Shid7631272016-08-17 04:16:31 +0000346 }
347 ), true); // accept first command
348 BOOST_CHECK_EQUAL(authorize1(
349 [&timestampComp] (Interest& interest) {
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000350 setNameComponent(interest, ndn::command_interest::POS_TIMESTAMP, timestampComp);
Junxiao Shid7631272016-08-17 04:16:31 +0000351 }
352 ), false); // reject second command because timestamp equals first command
353 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
354}
355
Davide Pesaventod96744d2018-02-03 19:16:07 -0500356BOOST_FIXTURE_TEST_CASE(MissingAuthorizationsSection, CommandAuthenticatorFixture)
357{
358 Name id0("/localhost/CommandAuthenticator/0");
Davide Pesavento21353752020-11-20 00:43:44 -0500359 BOOST_REQUIRE(m_keyChain.createIdentity(id0));
Davide Pesaventod96744d2018-02-03 19:16:07 -0500360
361 makeModules({"module42"});
362 loadConfig("");
363
364 BOOST_CHECK_EQUAL(authorize("module42", id0), false);
365 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
366}
367
Junxiao Shid7631272016-08-17 04:16:31 +0000368BOOST_AUTO_TEST_SUITE_END() // Rejects
369
370BOOST_AUTO_TEST_SUITE(BadConfig)
371
372BOOST_AUTO_TEST_CASE(EmptyAuthorizationsSection)
373{
374 const std::string& config = R"CONFIG(
375 authorizations
376 {
377 }
378 )CONFIG";
379
380 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
381}
382
383BOOST_AUTO_TEST_CASE(UnrecognizedKey)
384{
385 const std::string& config = R"CONFIG(
386 authorizations
387 {
388 unrecognized_key
389 {
390 }
391 }
392 )CONFIG";
393
394 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
395}
396
397BOOST_AUTO_TEST_CASE(CertfileMissing)
398{
399 const std::string& config = R"CONFIG(
400 authorizations
401 {
402 authorize
403 {
404 privileges
405 {
406 }
407 }
408 }
409 )CONFIG";
410
411 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
412}
413
414BOOST_AUTO_TEST_CASE(CertUnreadable)
415{
416 const std::string& config = R"CONFIG(
417 authorizations
418 {
419 authorize
420 {
421 certfile "1.ndncert"
422 privileges
423 {
424 }
425 }
426 }
427 )CONFIG";
428
429 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
430}
431
432BOOST_AUTO_TEST_CASE(PrivilegesMissing)
433{
434 const std::string& config = R"CONFIG(
435 authorizations
436 {
437 authorize
438 {
439 certfile any
440 }
441 }
442 )CONFIG";
443
444 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
445}
446
447BOOST_AUTO_TEST_CASE(UnregisteredModule)
448{
449 const std::string& config = R"CONFIG(
450 authorizations
451 {
452 authorize
453 {
454 certfile any
455 privileges
456 {
457 nosuchmodule
458 }
459 }
460 }
461 )CONFIG";
462
463 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
464}
465
466BOOST_AUTO_TEST_SUITE_END() // BadConfig
467
468BOOST_AUTO_TEST_SUITE_END() // TestCommandAuthenticator
469BOOST_AUTO_TEST_SUITE_END() // Mgmt
470
471} // namespace tests
472} // namespace nfd