blob: 3c2d59d04e664dc78dcfe29d8dc732317bc6d190 [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
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040030namespace nfd::tests {
Junxiao Shid7631272016-08-17 04:16:31 +000031
Davide Pesavento20cafa82022-07-25 01:15:03 -040032class CommandAuthenticatorFixture : public InterestSignerFixture
Junxiao Shid7631272016-08-17 04:16:31 +000033{
34protected:
Junxiao Shid7631272016-08-17 04:16:31 +000035 void
36 makeModules(std::initializer_list<std::string> modules)
37 {
Davide Pesavento20cafa82022-07-25 01:15:03 -040038 for (const auto& module : modules) {
Junxiao Shid7631272016-08-17 04:16:31 +000039 authorizations.emplace(module, authenticator->makeAuthorization(module, "verb"));
40 }
41 }
42
43 void
44 loadConfig(const std::string& config)
45 {
Junxiao Shid7631272016-08-17 04:16:31 +000046 ConfigFile cf;
47 authenticator->setConfigFile(cf);
Davide Pesavento20cafa82022-07-25 01:15:03 -040048 cf.parse(config, false, "command-authenticator-test.conf");
Junxiao Shid7631272016-08-17 04:16:31 +000049 }
50
51 bool
52 authorize(const std::string& module, const Name& identity,
Davide Pesavento87fc0f82018-04-11 23:43:51 -040053 const std::function<void(Interest&)>& modifyInterest = nullptr)
Junxiao Shid7631272016-08-17 04:16:31 +000054 {
Junxiao Shi8a1f1702017-07-03 00:05:08 +000055 Interest interest = this->makeControlCommandRequest(Name("/prefix/" + module + "/verb"),
Davide Pesaventod96744d2018-02-03 19:16:07 -050056 ControlParameters(), identity);
Junxiao Shid7631272016-08-17 04:16:31 +000057 if (modifyInterest != nullptr) {
Junxiao Shi8a1f1702017-07-03 00:05:08 +000058 modifyInterest(interest);
Junxiao Shid7631272016-08-17 04:16:31 +000059 }
60
Davide Pesavento20cafa82022-07-25 01:15:03 -040061 const auto& authorization = authorizations.at(module);
Junxiao Shid7631272016-08-17 04:16:31 +000062
63 bool isAccepted = false;
64 bool isRejected = false;
Junxiao Shi8a1f1702017-07-03 00:05:08 +000065 authorization(Name("/prefix"), interest, nullptr,
Junxiao Shid7631272016-08-17 04:16:31 +000066 [this, &isAccepted, &isRejected] (const std::string& requester) {
67 BOOST_REQUIRE_MESSAGE(!isAccepted && !isRejected,
68 "authorization function should invoke only one continuation");
69 isAccepted = true;
70 lastRequester = requester;
71 },
72 [this, &isAccepted, &isRejected] (ndn::mgmt::RejectReply act) {
73 BOOST_REQUIRE_MESSAGE(!isAccepted && !isRejected,
74 "authorization function should invoke only one continuation");
75 isRejected = true;
76 lastRejectReply = act;
77 });
78
Davide Pesaventod96744d2018-02-03 19:16:07 -050079 this->advanceClocks(1_ms, 10);
Junxiao Shid7631272016-08-17 04:16:31 +000080 BOOST_REQUIRE_MESSAGE(isAccepted || isRejected,
81 "authorization function should invoke one continuation");
82 return isAccepted;
83 }
84
85protected:
Davide Pesavento20cafa82022-07-25 01:15:03 -040086 shared_ptr<CommandAuthenticator> authenticator = CommandAuthenticator::create();
Junxiao Shid7631272016-08-17 04:16:31 +000087 std::unordered_map<std::string, ndn::mgmt::Authorization> authorizations;
88 std::string lastRequester;
89 ndn::mgmt::RejectReply lastRejectReply;
90};
91
92BOOST_AUTO_TEST_SUITE(Mgmt)
93BOOST_FIXTURE_TEST_SUITE(TestCommandAuthenticator, CommandAuthenticatorFixture)
94
95BOOST_AUTO_TEST_CASE(Certs)
96{
97 Name id0("/localhost/CommandAuthenticator/0");
98 Name id1("/localhost/CommandAuthenticator/1");
99 Name id2("/localhost/CommandAuthenticator/2");
Davide Pesavento21353752020-11-20 00:43:44 -0500100 BOOST_REQUIRE(m_keyChain.createIdentity(id0));
101 BOOST_REQUIRE(saveIdentityCert(id1, "1.ndncert", true));
102 BOOST_REQUIRE(saveIdentityCert(id2, "2.ndncert", true));
Junxiao Shid7631272016-08-17 04:16:31 +0000103
104 makeModules({"module0", "module1", "module2", "module3", "module4", "module5", "module6", "module7"});
Davide Pesavento20cafa82022-07-25 01:15:03 -0400105 const std::string config = R"CONFIG(
Junxiao Shid7631272016-08-17 04:16:31 +0000106 authorizations
107 {
108 authorize
109 {
110 certfile any
111 privileges
112 {
113 module1
114 module3
115 module5
116 module7
117 }
118 }
119 authorize
120 {
121 certfile "1.ndncert"
122 privileges
123 {
124 module2
125 module3
126 module6
127 module7
128 }
129 }
130 authorize
131 {
132 certfile "2.ndncert"
133 privileges
134 {
135 module4
136 module5
137 module6
138 module7
139 }
140 }
141 }
142 )CONFIG";
143 loadConfig(config);
144
145 // module0: none
146 BOOST_CHECK_EQUAL(authorize("module0", id0), false);
147 BOOST_CHECK_EQUAL(authorize("module0", id1), false);
148 BOOST_CHECK_EQUAL(authorize("module0", id2), false);
149
150 // module1: any
151 BOOST_CHECK_EQUAL(authorize("module1", id0), true);
152 BOOST_CHECK_EQUAL(authorize("module1", id1), true);
153 BOOST_CHECK_EQUAL(authorize("module1", id2), true);
154
155 // module2: id1
156 BOOST_CHECK_EQUAL(authorize("module2", id0), false);
157 BOOST_CHECK_EQUAL(authorize("module2", id1), true);
158 BOOST_CHECK_EQUAL(authorize("module2", id2), false);
159
160 // module3: any,id1
161 BOOST_CHECK_EQUAL(authorize("module3", id0), true);
162 BOOST_CHECK_EQUAL(authorize("module3", id1), true);
163 BOOST_CHECK_EQUAL(authorize("module3", id2), true);
164
165 // module4: id2
166 BOOST_CHECK_EQUAL(authorize("module4", id0), false);
167 BOOST_CHECK_EQUAL(authorize("module4", id1), false);
168 BOOST_CHECK_EQUAL(authorize("module4", id2), true);
169
170 // module5: any,id2
171 BOOST_CHECK_EQUAL(authorize("module5", id0), true);
172 BOOST_CHECK_EQUAL(authorize("module5", id1), true);
173 BOOST_CHECK_EQUAL(authorize("module5", id2), true);
174
175 // module6: id1,id2
176 BOOST_CHECK_EQUAL(authorize("module6", id0), false);
177 BOOST_CHECK_EQUAL(authorize("module6", id1), true);
178 BOOST_CHECK_EQUAL(authorize("module6", id2), true);
179
180 // module7: any,id1,id2
181 BOOST_CHECK_EQUAL(authorize("module7", id0), true);
182 BOOST_CHECK_EQUAL(authorize("module7", id1), true);
183 BOOST_CHECK_EQUAL(authorize("module7", id2), true);
184}
185
186BOOST_AUTO_TEST_CASE(Requester)
187{
188 Name id0("/localhost/CommandAuthenticator/0");
189 Name id1("/localhost/CommandAuthenticator/1");
Davide Pesavento21353752020-11-20 00:43:44 -0500190 BOOST_REQUIRE(m_keyChain.createIdentity(id0));
191 BOOST_REQUIRE(saveIdentityCert(id1, "1.ndncert", true));
Junxiao Shid7631272016-08-17 04:16:31 +0000192
193 makeModules({"module0", "module1"});
Davide Pesavento20cafa82022-07-25 01:15:03 -0400194 const std::string config = R"CONFIG(
Junxiao Shid7631272016-08-17 04:16:31 +0000195 authorizations
196 {
197 authorize
198 {
199 certfile any
200 privileges
201 {
202 module0
203 }
204 }
205 authorize
206 {
207 certfile "1.ndncert"
208 privileges
209 {
210 module1
211 }
212 }
213 }
214 )CONFIG";
215 loadConfig(config);
216
217 // module0: any
218 BOOST_CHECK_EQUAL(authorize("module0", id0), true);
219 BOOST_CHECK_EQUAL(lastRequester, "*");
220 BOOST_CHECK_EQUAL(authorize("module0", id1), true);
221 BOOST_CHECK_EQUAL(lastRequester, "*");
222
223 // module1: id1
224 BOOST_CHECK_EQUAL(authorize("module1", id0), false);
225 BOOST_CHECK_EQUAL(authorize("module1", id1), true);
226 BOOST_CHECK(id1.isPrefixOf(lastRequester));
227}
228
229class IdentityAuthorizedFixture : public CommandAuthenticatorFixture
230{
231protected:
232 IdentityAuthorizedFixture()
Junxiao Shid7631272016-08-17 04:16:31 +0000233 {
Davide Pesavento21353752020-11-20 00:43:44 -0500234 BOOST_REQUIRE(saveIdentityCert(id1, "1.ndncert", true));
Junxiao Shid7631272016-08-17 04:16:31 +0000235
236 makeModules({"module1"});
Davide Pesavento20cafa82022-07-25 01:15:03 -0400237 const std::string config = R"CONFIG(
Junxiao Shid7631272016-08-17 04:16:31 +0000238 authorizations
239 {
240 authorize
241 {
242 certfile "1.ndncert"
243 privileges
244 {
245 module1
246 }
247 }
248 }
249 )CONFIG";
250 loadConfig(config);
251 }
252
253 bool
Davide Pesavento87fc0f82018-04-11 23:43:51 -0400254 authorize1(const std::function<void(Interest&)>& modifyInterest)
Junxiao Shid7631272016-08-17 04:16:31 +0000255 {
256 return authorize("module1", id1, modifyInterest);
257 }
258
259protected:
Davide Pesavento20cafa82022-07-25 01:15:03 -0400260 const Name id1{"/localhost/CommandAuthenticator/1"};
Junxiao Shid7631272016-08-17 04:16:31 +0000261};
262
Davide Pesavento20cafa82022-07-25 01:15:03 -0400263BOOST_FIXTURE_TEST_SUITE(Reject, IdentityAuthorizedFixture)
Junxiao Shid7631272016-08-17 04:16:31 +0000264
265BOOST_AUTO_TEST_CASE(BadKeyLocator_NameTooShort)
266{
267 BOOST_CHECK_EQUAL(authorize1(
268 [] (Interest& interest) {
269 interest.setName("/prefix");
270 }
271 ), false);
272 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
273}
274
Davide Pesavento20cafa82022-07-25 01:15:03 -0400275BOOST_AUTO_TEST_CASE(BadSigInfo)
Junxiao Shid7631272016-08-17 04:16:31 +0000276{
277 BOOST_CHECK_EQUAL(authorize1(
278 [] (Interest& interest) {
279 setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO, "not-SignatureInfo");
280 }
281 ), false);
282 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
283}
284
Davide Pesavento20cafa82022-07-25 01:15:03 -0400285BOOST_AUTO_TEST_CASE(MissingKeyLocator)
Junxiao Shid7631272016-08-17 04:16:31 +0000286{
287 BOOST_CHECK_EQUAL(authorize1(
288 [] (Interest& interest) {
Junxiao Shia9079802017-08-26 14:12:30 +0000289 ndn::SignatureInfo sigInfo(tlv::SignatureSha256WithRsa);
Davide Pesaventodeb54272022-03-11 18:51:05 -0500290 setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO, ndn::make_span(sigInfo.wireEncode()));
Junxiao Shid7631272016-08-17 04:16:31 +0000291 }
292 ), false);
293 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
294}
295
Davide Pesavento20cafa82022-07-25 01:15:03 -0400296BOOST_AUTO_TEST_CASE(BadKeyLocatorType)
Junxiao Shid7631272016-08-17 04:16:31 +0000297{
298 BOOST_CHECK_EQUAL(authorize1(
299 [] (Interest& interest) {
300 ndn::KeyLocator kl;
Davide Pesaventoa599d2a2022-02-16 18:52:43 -0500301 kl.setKeyDigest(ndn::makeBinaryBlock(tlv::KeyDigest,
302 {0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD}));
Junxiao Shia9079802017-08-26 14:12:30 +0000303 ndn::SignatureInfo sigInfo(tlv::SignatureSha256WithRsa);
Junxiao Shid7631272016-08-17 04:16:31 +0000304 sigInfo.setKeyLocator(kl);
Davide Pesaventodeb54272022-03-11 18:51:05 -0500305 setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO, ndn::make_span(sigInfo.wireEncode()));
Junxiao Shid7631272016-08-17 04:16:31 +0000306 }
307 ), false);
308 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
309}
310
Junxiao Shid7631272016-08-17 04:16:31 +0000311BOOST_AUTO_TEST_CASE(NotAuthorized)
312{
313 Name id0("/localhost/CommandAuthenticator/0");
Davide Pesavento21353752020-11-20 00:43:44 -0500314 BOOST_REQUIRE(m_keyChain.createIdentity(id0));
Junxiao Shid7631272016-08-17 04:16:31 +0000315
316 BOOST_CHECK_EQUAL(authorize("module1", id0), false);
317 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
318}
319
320BOOST_AUTO_TEST_CASE(BadSig)
321{
322 BOOST_CHECK_EQUAL(authorize1(
323 [] (Interest& interest) {
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000324 setNameComponent(interest, ndn::command_interest::POS_SIG_VALUE, "bad-signature-bits");
Junxiao Shid7631272016-08-17 04:16:31 +0000325 }
326 ), false);
327 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
328}
329
330BOOST_AUTO_TEST_CASE(InvalidTimestamp)
331{
332 name::Component timestampComp;
333 BOOST_CHECK_EQUAL(authorize1(
334 [&timestampComp] (const Interest& interest) {
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000335 timestampComp = interest.getName().at(ndn::command_interest::POS_TIMESTAMP);
Junxiao Shid7631272016-08-17 04:16:31 +0000336 }
337 ), true); // accept first command
338 BOOST_CHECK_EQUAL(authorize1(
339 [&timestampComp] (Interest& interest) {
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000340 setNameComponent(interest, ndn::command_interest::POS_TIMESTAMP, timestampComp);
Junxiao Shid7631272016-08-17 04:16:31 +0000341 }
342 ), false); // reject second command because timestamp equals first command
343 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
344}
345
Davide Pesaventod96744d2018-02-03 19:16:07 -0500346BOOST_FIXTURE_TEST_CASE(MissingAuthorizationsSection, CommandAuthenticatorFixture)
347{
348 Name id0("/localhost/CommandAuthenticator/0");
Davide Pesavento21353752020-11-20 00:43:44 -0500349 BOOST_REQUIRE(m_keyChain.createIdentity(id0));
Davide Pesaventod96744d2018-02-03 19:16:07 -0500350
351 makeModules({"module42"});
352 loadConfig("");
353
354 BOOST_CHECK_EQUAL(authorize("module42", id0), false);
355 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
356}
357
Davide Pesavento20cafa82022-07-25 01:15:03 -0400358BOOST_AUTO_TEST_SUITE_END() // Reject
Junxiao Shid7631272016-08-17 04:16:31 +0000359
360BOOST_AUTO_TEST_SUITE(BadConfig)
361
362BOOST_AUTO_TEST_CASE(EmptyAuthorizationsSection)
363{
Davide Pesavento20cafa82022-07-25 01:15:03 -0400364 const std::string config = R"CONFIG(
Junxiao Shid7631272016-08-17 04:16:31 +0000365 authorizations
366 {
367 }
368 )CONFIG";
369
370 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
371}
372
373BOOST_AUTO_TEST_CASE(UnrecognizedKey)
374{
Davide Pesavento20cafa82022-07-25 01:15:03 -0400375 const std::string config = R"CONFIG(
Junxiao Shid7631272016-08-17 04:16:31 +0000376 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{
Davide Pesavento20cafa82022-07-25 01:15:03 -0400389 const std::string config = R"CONFIG(
Junxiao Shid7631272016-08-17 04:16:31 +0000390 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{
Davide Pesavento20cafa82022-07-25 01:15:03 -0400406 const std::string config = R"CONFIG(
Junxiao Shid7631272016-08-17 04:16:31 +0000407 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{
Davide Pesavento20cafa82022-07-25 01:15:03 -0400424 const std::string config = R"CONFIG(
Junxiao Shid7631272016-08-17 04:16:31 +0000425 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{
Davide Pesavento20cafa82022-07-25 01:15:03 -0400439 const std::string config = R"CONFIG(
Junxiao Shid7631272016-08-17 04:16:31 +0000440 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
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400461} // namespace nfd::tests