/* -*- 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 . */ #include "command-authenticator.hpp" #include "core/logger.hpp" #include #include #include #include namespace nfd { NFD_LOG_INIT("CommandAuthenticator"); // INFO: configuration change, etc // DEBUG: per authentication request result shared_ptr CommandAuthenticator::create() { return shared_ptr(new CommandAuthenticator()); } CommandAuthenticator::CommandAuthenticator() : m_validator(make_unique()) { } 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("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 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(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 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