blob: 051d7c9f99362ea9802de80e6834f9ba349e0616 [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
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040032namespace nfd::tests {
Junxiao Shid7631272016-08-17 04:16:31 +000033
Junxiao Shi8a1f1702017-07-03 00:05:08 +000034class CommandAuthenticatorFixture : public CommandInterestSignerFixture
Junxiao Shid7631272016-08-17 04:16:31 +000035{
36protected:
37 CommandAuthenticatorFixture()
38 : authenticator(CommandAuthenticator::create())
39 {
40 }
41
42 void
43 makeModules(std::initializer_list<std::string> modules)
44 {
45 for (const std::string& module : modules) {
46 authorizations.emplace(module, authenticator->makeAuthorization(module, "verb"));
47 }
48 }
49
50 void
51 loadConfig(const std::string& config)
52 {
Davide Pesaventod96744d2018-02-03 19:16:07 -050053 auto configPath = boost::filesystem::current_path() / "command-authenticator-test.conf";
Junxiao Shid7631272016-08-17 04:16:31 +000054 ConfigFile cf;
55 authenticator->setConfigFile(cf);
56 cf.parse(config, false, configPath.c_str());
57 }
58
59 bool
60 authorize(const std::string& module, const Name& identity,
Davide Pesavento87fc0f82018-04-11 23:43:51 -040061 const std::function<void(Interest&)>& modifyInterest = nullptr)
Junxiao Shid7631272016-08-17 04:16:31 +000062 {
Junxiao Shi8a1f1702017-07-03 00:05:08 +000063 Interest interest = this->makeControlCommandRequest(Name("/prefix/" + module + "/verb"),
Davide Pesaventod96744d2018-02-03 19:16:07 -050064 ControlParameters(), identity);
Junxiao Shid7631272016-08-17 04:16:31 +000065 if (modifyInterest != nullptr) {
Junxiao Shi8a1f1702017-07-03 00:05:08 +000066 modifyInterest(interest);
Junxiao Shid7631272016-08-17 04:16:31 +000067 }
68
69 ndn::mgmt::Authorization authorization = authorizations.at(module);
70
71 bool isAccepted = false;
72 bool isRejected = false;
Junxiao Shi8a1f1702017-07-03 00:05:08 +000073 authorization(Name("/prefix"), interest, nullptr,
Junxiao Shid7631272016-08-17 04:16:31 +000074 [this, &isAccepted, &isRejected] (const std::string& requester) {
75 BOOST_REQUIRE_MESSAGE(!isAccepted && !isRejected,
76 "authorization function should invoke only one continuation");
77 isAccepted = true;
78 lastRequester = requester;
79 },
80 [this, &isAccepted, &isRejected] (ndn::mgmt::RejectReply act) {
81 BOOST_REQUIRE_MESSAGE(!isAccepted && !isRejected,
82 "authorization function should invoke only one continuation");
83 isRejected = true;
84 lastRejectReply = act;
85 });
86
Davide Pesaventod96744d2018-02-03 19:16:07 -050087 this->advanceClocks(1_ms, 10);
Junxiao Shid7631272016-08-17 04:16:31 +000088 BOOST_REQUIRE_MESSAGE(isAccepted || isRejected,
89 "authorization function should invoke one continuation");
90 return isAccepted;
91 }
92
93protected:
94 shared_ptr<CommandAuthenticator> authenticator;
95 std::unordered_map<std::string, ndn::mgmt::Authorization> authorizations;
96 std::string lastRequester;
97 ndn::mgmt::RejectReply lastRejectReply;
98};
99
100BOOST_AUTO_TEST_SUITE(Mgmt)
101BOOST_FIXTURE_TEST_SUITE(TestCommandAuthenticator, CommandAuthenticatorFixture)
102
103BOOST_AUTO_TEST_CASE(Certs)
104{
105 Name id0("/localhost/CommandAuthenticator/0");
106 Name id1("/localhost/CommandAuthenticator/1");
107 Name id2("/localhost/CommandAuthenticator/2");
Davide Pesavento21353752020-11-20 00:43:44 -0500108 BOOST_REQUIRE(m_keyChain.createIdentity(id0));
109 BOOST_REQUIRE(saveIdentityCert(id1, "1.ndncert", true));
110 BOOST_REQUIRE(saveIdentityCert(id2, "2.ndncert", true));
Junxiao Shid7631272016-08-17 04:16:31 +0000111
112 makeModules({"module0", "module1", "module2", "module3", "module4", "module5", "module6", "module7"});
113 const std::string& config = R"CONFIG(
114 authorizations
115 {
116 authorize
117 {
118 certfile any
119 privileges
120 {
121 module1
122 module3
123 module5
124 module7
125 }
126 }
127 authorize
128 {
129 certfile "1.ndncert"
130 privileges
131 {
132 module2
133 module3
134 module6
135 module7
136 }
137 }
138 authorize
139 {
140 certfile "2.ndncert"
141 privileges
142 {
143 module4
144 module5
145 module6
146 module7
147 }
148 }
149 }
150 )CONFIG";
151 loadConfig(config);
152
153 // module0: none
154 BOOST_CHECK_EQUAL(authorize("module0", id0), false);
155 BOOST_CHECK_EQUAL(authorize("module0", id1), false);
156 BOOST_CHECK_EQUAL(authorize("module0", id2), false);
157
158 // module1: any
159 BOOST_CHECK_EQUAL(authorize("module1", id0), true);
160 BOOST_CHECK_EQUAL(authorize("module1", id1), true);
161 BOOST_CHECK_EQUAL(authorize("module1", id2), true);
162
163 // module2: id1
164 BOOST_CHECK_EQUAL(authorize("module2", id0), false);
165 BOOST_CHECK_EQUAL(authorize("module2", id1), true);
166 BOOST_CHECK_EQUAL(authorize("module2", id2), false);
167
168 // module3: any,id1
169 BOOST_CHECK_EQUAL(authorize("module3", id0), true);
170 BOOST_CHECK_EQUAL(authorize("module3", id1), true);
171 BOOST_CHECK_EQUAL(authorize("module3", id2), true);
172
173 // module4: id2
174 BOOST_CHECK_EQUAL(authorize("module4", id0), false);
175 BOOST_CHECK_EQUAL(authorize("module4", id1), false);
176 BOOST_CHECK_EQUAL(authorize("module4", id2), true);
177
178 // module5: any,id2
179 BOOST_CHECK_EQUAL(authorize("module5", id0), true);
180 BOOST_CHECK_EQUAL(authorize("module5", id1), true);
181 BOOST_CHECK_EQUAL(authorize("module5", id2), true);
182
183 // module6: id1,id2
184 BOOST_CHECK_EQUAL(authorize("module6", id0), false);
185 BOOST_CHECK_EQUAL(authorize("module6", id1), true);
186 BOOST_CHECK_EQUAL(authorize("module6", id2), true);
187
188 // module7: any,id1,id2
189 BOOST_CHECK_EQUAL(authorize("module7", id0), true);
190 BOOST_CHECK_EQUAL(authorize("module7", id1), true);
191 BOOST_CHECK_EQUAL(authorize("module7", id2), true);
192}
193
194BOOST_AUTO_TEST_CASE(Requester)
195{
196 Name id0("/localhost/CommandAuthenticator/0");
197 Name id1("/localhost/CommandAuthenticator/1");
Davide Pesavento21353752020-11-20 00:43:44 -0500198 BOOST_REQUIRE(m_keyChain.createIdentity(id0));
199 BOOST_REQUIRE(saveIdentityCert(id1, "1.ndncert", true));
Junxiao Shid7631272016-08-17 04:16:31 +0000200
201 makeModules({"module0", "module1"});
202 const std::string& config = R"CONFIG(
203 authorizations
204 {
205 authorize
206 {
207 certfile any
208 privileges
209 {
210 module0
211 }
212 }
213 authorize
214 {
215 certfile "1.ndncert"
216 privileges
217 {
218 module1
219 }
220 }
221 }
222 )CONFIG";
223 loadConfig(config);
224
225 // module0: any
226 BOOST_CHECK_EQUAL(authorize("module0", id0), true);
227 BOOST_CHECK_EQUAL(lastRequester, "*");
228 BOOST_CHECK_EQUAL(authorize("module0", id1), true);
229 BOOST_CHECK_EQUAL(lastRequester, "*");
230
231 // module1: id1
232 BOOST_CHECK_EQUAL(authorize("module1", id0), false);
233 BOOST_CHECK_EQUAL(authorize("module1", id1), true);
234 BOOST_CHECK(id1.isPrefixOf(lastRequester));
235}
236
237class IdentityAuthorizedFixture : public CommandAuthenticatorFixture
238{
239protected:
240 IdentityAuthorizedFixture()
241 : id1("/localhost/CommandAuthenticator/1")
242 {
Davide Pesavento21353752020-11-20 00:43:44 -0500243 BOOST_REQUIRE(saveIdentityCert(id1, "1.ndncert", true));
Junxiao Shid7631272016-08-17 04:16:31 +0000244
245 makeModules({"module1"});
246 const std::string& config = R"CONFIG(
247 authorizations
248 {
249 authorize
250 {
251 certfile "1.ndncert"
252 privileges
253 {
254 module1
255 }
256 }
257 }
258 )CONFIG";
259 loadConfig(config);
260 }
261
262 bool
Davide Pesavento87fc0f82018-04-11 23:43:51 -0400263 authorize1(const std::function<void(Interest&)>& modifyInterest)
Junxiao Shid7631272016-08-17 04:16:31 +0000264 {
265 return authorize("module1", id1, modifyInterest);
266 }
267
268protected:
269 Name id1;
270};
271
272BOOST_FIXTURE_TEST_SUITE(Rejects, IdentityAuthorizedFixture)
273
274BOOST_AUTO_TEST_CASE(BadKeyLocator_NameTooShort)
275{
276 BOOST_CHECK_EQUAL(authorize1(
277 [] (Interest& interest) {
278 interest.setName("/prefix");
279 }
280 ), false);
281 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
282}
283
284BOOST_AUTO_TEST_CASE(BadKeyLocator_BadSigInfo)
285{
286 BOOST_CHECK_EQUAL(authorize1(
287 [] (Interest& interest) {
288 setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO, "not-SignatureInfo");
289 }
290 ), false);
291 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
292}
293
294BOOST_AUTO_TEST_CASE(BadKeyLocator_MissingKeyLocator)
295{
296 BOOST_CHECK_EQUAL(authorize1(
297 [] (Interest& interest) {
Junxiao Shia9079802017-08-26 14:12:30 +0000298 ndn::SignatureInfo sigInfo(tlv::SignatureSha256WithRsa);
Davide Pesaventodeb54272022-03-11 18:51:05 -0500299 setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO, ndn::make_span(sigInfo.wireEncode()));
Junxiao Shid7631272016-08-17 04:16:31 +0000300 }
301 ), false);
302 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
303}
304
305BOOST_AUTO_TEST_CASE(BadKeyLocator_BadKeyLocatorType)
306{
307 BOOST_CHECK_EQUAL(authorize1(
308 [] (Interest& interest) {
309 ndn::KeyLocator kl;
Davide Pesaventoa599d2a2022-02-16 18:52:43 -0500310 kl.setKeyDigest(ndn::makeBinaryBlock(tlv::KeyDigest,
311 {0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD}));
Junxiao Shia9079802017-08-26 14:12:30 +0000312 ndn::SignatureInfo sigInfo(tlv::SignatureSha256WithRsa);
Junxiao Shid7631272016-08-17 04:16:31 +0000313 sigInfo.setKeyLocator(kl);
Davide Pesaventodeb54272022-03-11 18:51:05 -0500314 setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO, ndn::make_span(sigInfo.wireEncode()));
Junxiao Shid7631272016-08-17 04:16:31 +0000315 }
316 ), false);
317 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
318}
319
Junxiao Shid7631272016-08-17 04:16:31 +0000320BOOST_AUTO_TEST_CASE(NotAuthorized)
321{
322 Name id0("/localhost/CommandAuthenticator/0");
Davide Pesavento21353752020-11-20 00:43:44 -0500323 BOOST_REQUIRE(m_keyChain.createIdentity(id0));
Junxiao Shid7631272016-08-17 04:16:31 +0000324
325 BOOST_CHECK_EQUAL(authorize("module1", id0), false);
326 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
327}
328
329BOOST_AUTO_TEST_CASE(BadSig)
330{
331 BOOST_CHECK_EQUAL(authorize1(
332 [] (Interest& interest) {
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000333 setNameComponent(interest, ndn::command_interest::POS_SIG_VALUE, "bad-signature-bits");
Junxiao Shid7631272016-08-17 04:16:31 +0000334 }
335 ), false);
336 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
337}
338
339BOOST_AUTO_TEST_CASE(InvalidTimestamp)
340{
341 name::Component timestampComp;
342 BOOST_CHECK_EQUAL(authorize1(
343 [&timestampComp] (const Interest& interest) {
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000344 timestampComp = interest.getName().at(ndn::command_interest::POS_TIMESTAMP);
Junxiao Shid7631272016-08-17 04:16:31 +0000345 }
346 ), true); // accept first command
347 BOOST_CHECK_EQUAL(authorize1(
348 [&timestampComp] (Interest& interest) {
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000349 setNameComponent(interest, ndn::command_interest::POS_TIMESTAMP, timestampComp);
Junxiao Shid7631272016-08-17 04:16:31 +0000350 }
351 ), false); // reject second command because timestamp equals first command
352 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
353}
354
Davide Pesaventod96744d2018-02-03 19:16:07 -0500355BOOST_FIXTURE_TEST_CASE(MissingAuthorizationsSection, CommandAuthenticatorFixture)
356{
357 Name id0("/localhost/CommandAuthenticator/0");
Davide Pesavento21353752020-11-20 00:43:44 -0500358 BOOST_REQUIRE(m_keyChain.createIdentity(id0));
Davide Pesaventod96744d2018-02-03 19:16:07 -0500359
360 makeModules({"module42"});
361 loadConfig("");
362
363 BOOST_CHECK_EQUAL(authorize("module42", id0), false);
364 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
365}
366
Junxiao Shid7631272016-08-17 04:16:31 +0000367BOOST_AUTO_TEST_SUITE_END() // Rejects
368
369BOOST_AUTO_TEST_SUITE(BadConfig)
370
371BOOST_AUTO_TEST_CASE(EmptyAuthorizationsSection)
372{
373 const std::string& config = R"CONFIG(
374 authorizations
375 {
376 }
377 )CONFIG";
378
379 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
380}
381
382BOOST_AUTO_TEST_CASE(UnrecognizedKey)
383{
384 const std::string& config = R"CONFIG(
385 authorizations
386 {
387 unrecognized_key
388 {
389 }
390 }
391 )CONFIG";
392
393 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
394}
395
396BOOST_AUTO_TEST_CASE(CertfileMissing)
397{
398 const std::string& config = R"CONFIG(
399 authorizations
400 {
401 authorize
402 {
403 privileges
404 {
405 }
406 }
407 }
408 )CONFIG";
409
410 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
411}
412
413BOOST_AUTO_TEST_CASE(CertUnreadable)
414{
415 const std::string& config = R"CONFIG(
416 authorizations
417 {
418 authorize
419 {
420 certfile "1.ndncert"
421 privileges
422 {
423 }
424 }
425 }
426 )CONFIG";
427
428 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
429}
430
431BOOST_AUTO_TEST_CASE(PrivilegesMissing)
432{
433 const std::string& config = R"CONFIG(
434 authorizations
435 {
436 authorize
437 {
438 certfile any
439 }
440 }
441 )CONFIG";
442
443 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
444}
445
446BOOST_AUTO_TEST_CASE(UnregisteredModule)
447{
448 const std::string& config = R"CONFIG(
449 authorizations
450 {
451 authorize
452 {
453 certfile any
454 privileges
455 {
456 nosuchmodule
457 }
458 }
459 }
460 )CONFIG";
461
462 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
463}
464
465BOOST_AUTO_TEST_SUITE_END() // BadConfig
466
467BOOST_AUTO_TEST_SUITE_END() // TestCommandAuthenticator
468BOOST_AUTO_TEST_SUITE_END() // Mgmt
469
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400470} // namespace nfd::tests