security: Support wildcard in NFD configuration
Change-Id: Ie27abd2315be0adf2e813049208e9cb96d16aff5
Refs: #1559
diff --git a/daemon/mgmt/command-validator.cpp b/daemon/mgmt/command-validator.cpp
index f7b0df2..ea596b1 100644
--- a/daemon/mgmt/command-validator.cpp
+++ b/daemon/mgmt/command-validator.cpp
@@ -96,46 +96,58 @@
continue;
}
- path certfilePath = absolute(certfile, path(filename).parent_path());
- NFD_LOG_DEBUG("generated certfile path: " << certfilePath.native());
-
- std::ifstream in;
- in.open(certfilePath.c_str());
- if (!in.is_open())
- {
- std::string msg = "Unable to open certificate file " + certfilePath.native();
- if (!isDryRun)
- {
- throw ConfigFile::Error(msg);
- }
- aggregateErrors(dryRunErrors, msg);
- continue;
- }
-
shared_ptr<ndn::IdentityCertificate> id;
- try
- {
- id = ndn::io::load<ndn::IdentityCertificate>(in);
- }
- catch(const std::runtime_error& error)
- {
- // do nothing
- }
- if (!static_cast<bool>(id)) {
- std::string msg = "Malformed certificate file " + certfilePath.native();
- if (!isDryRun)
- {
- throw ConfigFile::Error(msg);
+ if (certfile != "any")
+ {
+ path certfilePath = absolute(certfile, path(filename).parent_path());
+ NFD_LOG_DEBUG("generated certfile path: " << certfilePath.native());
+
+ std::ifstream in;
+ in.open(certfilePath.c_str());
+ if (!in.is_open())
+ {
+ std::string msg = "Unable to open certificate file " + certfilePath.native();
+ if (!isDryRun)
+ {
+ throw ConfigFile::Error(msg);
+ }
+ aggregateErrors(dryRunErrors, msg);
+ continue;
+ }
+
+ try
+ {
+ id = ndn::io::load<ndn::IdentityCertificate>(in);
+ }
+ catch (const std::runtime_error& error)
+ {
+ // do nothing
+ }
+
+ if (!static_cast<bool>(id)) {
+ std::string msg = "Malformed certificate file " + certfilePath.native();
+ if (!isDryRun)
+ {
+ throw ConfigFile::Error(msg);
+ }
+ aggregateErrors(dryRunErrors, msg);
+ continue;
}
- aggregateErrors(dryRunErrors, msg);
- continue;
- }
- in.close();
+ in.close();
+ }
+ std::string keyNameForLogging;
+ if (static_cast<bool>(id))
+ keyNameForLogging = id->getPublicKeyName().toUri();
+ else
+ {
+ keyNameForLogging = "wildcard";
+ NFD_LOG_WARN("Wildcard identity is intended for demo purpose only and " <<
+ "SHOULD NOT be used in production environment");
+ }
const ConfigSection* privileges = 0;
-
try
{
privileges = &authIt->second.get_child("privileges");
@@ -143,7 +155,7 @@
catch (const std::runtime_error& error)
{
std::string msg = "No privileges section found for certificate file " +
- certfile + " (" + id->getPublicKeyName().toUri() + ")";
+ certfile + " (" + keyNameForLogging + ")";
if (!isDryRun)
{
throw ConfigFile::Error(msg);
@@ -155,7 +167,7 @@
if (privileges->begin() == privileges->end())
{
NFD_LOG_WARN("No privileges specified for certificate file " << certfile
- << " (" << id->getPublicKeyName().toUri() << ")");
+ << " (" << keyNameForLogging << ")");
}
ConfigSection::const_iterator privIt;
@@ -165,18 +177,21 @@
if (m_supportedPrivileges.find(privilegeName) != m_supportedPrivileges.end())
{
NFD_LOG_INFO("Giving privilege \"" << privilegeName
- << "\" to identity " << id->getPublicKeyName());
+ << "\" to identity " << keyNameForLogging);
if (!isDryRun)
{
const std::string regex = "^<localhost><nfd><" + privilegeName + ">";
- m_validator.addInterestRule(regex, *id);
+ if (static_cast<bool>(id))
+ m_validator.addInterestRule(regex, *id);
+ else
+ m_validator.addInterestBypassRule(regex);
}
}
else
{
// Invalid configuration
- std::string msg = "Invalid privilege \"" + privilegeName + "\" for certificate file " +
- certfile + " (" + id->getPublicKeyName().toUri() + ")";
+ std::string msg = "Invalid privilege \"" + privilegeName +
+ "\" for certificate file " + certfile + " (" + keyNameForLogging + ")";
if (!isDryRun)
{
throw ConfigFile::Error(msg);
diff --git a/nfd.conf.sample.in b/nfd.conf.sample.in
index 74d4333..7e18358 100644
--- a/nfd.conf.sample.in
+++ b/nfd.conf.sample.in
@@ -139,7 +139,9 @@
; your machine. You may move your newly created key to the location it
; specifies or path.
- certfile keys/default.ndncert ; NDN identity certificate file
+ ; certfile keys/default.ndncert ; NDN identity certificate file
+ certfile any ; "any" authorizes command interests signed under any certificate,
+ ; i.e., no actual validation.
privileges ; set of privileges granted to this identity
{
faces
diff --git a/tests/daemon/mgmt/command-validator.cpp b/tests/daemon/mgmt/command-validator.cpp
index 09fd6b9..834cc5b 100644
--- a/tests/daemon/mgmt/command-validator.cpp
+++ b/tests/daemon/mgmt/command-validator.cpp
@@ -593,6 +593,66 @@
bind(&validateErrorMessage, error.str(), _1));
}
+BOOST_FIXTURE_TEST_CASE(Wildcard, TwoValidatorFixture)
+{
+ const std::string WILDCARD_CERT_CONFIG =
+ "authorizations\n"
+ "{\n"
+ " authorize\n"
+ " {\n"
+ " certfile any\n"
+ " privileges\n"
+ " {\n"
+ " faces\n"
+ " stats\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+ shared_ptr<Interest> fibCommand = make_shared<Interest>("/localhost/nfd/fib/insert");
+ shared_ptr<Interest> statsCommand = make_shared<Interest>("/localhost/nfd/stats/dosomething");
+ shared_ptr<Interest> facesCommand = make_shared<Interest>("/localhost/nfd/faces/create");
+
+ ndn::CommandInterestGenerator generator;
+ generator.generateWithIdentity(*fibCommand, m_tester1.getIdentityName());
+ generator.generateWithIdentity(*statsCommand, m_tester1.getIdentityName());
+ generator.generateWithIdentity(*facesCommand, m_tester1.getIdentityName());
+
+ ConfigFile config;
+ CommandValidator validator;
+ validator.addSupportedPrivilege("faces");
+ validator.addSupportedPrivilege("fib");
+ validator.addSupportedPrivilege("stats");
+
+ validator.setConfigFile(config);
+
+ config.parse(WILDCARD_CERT_CONFIG, false, CONFIG_PATH.native());
+
+ validator.validate(*fibCommand,
+ bind(&CommandValidatorTester::onValidated, boost::ref(m_tester1), _1),
+ bind(&CommandValidatorTester::onValidationFailed,
+ boost::ref(m_tester1), _1, _2));
+
+ BOOST_REQUIRE(m_tester1.commandValidationFailed());
+ m_tester1.resetValidation();
+
+ validator.validate(*statsCommand,
+ bind(&CommandValidatorTester::onValidated, boost::ref(m_tester1), _1),
+ bind(&CommandValidatorTester::onValidationFailed,
+ boost::ref(m_tester1), _1, _2));
+
+ BOOST_REQUIRE(m_tester1.commandValidated());
+ m_tester1.resetValidation();
+
+ validator.validate(*facesCommand,
+ bind(&CommandValidatorTester::onValidated, boost::ref(m_tester1), _1),
+ bind(&CommandValidatorTester::onValidationFailed,
+ boost::ref(m_tester1), _1, _2));
+
+ BOOST_REQUIRE(m_tester1.commandValidated());
+ m_tester1.resetValidation();
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace tests