blob: 7d2ed6ead920bb761f22cc781f1864dfdee97614 [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"
27#include <ndn-cxx/security/signing-helpers.hpp>
28#include <boost/filesystem.hpp>
29
30#include "tests/test-common.hpp"
31#include "tests/identity-management-fixture.hpp"
32
33namespace nfd {
34namespace tests {
35
36class CommandAuthenticatorFixture : public IdentityManagementTimeFixture
37{
38protected:
39 CommandAuthenticatorFixture()
40 : authenticator(CommandAuthenticator::create())
41 {
42 }
43
44 void
45 makeModules(std::initializer_list<std::string> modules)
46 {
47 for (const std::string& module : modules) {
48 authorizations.emplace(module, authenticator->makeAuthorization(module, "verb"));
49 }
50 }
51
52 void
53 loadConfig(const std::string& config)
54 {
55 boost::filesystem::path configPath = boost::filesystem::current_path() /=
56 "command-authenticator-test.conf";
57 ConfigFile cf;
58 authenticator->setConfigFile(cf);
59 cf.parse(config, false, configPath.c_str());
60 }
61
62 bool
63 authorize(const std::string& module, const Name& identity,
64 const function<void(Interest&)>& modifyInterest = nullptr)
65 {
66 auto interest = makeInterest(Name("/prefix").append(module).append("verb"));
67 m_keyChain.sign(*interest, signingByIdentity(identity));
68 if (modifyInterest != nullptr) {
69 modifyInterest(*interest);
70 }
71
72 ndn::mgmt::Authorization authorization = authorizations.at(module);
73
74 bool isAccepted = false;
75 bool isRejected = false;
76 authorization(Name("/prefix"), *interest, nullptr,
77 [this, &isAccepted, &isRejected] (const std::string& requester) {
78 BOOST_REQUIRE_MESSAGE(!isAccepted && !isRejected,
79 "authorization function should invoke only one continuation");
80 isAccepted = true;
81 lastRequester = requester;
82 },
83 [this, &isAccepted, &isRejected] (ndn::mgmt::RejectReply act) {
84 BOOST_REQUIRE_MESSAGE(!isAccepted && !isRejected,
85 "authorization function should invoke only one continuation");
86 isRejected = true;
87 lastRejectReply = act;
88 });
89
90 this->advanceClocks(time::milliseconds(1), 10);
91 BOOST_REQUIRE_MESSAGE(isAccepted || isRejected,
92 "authorization function should invoke one continuation");
93 return isAccepted;
94 }
95
96protected:
97 shared_ptr<CommandAuthenticator> authenticator;
98 std::unordered_map<std::string, ndn::mgmt::Authorization> authorizations;
99 std::string lastRequester;
100 ndn::mgmt::RejectReply lastRejectReply;
101};
102
103BOOST_AUTO_TEST_SUITE(Mgmt)
104BOOST_FIXTURE_TEST_SUITE(TestCommandAuthenticator, CommandAuthenticatorFixture)
105
106BOOST_AUTO_TEST_CASE(Certs)
107{
108 Name id0("/localhost/CommandAuthenticator/0");
109 Name id1("/localhost/CommandAuthenticator/1");
110 Name id2("/localhost/CommandAuthenticator/2");
111 BOOST_REQUIRE(addIdentity(id0));
112 BOOST_REQUIRE(saveIdentityCertificate(id1, "1.ndncert", true));
113 BOOST_REQUIRE(saveIdentityCertificate(id2, "2.ndncert", true));
114
115 makeModules({"module0", "module1", "module2", "module3", "module4", "module5", "module6", "module7"});
116 const std::string& config = R"CONFIG(
117 authorizations
118 {
119 authorize
120 {
121 certfile any
122 privileges
123 {
124 module1
125 module3
126 module5
127 module7
128 }
129 }
130 authorize
131 {
132 certfile "1.ndncert"
133 privileges
134 {
135 module2
136 module3
137 module6
138 module7
139 }
140 }
141 authorize
142 {
143 certfile "2.ndncert"
144 privileges
145 {
146 module4
147 module5
148 module6
149 module7
150 }
151 }
152 }
153 )CONFIG";
154 loadConfig(config);
155
156 // module0: none
157 BOOST_CHECK_EQUAL(authorize("module0", id0), false);
158 BOOST_CHECK_EQUAL(authorize("module0", id1), false);
159 BOOST_CHECK_EQUAL(authorize("module0", id2), false);
160
161 // module1: any
162 BOOST_CHECK_EQUAL(authorize("module1", id0), true);
163 BOOST_CHECK_EQUAL(authorize("module1", id1), true);
164 BOOST_CHECK_EQUAL(authorize("module1", id2), true);
165
166 // module2: id1
167 BOOST_CHECK_EQUAL(authorize("module2", id0), false);
168 BOOST_CHECK_EQUAL(authorize("module2", id1), true);
169 BOOST_CHECK_EQUAL(authorize("module2", id2), false);
170
171 // module3: any,id1
172 BOOST_CHECK_EQUAL(authorize("module3", id0), true);
173 BOOST_CHECK_EQUAL(authorize("module3", id1), true);
174 BOOST_CHECK_EQUAL(authorize("module3", id2), true);
175
176 // module4: id2
177 BOOST_CHECK_EQUAL(authorize("module4", id0), false);
178 BOOST_CHECK_EQUAL(authorize("module4", id1), false);
179 BOOST_CHECK_EQUAL(authorize("module4", id2), true);
180
181 // module5: any,id2
182 BOOST_CHECK_EQUAL(authorize("module5", id0), true);
183 BOOST_CHECK_EQUAL(authorize("module5", id1), true);
184 BOOST_CHECK_EQUAL(authorize("module5", id2), true);
185
186 // module6: id1,id2
187 BOOST_CHECK_EQUAL(authorize("module6", id0), false);
188 BOOST_CHECK_EQUAL(authorize("module6", id1), true);
189 BOOST_CHECK_EQUAL(authorize("module6", id2), true);
190
191 // module7: any,id1,id2
192 BOOST_CHECK_EQUAL(authorize("module7", id0), true);
193 BOOST_CHECK_EQUAL(authorize("module7", id1), true);
194 BOOST_CHECK_EQUAL(authorize("module7", id2), true);
195}
196
197BOOST_AUTO_TEST_CASE(Requester)
198{
199 Name id0("/localhost/CommandAuthenticator/0");
200 Name id1("/localhost/CommandAuthenticator/1");
201 BOOST_REQUIRE(addIdentity(id0));
202 BOOST_REQUIRE(saveIdentityCertificate(id1, "1.ndncert", true));
203
204 makeModules({"module0", "module1"});
205 const std::string& config = R"CONFIG(
206 authorizations
207 {
208 authorize
209 {
210 certfile any
211 privileges
212 {
213 module0
214 }
215 }
216 authorize
217 {
218 certfile "1.ndncert"
219 privileges
220 {
221 module1
222 }
223 }
224 }
225 )CONFIG";
226 loadConfig(config);
227
228 // module0: any
229 BOOST_CHECK_EQUAL(authorize("module0", id0), true);
230 BOOST_CHECK_EQUAL(lastRequester, "*");
231 BOOST_CHECK_EQUAL(authorize("module0", id1), true);
232 BOOST_CHECK_EQUAL(lastRequester, "*");
233
234 // module1: id1
235 BOOST_CHECK_EQUAL(authorize("module1", id0), false);
236 BOOST_CHECK_EQUAL(authorize("module1", id1), true);
237 BOOST_CHECK(id1.isPrefixOf(lastRequester));
238}
239
240class IdentityAuthorizedFixture : public CommandAuthenticatorFixture
241{
242protected:
243 IdentityAuthorizedFixture()
244 : id1("/localhost/CommandAuthenticator/1")
245 {
246 BOOST_REQUIRE(saveIdentityCertificate(id1, "1.ndncert", true));
247
248 makeModules({"module1"});
249 const std::string& config = R"CONFIG(
250 authorizations
251 {
252 authorize
253 {
254 certfile "1.ndncert"
255 privileges
256 {
257 module1
258 }
259 }
260 }
261 )CONFIG";
262 loadConfig(config);
263 }
264
265 bool
266 authorize1(const function<void(Interest&)>& modifyInterest)
267 {
268 return authorize("module1", id1, modifyInterest);
269 }
270
271protected:
272 Name id1;
273};
274
275BOOST_FIXTURE_TEST_SUITE(Rejects, IdentityAuthorizedFixture)
276
277BOOST_AUTO_TEST_CASE(BadKeyLocator_NameTooShort)
278{
279 BOOST_CHECK_EQUAL(authorize1(
280 [] (Interest& interest) {
281 interest.setName("/prefix");
282 }
283 ), false);
284 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
285}
286
287BOOST_AUTO_TEST_CASE(BadKeyLocator_BadSigInfo)
288{
289 BOOST_CHECK_EQUAL(authorize1(
290 [] (Interest& interest) {
291 setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO, "not-SignatureInfo");
292 }
293 ), false);
294 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
295}
296
297BOOST_AUTO_TEST_CASE(BadKeyLocator_MissingKeyLocator)
298{
299 BOOST_CHECK_EQUAL(authorize1(
300 [] (Interest& interest) {
301 ndn::SignatureInfo sigInfo;
302 setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO,
303 sigInfo.wireEncode().begin(), sigInfo.wireEncode().end());
304 }
305 ), false);
306 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
307}
308
309BOOST_AUTO_TEST_CASE(BadKeyLocator_BadKeyLocatorType)
310{
311 BOOST_CHECK_EQUAL(authorize1(
312 [] (Interest& interest) {
313 ndn::KeyLocator kl;
314 kl.setKeyDigest(ndn::encoding::makeBinaryBlock(tlv::KeyDigest, "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD", 8));
315 ndn::SignatureInfo sigInfo;
316 sigInfo.setKeyLocator(kl);
317 setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO,
318 sigInfo.wireEncode().begin(), sigInfo.wireEncode().end());
319 }
320 ), false);
321 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
322}
323
Junxiao Shid7631272016-08-17 04:16:31 +0000324BOOST_AUTO_TEST_CASE(NotAuthorized)
325{
326 Name id0("/localhost/CommandAuthenticator/0");
327 BOOST_REQUIRE(addIdentity(id0));
328
329 BOOST_CHECK_EQUAL(authorize("module1", id0), false);
330 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
331}
332
333BOOST_AUTO_TEST_CASE(BadSig)
334{
335 BOOST_CHECK_EQUAL(authorize1(
336 [] (Interest& interest) {
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000337 setNameComponent(interest, ndn::command_interest::POS_SIG_VALUE, "bad-signature-bits");
Junxiao Shid7631272016-08-17 04:16:31 +0000338 }
339 ), false);
340 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
341}
342
Junxiao Shi16a3adf2017-05-26 17:38:51 +0000343BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(InvalidTimestamp, 2)
Junxiao Shid7631272016-08-17 04:16:31 +0000344BOOST_AUTO_TEST_CASE(InvalidTimestamp)
345{
346 name::Component timestampComp;
347 BOOST_CHECK_EQUAL(authorize1(
348 [&timestampComp] (const Interest& interest) {
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000349 timestampComp = interest.getName().at(ndn::command_interest::POS_TIMESTAMP);
Junxiao Shid7631272016-08-17 04:16:31 +0000350 }
351 ), true); // accept first command
352 BOOST_CHECK_EQUAL(authorize1(
353 [&timestampComp] (Interest& interest) {
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000354 setNameComponent(interest, ndn::command_interest::POS_TIMESTAMP, timestampComp);
Junxiao Shid7631272016-08-17 04:16:31 +0000355 }
356 ), false); // reject second command because timestamp equals first command
357 BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
358}
359
360BOOST_AUTO_TEST_SUITE_END() // Rejects
361
362BOOST_AUTO_TEST_SUITE(BadConfig)
363
364BOOST_AUTO_TEST_CASE(EmptyAuthorizationsSection)
365{
366 const std::string& config = R"CONFIG(
367 authorizations
368 {
369 }
370 )CONFIG";
371
372 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
373}
374
375BOOST_AUTO_TEST_CASE(UnrecognizedKey)
376{
377 const std::string& config = R"CONFIG(
378 authorizations
379 {
380 unrecognized_key
381 {
382 }
383 }
384 )CONFIG";
385
386 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
387}
388
389BOOST_AUTO_TEST_CASE(CertfileMissing)
390{
391 const std::string& config = R"CONFIG(
392 authorizations
393 {
394 authorize
395 {
396 privileges
397 {
398 }
399 }
400 }
401 )CONFIG";
402
403 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
404}
405
406BOOST_AUTO_TEST_CASE(CertUnreadable)
407{
408 const std::string& config = R"CONFIG(
409 authorizations
410 {
411 authorize
412 {
413 certfile "1.ndncert"
414 privileges
415 {
416 }
417 }
418 }
419 )CONFIG";
420
421 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
422}
423
424BOOST_AUTO_TEST_CASE(PrivilegesMissing)
425{
426 const std::string& config = R"CONFIG(
427 authorizations
428 {
429 authorize
430 {
431 certfile any
432 }
433 }
434 )CONFIG";
435
436 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
437}
438
439BOOST_AUTO_TEST_CASE(UnregisteredModule)
440{
441 const std::string& config = R"CONFIG(
442 authorizations
443 {
444 authorize
445 {
446 certfile any
447 privileges
448 {
449 nosuchmodule
450 }
451 }
452 }
453 )CONFIG";
454
455 BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
456}
457
458BOOST_AUTO_TEST_SUITE_END() // BadConfig
459
460BOOST_AUTO_TEST_SUITE_END() // TestCommandAuthenticator
461BOOST_AUTO_TEST_SUITE_END() // Mgmt
462
463} // namespace tests
464} // namespace nfd