diff --git a/daemon/main.cpp b/daemon/main.cpp index 541d8ffb..e4ead643 100644 --- a/daemon/main.cpp +++ b/daemon/main.cpp @@ -12,6 +12,7 @@ #include "mgmt/face-manager.hpp" #include "mgmt/local-control-header-manager.hpp" #include "mgmt/strategy-choice-manager.hpp" +#include "mgmt/config-file.hpp" #include "face/tcp-factory.hpp" #ifdef HAVE_UNIX_SOCKETS @@ -39,6 +40,7 @@ struct ProgramOptions std::pair m_tcpListen; std::vector m_tcpOutgoings; std::string m_unixListen; + std::string m_config; }; static ProgramOptions g_options; @@ -67,7 +69,8 @@ usage(char* programName) "[--unix-listen \"/var/run/nfd.sock\"] " #endif "[--tcp-connect \"192.0.2.1:6363\" " - "[--prefix ]]\n" + "[--prefix ]] " + "[--config /path/to/nfd.conf]\n" "\trun forwarding daemon\n" "\t--tcp-listen : listen on IP and port\n" #ifdef HAVE_UNIX_SOCKETS @@ -76,6 +79,7 @@ usage(char* programName) "\t--tcp-connect : connect to IP and port (can occur multiple times)\n" "\t--prefix : add this face as nexthop to FIB entry " "(must appear after --tcp-connect, can occur multiple times)\n" + "\t--config ]: path to configuration file\n" "\n", programName, programName ); @@ -99,6 +103,7 @@ parseCommandLine(int argc, char** argv) g_options.m_tcpListen = std::make_pair("0.0.0.0", "6363"); g_options.m_unixListen = "/var/run/nfd.sock"; g_options.m_tcpOutgoings.clear(); + g_options.m_config = DEFAULT_CONFIG_FILE; while (1) { int option_index = 0; @@ -108,6 +113,7 @@ parseCommandLine(int argc, char** argv) { "tcp-connect" , required_argument, 0, 0 }, { "prefix" , required_argument, 0, 0 }, { "unix-listen" , required_argument, 0, 0 }, + { "config" , required_argument, 0, 0 }, { 0 , 0 , 0, 0 } }; int c = getopt_long_only(argc, argv, "", long_options, &option_index); @@ -134,10 +140,14 @@ parseCommandLine(int argc, char** argv) case 4://unix-listen g_options.m_unixListen = ::optarg; break; + case 5://config + g_options.m_config = ::optarg; + break; } break; } } + return true; } @@ -206,9 +216,14 @@ initializeUnix() void initializeMgmt() { + ConfigFile config; + g_internalFace = make_shared(); g_forwarder->addFace(g_internalFace); + g_internalFace->getValidator().setConfigFile(config); + + g_fibManager = new FibManager(g_forwarder->getFib(), bind(&Forwarder::getFace, g_forwarder, _1), g_internalFace); @@ -222,6 +237,11 @@ initializeMgmt() g_strategyChoiceManager = new StrategyChoiceManager(g_forwarder->getStrategyChoice(), g_internalFace); + /// \todo add face manager section handler + + /// \todo add parsing back when there is an official default config file + // config.parse(g_options.m_config); + shared_ptr entry = g_forwarder->getFib().insert("/localhost/nfd").first; entry->addNextHop(g_internalFace, 0); } diff --git a/daemon/mgmt/command-validator.cpp b/daemon/mgmt/command-validator.cpp new file mode 100644 index 00000000..9028ba2d --- /dev/null +++ b/daemon/mgmt/command-validator.cpp @@ -0,0 +1,172 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (C) 2014 Named Data Networking Project + * See COPYING for copyright and distribution information. + */ + +#include "command-validator.hpp" +#include +#include + +namespace nfd { + +NFD_LOG_INIT("CommandValidator"); + +CommandValidator::CommandValidator() +{ + +} + +CommandValidator::~CommandValidator() +{ + +} + +void +CommandValidator::setConfigFile(ConfigFile& configFile) +{ + configFile.addSectionHandler("authorizations", + bind(&CommandValidator::onConfig, this, _1, _2)); +} + +static inline void +aggregateErrors(std::stringstream& ss, const std::string& msg) +{ + if (!ss.str().empty()) + { + ss << "\n"; + } + ss << msg; +} + +void +CommandValidator::onConfig(const ConfigSection& section, + bool isDryRun) +{ + const ConfigSection EMPTY_SECTION; + + if (section.begin() == section.end()) + { + throw ConfigFile::Error("No authorize sections found"); + } + + std::stringstream dryRunErrors; + ConfigSection::const_iterator authIt; + for (authIt = section.begin(); authIt != section.end(); authIt++) + { + std::string keyfile; + try + { + keyfile = authIt->second.get("keyfile"); + } + catch (const std::runtime_error& e) + { + std::string msg = "No keyfile specified"; + if (!isDryRun) + { + throw ConfigFile::Error(msg); + } + aggregateErrors(dryRunErrors, msg); + continue; + } + + std::ifstream in; + in.open(keyfile.c_str()); + if (!in.is_open()) + { + std::string msg = "Unable to open key file " + keyfile; + if (!isDryRun) + { + throw ConfigFile::Error(msg); + } + aggregateErrors(dryRunErrors, msg); + continue; + } + + shared_ptr id; + try + { + id = ndn::io::load(in); + } + catch(const std::runtime_error& error) + { + std::string msg = "Malformed key file " + keyfile; + if (!isDryRun) + { + throw ConfigFile::Error(msg); + } + aggregateErrors(dryRunErrors, msg); + continue; + } + + in.close(); + + const ConfigSection* privileges = 0; + + try + { + privileges = &authIt->second.get_child("privileges"); + } + catch (const std::runtime_error& error) + { + std::string msg = "No privileges section found for key file " + + keyfile + " (" + id->getPublicKeyName().toUri() + ")"; + if (!isDryRun) + { + throw ConfigFile::Error(msg); + } + aggregateErrors(dryRunErrors, msg); + continue; + } + + if (privileges->begin() == privileges->end()) + { + NFD_LOG_WARN("No privileges specified for key file " << keyfile + " (" << id->getPublicKeyName().toUri() << ")"); + } + + ConfigSection::const_iterator privIt; + for (privIt = privileges->begin(); privIt != privileges->end(); privIt++) + { + const std::string& privilegeName = privIt->first; + if (m_supportedPrivileges.find(privilegeName) != m_supportedPrivileges.end()) + { + NFD_LOG_INFO("Giving privilege \"" << privilegeName + << "\" to key " << id->getPublicKeyName()); + if (!isDryRun) + { + const std::string regex = "^<" + privilegeName + ">"; + m_validator.addInterestRule(regex, *id); + } + } + else + { + // Invalid configuration + std::string msg = "Invalid privilege \"" + privilegeName + "\" for key file " + + keyfile + " (" + id->getPublicKeyName().toUri() + ")"; + if (!isDryRun) + { + throw ConfigFile::Error(msg); + } + aggregateErrors(dryRunErrors, msg); + } + } + } + + if (!dryRunErrors.str().empty()) + { + throw ConfigFile::Error(dryRunErrors.str()); + } +} + +void +CommandValidator::addSupportedPrivilege(const std::string& privilege) +{ + if (m_supportedPrivileges.find(privilege) != m_supportedPrivileges.end()) + { + throw CommandValidator::Error("Duplicated privivilege: " + privilege); + } + m_supportedPrivileges.insert(privilege); +} + +} // namespace nfd + diff --git a/daemon/mgmt/command-validator.hpp b/daemon/mgmt/command-validator.hpp new file mode 100644 index 00000000..466bb702 --- /dev/null +++ b/daemon/mgmt/command-validator.hpp @@ -0,0 +1,95 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (C) 2014 Named Data Networking Project + * See COPYING for copyright and distribution information. + */ + +#ifndef NFD_MGMT_COMMAND_VALIDATOR_HPP +#define NFD_MGMT_COMMAND_VALIDATOR_HPP + +#include "config-file.hpp" +#include + +namespace nfd { + +class CommandValidator +{ +public: + + class Error : public std::runtime_error + { + public: + Error(const std::string& what) + : std::runtime_error(what) + { + + } + }; + + CommandValidator(); + + ~CommandValidator(); + + void + setConfigFile(ConfigFile& configFile); + + /** + * \param section "authorizations" section to parse + * \param isDryRun true if performing a dry run of configuration, false otherwise + * \throws ConfigFile::Error on parse error + */ + void + onConfig(const ConfigSection& section, bool isDryRun); + + /** + * \param privilege name of privilege to add + * \throws CommandValidator::Error on duplicated privilege + */ + void + addSupportedPrivilege(const std::string& privilege); + + void + addInterestRule(const std::string& regex, + const ndn::IdentityCertificate& certificate); + + void + addInterestRule(const std::string& regex, + const Name& keyName, + const ndn::PublicKey& publicKey); + + void + validate(const Interest& interest, + const ndn::OnInterestValidated& onValidated, + const ndn::OnInterestValidationFailed& onValidationFailed); + +private: + ndn::CommandInterestValidator m_validator; + std::set m_supportedPrivileges; +}; + +inline void +CommandValidator::addInterestRule(const std::string& regex, + const ndn::IdentityCertificate& certificate) +{ + m_validator.addInterestRule(regex, certificate); +} + +inline void +CommandValidator::addInterestRule(const std::string& regex, + const Name& keyName, + const ndn::PublicKey& publicKey) +{ + m_validator.addInterestRule(regex, keyName, publicKey); +} + +inline void +CommandValidator::validate(const Interest& interest, + const ndn::OnInterestValidated& onValidated, + const ndn::OnInterestValidationFailed& onValidationFailed) +{ + m_validator.validate(interest, onValidated, onValidationFailed); +} + +} // namespace nfd + +#endif // NFD_MGMT_COMMAND_VALIDATOR_HPP diff --git a/daemon/mgmt/config-file.cpp b/daemon/mgmt/config-file.cpp index a55650e2..8018310e 100644 --- a/daemon/mgmt/config-file.cpp +++ b/daemon/mgmt/config-file.cpp @@ -34,7 +34,7 @@ ConfigFile::parse(const char* filename, bool isDryRun) { std::string msg = "Failed to read configuration file: "; msg += filename; - throw Error(filename); + throw Error(msg); } parse(inputFile, isDryRun, filename); inputFile.close(); diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp index 30e3abdb..9874176e 100644 --- a/daemon/mgmt/face-manager.cpp +++ b/daemon/mgmt/face-manager.cpp @@ -34,7 +34,7 @@ const size_t FaceManager::COMMAND_UNSIGNED_NCOMPS = const size_t FaceManager::COMMAND_SIGNED_NCOMPS = FaceManager::COMMAND_UNSIGNED_NCOMPS + - 0; // No signed Interest support in mock, otherwise 4 (timestamp, nonce, signed info tlv, signature tlv) + 4; // (timestamp, nonce, signed info tlv, signature tlv) const FaceManager::VerbAndProcessor FaceManager::COMMAND_VERBS[] = { @@ -52,8 +52,8 @@ const FaceManager::VerbAndProcessor FaceManager::COMMAND_VERBS[] = FaceManager::FaceManager(FaceTable& faceTable, - shared_ptr face) - : ManagerBase(face) + shared_ptr face) + : ManagerBase(face, FACE_MANAGER_PRIVILEGE) , m_faceTable(faceTable) , m_verbDispatch(COMMAND_VERBS, COMMAND_VERBS + @@ -411,7 +411,9 @@ FaceManager::onFaceRequest(const Interest& request) return; } - onValidatedFaceRequest(request.shared_from_this()); + validate(request, + bind(&FaceManager::onValidatedFaceRequest, this, _1), + bind(&ManagerBase::onCommandValidationFailed, this, _1, _2)); } void @@ -430,14 +432,6 @@ FaceManager::onValidatedFaceRequest(const shared_ptr& request) return; } - /// \todo authorize command - if (false) - { - NFD_LOG_INFO("command result: unauthorized verb: " << command); - sendResponse(command, 403, "Unauthorized command"); - return; - } - NFD_LOG_INFO("command result: processing verb: " << verb); (verbProcessor->second)(this, command, options); } diff --git a/daemon/mgmt/face-manager.hpp b/daemon/mgmt/face-manager.hpp index 87574cdc..316af2ae 100644 --- a/daemon/mgmt/face-manager.hpp +++ b/daemon/mgmt/face-manager.hpp @@ -35,7 +35,7 @@ public: */ FaceManager(FaceTable& faceTable, - shared_ptr face); + shared_ptr face); /** \brief Subscribe to a face management section(s) for the config file */ diff --git a/daemon/mgmt/fib-manager.cpp b/daemon/mgmt/fib-manager.cpp index 8e271140..dee765ba 100644 --- a/daemon/mgmt/fib-manager.cpp +++ b/daemon/mgmt/fib-manager.cpp @@ -17,18 +17,18 @@ namespace nfd { NFD_LOG_INIT("FibManager"); -const Name FibManager::FIB_MANAGER_COMMAND_PREFIX = "/localhost/nfd/fib"; +const Name FibManager::COMMAND_PREFIX = "/localhost/nfd/fib"; -const size_t FibManager::FIB_MANAGER_COMMAND_UNSIGNED_NCOMPS = - FibManager::FIB_MANAGER_COMMAND_PREFIX.size() + +const size_t FibManager::COMMAND_UNSIGNED_NCOMPS = + FibManager::COMMAND_PREFIX.size() + 1 + // verb 1; // verb options -const size_t FibManager::FIB_MANAGER_COMMAND_SIGNED_NCOMPS = - FibManager::FIB_MANAGER_COMMAND_UNSIGNED_NCOMPS + - 0; // No signed Interest support in mock, otherwise 3 (timestamp, signed info tlv, signature tlv) +const size_t FibManager::COMMAND_SIGNED_NCOMPS = + FibManager::COMMAND_UNSIGNED_NCOMPS + + 4; // (timestamp, nonce, signed info tlv, signature tlv) -const FibManager::VerbAndProcessor FibManager::FIB_MANAGER_COMMAND_VERBS[] = +const FibManager::VerbAndProcessor FibManager::COMMAND_VERBS[] = { VerbAndProcessor( Name::Component("insert"), @@ -45,8 +45,6 @@ const FibManager::VerbAndProcessor FibManager::FIB_MANAGER_COMMAND_VERBS[] = &FibManager::addNextHop ), - - VerbAndProcessor( Name::Component("remove-nexthop"), &FibManager::removeNextHop @@ -56,13 +54,13 @@ const FibManager::VerbAndProcessor FibManager::FIB_MANAGER_COMMAND_VERBS[] = FibManager::FibManager(Fib& fib, function(FaceId)> getFace, - shared_ptr face) - : ManagerBase(face), + shared_ptr face) + : ManagerBase(face, FIB_PRIVILEGE), m_managedFib(fib), m_getFace(getFace), - m_verbDispatch(FIB_MANAGER_COMMAND_VERBS, - FIB_MANAGER_COMMAND_VERBS + - (sizeof(FIB_MANAGER_COMMAND_VERBS) / sizeof(VerbAndProcessor))) + m_verbDispatch(COMMAND_VERBS, + COMMAND_VERBS + + (sizeof(COMMAND_VERBS) / sizeof(VerbAndProcessor))) { face->setInterestFilter("/localhost/nfd/fib", bind(&FibManager::onFibRequest, this, _2)); @@ -74,56 +72,56 @@ FibManager::onFibRequest(const Interest& request) const Name& command = request.getName(); const size_t commandNComps = command.size(); - - - if (FIB_MANAGER_COMMAND_UNSIGNED_NCOMPS <= commandNComps && - commandNComps < FIB_MANAGER_COMMAND_SIGNED_NCOMPS) + if (COMMAND_UNSIGNED_NCOMPS <= commandNComps && + commandNComps < COMMAND_SIGNED_NCOMPS) { NFD_LOG_INFO("command result: unsigned verb: " << command); sendResponse(command, 401, "Signature required"); return; } - else if (commandNComps < FIB_MANAGER_COMMAND_SIGNED_NCOMPS || - !FIB_MANAGER_COMMAND_PREFIX.isPrefixOf(command)) + else if (commandNComps < COMMAND_SIGNED_NCOMPS || + !COMMAND_PREFIX.isPrefixOf(command)) { NFD_LOG_INFO("command result: malformed"); sendResponse(command, 400, "Malformed command"); return; } - const Name::Component& verb = command.get(FIB_MANAGER_COMMAND_PREFIX.size()); + validate(request, + bind(&FibManager::onValidatedFibRequest, + this, _1), + bind(&ManagerBase::onCommandValidationFailed, + this, _1, _2)); +} + +void +FibManager::onValidatedFibRequest(const shared_ptr& request) +{ + const Name& command = request->getName(); + const Name::Component& verb = command.get(COMMAND_PREFIX.size()); VerbDispatchTable::const_iterator verbProcessor = m_verbDispatch.find (verb); if (verbProcessor != m_verbDispatch.end()) { FibManagementOptions options; - if (!extractOptions(request, options)) + if (!extractOptions(*request, options)) { + NFD_LOG_INFO("command result: malformed verb: " << verb); sendResponse(command, 400, "Malformed command"); return; } - /// \todo authorize command - if (false) - { - NFD_LOG_INFO("command result: unauthorized verb: " << command); - sendResponse(request.getName(), 403, "Unauthorized command"); - return; - } - NFD_LOG_INFO("command result: processing verb: " << verb); ControlResponse response; (verbProcessor->second)(this, options, response); - sendResponse(command, response); } else { NFD_LOG_INFO("command result: unsupported verb: " << verb); - sendResponse(request.getName(), 501, "Unsupported command"); + sendResponse(command, 501, "Unsupported command"); } - } bool @@ -131,8 +129,7 @@ FibManager::extractOptions(const Interest& request, FibManagementOptions& extractedOptions) { const Name& command = request.getName(); - const size_t optionCompIndex = - FIB_MANAGER_COMMAND_PREFIX.size() + 1; + const size_t optionCompIndex = COMMAND_PREFIX.size() + 1; try { @@ -220,7 +217,7 @@ FibManager::addNextHop(const FibManagementOptions& options, void FibManager::removeNextHop(const FibManagementOptions& options, - ControlResponse &response) + ControlResponse& response) { NFD_LOG_DEBUG("remove-nexthop prefix: " << options.getName() << " faceid: " << options.getFaceId()); diff --git a/daemon/mgmt/fib-manager.hpp b/daemon/mgmt/fib-manager.hpp index c7b77935..43b410e6 100644 --- a/daemon/mgmt/fib-manager.hpp +++ b/daemon/mgmt/fib-manager.hpp @@ -22,23 +22,29 @@ using ndn::nfd::FibManagementOptions; class Forwarder; class Fib; +const std::string FIB_PRIVILEGE = "fib"; // config file privilege name + class FibManager : public ManagerBase { public: FibManager(Fib& fib, function(FaceId)> getFace, - shared_ptr face); + shared_ptr face); void onFibRequest(const Interest& request); private: + void + onValidatedFibRequest(const shared_ptr& request); + void insertEntry(const FibManagementOptions& options, ControlResponse& response); + void deleteEntry(const FibManagementOptions& options, ControlResponse& response); @@ -55,9 +61,6 @@ private: extractOptions(const Interest& request, FibManagementOptions& extractedOptions); - // void - // onConfig(ConfigFile::Node section, bool isDryRun); - private: Fib& m_managedFib; @@ -75,17 +78,17 @@ private: const VerbDispatchTable m_verbDispatch; - static const Name FIB_MANAGER_COMMAND_PREFIX; // /localhost/nfd/fib + static const Name COMMAND_PREFIX; // /localhost/nfd/fib // number of components in an invalid, but not malformed, unsigned command. // (/localhost/nfd/fib + verb + options) = 5 - static const size_t FIB_MANAGER_COMMAND_UNSIGNED_NCOMPS; + static const size_t COMMAND_UNSIGNED_NCOMPS; // number of components in a valid signed Interest. - // 5 in mock (see UNSIGNED_NCOMPS), 8 with signed Interest support. - static const size_t FIB_MANAGER_COMMAND_SIGNED_NCOMPS; + // UNSIGNED_NCOMPS + 4 command Interest components = 9 + static const size_t COMMAND_SIGNED_NCOMPS; - static const VerbAndProcessor FIB_MANAGER_COMMAND_VERBS[]; + static const VerbAndProcessor COMMAND_VERBS[]; }; diff --git a/daemon/mgmt/internal-face.hpp b/daemon/mgmt/internal-face.hpp index 8d5805c5..3ce32e34 100644 --- a/daemon/mgmt/internal-face.hpp +++ b/daemon/mgmt/internal-face.hpp @@ -10,6 +10,8 @@ #include "face/face.hpp" #include "app-face.hpp" +#include "command-validator.hpp" + namespace nfd { class InternalFace : public Face, public AppFace @@ -25,6 +27,12 @@ public: InternalFace(); + CommandValidator& + getValidator(); + + virtual + ~InternalFace(); + // Overridden Face methods for forwarder virtual void @@ -45,17 +53,19 @@ public: virtual void put(const Data& data); - virtual - ~InternalFace(); - private: - // void - // onConfig(ConfigFile::Node section, bool isDryRun); - std::map m_interestFilters; + CommandValidator m_validator; }; +inline CommandValidator& +InternalFace::getValidator() +{ + return m_validator; +} + + } // namespace nfd #endif //NFD_MGMT_INTERNAL_FACE_HPP diff --git a/daemon/mgmt/local-control-header-manager.cpp b/daemon/mgmt/local-control-header-manager.cpp index 5717f543..aae1d0ce 100644 --- a/daemon/mgmt/local-control-header-manager.cpp +++ b/daemon/mgmt/local-control-header-manager.cpp @@ -6,6 +6,7 @@ #include "local-control-header-manager.hpp" #include "face/local-face.hpp" +#include "mgmt/internal-face.hpp" namespace nfd { @@ -20,26 +21,23 @@ const size_t LocalControlHeaderManager::COMMAND_UNSIGNED_NCOMPS = const size_t LocalControlHeaderManager::COMMAND_SIGNED_NCOMPS = LocalControlHeaderManager::COMMAND_UNSIGNED_NCOMPS + - 0; // No signed Interest support in mock + 4; // (timestamp, nonce, signed info tlv, signature tlv) LocalControlHeaderManager::LocalControlHeaderManager(function(FaceId)> getFace, - shared_ptr face) - : ManagerBase(face), + shared_ptr face) + : ManagerBase(face, CONTROL_HEADER_PRIVILEGE), m_getFace(getFace) { face->setInterestFilter("/localhost/nfd/control-header", bind(&LocalControlHeaderManager::onLocalControlHeaderRequest, this, _2)); } + + void LocalControlHeaderManager::onLocalControlHeaderRequest(const Interest& request) { - static const Name::Component MODULE_IN_FACEID("in-faceid"); - static const Name::Component MODULE_NEXTHOP_FACEID("nexthop-faceid"); - static const Name::Component VERB_ENABLE("enable"); - static const Name::Component VERB_DISABLE("disable"); - const Name& command = request.getName(); const size_t commandNComps = command.size(); @@ -59,35 +57,53 @@ LocalControlHeaderManager::onLocalControlHeaderRequest(const Interest& request) return; } + validate(request, + bind(&LocalControlHeaderManager::onCommandValidated, + this, _1), + bind(&ManagerBase::onCommandValidationFailed, + this, _1, _2)); + + +} + +void +LocalControlHeaderManager::onCommandValidated(const shared_ptr& command) +{ + static const Name::Component MODULE_IN_FACEID("in-faceid"); + static const Name::Component MODULE_NEXTHOP_FACEID("nexthop-faceid"); + static const Name::Component VERB_ENABLE("enable"); + static const Name::Component VERB_DISABLE("disable"); + shared_ptr face = - dynamic_pointer_cast(m_getFace(request.getIncomingFaceId())); + dynamic_pointer_cast(m_getFace(command->getIncomingFaceId())); if (!static_cast(face)) { - NFD_LOG_INFO("command result: request to enable control header on non-local face"); - sendResponse(command, 400, "Command not supported on the requested face"); + NFD_LOG_INFO("command result: command to enable control header on non-local face"); + sendResponse(command->getName(), 400, "Command not supported on the requested face"); return; } - const Name::Component& module = command.get(COMMAND_PREFIX.size()); - const Name::Component& verb = command.get(COMMAND_PREFIX.size() + 1); + const Name& commandName = command->getName(); + const Name::Component& module = commandName[COMMAND_PREFIX.size()]; + const Name::Component& verb = commandName[COMMAND_PREFIX.size() + 1]; if (module == MODULE_IN_FACEID) { if (verb == VERB_ENABLE) { face->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID, true); - sendResponse(command, 200, "Success"); + sendResponse(commandName, 200, "Success"); } else if (verb == VERB_DISABLE) { face->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID, false); - sendResponse(command, 200, "Success"); + sendResponse(commandName, 200, "Success"); } else { NFD_LOG_INFO("command result: unsupported verb: " << verb); - sendResponse(command, 501, "Unsupported"); + sendResponse(commandName, 501, "Unsupported"); } } else if (module == MODULE_NEXTHOP_FACEID) @@ -95,23 +111,23 @@ LocalControlHeaderManager::onLocalControlHeaderRequest(const Interest& request) if (verb == VERB_ENABLE) { face->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID, true); - sendResponse(command, 200, "Success"); + sendResponse(commandName, 200, "Success"); } else if (verb == VERB_DISABLE) { face->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID, false); - sendResponse(command, 200, "Success"); + sendResponse(commandName, 200, "Success"); } else { NFD_LOG_INFO("command result: unsupported verb: " << verb); - sendResponse(command, 501, "Unsupported"); + sendResponse(commandName, 501, "Unsupported"); } } else { NFD_LOG_INFO("command result: unsupported module: " << module); - sendResponse(command, 501, "Unsupported"); + sendResponse(commandName, 501, "Unsupported"); } } diff --git a/daemon/mgmt/local-control-header-manager.hpp b/daemon/mgmt/local-control-header-manager.hpp index 8c03e4ee..0aa5d637 100644 --- a/daemon/mgmt/local-control-header-manager.hpp +++ b/daemon/mgmt/local-control-header-manager.hpp @@ -14,26 +14,31 @@ namespace nfd { +const std::string CONTROL_HEADER_PRIVILEGE = "control-header"; // config file privilege name + class LocalControlHeaderManager : public ManagerBase { public: LocalControlHeaderManager(function(FaceId)> getFace, - shared_ptr face); + shared_ptr face); void onLocalControlHeaderRequest(const Interest& request); + void + onCommandValidated(const shared_ptr& command); + private: function(FaceId)> m_getFace; static const Name COMMAND_PREFIX; // /localhost/nfd/control-header // number of components in an invalid, but not malformed, unsigned command. - // (/localhost/nfd/control-headeer + control-module + verb) = 5 + // (/localhost/nfd/control-header + control-module + verb) = 5 static const size_t COMMAND_UNSIGNED_NCOMPS; // number of components in a valid signed Interest. - // 5 in mock (see UNSIGNED_NCOMPS) + // UNSIGNED_NCOMPS + 4 command Interest components = 9 static const size_t COMMAND_SIGNED_NCOMPS; }; diff --git a/daemon/mgmt/manager-base.cpp b/daemon/mgmt/manager-base.cpp index 19944167..bd94b187 100644 --- a/daemon/mgmt/manager-base.cpp +++ b/daemon/mgmt/manager-base.cpp @@ -5,16 +5,15 @@ */ #include "manager-base.hpp" -#include "mgmt/app-face.hpp" namespace nfd { NFD_LOG_INIT("ManagerBase"); -ManagerBase::ManagerBase(shared_ptr face) +ManagerBase::ManagerBase(shared_ptr face, const std::string& privilege) : m_face(face) { - + face->getValidator().addSupportedPrivilege(privilege); } ManagerBase::~ManagerBase() @@ -49,5 +48,13 @@ ManagerBase::sendResponse(const Name& name, m_face->put(*responseData); } +void +ManagerBase::onCommandValidationFailed(const shared_ptr& command, + const std::string& error) +{ + NFD_LOG_INFO("command result: unauthorized verb: " << command); + sendResponse(command->getName(), 403, "Unauthorized command"); +} + } // namespace nfd diff --git a/daemon/mgmt/manager-base.hpp b/daemon/mgmt/manager-base.hpp index 78c6efee..95228129 100644 --- a/daemon/mgmt/manager-base.hpp +++ b/daemon/mgmt/manager-base.hpp @@ -10,25 +10,34 @@ #include "common.hpp" #include +#include "mgmt/command-validator.hpp" +#include "mgmt/internal-face.hpp" + + namespace nfd { using ndn::nfd::ControlResponse; -class AppFace; +class InternalFace; class ManagerBase { public: + struct Error : public std::runtime_error { Error(const std::string& what) : std::runtime_error(what) {} }; - ManagerBase(shared_ptr face); + ManagerBase(shared_ptr face, const std::string& privilege); virtual ~ManagerBase(); + void + onCommandValidationFailed(const shared_ptr& command, + const std::string& error); + protected: void @@ -50,8 +59,23 @@ protected: uint32_t code, const std::string& text); +PUBLIC_WITH_TESTS_ELSE_PROTECTED: + void + addInterestRule(const std::string& regex, + const ndn::IdentityCertificate& certificate); + + void + addInterestRule(const std::string& regex, + const Name& keyName, + const ndn::PublicKey& publicKey); + + void + validate(const Interest& interest, + const ndn::OnInterestValidated& onValidated, + const ndn::OnInterestValidationFailed& onValidationFailed); + protected: - shared_ptr m_face; + shared_ptr m_face; }; inline void @@ -73,6 +97,29 @@ ManagerBase::setResponse(ControlResponse& response, response.setBody(body); } +inline void +ManagerBase::addInterestRule(const std::string& regex, + const ndn::IdentityCertificate& certificate) +{ + m_face->getValidator().addInterestRule(regex, certificate); +} + +inline void +ManagerBase::addInterestRule(const std::string& regex, + const Name& keyName, + const ndn::PublicKey& publicKey) +{ + m_face->getValidator().addInterestRule(regex, keyName, publicKey); +} + +inline void +ManagerBase::validate(const Interest& interest, + const ndn::OnInterestValidated& onValidated, + const ndn::OnInterestValidationFailed& onValidationFailed) +{ + m_face->getValidator().validate(interest, onValidated, onValidationFailed); +} + } // namespace nfd diff --git a/daemon/mgmt/strategy-choice-manager.cpp b/daemon/mgmt/strategy-choice-manager.cpp index 00761dd1..665f4a8e 100644 --- a/daemon/mgmt/strategy-choice-manager.cpp +++ b/daemon/mgmt/strategy-choice-manager.cpp @@ -21,11 +21,11 @@ const size_t StrategyChoiceManager::COMMAND_UNSIGNED_NCOMPS = const size_t StrategyChoiceManager::COMMAND_SIGNED_NCOMPS = StrategyChoiceManager::COMMAND_UNSIGNED_NCOMPS + - 0; // No signed Interest support in mock, otherwise 4 (timestamp, nonce, signed info tlv, signature tlv) + 4; // (timestamp, nonce, signed info tlv, signature tlv) StrategyChoiceManager::StrategyChoiceManager(StrategyChoice& strategyChoice, - shared_ptr face) - : ManagerBase(face) + shared_ptr face) + : ManagerBase(face, STRATEGY_CHOICE_PRIVILEGE) , m_strategyChoice(strategyChoice) { face->setInterestFilter("/localhost/nfd/strategy-choice", @@ -59,7 +59,9 @@ StrategyChoiceManager::onStrategyChoiceRequest(const Interest& request) return; } - onValidatedStrategyChoiceRequest(request.shared_from_this()); + validate(request, + bind(&StrategyChoiceManager::onValidatedStrategyChoiceRequest, this, _1), + bind(&ManagerBase::onCommandValidationFailed, this, _1, _2)); } void diff --git a/daemon/mgmt/strategy-choice-manager.hpp b/daemon/mgmt/strategy-choice-manager.hpp index 34046aca..6313fbb2 100644 --- a/daemon/mgmt/strategy-choice-manager.hpp +++ b/daemon/mgmt/strategy-choice-manager.hpp @@ -21,7 +21,7 @@ class StrategyChoiceManager : public ManagerBase { public: StrategyChoiceManager(StrategyChoice& strategyChoice, - shared_ptr face); + shared_ptr face); virtual ~StrategyChoiceManager(); diff --git a/tests/mgmt/command-validator.cpp b/tests/mgmt/command-validator.cpp new file mode 100644 index 00000000..7a6d39d1 --- /dev/null +++ b/tests/mgmt/command-validator.cpp @@ -0,0 +1,585 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (C) 2014 Named Data Networking Project + * See COPYING for copyright and distribution information. + */ + +#include "mgmt/command-validator.hpp" +#include "mgmt/config-file.hpp" + +#include "tests/test-common.hpp" + +#include +#include +#include +#include + +namespace nfd { + +namespace tests { + +NFD_LOG_INIT("CommandValidatorTest"); + +BOOST_FIXTURE_TEST_SUITE(MgmtCommandValidator, BaseFixture) + +// authorizations +// { +// ; an authorize section grants privileges to a key +// authorize +// { +// keyfile "tests/mgmt/key1.pub" ; public key file +// privileges ; set of privileges granted to this public key +// { +// fib +// stats +// } +// } + +// authorize +// { +// keyfile "tests/mgmt/key2.pub" ; public key file +// privileges ; set of privileges granted to this public key +// { +// faces +// } +// } +// } + +const std::string CONFIG = +"authorizations\n" +"{\n" +" authorize\n" +" {\n" +" keyfile \"tests/mgmt/key1.pub\"\n" +" privileges\n" +" {\n" +" fib\n" +" stats\n" +" }\n" +" }\n" +" authorize\n" +" {\n" +" keyfile \"tests/mgmt/key2.pub\"\n" +" privileges\n" +" {\n" +" faces\n" +" }\n" +" }\n" + "}\n"; + +class CommandValidatorTester +{ +public: + + CommandValidatorTester() + : m_validated(false), + m_validationFailed(false) + { + + } + + void + generateIdentity(const Name& prefix) + { + m_identityName = prefix; + m_identityName.append(boost::lexical_cast(ndn::time::now())); + + const Name certName = m_keys.createIdentity(m_identityName); + + m_certificate = m_keys.getCertificate(certName); + } + + void + saveIdentityToFile(const char* filename) + { + std::ofstream out; + out.open(filename); + + BOOST_REQUIRE(out.is_open()); + BOOST_REQUIRE(static_cast(m_certificate)); + + ndn::io::save(*m_certificate, out); + + out.close(); + } + + const Name& + getIdentityName() const + { + BOOST_REQUIRE_NE(m_identityName, Name()); + return m_identityName; + } + + const Name& + getPublicKeyName() const + { + BOOST_REQUIRE(static_cast(m_certificate)); + return m_certificate->getPublicKeyName(); + } + + void + onValidated(const shared_ptr& interest) + { + // NFD_LOG_DEBUG("validated command"); + m_validated = true; + } + + void + onValidationFailed(const shared_ptr& interest, const std::string& info) + { + NFD_LOG_DEBUG("validation failed: " << info); + m_validationFailed = true; + } + + bool + commandValidated() const + { + return m_validated; + } + + bool + commandValidationFailed() const + { + return m_validationFailed; + } + + void + resetValidation() + { + m_validated = false; + m_validationFailed = false; + } + + ~CommandValidatorTester() + { + m_keys.deleteIdentity(m_identityName); + } + +private: + bool m_validated; + bool m_validationFailed; + + ndn::KeyChain m_keys; + Name m_identityName; + shared_ptr m_certificate; +}; + +class TwoValidatorFixture : public BaseFixture +{ +public: + TwoValidatorFixture() + { + m_tester1.generateIdentity("/test/CommandValidator/TwoKeys/id1"); + m_tester1.saveIdentityToFile("tests/mgmt/key1.pub"); + + m_tester2.generateIdentity("/test/CommandValidator/TwoKeys/id2"); + m_tester2.saveIdentityToFile("tests/mgmt/key2.pub"); + } + + ~TwoValidatorFixture() + { + boost::system::error_code error; + boost::filesystem::remove("tests/mgmt/key1.pub", error); + boost::filesystem::remove("tests/mgmt/key2.pub", error); + } + +protected: + CommandValidatorTester m_tester1; + CommandValidatorTester m_tester2; +}; + +BOOST_FIXTURE_TEST_CASE(TwoKeys, TwoValidatorFixture) +{ + shared_ptr fibCommand = make_shared("/localhost/nfd/fib/insert"); + shared_ptr statsCommand = make_shared("/localhost/nfd/stats/dosomething"); + shared_ptr facesCommand = make_shared("/localhost/nfd/faces/create"); + + ndn::CommandInterestGenerator generator; + generator.generateWithIdentity(*fibCommand, m_tester1.getIdentityName()); + generator.generateWithIdentity(*statsCommand, m_tester1.getIdentityName()); + generator.generateWithIdentity(*facesCommand, m_tester2.getIdentityName()); + + ConfigFile config; + CommandValidator validator; + validator.addSupportedPrivilege("faces"); + validator.addSupportedPrivilege("fib"); + validator.addSupportedPrivilege("stats"); + + config.addSectionHandler("authorizations", + bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2)); + config.parse(CONFIG, false); + + validator.validate(*fibCommand, + 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(*statsCommand, + bind(&CommandValidatorTester::onValidated, boost::ref(m_tester1), _1), + bind(&CommandValidatorTester::onValidationFailed, boost::ref(m_tester1), _1, _2)); + + BOOST_REQUIRE(m_tester1.commandValidated()); + + validator.validate(*facesCommand, + bind(&CommandValidatorTester::onValidated, boost::ref(m_tester2), _1), + bind(&CommandValidatorTester::onValidationFailed, boost::ref(m_tester2), _1, _2)); + + BOOST_REQUIRE(m_tester2.commandValidated()); + m_tester2.resetValidation(); + + // use key2 for fib command (authorized for key1 only) + shared_ptr unauthorizedFibCommand = make_shared("/localhost/nfd/fib/insert"); + generator.generateWithIdentity(*unauthorizedFibCommand, m_tester2.getIdentityName()); + + validator.validate(*unauthorizedFibCommand, + bind(&CommandValidatorTester::onValidated, boost::ref(m_tester2), _1), + bind(&CommandValidatorTester::onValidationFailed, boost::ref(m_tester2), _1, _2)); + + BOOST_REQUIRE(m_tester2.commandValidationFailed()); +} + +BOOST_FIXTURE_TEST_CASE(TwoKeysDryRun, TwoValidatorFixture) +{ + CommandValidatorTester tester1; + tester1.generateIdentity("/test/CommandValidator/TwoKeys/id1"); + tester1.saveIdentityToFile("tests/mgmt/key1.pub"); + + CommandValidatorTester tester2; + tester2.generateIdentity("/test/CommandValidator/TwoKeys/id2"); + tester2.saveIdentityToFile("tests/mgmt/key2.pub"); + + shared_ptr fibCommand = make_shared("/localhost/nfd/fib/insert"); + shared_ptr statsCommand = make_shared("/localhost/nfd/stats/dosomething"); + shared_ptr facesCommand = make_shared("/localhost/nfd/faces/create"); + + ndn::CommandInterestGenerator generator; + generator.generateWithIdentity(*fibCommand, m_tester1.getIdentityName()); + generator.generateWithIdentity(*statsCommand, m_tester1.getIdentityName()); + generator.generateWithIdentity(*facesCommand, m_tester2.getIdentityName()); + + ConfigFile config; + CommandValidator validator; + validator.addSupportedPrivilege("faces"); + validator.addSupportedPrivilege("fib"); + validator.addSupportedPrivilege("stats"); + + config.addSectionHandler("authorizations", + bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2)); + config.parse(CONFIG, true); + + 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.commandValidationFailed()); + + validator.validate(*facesCommand, + bind(&CommandValidatorTester::onValidated, boost::ref(m_tester2), _1), + bind(&CommandValidatorTester::onValidationFailed, boost::ref(m_tester2), _1, _2)); + + BOOST_REQUIRE(m_tester2.commandValidationFailed()); + m_tester2.resetValidation(); + + // use key2 for fib command (authorized for key1 only) + shared_ptr unauthorizedFibCommand = make_shared("/localhost/nfd/fib/insert"); + generator.generateWithIdentity(*unauthorizedFibCommand, m_tester2.getIdentityName()); + + validator.validate(*unauthorizedFibCommand, + bind(&CommandValidatorTester::onValidated, boost::ref(m_tester2), _1), + bind(&CommandValidatorTester::onValidationFailed, boost::ref(m_tester2), _1, _2)); + + BOOST_REQUIRE(m_tester2.commandValidationFailed()); +} + +BOOST_AUTO_TEST_CASE(NoAuthorizeSections) +{ + const std::string NO_AUTHORIZE_CONFIG = + "authorizations\n" + "{\n" + "}\n"; + + ConfigFile config; + CommandValidator validator; + + config.addSectionHandler("authorizations", + bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2)); + BOOST_CHECK_THROW(config.parse(NO_AUTHORIZE_CONFIG, false), ConfigFile::Error); +} + +BOOST_AUTO_TEST_CASE(NoPrivilegesSections) +{ + const std::string NO_PRIVILEGES_CONFIG = + "authorizations\n" + "{\n" + " authorize\n" + " {\n" + " keyfile \"tests/mgmt/key1.pub\"\n" + " }\n" + "}\n"; + + ConfigFile config; + CommandValidator validator; + + config.addSectionHandler("authorizations", + bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2)); + BOOST_CHECK_THROW(config.parse(NO_PRIVILEGES_CONFIG, false), ConfigFile::Error); +} + +BOOST_AUTO_TEST_CASE(InvalidKeyFile) +{ + const std::string INVALID_KEY_CONFIG = + "authorizations\n" + "{\n" + " authorize\n" + " {\n" + " keyfile \"tests/mgmt/notakeyfile.pub\"\n" + " privileges\n" + " {\n" + " fib\n" + " stats\n" + " }\n" + " }\n" + "}\n"; + + ConfigFile config; + CommandValidator validator; + + config.addSectionHandler("authorizations", + bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2)); + BOOST_CHECK_THROW(config.parse(INVALID_KEY_CONFIG, false), ConfigFile::Error); +} + +BOOST_AUTO_TEST_CASE(NoKeyFile) +{ + const std::string NO_KEY_CONFIG = + "authorizations\n" + "{\n" + " authorize\n" + " {\n" + " privileges\n" + " {\n" + " fib\n" + " stats\n" + " }\n" + " }\n" + "}\n"; + + + ConfigFile config; + CommandValidator validator; + + config.addSectionHandler("authorizations", + bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2)); + BOOST_CHECK_THROW(config.parse(NO_KEY_CONFIG, false), ConfigFile::Error); +} + +BOOST_AUTO_TEST_CASE(MalformedKey) +{ + const std::string MALFORMED_KEY_CONFIG = + "authorizations\n" + "{\n" + " authorize\n" + " {\n" + " keyfile \"tests/mgmt/malformedkey.pub\"\n" + " privileges\n" + " {\n" + " fib\n" + " stats\n" + " }\n" + " }\n" + "}\n"; + + + ConfigFile config; + CommandValidator validator; + + config.addSectionHandler("authorizations", + bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2)); + BOOST_CHECK_THROW(config.parse(MALFORMED_KEY_CONFIG, false), ConfigFile::Error); +} + +bool +validateErrorMessage(const std::string& expectedMessage, const ConfigFile::Error& error) +{ + bool gotExpected = error.what() == expectedMessage; + if (!gotExpected) + { + NFD_LOG_WARN("\ncaught exception: " << error.what() + << "\n\nexpected exception: " << expectedMessage); + } + return gotExpected; +} + +BOOST_AUTO_TEST_CASE(NoAuthorizeSectionsDryRun) +{ + const std::string NO_AUTHORIZE_CONFIG = + "authorizations\n" + "{\n" + "}\n"; + + ConfigFile config; + CommandValidator validator; + + config.addSectionHandler("authorizations", + bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2)); + BOOST_CHECK_EXCEPTION(config.parse(NO_AUTHORIZE_CONFIG, true), + ConfigFile::Error, + bind(&validateErrorMessage, + "No authorize sections found", _1)); +} + +BOOST_FIXTURE_TEST_CASE(NoPrivilegesSectionsDryRun, TwoValidatorFixture) +{ + const std::string NO_PRIVILEGES_CONFIG = + "authorizations\n" + "{\n" + " authorize\n" + " {\n" + " keyfile \"tests/mgmt/key1.pub\"\n" + " }\n" + " authorize\n" + " {\n" + " keyfile \"tests/mgmt/key2.pub\"\n" + " }\n" + "}\n"; + + // CommandValidatorTester tester1; + // tester1.generateIdentity("/tests/CommandValidator/TwoKeys/id1"); + // tester1.saveIdentityToFile("tests/mgmt/key1.pub"); + + // CommandValidatorTester tester2; + // tester2.generateIdentity("/tests/CommandValidator/TwoKeys/id2"); + // tester2.saveIdentityToFile("tests/mgmt/key2.pub"); + + ConfigFile config; + CommandValidator validator; + + config.addSectionHandler("authorizations", + bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2)); + + std::stringstream expectedError; + expectedError << "No privileges section found for key file tests/mgmt/key1.pub " + << "(" << m_tester1.getPublicKeyName().toUri() << ")\n" + << "No privileges section found for key file tests/mgmt/key2.pub " + << "(" << m_tester2.getPublicKeyName().toUri() << ")"; + + BOOST_CHECK_EXCEPTION(config.parse(NO_PRIVILEGES_CONFIG, true), + ConfigFile::Error, + bind(&validateErrorMessage, expectedError.str(), _1)); +} + +BOOST_AUTO_TEST_CASE(InvalidKeyFileDryRun) +{ + const std::string INVALID_KEY_CONFIG = + "authorizations\n" + "{\n" + " authorize\n" + " {\n" + " keyfile \"tests/mgmt/notakeyfile.pub\"\n" + " privileges\n" + " {\n" + " fib\n" + " stats\n" + " }\n" + " }\n" + " authorize\n" + " {\n" + " keyfile \"tests/mgmt/stillnotakeyfile.pub\"\n" + " privileges\n" + " {\n" + " }\n" + " }\n" + "}\n"; + + ConfigFile config; + CommandValidator validator; + + config.addSectionHandler("authorizations", + bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2)); + + BOOST_CHECK_EXCEPTION(config.parse(INVALID_KEY_CONFIG, true), + ConfigFile::Error, + bind(&validateErrorMessage, + "Unable to open key file tests/mgmt/notakeyfile.pub\n" + "Unable to open key file tests/mgmt/stillnotakeyfile.pub", _1)); +} + +BOOST_AUTO_TEST_CASE(NoKeyFileDryRun) +{ + const std::string NO_KEY_CONFIG = + "authorizations\n" + "{\n" + " authorize\n" + " {\n" + " privileges\n" + " {\n" + " fib\n" + " stats\n" + " }\n" + " }\n" + " authorize\n" + " {\n" + " }\n" + "}\n"; + + + ConfigFile config; + CommandValidator validator; + + config.addSectionHandler("authorizations", + bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2)); + BOOST_CHECK_EXCEPTION(config.parse(NO_KEY_CONFIG, true), + ConfigFile::Error, + bind(&validateErrorMessage, + "No keyfile specified\n" + "No keyfile specified", _1)); +} + +BOOST_AUTO_TEST_CASE(MalformedKeyDryRun) +{ + const std::string MALFORMED_KEY_CONFIG = + "authorizations\n" + "{\n" + " authorize\n" + " {\n" + " keyfile \"tests/mgmt/malformedkey.pub\"\n" + " privileges\n" + " {\n" + " fib\n" + " stats\n" + " }\n" + " }\n" + " authorize\n" + " {\n" + " keyfile \"tests/mgmt/malformedkey.pub\"\n" + " }\n" + "}\n"; + + + ConfigFile config; + CommandValidator validator; + + config.addSectionHandler("authorizations", + bind(&CommandValidator::onConfig, boost::ref(validator), _1, _2)); + BOOST_CHECK_EXCEPTION(config.parse(MALFORMED_KEY_CONFIG, true), + ConfigFile::Error, + bind(&validateErrorMessage, + "Malformed key file tests/mgmt/malformedkey.pub\n" + "Malformed key file tests/mgmt/malformedkey.pub", _1)); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace tests + +} // namespace nfd + diff --git a/tests/mgmt/face-manager.cpp b/tests/mgmt/face-manager.cpp index 92dc6802..99376320 100644 --- a/tests/mgmt/face-manager.cpp +++ b/tests/mgmt/face-manager.cpp @@ -13,6 +13,7 @@ #include "common.hpp" #include "tests/test-common.hpp" +#include "validation-common.hpp" namespace nfd { namespace tests { @@ -274,6 +275,13 @@ public: return m_manager; } + void + addInterestRule(const std::string& regex, + ndn::IdentityCertificate& certificate) + { + m_manager.addInterestRule(regex, certificate); + } + bool didFaceTableAddFire() const { @@ -669,9 +677,85 @@ BOOST_AUTO_TEST_CASE(MalformedCommmand) BOOST_REQUIRE(didCallbackFire()); } -/// \todo add tests for unsigned and unauthorized commands +BOOST_AUTO_TEST_CASE(UnsignedCommand) +{ + ndn::nfd::FaceManagementOptions options; + options.setUri("tcp://127.0.0.1"); -BOOST_AUTO_TEST_CASE(UnsupportedVerb) + Block encodedOptions(options.wireEncode()); + + Name commandName("/localhost/nfd/faces"); + commandName.append("create"); + commandName.append(encodedOptions); + + shared_ptr command(make_shared(commandName)); + + getFace()->onReceiveData += + bind(&FaceManagerFixture::validateControlResponse, this, _1, + command->getName(), 401, "Signature required"); + + getManager().onFaceRequest(*command); + + BOOST_REQUIRE(didCallbackFire()); +} + +BOOST_FIXTURE_TEST_CASE(UnauthorizedCommand, UnauthorizedCommandFixture) +{ + ndn::nfd::FaceManagementOptions options; + options.setUri("tcp://127.0.0.1"); + + Block encodedOptions(options.wireEncode()); + + Name commandName("/localhost/nfd/faces"); + commandName.append("create"); + commandName.append(encodedOptions); + + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + + getFace()->onReceiveData += + bind(&FaceManagerFixture::validateControlResponse, this, _1, + command->getName(), 403, "Unauthorized command"); + + getManager().onFaceRequest(*command); + + BOOST_REQUIRE(didCallbackFire()); +} + +template class AuthorizedCommandFixture : public CommandFixture +{ +public: + AuthorizedCommandFixture() + { + const std::string regex = "^"; + T::addInterestRule(regex, *CommandFixture::m_certificate); + } + + virtual + ~AuthorizedCommandFixture() + { + + } +}; + +// template <> class AuthorizedCommandFixture : +// public CommandFixture +// { +// public: +// AuthorizedCommandFixture() +// { +// const std::string regex = "^"; +// FaceManagerFixture::ManagerBase::addInterestRule(regex, *CommandFixture::m_certificate); +// } + +// virtual +// ~AuthorizedCommandFixture() +// { + +// } +// }; + +BOOST_FIXTURE_TEST_CASE(UnsupportedCommand, AuthorizedCommandFixture) { ndn::nfd::FaceManagementOptions options; @@ -682,6 +766,7 @@ BOOST_AUTO_TEST_CASE(UnsupportedVerb) commandName.append(encodedOptions); shared_ptr command(make_shared(commandName)); + generateCommand(*command); getFace()->onReceiveData += bind(&FaceManagerFixture::validateControlResponse, this, _1, @@ -743,13 +828,15 @@ private: bool m_destroyFaceFired; }; -BOOST_FIXTURE_TEST_CASE(ValidatedFaceRequestBadOptionParse, ValidatedFaceRequestFixture) +BOOST_FIXTURE_TEST_CASE(ValidatedFaceRequestBadOptionParse, + AuthorizedCommandFixture) { Name commandName("/localhost/nfd/faces"); commandName.append("create"); commandName.append("NotReallyOptions"); shared_ptr command(make_shared(commandName)); + generateCommand(*command); getFace()->onReceiveData += bind(&ValidatedFaceRequestFixture::validateControlResponse, this, _1, @@ -760,7 +847,8 @@ BOOST_FIXTURE_TEST_CASE(ValidatedFaceRequestBadOptionParse, ValidatedFaceRequest BOOST_REQUIRE(didCallbackFire()); } -BOOST_FIXTURE_TEST_CASE(ValidatedFaceRequestCreateFace, ValidatedFaceRequestFixture) +BOOST_FIXTURE_TEST_CASE(ValidatedFaceRequestCreateFace, + AuthorizedCommandFixture) { ndn::nfd::FaceManagementOptions options; options.setUri("tcp://127.0.0.1"); @@ -772,12 +860,14 @@ BOOST_FIXTURE_TEST_CASE(ValidatedFaceRequestCreateFace, ValidatedFaceRequestFixt commandName.append(encodedOptions); shared_ptr command(make_shared(commandName)); + generateCommand(*command); onValidatedFaceRequest(command); BOOST_CHECK(didCreateFaceFire()); } -BOOST_FIXTURE_TEST_CASE(ValidatedFaceRequestDestroyFace, ValidatedFaceRequestFixture) +BOOST_FIXTURE_TEST_CASE(ValidatedFaceRequestDestroyFace, + AuthorizedCommandFixture) { ndn::nfd::FaceManagementOptions options; options.setUri("tcp://127.0.0.1"); @@ -789,6 +879,7 @@ BOOST_FIXTURE_TEST_CASE(ValidatedFaceRequestDestroyFace, ValidatedFaceRequestFix commandName.append(encodedOptions); shared_ptr command(make_shared(commandName)); + generateCommand(*command); onValidatedFaceRequest(command); BOOST_CHECK(didDestroyFaceFire()); @@ -812,7 +903,7 @@ public: } }; -BOOST_FIXTURE_TEST_CASE(CreateFaceBadUri, FaceFixture) +BOOST_FIXTURE_TEST_CASE(CreateFaceBadUri, AuthorizedCommandFixture) { ndn::nfd::FaceManagementOptions options; options.setUri("tcp:/127.0.0.1"); @@ -823,16 +914,19 @@ BOOST_FIXTURE_TEST_CASE(CreateFaceBadUri, FaceFixture) commandName.append("create"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + getFace()->onReceiveData += bind(&FaceFixture::validateControlResponse, this, _1, - commandName, 400, "Malformed command"); + command->getName(), 400, "Malformed command"); - createFace(commandName, options); + createFace(command->getName(), options); BOOST_REQUIRE(didCallbackFire()); } -BOOST_FIXTURE_TEST_CASE(CreateFaceUnknownScheme, FaceFixture) +BOOST_FIXTURE_TEST_CASE(CreateFaceUnknownScheme, AuthorizedCommandFixture) { ndn::nfd::FaceManagementOptions options; // this will be an unsupported protocol because no factories have been @@ -845,16 +939,19 @@ BOOST_FIXTURE_TEST_CASE(CreateFaceUnknownScheme, FaceFixture) commandName.append("create"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + getFace()->onReceiveData += bind(&FaceFixture::validateControlResponse, this, _1, - commandName, 501, "Unsupported protocol"); + command->getName(), 501, "Unsupported protocol"); - createFace(commandName, options); + createFace(command->getName(), options); BOOST_REQUIRE(didCallbackFire()); } -BOOST_FIXTURE_TEST_CASE(OnCreated, FaceFixture) +BOOST_FIXTURE_TEST_CASE(OnCreated, AuthorizedCommandFixture) { ndn::nfd::FaceManagementOptions options; options.setUri("tcp://127.0.0.1"); @@ -865,6 +962,9 @@ BOOST_FIXTURE_TEST_CASE(OnCreated, FaceFixture) commandName.append("create"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + ndn::nfd::FaceManagementOptions resultOptions; resultOptions.setUri("tcp://127.0.0.1"); resultOptions.setFaceId(-1); @@ -873,17 +973,17 @@ BOOST_FIXTURE_TEST_CASE(OnCreated, FaceFixture) getFace()->onReceiveData += bind(&FaceFixture::validateControlResponse, this, _1, - commandName, 200, "Success", encodedResultOptions); + command->getName(), 200, "Success", encodedResultOptions); - onCreated(commandName, options, make_shared()); + onCreated(command->getName(), options, make_shared()); BOOST_REQUIRE(didCallbackFire()); BOOST_CHECK(TestFaceTableFixture::m_faceTable.didAddFire()); } -BOOST_FIXTURE_TEST_CASE(OnConnectFailed, FaceFixture) +BOOST_FIXTURE_TEST_CASE(OnConnectFailed, AuthorizedCommandFixture) { - ndn::nfd::FaceManagementOptions options; + ndn::nfd::FaceManagementOptions options; options.setUri("tcp://127.0.0.1"); Block encodedOptions(options.wireEncode()); @@ -892,18 +992,21 @@ BOOST_FIXTURE_TEST_CASE(OnConnectFailed, FaceFixture) commandName.append("create"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + getFace()->onReceiveData += bind(&FaceFixture::validateControlResponse, this, _1, - commandName, 400, "Failed to create face"); + command->getName(), 400, "Failed to create face"); - onConnectFailed(commandName, "unit-test-reason"); + onConnectFailed(command->getName(), "unit-test-reason"); BOOST_REQUIRE(didCallbackFire()); BOOST_CHECK_EQUAL(TestFaceTableFixture::m_faceTable.didAddFire(), false); } -BOOST_FIXTURE_TEST_CASE(DestroyFace, FaceFixture) +BOOST_FIXTURE_TEST_CASE(DestroyFace, AuthorizedCommandFixture) { ndn::nfd::FaceManagementOptions options; options.setUri("tcp://127.0.0.1"); @@ -914,11 +1017,14 @@ BOOST_FIXTURE_TEST_CASE(DestroyFace, FaceFixture) commandName.append("destroy"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + getFace()->onReceiveData += bind(&FaceFixture::validateControlResponse, this, _1, - commandName, 200, "Success"); + command->getName(), 200, "Success"); - destroyFace(commandName, options); + destroyFace(command->getName(), options); BOOST_REQUIRE(didCallbackFire()); BOOST_CHECK(TestFaceTableFixture::m_faceTable.didRemoveFire()); diff --git a/tests/mgmt/fib-manager.cpp b/tests/mgmt/fib-manager.cpp index 9905f8a4..e6748be9 100644 --- a/tests/mgmt/fib-manager.cpp +++ b/tests/mgmt/fib-manager.cpp @@ -11,6 +11,7 @@ #include "mgmt/internal-face.hpp" #include "tests/face/dummy-face.hpp" +#include "validation-common.hpp" #include "tests/test-common.hpp" namespace nfd { @@ -22,10 +23,9 @@ class FibManagerFixture : protected BaseFixture { public: - FibManagerFixture() - : m_callbackFired(false) + virtual + ~FibManagerFixture() { - } shared_ptr @@ -57,10 +57,10 @@ public: control.wireDecode(controlRaw); - NFD_LOG_DEBUG("received control response" - << " Name: " << response.getName() - << " code: " << control.getCode() - << " text: " << control.getText()); + // NFD_LOG_DEBUG("received control response" + // << " Name: " << response.getName() + // << " code: " << control.getCode() + // << " text: " << control.getText()); BOOST_CHECK_EQUAL(response.getName(), expectedName); BOOST_CHECK_EQUAL(control.getCode(), expectedCode); @@ -114,12 +114,70 @@ public: m_callbackFired = false; } + shared_ptr + getInternalFace() + { + return m_face; + } + + FibManager& + getFibManager() + { + return m_manager; + } + + Fib& + getFib() + { + return m_fib; + } + + void + addInterestRule(const std::string& regex, + ndn::IdentityCertificate& certificate) + { + m_manager.addInterestRule(regex, certificate); + } + +protected: + FibManagerFixture() + : m_face(make_shared()) + , m_nameTree(1024) + , m_fib(m_nameTree) + , m_manager(boost::ref(m_fib), + bind(&FibManagerFixture::getFace, this, _1), + m_face) + , m_callbackFired(false) + { + } + private: + shared_ptr m_face; + NameTree m_nameTree; + Fib m_fib; + FibManager m_manager; + std::vector > m_faces; bool m_callbackFired; }; -BOOST_FIXTURE_TEST_SUITE(MgmtFibManager, FibManagerFixture) +template class AuthorizedCommandFixture: + public CommandFixture +{ +public: + AuthorizedCommandFixture() + { + const std::string regex = "^"; + T::addInterestRule(regex, *CommandFixture::m_certificate); + } + + virtual + ~AuthorizedCommandFixture() + { + } +}; + +BOOST_FIXTURE_TEST_SUITE(MgmtFibManager, AuthorizedCommandFixture) bool foundNextHop(FaceId id, uint32_t cost, const fib::NextHop& next) @@ -165,12 +223,7 @@ addedNextHopWithFace(const Fib& fib, const Name& prefix, size_t oldSize, BOOST_AUTO_TEST_CASE(TestFireInterestFilter) { - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, this, _1), - face); + shared_ptr face = getInternalFace(); Interest command("/localhost/nfd/fib"); @@ -185,12 +238,7 @@ BOOST_AUTO_TEST_CASE(TestFireInterestFilter) BOOST_AUTO_TEST_CASE(MalformedCommmand) { - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, this, _1), - face); + shared_ptr face = getInternalFace(); BOOST_REQUIRE(didCallbackFire() == false); @@ -200,19 +248,14 @@ BOOST_AUTO_TEST_CASE(MalformedCommmand) bind(&FibManagerFixture::validateControlResponse, this, _1, command.getName(), 400, "Malformed command"); - manager.onFibRequest(command); + getFibManager().onFibRequest(command); BOOST_REQUIRE(didCallbackFire()); } BOOST_AUTO_TEST_CASE(UnsupportedVerb) { - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, this, _1), - face); + shared_ptr face = getInternalFace(); FibManagementOptions options; options.setName("/hello"); @@ -225,12 +268,14 @@ BOOST_AUTO_TEST_CASE(UnsupportedVerb) commandName.append("unsupported"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + face->onReceiveData += bind(&FibManagerFixture::validateControlResponse, this, _1, - commandName, 501, "Unsupported command"); + command->getName(), 501, "Unsupported command"); - Interest command(commandName); - manager.onFibRequest(command); + getFibManager().onFibRequest(*command); BOOST_REQUIRE(didCallbackFire()); } @@ -239,12 +284,7 @@ BOOST_AUTO_TEST_CASE(UnsignedCommand) { addFace(make_shared()); - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, this, _1), - face); + shared_ptr face = getInternalFace(); FibManagementOptions options; options.setName("/hello"); @@ -257,29 +297,24 @@ BOOST_AUTO_TEST_CASE(UnsignedCommand) commandName.append("add-nexthop"); commandName.append(encodedOptions); - face->onReceiveData += - bind(&FibManagerFixture::validateControlResponse, this, _1, - commandName, 404, "Prefix not found"); - /// \todo enable once sig checking implemented - // bind(&FibManagerFixture::validateControlResponse, this, _1, 401, "Signature required"); - Interest command(commandName); - manager.onFibRequest(command); + + face->onReceiveData += + bind(&FibManagerFixture::validateControlResponse, + this, _1, command.getName(), 401, "Signature required"); + + + getFibManager().onFibRequest(command); BOOST_REQUIRE(didCallbackFire()); - BOOST_REQUIRE(!addedNextHopWithCost(fib, "/hello", 0, 101)); + BOOST_REQUIRE(!addedNextHopWithCost(getFib(), "/hello", 0, 101)); } -BOOST_AUTO_TEST_CASE(UnauthorizedCommand) +BOOST_FIXTURE_TEST_CASE(UnauthorizedCommand, UnauthorizedCommandFixture) { addFace(make_shared()); - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, this, _1), - face); + shared_ptr face = getInternalFace(); FibManagementOptions options; options.setName("/hello"); @@ -292,40 +327,37 @@ BOOST_AUTO_TEST_CASE(UnauthorizedCommand) commandName.append("add-nexthop"); commandName.append(encodedOptions); - face->onReceiveData += - bind(&FibManagerFixture::validateControlResponse, this, _1, - commandName, 404, "Prefix not found"); - /// \todo enable once sig checking implemented - // bind(&FibManagerFixture::validateControlResponse, this, _1, 403, "Unauthorized command"); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); - Interest command(commandName); - manager.onFibRequest(command); + face->onReceiveData += + bind(&FibManagerFixture::validateControlResponse, + this, _1, command->getName(), 403, "Unauthorized command"); + + getFibManager().onFibRequest(*command); BOOST_REQUIRE(didCallbackFire()); - BOOST_REQUIRE(!addedNextHopWithCost(fib, "/hello", 0, 101)); + BOOST_REQUIRE(!addedNextHopWithCost(getFib(), "/hello", 0, 101)); } BOOST_AUTO_TEST_CASE(BadOptionParse) { addFace(make_shared()); - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, this, _1), - face); + shared_ptr face = getInternalFace(); Name commandName("/localhost/nfd/fib"); commandName.append("add-nexthop"); commandName.append("NotReallyOptions"); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + face->onReceiveData += bind(&FibManagerFixture::validateControlResponse, this, _1, - commandName, 400, "Malformed command"); + command->getName(), 400, "Malformed command"); - Interest command(commandName); - manager.onFibRequest(command); + getFibManager().onFibRequest(*command); BOOST_REQUIRE(didCallbackFire()); } @@ -334,12 +366,7 @@ BOOST_AUTO_TEST_CASE(UnknownFaceId) { addFace(make_shared()); - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, this, _1), - face); + shared_ptr face = getInternalFace(); FibManagementOptions options; options.setName("/hello"); @@ -352,27 +379,24 @@ BOOST_AUTO_TEST_CASE(UnknownFaceId) commandName.append("add-nexthop"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + face->onReceiveData += bind(&FibManagerFixture::validateControlResponse, this, _1, - commandName, 404, "Face not found"); + command->getName(), 404, "Face not found"); - Interest command(commandName); - manager.onFibRequest(command); + getFibManager().onFibRequest(*command); BOOST_REQUIRE(didCallbackFire()); - BOOST_REQUIRE(addedNextHopWithCost(fib, "/hello", 0, 101) == false); + BOOST_REQUIRE(addedNextHopWithCost(getFib(), "/hello", 0, 101) == false); } BOOST_AUTO_TEST_CASE(TestImplicitFaceId) { addFace(make_shared()); - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, this, _1), - face); + shared_ptr face = getInternalFace(); FibManagementOptions options; options.setName("/hello"); @@ -392,30 +416,27 @@ BOOST_AUTO_TEST_CASE(TestImplicitFaceId) Block encodedExpectedOptions(expectedOptions.wireEncode()); + shared_ptr command(make_shared(commandName)); + command->setIncomingFaceId(1); + generateCommand(*command); + face->onReceiveData += bind(&FibManagerFixture::validateControlResponse, this, _1, - commandName, 200, "Success", encodedExpectedOptions); + command->getName(), 200, "Success", encodedExpectedOptions); - fib.insert("/hello"); + getFib().insert("/hello"); - Interest command(commandName); - command.setIncomingFaceId(1); - manager.onFibRequest(command); + getFibManager().onFibRequest(*command); BOOST_REQUIRE(didCallbackFire()); - BOOST_REQUIRE(addedNextHopWithFace(fib, "/hello", 0, 101, getFace(1))); + BOOST_REQUIRE(addedNextHopWithFace(getFib(), "/hello", 0, 101, getFace(1))); } BOOST_AUTO_TEST_CASE(AddNextHopVerbInitialAdd) { addFace(make_shared()); - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, this, _1), - face); + shared_ptr face = getInternalFace(); FibManagementOptions options; options.setName("/hello"); @@ -428,31 +449,27 @@ BOOST_AUTO_TEST_CASE(AddNextHopVerbInitialAdd) commandName.append("add-nexthop"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + face->onReceiveData += bind(&FibManagerFixture::validateControlResponse, this, _1, - commandName, 200, "Success", encodedOptions); + command->getName(), 200, "Success", encodedOptions); - fib.insert("/hello"); + getFib().insert("/hello"); - Interest command(commandName); - manager.onFibRequest(command); + getFibManager().onFibRequest(*command); BOOST_REQUIRE(didCallbackFire()); - BOOST_REQUIRE(addedNextHopWithCost(fib, "/hello", 0, 101)); + BOOST_REQUIRE(addedNextHopWithCost(getFib(), "/hello", 0, 101)); } BOOST_AUTO_TEST_CASE(AddNextHopVerbAddToExisting) { addFace(make_shared()); + shared_ptr face = getInternalFace(); - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, this, _1), - face); - - fib.insert("/hello"); + getFib().insert("/hello"); for (int i = 1; i <= 2; i++) { @@ -468,16 +485,18 @@ BOOST_AUTO_TEST_CASE(AddNextHopVerbAddToExisting) commandName.append("add-nexthop"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + face->onReceiveData += bind(&FibManagerFixture::validateControlResponse, this, _1, - commandName, 200, "Success", encodedOptions); + command->getName(), 200, "Success", encodedOptions); - Interest command(commandName); - manager.onFibRequest(command); + getFibManager().onFibRequest(*command); BOOST_REQUIRE(didCallbackFire()); resetCallbackFired(); - shared_ptr entry = fib.findExactMatch("/hello"); + shared_ptr entry = getFib().findExactMatch("/hello"); if (static_cast(entry)) { @@ -499,16 +518,9 @@ BOOST_AUTO_TEST_CASE(AddNextHopVerbAddToExisting) BOOST_AUTO_TEST_CASE(AddNextHopVerbUpdateFaceCost) { addFace(make_shared()); + shared_ptr face = getInternalFace(); - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, - this, _1), - face); - - fib.insert("/hello"); + getFib().insert("/hello"); FibManagementOptions options; options.setName("/hello"); @@ -523,12 +535,14 @@ BOOST_AUTO_TEST_CASE(AddNextHopVerbUpdateFaceCost) commandName.append("add-nexthop"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + face->onReceiveData += bind(&FibManagerFixture::validateControlResponse, this, _1, - commandName, 200, "Success", encodedOptions); + command->getName(), 200, "Success", encodedOptions); - Interest command(commandName); - manager.onFibRequest(command); + getFibManager().onFibRequest(*command); BOOST_REQUIRE(didCallbackFire()); } @@ -545,17 +559,19 @@ BOOST_AUTO_TEST_CASE(AddNextHopVerbUpdateFaceCost) commandName.append("add-nexthop"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + face->onReceiveData += bind(&FibManagerFixture::validateControlResponse, this, _1, - commandName, 200, "Success", encodedOptions); + command->getName(), 200, "Success", encodedOptions); - Interest command(commandName); - manager.onFibRequest(command); + getFibManager().onFibRequest(*command); BOOST_REQUIRE(didCallbackFire()); } - shared_ptr entry = fib.findExactMatch("/hello"); + shared_ptr entry = getFib().findExactMatch("/hello"); // Add faces with cost == FaceID for the name /hello // This test assumes: @@ -576,12 +592,7 @@ BOOST_AUTO_TEST_CASE(AddNextHopVerbUpdateFaceCost) BOOST_AUTO_TEST_CASE(Insert) { - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, this, _1), - face); + shared_ptr face = getInternalFace(); { FibManagementOptions options; @@ -593,17 +604,19 @@ BOOST_AUTO_TEST_CASE(Insert) commandName.append("insert"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + face->onReceiveData += bind(&FibManagerFixture::validateControlResponse, this, _1, - commandName, 200, "Success", encodedOptions); + command->getName(), 200, "Success", encodedOptions); - Interest command(commandName); - manager.onFibRequest(command); + getFibManager().onFibRequest(*command); } BOOST_REQUIRE(didCallbackFire()); - shared_ptr entry = fib.findExactMatch("/hello"); + shared_ptr entry = getFib().findExactMatch("/hello"); if (static_cast(entry)) { const fib::NextHopList& hops = entry->getNextHops(); @@ -611,6 +624,7 @@ BOOST_AUTO_TEST_CASE(Insert) } resetCallbackFired(); + face->onReceiveData.clear(); { FibManagementOptions options; @@ -622,17 +636,19 @@ BOOST_AUTO_TEST_CASE(Insert) commandName.append("insert"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + face->onReceiveData += bind(&FibManagerFixture::validateControlResponse, this, _1, - commandName, 200, "Success", encodedOptions); + command->getName(), 200, "Success", encodedOptions); - Interest command(commandName); - manager.onFibRequest(command); + getFibManager().onFibRequest(*command); } BOOST_REQUIRE(didCallbackFire()); - entry = fib.findExactMatch("/hello"); + entry = getFib().findExactMatch("/hello"); if (static_cast(entry)) { const fib::NextHopList& hops = entry->getNextHops(); @@ -642,7 +658,7 @@ BOOST_AUTO_TEST_CASE(Insert) } void -testRemove(FibManagerFixture* fixture, +testRemove(CommandFixture* fixture, FibManager& manager, Fib& fib, shared_ptr face, @@ -657,12 +673,14 @@ testRemove(FibManagerFixture* fixture, commandName.append("delete"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + fixture->generateCommand(*command); + face->onReceiveData += bind(&FibManagerFixture::validateControlResponse, fixture, _1, - commandName, 200, "Success", encodedOptions); + command->getName(), 200, "Success", encodedOptions); - Interest command(commandName); - manager.onFibRequest(command); + manager.onFibRequest(*command); BOOST_REQUIRE(fixture->didCallbackFire()); @@ -675,12 +693,9 @@ testRemove(FibManagerFixture* fixture, BOOST_AUTO_TEST_CASE(Delete) { - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, this, _1), - face); + shared_ptr face = getInternalFace(); + FibManager& manager = getFibManager(); + Fib& fib = getFib(); fib.insert("/a"); fib.insert("/a/b"); @@ -730,7 +745,7 @@ removedNextHopWithCost(const Fib& fib, const Name& prefix, size_t oldSize, uint3 } void -testRemoveNextHop(FibManagerFixture* fixture, +testRemoveNextHop(CommandFixture* fixture, FibManager& manager, Fib& fib, shared_ptr face, @@ -747,12 +762,14 @@ testRemoveNextHop(FibManagerFixture* fixture, commandName.append("remove-nexthop"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + fixture->generateCommand(*command); + face->onReceiveData += bind(&FibManagerFixture::validateControlResponse, fixture, _1, - commandName, 200, "Success", encodedOptions); + command->getName(), 200, "Success", encodedOptions); - Interest command(commandName); - manager.onFibRequest(command); + manager.onFibRequest(*command); BOOST_REQUIRE(fixture->didCallbackFire()); @@ -770,12 +787,9 @@ BOOST_AUTO_TEST_CASE(RemoveNextHop) addFace(face2); addFace(face3); - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, this, _1), - face); + shared_ptr face = getInternalFace(); + FibManager& manager = getFibManager(); + Fib& fib = getFib(); shared_ptr entry = fib.insert("/hello").first; @@ -792,7 +806,7 @@ BOOST_AUTO_TEST_CASE(RemoveNextHop) testRemoveNextHop(this, manager, fib, face, "/hello", 1); BOOST_REQUIRE(removedNextHopWithCost(fib, "/hello", 1, 101)); - if (!static_cast(fib.findExactMatch("/hello"))) + if (!static_cast(getFib().findExactMatch("/hello"))) { BOOST_FAIL("removed entry after removing all next hops"); } @@ -801,12 +815,7 @@ BOOST_AUTO_TEST_CASE(RemoveNextHop) BOOST_AUTO_TEST_CASE(RemoveNoFace) { - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, this, _1), - face); + shared_ptr face = getInternalFace(); FibManagementOptions options; options.setName("/hello"); @@ -818,12 +827,14 @@ BOOST_AUTO_TEST_CASE(RemoveNoFace) commandName.append("remove-nexthop"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + face->onReceiveData += bind(&FibManagerFixture::validateControlResponse, this, _1, - commandName, 404, "Face not found"); + command->getName(), 404, "Face not found"); - Interest command(commandName); - manager.onFibRequest(command); + getFibManager().onFibRequest(*command); BOOST_REQUIRE(didCallbackFire()); } @@ -832,12 +843,7 @@ BOOST_AUTO_TEST_CASE(RemoveNoPrefix) { addFace(make_shared()); - shared_ptr face(make_shared()); - NameTree nameTree(1024); - Fib fib(nameTree); - FibManager manager(fib, - bind(&FibManagerFixture::getFace, this, _1), - face); + shared_ptr face = getInternalFace(); FibManagementOptions options; options.setName("/hello"); @@ -849,12 +855,14 @@ BOOST_AUTO_TEST_CASE(RemoveNoPrefix) commandName.append("remove-nexthop"); commandName.append(encodedOptions); + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + face->onReceiveData += bind(&FibManagerFixture::validateControlResponse, this, _1, - commandName, 404, "Prefix not found"); + command->getName(), 404, "Prefix not found"); - Interest command(commandName); - manager.onFibRequest(command); + getFibManager().onFibRequest(*command); BOOST_REQUIRE(didCallbackFire()); } diff --git a/tests/mgmt/local-control-header-manager.cpp b/tests/mgmt/local-control-header-manager.cpp index 43a649d6..168f43f4 100644 --- a/tests/mgmt/local-control-header-manager.cpp +++ b/tests/mgmt/local-control-header-manager.cpp @@ -9,6 +9,7 @@ #include "tests/face/dummy-face.hpp" #include "tests/test-common.hpp" +#include "validation-common.hpp" namespace nfd { namespace tests { @@ -19,12 +20,6 @@ class LocalControlHeaderManagerFixture : protected BaseFixture { public: - LocalControlHeaderManagerFixture() - : m_callbackFired(false) - { - - } - shared_ptr getFace(FaceId id) { @@ -42,6 +37,25 @@ public: m_faces.push_back(face); } + shared_ptr + getInternalFace() + { + return m_face; + } + + LocalControlHeaderManager& + getManager() + { + return m_manager; + } + + void + addInterestRule(const std::string& regex, + ndn::IdentityCertificate& certificate) + { + m_manager.addInterestRule(regex, certificate); + } + void validateControlResponse(const Data& response, const Name& expectedName, @@ -82,49 +96,76 @@ public: m_callbackFired = false; } +protected: + LocalControlHeaderManagerFixture() + : m_face(make_shared()), + m_manager(bind(&LocalControlHeaderManagerFixture::getFace, this, _1), + m_face), + m_callbackFired(false) + { + } + private: + shared_ptr m_face; + LocalControlHeaderManager m_manager; std::vector > m_faces; bool m_callbackFired; }; -BOOST_FIXTURE_TEST_SUITE(MgmtLocalControlHeaderManager, LocalControlHeaderManagerFixture) +template class AuthorizedCommandFixture: + public CommandFixture +{ +public: + AuthorizedCommandFixture() + { + const std::string regex = "^"; + T::addInterestRule(regex, *CommandFixture::m_certificate); + } + + virtual + ~AuthorizedCommandFixture() + { + } +}; + +BOOST_FIXTURE_TEST_SUITE(MgmtLocalControlHeaderManager, + AuthorizedCommandFixture) BOOST_AUTO_TEST_CASE(InFaceId) { shared_ptr dummy = make_shared(); addFace(dummy); - shared_ptr face(make_shared()); - - LocalControlHeaderManager manager(bind(&LocalControlHeaderManagerFixture::getFace, this, _1), - face); - Name enable("/localhost/nfd/control-header/in-faceid/enable"); + shared_ptr enableCommand(make_shared(enable)); + enableCommand->setIncomingFaceId(1); - face->onReceiveData += + generateCommand(*enableCommand); + + getInternalFace()->onReceiveData += bind(&LocalControlHeaderManagerFixture::validateControlResponse, this, _1, - enable, 200, "Success"); + enableCommand->getName(), 200, "Success"); - Interest enableCommand(enable); - enableCommand.setIncomingFaceId(1); - manager.onLocalControlHeaderRequest(enableCommand); + getManager().onLocalControlHeaderRequest(*enableCommand); BOOST_REQUIRE(didCallbackFire()); BOOST_REQUIRE(dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID)); BOOST_CHECK(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID)); - face->onReceiveData.clear(); + getInternalFace()->onReceiveData.clear(); resetCallbackFired(); Name disable("/localhost/nfd/control-header/in-faceid/disable"); + shared_ptr disableCommand(make_shared(disable)); + disableCommand->setIncomingFaceId(1); - face->onReceiveData += + generateCommand(*disableCommand); + + getInternalFace()->onReceiveData += bind(&LocalControlHeaderManagerFixture::validateControlResponse, this, _1, - disable, 200, "Success"); + disableCommand->getName(), 200, "Success"); - Interest disableCommand(disable); - disableCommand.setIncomingFaceId(1); - manager.onLocalControlHeaderRequest(disableCommand); + getManager().onLocalControlHeaderRequest(*disableCommand); BOOST_REQUIRE(didCallbackFire()); BOOST_REQUIRE(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID)); @@ -136,38 +177,36 @@ BOOST_AUTO_TEST_CASE(NextHopFaceId) shared_ptr dummy = make_shared(); addFace(dummy); - shared_ptr face(make_shared()); - - LocalControlHeaderManager manager(bind(&LocalControlHeaderManagerFixture::getFace, this, _1), - face); - Name enable("/localhost/nfd/control-header/nexthop-faceid/enable"); - face->onReceiveData += - bind(&LocalControlHeaderManagerFixture::validateControlResponse, this, _1, - enable, 200, "Success"); + shared_ptr enableCommand(make_shared(enable)); + enableCommand->setIncomingFaceId(1); + generateCommand(*enableCommand); - Interest enableCommand(enable); - enableCommand.setIncomingFaceId(1); - manager.onLocalControlHeaderRequest(enableCommand); + getInternalFace()->onReceiveData += + bind(&LocalControlHeaderManagerFixture::validateControlResponse, this, _1, + enableCommand->getName(), 200, "Success"); + + getManager().onLocalControlHeaderRequest(*enableCommand); BOOST_REQUIRE(didCallbackFire()); BOOST_REQUIRE(dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID)); BOOST_CHECK(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID)); - - face->onReceiveData.clear(); + getInternalFace()->onReceiveData.clear(); resetCallbackFired(); Name disable("/localhost/nfd/control-header/nexthop-faceid/disable"); + shared_ptr disableCommand(make_shared(disable)); + disableCommand->setIncomingFaceId(1); - face->onReceiveData += + generateCommand(*disableCommand); + + getInternalFace()->onReceiveData += bind(&LocalControlHeaderManagerFixture::validateControlResponse, this, _1, - disable, 200, "Success"); + disableCommand->getName(), 200, "Success"); - Interest disableCommand(disable); - disableCommand.setIncomingFaceId(1); - manager.onLocalControlHeaderRequest(disableCommand); + getManager().onLocalControlHeaderRequest(*disableCommand); BOOST_REQUIRE(didCallbackFire()); BOOST_REQUIRE(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID)); @@ -179,20 +218,15 @@ BOOST_AUTO_TEST_CASE(ShortCommand) shared_ptr dummy = make_shared(); addFace(dummy); - shared_ptr face(make_shared()); - - LocalControlHeaderManager manager(bind(&LocalControlHeaderManagerFixture::getFace, this, _1), - face); - Name commandName("/localhost/nfd/control-header"); + Interest command(commandName); + command.setIncomingFaceId(1); - face->onReceiveData += + getInternalFace()->onReceiveData += bind(&LocalControlHeaderManagerFixture::validateControlResponse, this, _1, commandName, 400, "Malformed command"); - Interest command(commandName); - command.setIncomingFaceId(1); - manager.onLocalControlHeaderRequest(command); + getManager().onLocalControlHeaderRequest(command); BOOST_REQUIRE(didCallbackFire()); BOOST_CHECK(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID)); @@ -204,20 +238,15 @@ BOOST_AUTO_TEST_CASE(ShortCommandModule) shared_ptr dummy = make_shared(); addFace(dummy); - shared_ptr face(make_shared()); - - LocalControlHeaderManager manager(bind(&LocalControlHeaderManagerFixture::getFace, this, _1), - face); - Name commandName("/localhost/nfd/control-header/in-faceid"); - face->onReceiveData += + getInternalFace()->onReceiveData += bind(&LocalControlHeaderManagerFixture::validateControlResponse, this, _1, commandName, 400, "Malformed command"); Interest command(commandName); command.setIncomingFaceId(1); - manager.onLocalControlHeaderRequest(command); + getManager().onLocalControlHeaderRequest(command); BOOST_REQUIRE(didCallbackFire()); BOOST_CHECK(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID)); @@ -229,20 +258,17 @@ BOOST_AUTO_TEST_CASE(UnsupportedModule) shared_ptr dummy = make_shared(); addFace(dummy); - shared_ptr face(make_shared()); - - LocalControlHeaderManager manager(bind(&LocalControlHeaderManagerFixture::getFace, this, _1), - face); - Name commandName("/localhost/nfd/control-header/madeup/moremadeup"); + shared_ptr command(make_shared(commandName)); + command->setIncomingFaceId(1); - face->onReceiveData += + generateCommand(*command); + + getInternalFace()->onReceiveData += bind(&LocalControlHeaderManagerFixture::validateControlResponse, this, _1, - commandName, 501, "Unsupported"); + command->getName(), 501, "Unsupported"); - Interest command(commandName); - command.setIncomingFaceId(1); - manager.onLocalControlHeaderRequest(command); + getManager().onLocalControlHeaderRequest(*command); BOOST_REQUIRE(didCallbackFire()); BOOST_CHECK(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID)); @@ -254,20 +280,18 @@ BOOST_AUTO_TEST_CASE(InFaceIdUnsupportedVerb) shared_ptr dummy = make_shared(); addFace(dummy); - shared_ptr face(make_shared()); - - LocalControlHeaderManager manager(bind(&LocalControlHeaderManagerFixture::getFace, this, _1), - face); - Name commandName("/localhost/nfd/control-header/in-faceid/madeup"); + shared_ptr command(make_shared(commandName)); + command->setIncomingFaceId(1); - face->onReceiveData += + + generateCommand(*command); + + getInternalFace()->onReceiveData += bind(&LocalControlHeaderManagerFixture::validateControlResponse, this, _1, - commandName, 501, "Unsupported"); + command->getName(), 501, "Unsupported"); - Interest command(commandName); - command.setIncomingFaceId(1); - manager.onLocalControlHeaderRequest(command); + getManager().onLocalControlHeaderRequest(*command); BOOST_REQUIRE(didCallbackFire()); BOOST_CHECK(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID)); @@ -279,26 +303,45 @@ BOOST_AUTO_TEST_CASE(NextHopFaceIdUnsupportedVerb) shared_ptr dummy = make_shared(); addFace(dummy); - shared_ptr face(make_shared()); - - LocalControlHeaderManager manager(bind(&LocalControlHeaderManagerFixture::getFace, this, _1), - face); - Name commandName("/localhost/nfd/control-header/nexthop-faceid/madeup"); + shared_ptr command(make_shared(commandName)); + command->setIncomingFaceId(1); - face->onReceiveData += + generateCommand(*command); + + getInternalFace()->onReceiveData += bind(&LocalControlHeaderManagerFixture::validateControlResponse, this, _1, - commandName, 501, "Unsupported"); + command->getName(), 501, "Unsupported"); - Interest command(commandName); - command.setIncomingFaceId(1); - manager.onLocalControlHeaderRequest(command); + getManager().onLocalControlHeaderRequest(*command); BOOST_REQUIRE(didCallbackFire()); BOOST_CHECK(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID)); BOOST_CHECK(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID)); } +BOOST_FIXTURE_TEST_CASE(UnauthorizedCommand, + UnauthorizedCommandFixture) +{ + shared_ptr dummy = make_shared(); + addFace(dummy); + + Name enable("/localhost/nfd/control-header/in-faceid/enable"); + shared_ptr enableCommand(make_shared(enable)); + enableCommand->setIncomingFaceId(1); + + generateCommand(*enableCommand); + + getInternalFace()->onReceiveData += + bind(&LocalControlHeaderManagerFixture::validateControlResponse, this, _1, + enableCommand->getName(), 403, "Unauthorized command"); + + getManager().onLocalControlHeaderRequest(*enableCommand); + + BOOST_REQUIRE(didCallbackFire()); + BOOST_REQUIRE(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID)); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace tests diff --git a/tests/mgmt/malformedkey.pub b/tests/mgmt/malformedkey.pub new file mode 100644 index 00000000..38b2fbbb --- /dev/null +++ b/tests/mgmt/malformedkey.pub @@ -0,0 +1 @@ +definitely not a key \ No newline at end of file diff --git a/tests/mgmt/manager-base.cpp b/tests/mgmt/manager-base.cpp index f6ddcb77..fb109731 100644 --- a/tests/mgmt/manager-base.cpp +++ b/tests/mgmt/manager-base.cpp @@ -20,7 +20,7 @@ class ManagerBaseTest : public ManagerBase, protected BaseFixture public: ManagerBaseTest() - : ManagerBase(make_shared()), + : ManagerBase(make_shared(), "TEST-PRIVILEGE"), m_callbackFired(false) { diff --git a/tests/mgmt/strategy-choice-manager.cpp b/tests/mgmt/strategy-choice-manager.cpp index e2285c27..dd3291bc 100644 --- a/tests/mgmt/strategy-choice-manager.cpp +++ b/tests/mgmt/strategy-choice-manager.cpp @@ -15,6 +15,7 @@ #include "tests/test-common.hpp" +#include "validation-common.hpp" namespace nfd { namespace tests { @@ -90,6 +91,12 @@ public: } + virtual + ~StrategyChoiceManagerFixture() + { + + } + void validateControlResponseCommon(const Data& response, const Name& expectedName, @@ -177,6 +184,13 @@ public: return m_strategyChoice; } + void + addInterestRule(const std::string& regex, + ndn::IdentityCertificate& certificate) + { + m_manager.addInterestRule(regex, certificate); + } + protected: Forwarder m_forwarder; NameTree m_nameTree; @@ -203,9 +217,26 @@ public: } }; -BOOST_FIXTURE_TEST_SUITE(MgmtStrategyChoiceManager, AllStrategiesFixture) +template class AuthorizedCommandFixture : public CommandFixture +{ +public: + AuthorizedCommandFixture() + { + const std::string regex = "^"; + T::addInterestRule(regex, *CommandFixture::m_certificate); + } -BOOST_AUTO_TEST_CASE(TestFireInterestFilter) + virtual + ~AuthorizedCommandFixture() + { + + } +}; + +BOOST_FIXTURE_TEST_SUITE(MgmtStrategyChoiceManager, + AuthorizedCommandFixture) + +BOOST_FIXTURE_TEST_CASE(TestFireInterestFilter, AllStrategiesFixture) { shared_ptr command(make_shared("/localhost/nfd/strategy-choice")); @@ -218,7 +249,7 @@ BOOST_AUTO_TEST_CASE(TestFireInterestFilter) BOOST_REQUIRE(didCallbackFire()); } -BOOST_AUTO_TEST_CASE(MalformedCommmand) +BOOST_FIXTURE_TEST_CASE(MalformedCommmand, AllStrategiesFixture) { shared_ptr command(make_shared("/localhost/nfd/strategy-choice")); @@ -231,6 +262,54 @@ BOOST_AUTO_TEST_CASE(MalformedCommmand) BOOST_REQUIRE(didCallbackFire()); } +BOOST_FIXTURE_TEST_CASE(UnsignedCommand, AllStrategiesFixture) +{ + ndn::nfd::FibManagementOptions options; + options.setName("/test"); + options.setStrategy("/localhost/nfd/strategy/best-route"); + + Block encodedOptions(options.wireEncode()); + + Name commandName("/localhost/nfd/strategy-choice"); + commandName.append("set"); + commandName.append(encodedOptions); + + shared_ptr command(make_shared(commandName)); + + getFace()->onReceiveData += + bind(&StrategyChoiceManagerFixture::validateControlResponse, this, _1, + command->getName(), 401, "Signature required"); + + getManager().onStrategyChoiceRequest(*command); + + BOOST_REQUIRE(didCallbackFire()); +} + +BOOST_FIXTURE_TEST_CASE(UnauthorizedCommand, + UnauthorizedCommandFixture) +{ + ndn::nfd::FibManagementOptions options; + options.setName("/test"); + options.setStrategy("/localhost/nfd/strategy/best-route"); + + Block encodedOptions(options.wireEncode()); + + Name commandName("/localhost/nfd/strategy-choice"); + commandName.append("set"); + commandName.append(encodedOptions); + + shared_ptr command(make_shared(commandName)); + generateCommand(*command); + + getFace()->onReceiveData += + bind(&StrategyChoiceManagerFixture::validateControlResponse, this, _1, + command->getName(), 403, "Unauthorized command"); + + getManager().onStrategyChoiceRequest(*command); + + BOOST_REQUIRE(didCallbackFire()); +} + BOOST_AUTO_TEST_CASE(UnsupportedVerb) { ndn::nfd::FibManagementOptions options; @@ -243,6 +322,7 @@ BOOST_AUTO_TEST_CASE(UnsupportedVerb) commandName.append(encodedOptions); shared_ptr command(make_shared(commandName)); + generateCommand(*command); getFace()->onReceiveData += bind(&StrategyChoiceManagerFixture::validateControlResponse, this, _1, @@ -260,6 +340,7 @@ BOOST_AUTO_TEST_CASE(BadOptionParse) commandName.append("NotReallyOptions"); shared_ptr command(make_shared(commandName)); + generateCommand(*command); getFace()->onReceiveData += bind(&StrategyChoiceManagerFixture::validateControlResponse, this, _1, @@ -311,6 +392,7 @@ BOOST_AUTO_TEST_CASE(SetUnsupportedStrategy) commandName.append(encodedOptions); shared_ptr command(make_shared(commandName)); + generateCommand(*command); getFace()->onReceiveData += bind(&StrategyChoiceManagerFixture::validateControlResponse, this, _1, @@ -355,6 +437,7 @@ public: // commandName.append(encodedOptions); // shared_ptr command(make_shared(commandName)); +// generateCommand(*command); // getFace()->onReceiveData += // bind(&StrategyChoiceManagerFixture::validateControlResponse, this, _1, @@ -383,6 +466,7 @@ BOOST_AUTO_TEST_CASE(Unset) commandName.append(encodedOptions); shared_ptr command(make_shared(commandName)); + generateCommand(*command); getFace()->onReceiveData += bind(&StrategyChoiceManagerFixture::validateControlResponse, this, _1, @@ -408,6 +492,7 @@ BOOST_AUTO_TEST_CASE(UnsetRoot) commandName.append(encodedOptions); shared_ptr command(make_shared(commandName)); + generateCommand(*command); getFace()->onReceiveData += bind(&StrategyChoiceManagerFixture::validateControlResponse, this, _1, diff --git a/tests/mgmt/validation-common.hpp b/tests/mgmt/validation-common.hpp new file mode 100644 index 00000000..8e16103e --- /dev/null +++ b/tests/mgmt/validation-common.hpp @@ -0,0 +1,88 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (C) 2014 Named Data Networking Project + * See COPYING for copyright and distribution information. + */ + +#ifndef VALIDATION_COMMON_HPP +#define VALIDATION_COMMON_HPP + +#include + +namespace nfd { +namespace tests { + +// class ValidatedManagementFixture +// { +// public: +// ValidatedManagementFixture() +// : m_validator(make_shared()) +// { +// } + +// virtual +// ~ValidatedManagementFixture() +// { +// } + +// protected: +// shared_ptr m_validator; +// }; + + +template +class CommandFixture : public T +{ +public: + virtual + ~CommandFixture() + { + m_keys.deleteIdentity(m_identityName); + + } + + void + generateCommand(Interest& interest) + { + m_generator.generateWithIdentity(interest, m_identityName); + } + + const Name& + getIdentityName() const + { + return m_identityName; + } + +protected: + CommandFixture() + : m_identityName("/unit-test/CommandFixture/id"), + m_certificate(m_keys.getCertificate(m_keys.createIdentity(m_identityName))) + { + + } + +protected: + ndn::KeyChain m_keys; + const Name m_identityName; + shared_ptr m_certificate; + ndn::CommandInterestGenerator m_generator; +}; + +template +class UnauthorizedCommandFixture : public CommandFixture +{ +public: + UnauthorizedCommandFixture() + { + } + + virtual + ~UnauthorizedCommandFixture() + { + } +}; + +} //namespace tests +} // namespace nfd + +#endif // VALIDATION_COMMON_HPP diff --git a/wscript b/wscript index 7d654ab9..dbdff3ec 100644 --- a/wscript +++ b/wscript @@ -5,7 +5,7 @@ from waflib import Build, Logs, Utils, Task, TaskGen, Configure import os def options(opt): - opt.load('compiler_cxx') + opt.load('compiler_cxx gnu_dirs') opt.load('boost doxygen coverage unix-socket', tooldir=['.waf-tools']) nfdopt = opt.add_option_group('NFD Options') @@ -15,7 +15,7 @@ def options(opt): help='''Use NDN-CPP library from the specified path''') def configure(conf): - conf.load("compiler_cxx boost") + conf.load("compiler_cxx boost gnu_dirs") try: conf.load("doxygen") except: @@ -67,6 +67,8 @@ def configure(conf): conf.load('coverage') + conf.define('DEFAULT_CONFIG_FILE', '%s/nfd/nfd.conf' % conf.env['SYSCONFDIR']) + conf.write_config_header('daemon/config.hpp') def build(bld):