mgmt: CommandAuthenticator

refs #2063

Change-Id: I19a82d8d1fdfb3cc5a003166b1a8c1c32bbf24b5
This commit is contained in:
Junxiao Shi committed 2016-08-17 04:16:31 +00:00
1 parent f5409d434a
commit d7631279f7
6 files changed
+872 -14

No files matched your search

+234
View File
@@ -0,0 +1,234 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "command-authenticator.hpp"
#include "core/logger.hpp"
#include <ndn-cxx/security/identity-certificate.hpp>
#include <ndn-cxx/security/validator-null.hpp>
#include <ndn-cxx/util/io.hpp>
#include <boost/filesystem.hpp>
namespace nfd {
NFD_LOG_INIT("CommandAuthenticator");
// INFO: configuration change, etc
// DEBUG: per authentication request result
shared_ptr<CommandAuthenticator>
CommandAuthenticator::create()
{
return shared_ptr<CommandAuthenticator>(new CommandAuthenticator());
}
CommandAuthenticator::CommandAuthenticator()
: m_validator(make_unique<ndn::ValidatorNull>())
{
}
void
CommandAuthenticator::setConfigFile(ConfigFile& configFile)
{
configFile.addSectionHandler("authorizations",
bind(&CommandAuthenticator::processConfig, this, _1, _2, _3));
}
void
CommandAuthenticator::processConfig(const ConfigSection& section, bool isDryRun, const std::string& filename)
{
if (!isDryRun) {
NFD_LOG_INFO("clear-authorizations");
for (auto& kv : m_moduleAuth) {
kv.second.allowAny = false;
kv.second.certs.clear();
}
}
if (section.empty()) {
BOOST_THROW_EXCEPTION(ConfigFile::Error("'authorize' is missing under 'authorizations'"));
}
int authSectionIndex = 0;
for (const auto& kv : section) {
if (kv.first != "authorize") {
BOOST_THROW_EXCEPTION(ConfigFile::Error(
"'" + kv.first + "' section is not permitted under 'authorizations'"));
}
const ConfigSection& authSection = kv.second;
std::string certfile;
try {
certfile = authSection.get<std::string>("certfile");
}
catch (const boost::property_tree::ptree_error&) {
BOOST_THROW_EXCEPTION(ConfigFile::Error(
"'certfile' is missing under authorize[" + to_string(authSectionIndex) + "]"));
}
bool isAny = false;
shared_ptr<ndn::IdentityCertificate> cert;
if (certfile == "any") {
isAny = true;
NFD_LOG_WARN("'certfile any' is intended for demo purposes only and "
"SHOULD NOT be used in production environments");
}
else {
using namespace boost::filesystem;
path certfilePath = absolute(certfile, path(filename).parent_path());
cert = ndn::io::load<ndn::IdentityCertificate>(certfilePath.string());
if (cert == nullptr) {
BOOST_THROW_EXCEPTION(ConfigFile::Error(
"cannot load certfile " + certfilePath.string() +
" for authorize[" + to_string(authSectionIndex) + "]"));
}
}
const ConfigSection* privSection = nullptr;
try {
privSection = &authSection.get_child("privileges");
}
catch (const boost::property_tree::ptree_error&) {
BOOST_THROW_EXCEPTION(ConfigFile::Error(
"'privileges' is missing under authorize[" + to_string(authSectionIndex) + "]"));
}
if (privSection->empty()) {
NFD_LOG_WARN("No privileges granted to certificate " << certfile);
}
for (const auto& kv : *privSection) {
const std::string& module = kv.first;
auto found = m_moduleAuth.find(module);
if (found == m_moduleAuth.end()) {
BOOST_THROW_EXCEPTION(ConfigFile::Error(
"unknown module '" + module + "' under authorize[" + to_string(authSectionIndex) + "]"));
}
if (isDryRun) {
continue;
}
if (isAny) {
found->second.allowAny = true;
NFD_LOG_INFO("authorize module=" << module << " signer=any");
}
else {
const Name& keyName = cert->getPublicKeyName();
found->second.certs.emplace(keyName, cert->getPublicKeyInfo());
NFD_LOG_INFO("authorize module=" << module << " signer=" << keyName <<
" certfile=" << certfile);
}
}
++authSectionIndex;
}
}
ndn::mgmt::Authorization
CommandAuthenticator::makeAuthorization(const std::string& module, const std::string& verb)
{
m_moduleAuth[module]; // declares module, so that privilege is recognized
auto self = this->shared_from_this();
return [=] (const Name& prefix, const Interest& interest,
const ndn::mgmt::ControlParameters* params,
const ndn::mgmt::AcceptContinuation& accept,
const ndn::mgmt::RejectContinuation& reject) {
const AuthorizedCerts& authorized = self->m_moduleAuth.at(module);
if (authorized.allowAny) {
NFD_LOG_DEBUG("accept " << interest.getName() << " allowAny");
accept("*");
return;
}
bool isOk = false;
Name keyName;
std::tie(isOk, keyName) = CommandAuthenticator::extractKeyName(interest);
if (!isOk) {
NFD_LOG_DEBUG("reject " << interest.getName() << " bad-KeyLocator");
reject(ndn::mgmt::RejectReply::SILENT);
return;
}
auto found = authorized.certs.find(keyName);
if (found == authorized.certs.end()) {
NFD_LOG_DEBUG("reject " << interest.getName() << " signer=" << keyName << " not-authorized");
reject(ndn::mgmt::RejectReply::STATUS403);
return;
}
bool hasGoodSig = ndn::Validator::verifySignature(interest, found->second);
if (!hasGoodSig) {
NFD_LOG_DEBUG("reject " << interest.getName() << " signer=" << keyName << " bad-sig");
reject(ndn::mgmt::RejectReply::STATUS403);
return;
}
self->m_validator.validate(interest,
bind([=] {
NFD_LOG_DEBUG("accept " << interest.getName() << " signer=" << keyName);
accept(keyName.toUri());
}),
bind([=] {
NFD_LOG_DEBUG("reject " << interest.getName() << " signer=" << keyName << " invalid-timestamp");
reject(ndn::mgmt::RejectReply::STATUS403);
}));
};
}
std::pair<bool, Name>
CommandAuthenticator::extractKeyName(const Interest& interest)
{
const Name& name = interest.getName();
if (name.size() < ndn::signed_interest::MIN_LENGTH) {
return {false, Name()};
}
ndn::SignatureInfo sig;
try {
sig.wireDecode(name[ndn::signed_interest::POS_SIG_INFO].blockFromValue());
}
catch (const tlv::Error&) {
return {false, Name()};
}
if (!sig.hasKeyLocator()) {
return {false, Name()};
}
const ndn::KeyLocator& keyLocator = sig.getKeyLocator();
if (keyLocator.getType() != ndn::KeyLocator::KeyLocator_Name) {
return {false, Name()};
}
try {
return {true, ndn::IdentityCertificate::certificateNameToPublicKeyName(keyLocator.getName())};
}
catch (const ndn::IdentityCertificate::Error&) {
return {false, Name()};
}
}
} // namespace nfd
+80
View File
@@ -0,0 +1,80 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_DAEMON_MGMT_COMMAND_AUTHENTICATOR_HPP
#define NFD_DAEMON_MGMT_COMMAND_AUTHENTICATOR_HPP
#include "core/config-file.hpp"
#include <ndn-cxx/mgmt/dispatcher.hpp>
#include <ndn-cxx/security/command-interest-validator.hpp>
#include <ndn-cxx/security/public-key.hpp>
namespace nfd {
/** \brief provides ControlCommand authorization according to NFD configuration file
*/
class CommandAuthenticator : public enable_shared_from_this<CommandAuthenticator>, noncopyable
{
public:
static shared_ptr<CommandAuthenticator>
create();
void
setConfigFile(ConfigFile& configFile);
/** \return an Authorization function for module/verb command
* \param module management module name
* \param verb command verb; currently it's ignored
* \note This must be called before parsing configuration file
*/
ndn::mgmt::Authorization
makeAuthorization(const std::string& module, const std::string& verb);
private:
CommandAuthenticator();
/** \brief process "authorizations" section
* \throw ConfigFile::Error on parse error
*/
void
processConfig(const ConfigSection& section, bool isDryRun, const std::string& filename);
static std::pair<bool, Name>
extractKeyName(const Interest& interest);
private:
struct AuthorizedCerts
{
bool allowAny = false;
std::unordered_map<Name, ndn::PublicKey> certs; ///< keyName => publicKey
};
std::unordered_map<std::string, AuthorizedCerts> m_moduleAuth; ///< module => certs
ndn::security::CommandInterestValidator m_validator;
};
} // namespace nfd
#endif // NFD_DAEMON_MGMT_COMMAND_AUTHENTICATOR_HPP
@@ -0,0 +1,478 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mgmt/command-authenticator.hpp"
#include <ndn-cxx/security/signing-helpers.hpp>
#include <boost/filesystem.hpp>
#include "tests/test-common.hpp"
#include "tests/identity-management-fixture.hpp"
namespace nfd {
namespace tests {
class CommandAuthenticatorFixture : public IdentityManagementTimeFixture
{
protected:
CommandAuthenticatorFixture()
: authenticator(CommandAuthenticator::create())
{
}
void
makeModules(std::initializer_list<std::string> modules)
{
for (const std::string& module : modules) {
authorizations.emplace(module, authenticator->makeAuthorization(module, "verb"));
}
}
void
loadConfig(const std::string& config)
{
boost::filesystem::path configPath = boost::filesystem::current_path() /=
"command-authenticator-test.conf";
ConfigFile cf;
authenticator->setConfigFile(cf);
cf.parse(config, false, configPath.c_str());
}
bool
authorize(const std::string& module, const Name& identity,
const function<void(Interest&)>& modifyInterest = nullptr)
{
auto interest = makeInterest(Name("/prefix").append(module).append("verb"));
m_keyChain.sign(*interest, signingByIdentity(identity));
if (modifyInterest != nullptr) {
modifyInterest(*interest);
}
ndn::mgmt::Authorization authorization = authorizations.at(module);
bool isAccepted = false;
bool isRejected = false;
authorization(Name("/prefix"), *interest, nullptr,
[this, &isAccepted, &isRejected] (const std::string& requester) {
BOOST_REQUIRE_MESSAGE(!isAccepted && !isRejected,
"authorization function should invoke only one continuation");
isAccepted = true;
lastRequester = requester;
},
[this, &isAccepted, &isRejected] (ndn::mgmt::RejectReply act) {
BOOST_REQUIRE_MESSAGE(!isAccepted && !isRejected,
"authorization function should invoke only one continuation");
isRejected = true;
lastRejectReply = act;
});
this->advanceClocks(time::milliseconds(1), 10);
BOOST_REQUIRE_MESSAGE(isAccepted || isRejected,
"authorization function should invoke one continuation");
return isAccepted;
}
protected:
shared_ptr<CommandAuthenticator> authenticator;
std::unordered_map<std::string, ndn::mgmt::Authorization> authorizations;
std::string lastRequester;
ndn::mgmt::RejectReply lastRejectReply;
};
BOOST_AUTO_TEST_SUITE(Mgmt)
BOOST_FIXTURE_TEST_SUITE(TestCommandAuthenticator, CommandAuthenticatorFixture)
BOOST_AUTO_TEST_CASE(Certs)
{
Name id0("/localhost/CommandAuthenticator/0");
Name id1("/localhost/CommandAuthenticator/1");
Name id2("/localhost/CommandAuthenticator/2");
BOOST_REQUIRE(addIdentity(id0));
BOOST_REQUIRE(saveIdentityCertificate(id1, "1.ndncert", true));
BOOST_REQUIRE(saveIdentityCertificate(id2, "2.ndncert", true));
makeModules({"module0", "module1", "module2", "module3", "module4", "module5", "module6", "module7"});
const std::string& config = R"CONFIG(
authorizations
{
authorize
{
certfile any
privileges
{
module1
module3
module5
module7
}
}
authorize
{
certfile "1.ndncert"
privileges
{
module2
module3
module6
module7
}
}
authorize
{
certfile "2.ndncert"
privileges
{
module4
module5
module6
module7
}
}
}
)CONFIG";
loadConfig(config);
// module0: none
BOOST_CHECK_EQUAL(authorize("module0", id0), false);
BOOST_CHECK_EQUAL(authorize("module0", id1), false);
BOOST_CHECK_EQUAL(authorize("module0", id2), false);
// module1: any
BOOST_CHECK_EQUAL(authorize("module1", id0), true);
BOOST_CHECK_EQUAL(authorize("module1", id1), true);
BOOST_CHECK_EQUAL(authorize("module1", id2), true);
// module2: id1
BOOST_CHECK_EQUAL(authorize("module2", id0), false);
BOOST_CHECK_EQUAL(authorize("module2", id1), true);
BOOST_CHECK_EQUAL(authorize("module2", id2), false);
// module3: any,id1
BOOST_CHECK_EQUAL(authorize("module3", id0), true);
BOOST_CHECK_EQUAL(authorize("module3", id1), true);
BOOST_CHECK_EQUAL(authorize("module3", id2), true);
// module4: id2
BOOST_CHECK_EQUAL(authorize("module4", id0), false);
BOOST_CHECK_EQUAL(authorize("module4", id1), false);
BOOST_CHECK_EQUAL(authorize("module4", id2), true);
// module5: any,id2
BOOST_CHECK_EQUAL(authorize("module5", id0), true);
BOOST_CHECK_EQUAL(authorize("module5", id1), true);
BOOST_CHECK_EQUAL(authorize("module5", id2), true);
// module6: id1,id2
BOOST_CHECK_EQUAL(authorize("module6", id0), false);
BOOST_CHECK_EQUAL(authorize("module6", id1), true);
BOOST_CHECK_EQUAL(authorize("module6", id2), true);
// module7: any,id1,id2
BOOST_CHECK_EQUAL(authorize("module7", id0), true);
BOOST_CHECK_EQUAL(authorize("module7", id1), true);
BOOST_CHECK_EQUAL(authorize("module7", id2), true);
}
BOOST_AUTO_TEST_CASE(Requester)
{
Name id0("/localhost/CommandAuthenticator/0");
Name id1("/localhost/CommandAuthenticator/1");
BOOST_REQUIRE(addIdentity(id0));
BOOST_REQUIRE(saveIdentityCertificate(id1, "1.ndncert", true));
makeModules({"module0", "module1"});
const std::string& config = R"CONFIG(
authorizations
{
authorize
{
certfile any
privileges
{
module0
}
}
authorize
{
certfile "1.ndncert"
privileges
{
module1
}
}
}
)CONFIG";
loadConfig(config);
// module0: any
BOOST_CHECK_EQUAL(authorize("module0", id0), true);
BOOST_CHECK_EQUAL(lastRequester, "*");
BOOST_CHECK_EQUAL(authorize("module0", id1), true);
BOOST_CHECK_EQUAL(lastRequester, "*");
// module1: id1
BOOST_CHECK_EQUAL(authorize("module1", id0), false);
BOOST_CHECK_EQUAL(authorize("module1", id1), true);
BOOST_CHECK(id1.isPrefixOf(lastRequester));
}
class IdentityAuthorizedFixture : public CommandAuthenticatorFixture
{
protected:
IdentityAuthorizedFixture()
: id1("/localhost/CommandAuthenticator/1")
{
BOOST_REQUIRE(saveIdentityCertificate(id1, "1.ndncert", true));
makeModules({"module1"});
const std::string& config = R"CONFIG(
authorizations
{
authorize
{
certfile "1.ndncert"
privileges
{
module1
}
}
}
)CONFIG";
loadConfig(config);
}
bool
authorize1(const function<void(Interest&)>& modifyInterest)
{
return authorize("module1", id1, modifyInterest);
}
protected:
Name id1;
};
BOOST_FIXTURE_TEST_SUITE(Rejects, IdentityAuthorizedFixture)
BOOST_AUTO_TEST_CASE(BadKeyLocator_NameTooShort)
{
BOOST_CHECK_EQUAL(authorize1(
[] (Interest& interest) {
interest.setName("/prefix");
}
), false);
BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
}
BOOST_AUTO_TEST_CASE(BadKeyLocator_BadSigInfo)
{
BOOST_CHECK_EQUAL(authorize1(
[] (Interest& interest) {
setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO, "not-SignatureInfo");
}
), false);
BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
}
BOOST_AUTO_TEST_CASE(BadKeyLocator_MissingKeyLocator)
{
BOOST_CHECK_EQUAL(authorize1(
[] (Interest& interest) {
ndn::SignatureInfo sigInfo;
setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO,
sigInfo.wireEncode().begin(), sigInfo.wireEncode().end());
}
), false);
BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
}
BOOST_AUTO_TEST_CASE(BadKeyLocator_BadKeyLocatorType)
{
BOOST_CHECK_EQUAL(authorize1(
[] (Interest& interest) {
ndn::KeyLocator kl;
kl.setKeyDigest(ndn::encoding::makeBinaryBlock(tlv::KeyDigest, "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD", 8));
ndn::SignatureInfo sigInfo;
sigInfo.setKeyLocator(kl);
setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO,
sigInfo.wireEncode().begin(), sigInfo.wireEncode().end());
}
), false);
BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
}
BOOST_AUTO_TEST_CASE(BadKeyLocator_BadCertName)
{
BOOST_CHECK_EQUAL(authorize1(
[] (Interest& interest) {
ndn::KeyLocator kl;
kl.setName("/bad/cert/name");
ndn::SignatureInfo sigInfo;
sigInfo.setKeyLocator(kl);
setNameComponent(interest, ndn::signed_interest::POS_SIG_INFO,
sigInfo.wireEncode().begin(), sigInfo.wireEncode().end());
}
), false);
BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::SILENT);
}
BOOST_AUTO_TEST_CASE(NotAuthorized)
{
Name id0("/localhost/CommandAuthenticator/0");
BOOST_REQUIRE(addIdentity(id0));
BOOST_CHECK_EQUAL(authorize("module1", id0), false);
BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
}
BOOST_AUTO_TEST_CASE(BadSig)
{
BOOST_CHECK_EQUAL(authorize1(
[] (Interest& interest) {
setNameComponent(interest, ndn::signed_interest::POS_SIG_VALUE, "bad-signature-bits");
}
), false);
BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
}
BOOST_AUTO_TEST_CASE(InvalidTimestamp)
{
name::Component timestampComp;
BOOST_CHECK_EQUAL(authorize1(
[&timestampComp] (const Interest& interest) {
timestampComp = interest.getName().at(ndn::signed_interest::POS_TIMESTAMP);
}
), true); // accept first command
BOOST_CHECK_EQUAL(authorize1(
[&timestampComp] (Interest& interest) {
setNameComponent(interest, ndn::signed_interest::POS_TIMESTAMP, timestampComp);
}
), false); // reject second command because timestamp equals first command
BOOST_CHECK(lastRejectReply == ndn::mgmt::RejectReply::STATUS403);
}
BOOST_AUTO_TEST_SUITE_END() // Rejects
BOOST_AUTO_TEST_SUITE(BadConfig)
BOOST_AUTO_TEST_CASE(EmptyAuthorizationsSection)
{
const std::string& config = R"CONFIG(
authorizations
{
}
)CONFIG";
BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
}
BOOST_AUTO_TEST_CASE(UnrecognizedKey)
{
const std::string& config = R"CONFIG(
authorizations
{
unrecognized_key
{
}
}
)CONFIG";
BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
}
BOOST_AUTO_TEST_CASE(CertfileMissing)
{
const std::string& config = R"CONFIG(
authorizations
{
authorize
{
privileges
{
}
}
}
)CONFIG";
BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
}
BOOST_AUTO_TEST_CASE(CertUnreadable)
{
const std::string& config = R"CONFIG(
authorizations
{
authorize
{
certfile "1.ndncert"
privileges
{
}
}
}
)CONFIG";
BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
}
BOOST_AUTO_TEST_CASE(PrivilegesMissing)
{
const std::string& config = R"CONFIG(
authorizations
{
authorize
{
certfile any
}
}
)CONFIG";
BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
}
BOOST_AUTO_TEST_CASE(UnregisteredModule)
{
const std::string& config = R"CONFIG(
authorizations
{
authorize
{
certfile any
privileges
{
nosuchmodule
}
}
}
)CONFIG";
BOOST_CHECK_THROW(loadConfig(config), ConfigFile::Error);
}
BOOST_AUTO_TEST_SUITE_END() // BadConfig
BOOST_AUTO_TEST_SUITE_END() // TestCommandAuthenticator
BOOST_AUTO_TEST_SUITE_END() // Mgmt
} // namespace tests
} // namespace nfd
+34 -3
View File
@@ -24,6 +24,8 @@
*/
#include "identity-management-fixture.hpp"
#include <ndn-cxx/util/io.hpp>
#include <boost/filesystem.hpp>
namespace nfd {
namespace tests {
@@ -31,18 +33,23 @@ namespace tests {
IdentityManagementFixture::IdentityManagementFixture()
: m_keyChain("sqlite3", "file")
{
m_keyChain.getDefaultCertificate(); // side effect: creation of the default cert if doesn't exist
m_keyChain.getDefaultCertificate(); // side effect: create a default cert if it doesn't exist
}
IdentityManagementFixture::~IdentityManagementFixture()
{
for (auto&& id : m_identities) {
for (const auto& id : m_identities) {
m_keyChain.deleteIdentity(id);
}
boost::system::error_code ec;
for (const auto& certFile : m_certFiles) {
boost::filesystem::remove(certFile, ec); // ignore error
}
}
bool
IdentityManagementFixture::addIdentity(const ndn::Name& identity, const ndn::KeyParams& params)
IdentityManagementFixture::addIdentity(const Name& identity, const ndn::KeyParams& params)
{
try {
m_keyChain.createIdentity(identity, params);
@@ -54,5 +61,29 @@ IdentityManagementFixture::addIdentity(const ndn::Name& identity, const ndn::Key
}
}
bool
IdentityManagementFixture::saveIdentityCertificate(const Name& identity, const std::string& filename, bool wantAdd)
{
shared_ptr<ndn::IdentityCertificate> cert;
try {
cert = m_keyChain.getCertificate(m_keyChain.getDefaultCertificateNameForIdentity(identity));
}
catch (const ndn::SecPublicInfo::Error&) {
if (wantAdd && this->addIdentity(identity)) {
return this->saveIdentityCertificate(identity, filename, false);
}
return false;
}
m_certFiles.push_back(filename);
try {
ndn::io::save(*cert, filename);
return true;
}
catch (const ndn::io::Error&) {
return false;
}
}
} // namespace tests
} // namespace nfd
+22 -11
View File
@@ -28,37 +28,48 @@
#include "tests/test-common.hpp"
#include <ndn-cxx/security/key-chain.hpp>
#include <vector>
#include "boost-test.hpp"
namespace nfd {
namespace tests {
/**
* @brief IdentityManagementFixture is a test suite level fixture.
*
* Test cases in the suite can use this fixture to create identities.
* Identities added via addIdentity method are automatically deleted
* during test teardown.
/** \brief a fixture that cleans up KeyChain identities and certificate files upon destruction
*/
class IdentityManagementFixture : public virtual BaseFixture
{
public:
IdentityManagementFixture();
/** \brief deletes created identities and saved certificate files
*/
~IdentityManagementFixture();
// @brief add identity, return true if succeed.
/** \brief add identity
* \return whether successful
*/
bool
addIdentity(const ndn::Name& identity,
addIdentity(const Name& identity,
const ndn::KeyParams& params = ndn::KeyChain::DEFAULT_KEY_PARAMS);
/** \brief save identity certificate to a file
* \param identity identity name
* \param filename file name, should be writable
* \param wantAdd if true, add new identity when necessary
* \return whether successful
*/
bool
saveIdentityCertificate(const Name& identity, const std::string& filename, bool wantAdd = false);
protected:
ndn::KeyChain m_keyChain;
private:
std::vector<ndn::Name> m_identities;
std::vector<std::string> m_certFiles;
};
/** \brief convenience base class for inheriting from both UnitTestTimeFixture
* and IdentityManagementFixture
*/
class IdentityManagementTimeFixture : public UnitTestTimeFixture
, public IdentityManagementFixture
{
+24
View File
@@ -150,6 +150,30 @@ makeLink(const Name& name, std::initializer_list<std::pair<uint32_t, Name>> dele
lp::Nack
makeNack(const Name& name, uint32_t nonce, lp::NackReason reason);
/** \brief replace a name component
* \param[inout] name name
* \param index name component index
* \param a arguments to name::Component constructor
*/
template<typename...A>
void
setNameComponent(Name& name, ssize_t index, const A& ...a)
{
Name name2 = name.getPrefix(index);
name2.append(name::Component(a...));
name2.append(name.getSubName(name2.size()));
name = name2;
}
template<typename Packet, typename...A>
void
setNameComponent(Packet& packet, ssize_t index, const A& ...a)
{
Name name = packet.getName();
setNameComponent(name, index, a...);
packet.setName(name);
}
} // namespace tests
} // namespace nfd