split configuration into pieces
Change-Id: I3039a3e15d9637e05b0f9678a7141258fb49e983
diff --git a/src/detail/ca-configuration.cpp b/src/detail/ca-configuration.cpp
new file mode 100644
index 0000000..b88352b
--- /dev/null
+++ b/src/detail/ca-configuration.cpp
@@ -0,0 +1,82 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert 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.
+ *
+ * ndncert 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 copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#include "detail/ca-configuration.hpp"
+#include "identity-challenge/challenge-module.hpp"
+#include "name-assignment/assignment-func.hpp"
+#include <ndn-cxx/util/io.hpp>
+#include <boost/filesystem.hpp>
+
+namespace ndn {
+namespace ndncert {
+namespace ca {
+
+void
+CaConfig::load(const std::string& fileName)
+{
+ JsonSection configJson;
+ try {
+ boost::property_tree::read_json(fileName, configJson);
+ }
+ catch (const std::exception& error) {
+ NDN_THROW(std::runtime_error("Failed to parse configuration file " + fileName + ", " + error.what()));
+ }
+ if (configJson.begin() == configJson.end()) {
+ NDN_THROW(std::runtime_error("No JSON configuration found in file: " + fileName));
+ }
+ m_caItem.parse(configJson);
+ if (m_caItem.m_supportedChallenges.size() == 0) {
+ NDN_THROW(std::runtime_error("At least one challenge should be specified."));
+ }
+ // parse redirection section if appears
+ m_redirection = nullopt;
+ auto redirectionItems = configJson.get_child_optional(CONFIG_REDIRECTION);
+ if (redirectionItems) {
+ for (const auto& item : *redirectionItems) {
+ auto caPrefixStr = item.second.get(CONFIG_CA_PREFIX, "");
+ auto caCertStr = item.second.get(CONFIG_CERTIFICATE, "");
+ if (caCertStr == "") {
+ NDN_THROW(std::runtime_error("Redirect-to item's ca-prefix or certificate cannot be empty."));
+ }
+ std::istringstream ss(caCertStr);
+ auto caCert = io::load<security::Certificate>(ss);
+ if (!m_redirection) {
+ m_redirection = std::vector<std::shared_ptr<security::Certificate>>();
+ }
+ m_redirection->push_back(caCert);
+ }
+ }
+ // parse name assignment if appears
+ m_nameAssignmentFuncs.clear();
+ auto nameAssignmentItems = configJson.get_child_optional(CONFIG_NAME_ASSIGNMENT);
+ if (nameAssignmentItems) {
+ for (const auto& item : *nameAssignmentItems) {
+ auto func = NameAssignmentFunc::createNameAssignmentFunc(item.first, item.second.data());
+ if (func == nullptr) {
+ NDN_THROW(std::runtime_error("Error on creating name assignment function"));
+ }
+ m_nameAssignmentFuncs.push_back(std::move(func));
+ }
+ }
+}
+
+} // namespace ca
+} // namespace ndncert
+} // namespace ndn
diff --git a/src/detail/ca-configuration.hpp b/src/detail/ca-configuration.hpp
new file mode 100644
index 0000000..da170b9
--- /dev/null
+++ b/src/detail/ca-configuration.hpp
@@ -0,0 +1,79 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert 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.
+ *
+ * ndncert 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 copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#ifndef NDNCERT_DETAIL_CA_CONFIGURATION_HPP
+#define NDNCERT_DETAIL_CA_CONFIGURATION_HPP
+
+#include "detail/ca-profile.hpp"
+
+namespace ndn {
+namespace ndncert {
+namespace ca {
+
+/**
+ * @brief CA's configuration on NDNCERT.
+ * @sa https://github.com/named-data/ndncert/wiki/NDNCERT-Protocol-0.3
+ *
+ * The format of CA configuration in JSON
+ * {
+ * "ca-prefix": "",
+ * "ca-info": "",
+ * "max-validity-period": "",
+ * "max-suffix-length": "",
+ * "probe-parameters":
+ * [
+ * {"probe-parameter-key": ""},
+ * {"probe-parameter-key": ""}
+ * ]
+ * "supported-challenges":
+ * [
+ * {"challenge": ""},
+ * {"challenge": ""}
+ * ]
+ * }
+ */
+class CaConfig
+{
+public:
+ /**
+ * Load CA configuration from the file.
+ * @throw std::runtime_error when config file cannot be correctly parsed.
+ */
+ void
+ load(const std::string& fileName);
+
+public:
+ CaProfile m_caItem;
+ /**
+ * Used for CA redirection
+ * @sa https://github.com/named-data/ndncert/wiki/NDNCERT-Protocol-0.3-PROBE-Extensions#probe-extension-for-redirection
+ */
+ optional<std::vector<std::shared_ptr<security::Certificate>>> m_redirection = nullopt;
+ /**
+ * Name Assignment Functions
+ */
+ std::vector<std::unique_ptr<NameAssignmentFunc>> m_nameAssignmentFuncs;
+};
+
+} // namespace ca
+} // namespace ndncert
+} // namespace ndn
+
+#endif // NDNCERT_DETAIL_CA_CONFIGURATION_HPP
diff --git a/src/detail/ca-profile.cpp b/src/detail/ca-profile.cpp
new file mode 100644
index 0000000..4599e06
--- /dev/null
+++ b/src/detail/ca-profile.cpp
@@ -0,0 +1,123 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert 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.
+ *
+ * ndncert 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 copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#include "detail/ca-profile.hpp"
+#include "identity-challenge/challenge-module.hpp"
+#include "name-assignment/assignment-func.hpp"
+#include <ndn-cxx/util/io.hpp>
+#include <boost/filesystem.hpp>
+
+namespace ndn {
+namespace ndncert {
+
+void
+CaProfile::parse(const JsonSection& configJson)
+{
+ // CA prefix
+ m_caPrefix = Name(configJson.get(CONFIG_CA_PREFIX, ""));
+ if (m_caPrefix.empty()) {
+ NDN_THROW(std::runtime_error("Cannot parse ca-prefix from the config file"));
+ }
+ // CA info
+ m_caInfo = configJson.get(CONFIG_CA_INFO, "");
+ // CA max validity period
+ m_maxValidityPeriod = time::seconds(configJson.get(CONFIG_MAX_VALIDITY_PERIOD, 86400));
+ // CA max suffix length
+ m_maxSuffixLength = nullopt;
+ auto maxSuffixLength = configJson.get_optional<size_t>(CONFIG_MAX_SUFFIX_LENGTH);
+ if (maxSuffixLength) {
+ m_maxSuffixLength = *maxSuffixLength;
+ }
+ // probe parameter keys
+ m_probeParameterKeys.clear();
+ auto probeParametersJson = configJson.get_child_optional(CONFIG_PROBE_PARAMETERS);
+ if (probeParametersJson) {
+ for (const auto& item : *probeParametersJson) {
+ auto probeParameter = item.second.get(CONFIG_PROBE_PARAMETER, "");
+ probeParameter = boost::algorithm::to_lower_copy(probeParameter);
+ if (probeParameter == "") {
+ NDN_THROW(std::runtime_error("Probe parameter key cannot be empty."));
+ }
+ m_probeParameterKeys.push_back(probeParameter);
+ }
+ }
+ // supported challenges
+ m_supportedChallenges.clear();
+ auto challengeListJson = configJson.get_child_optional(CONFIG_SUPPORTED_CHALLENGES);
+ if (challengeListJson) {
+ for (const auto& item : *challengeListJson) {
+ auto challengeType = item.second.get(CONFIG_CHALLENGE, "");
+ challengeType = boost::algorithm::to_lower_copy(challengeType);
+ if (challengeType == "") {
+ NDN_THROW(std::runtime_error("Challenge type canont be empty."));
+ }
+ if (!ChallengeModule::isChallengeSupported(challengeType)) {
+ NDN_THROW(std::runtime_error("Challenge " + challengeType + " is not supported."));
+ }
+ m_supportedChallenges.push_back(challengeType);
+ }
+ }
+ // anchor certificate
+ m_cert = nullptr;
+ auto certificateStr = configJson.get(CONFIG_CERTIFICATE, "");
+ if (certificateStr != "") {
+ std::istringstream ss(certificateStr);
+ m_cert = io::load<security::Certificate>(ss);
+ }
+}
+
+JsonSection
+CaProfile::toJson() const
+{
+ JsonSection caItem;
+ caItem.put(CONFIG_CA_PREFIX, m_caPrefix.toUri());
+ caItem.put(CONFIG_CA_INFO, m_caInfo);
+ caItem.put(CONFIG_MAX_VALIDITY_PERIOD, m_maxValidityPeriod.count());
+ if (m_maxSuffixLength) {
+ caItem.put(CONFIG_MAX_SUFFIX_LENGTH, *m_maxSuffixLength);
+ }
+ if (!m_probeParameterKeys.empty()) {
+ JsonSection probeParametersJson;
+ for (const auto& key : m_probeParameterKeys) {
+ JsonSection keyJson;
+ keyJson.put(CONFIG_PROBE_PARAMETER, key);
+ probeParametersJson.push_back(std::make_pair("", keyJson));
+ }
+ caItem.add_child("", probeParametersJson);
+ }
+ if (!m_supportedChallenges.empty()) {
+ JsonSection challengeListJson;
+ for (const auto& challenge : m_supportedChallenges) {
+ JsonSection challengeJson;
+ challengeJson.put(CONFIG_CHALLENGE, challenge);
+ challengeListJson.push_back(std::make_pair("", challengeJson));
+ }
+ caItem.add_child("", challengeListJson);
+ }
+ if (m_cert != nullptr) {
+ std::stringstream ss;
+ io::save(*m_cert, ss);
+ caItem.put("certificate", ss.str());
+ }
+ return caItem;
+}
+
+} // namespace ndncert
+} // namespace ndn
diff --git a/src/detail/ca-profile.hpp b/src/detail/ca-profile.hpp
new file mode 100644
index 0000000..c67f5dc
--- /dev/null
+++ b/src/detail/ca-profile.hpp
@@ -0,0 +1,100 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert 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.
+ *
+ * ndncert 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 copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#ifndef NDNCERT_DETAIL_CA_PROFILE_HPP
+#define NDNCERT_DETAIL_CA_PROFILE_HPP
+
+#include "name-assignment/assignment-func.hpp"
+
+namespace ndn {
+namespace ndncert {
+
+// used in parsing CA configuration file and Client CA profile storage file
+const std::string CONFIG_CA_PREFIX = "ca-prefix";
+const std::string CONFIG_CA_INFO = "ca-info";
+const std::string CONFIG_MAX_VALIDITY_PERIOD = "max-validity-period";
+const std::string CONFIG_MAX_SUFFIX_LENGTH = "max-suffix-length";
+const std::string CONFIG_PROBE_PARAMETERS = "probe-parameters";
+const std::string CONFIG_PROBE_PARAMETER = "probe-parameter-key";
+const std::string CONFIG_SUPPORTED_CHALLENGES = "supported-challenges";
+const std::string CONFIG_CHALLENGE = "challenge";
+const std::string CONFIG_CERTIFICATE = "certificate";
+const std::string CONFIG_REDIRECTION = "redirect-to";
+const std::string CONFIG_NAME_ASSIGNMENT = "name-assignment";
+
+struct CaProfile
+{
+public:
+ /**
+ * Parse the configuration json and modify current struct to the result.
+ * @param configJson the configuration json to parse
+ */
+ void
+ parse(const JsonSection& configJson);
+
+ /**
+ * @return the JSON representation of this profile.
+ */
+ JsonSection
+ toJson() const;
+
+public:
+ /**
+ * CA Name prefix (without /CA suffix).
+ */
+ Name m_caPrefix;
+ /**
+ * CA Information.
+ * Default: "".
+ */
+ std::string m_caInfo;
+ /**
+ * A list of parameter-keys for PROBE.
+ * Default: empty list.
+ */
+ std::list<std::string> m_probeParameterKeys;
+ /**
+ * Maximum allowed validity period of the certificate being requested.
+ * The value is in the unit of second.
+ * Default: one day (86400 seconds).
+ */
+ time::seconds m_maxValidityPeriod;
+ /**
+ * Maximum allowed suffix length of requested name.
+ * E.g., When its value is 2, at most 2 name components can be assigned after m_caPrefix.
+ * Default: none.
+ */
+ optional<size_t> m_maxSuffixLength = nullopt;
+ /**
+ * A list of supported challenges. Only CA side will have m_supportedChallenges.
+ * Default: empty list.
+ */
+ std::list<std::string> m_supportedChallenges;
+ /**
+ * CA's certificate. Only Client side will have m_cert.
+ * Default: nullptr.
+ */
+ std::shared_ptr<security::Certificate> m_cert;
+};
+
+} // namespace ndncert
+} // namespace ndn
+
+#endif // NDNCERT_DETAIL_CA_PROFILE_HPP
diff --git a/src/detail/error-encoder.hpp b/src/detail/error-encoder.hpp
index 99d9dd8..67fe80f 100644
--- a/src/detail/error-encoder.hpp
+++ b/src/detail/error-encoder.hpp
@@ -21,7 +21,7 @@
#ifndef NDNCERT_DETAIL_ERROR_ENCODER_HPP
#define NDNCERT_DETAIL_ERROR_ENCODER_HPP
-#include "configuration.hpp"
+#include "detail/ca-profile.hpp"
namespace ndn {
namespace ndncert {
diff --git a/src/detail/info-encoder.hpp b/src/detail/info-encoder.hpp
index 03adfd8..7f9180e 100644
--- a/src/detail/info-encoder.hpp
+++ b/src/detail/info-encoder.hpp
@@ -21,7 +21,7 @@
#ifndef NDNCERT_DETAIL_INFO_ENCODER_HPP
#define NDNCERT_DETAIL_INFO_ENCODER_HPP
-#include "configuration.hpp"
+#include "detail/ca-profile.hpp"
namespace ndn {
namespace ndncert {
diff --git a/src/detail/profile-storage.cpp b/src/detail/profile-storage.cpp
new file mode 100644
index 0000000..f880d1b
--- /dev/null
+++ b/src/detail/profile-storage.cpp
@@ -0,0 +1,103 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert 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.
+ *
+ * ndncert 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 copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#include "detail/profile-storage.hpp"
+#include "identity-challenge/challenge-module.hpp"
+#include "name-assignment/assignment-func.hpp"
+#include <ndn-cxx/util/io.hpp>
+#include <boost/filesystem.hpp>
+
+namespace ndn {
+namespace ndncert {
+namespace requester {
+
+void
+ProfileStorage::load(const std::string& fileName)
+{
+ JsonSection configJson;
+ try {
+ boost::property_tree::read_json(fileName, configJson);
+ }
+ catch (const std::exception& error) {
+ NDN_THROW(std::runtime_error("Failed to parse configuration file " + fileName + ", " + error.what()));
+ }
+ if (configJson.begin() == configJson.end()) {
+ NDN_THROW(std::runtime_error("No JSON configuration found in file: " + fileName));
+ }
+ load(configJson);
+}
+
+void
+ProfileStorage::load(const JsonSection& configSection)
+{
+ m_caItems.clear();
+ auto caList = configSection.get_child("ca-list");
+ for (auto item : caList) {
+ CaProfile caItem;
+ caItem.parse(item.second);
+ if (caItem.m_cert == nullptr) {
+ NDN_THROW(std::runtime_error("No CA certificate is loaded from JSON configuration."));
+ }
+ m_caItems.push_back(std::move(caItem));
+ }
+}
+
+void
+ProfileStorage::save(const std::string& fileName) const
+{
+ JsonSection configJson;
+ for (const auto& caItem : m_caItems) {
+ configJson.push_back(std::make_pair("", caItem.toJson()));
+ }
+ std::stringstream ss;
+ boost::property_tree::write_json(ss, configJson);
+ std::ofstream configFile;
+ configFile.open(fileName);
+ configFile << ss.str();
+ configFile.close();
+}
+
+void
+ProfileStorage::removeCaProfile(const Name& caName)
+{
+ m_caItems.remove_if([&](const CaProfile& item) { return item.m_caPrefix == caName; });
+}
+
+void
+ProfileStorage::addCaProfile(const CaProfile& profile)
+{
+ for (auto& item : m_caItems) {
+ if (item.m_caPrefix == profile.m_caPrefix) {
+ item = profile;
+ return;
+ }
+ }
+ m_caItems.push_back(profile);
+}
+
+const std::list<CaProfile>&
+ProfileStorage::getCaItems() const
+{
+ return m_caItems;
+}
+
+} // namespace requester
+} // namespace ndncert
+} // namespace ndn
diff --git a/src/detail/profile-storage.hpp b/src/detail/profile-storage.hpp
new file mode 100644
index 0000000..0f8d1ce
--- /dev/null
+++ b/src/detail/profile-storage.hpp
@@ -0,0 +1,73 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert 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.
+ *
+ * ndncert 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 copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#ifndef NDNCERT_CONFIGURATION_HPP
+#define NDNCERT_CONFIGURATION_HPP
+
+#include "detail/ca-profile.hpp"
+#include "name-assignment/assignment-func.hpp"
+
+namespace ndn {
+namespace ndncert {
+namespace requester {
+
+/**
+ * @brief Represents Client configuration
+ * @sa https://github.com/named-data/ndncert/wiki/Client-Configuration-Sample
+ */
+class ProfileStorage
+{
+public:
+ /**
+ * @throw std::runtime_error when config file cannot be correctly parsed.
+ */
+ void
+ load(const std::string& fileName);
+
+ /**
+ * @throw std::runtime_error when config file cannot be correctly parsed.
+ */
+ void
+ load(const JsonSection& configSection);
+
+ void
+ save(const std::string& fileName) const;
+
+ void
+ removeCaProfile(const Name& caName);
+
+ /**
+ * Be cautious. This will add a new trust anchor for requesters.
+ */
+ void
+ addCaProfile(const CaProfile& profile);
+
+ const std::list<CaProfile>&
+ getCaItems() const;
+
+private:
+ std::list<CaProfile> m_caItems;
+};
+
+} // namespace requester
+} // namespace ndncert
+} // namespace ndn
+
+#endif // NDNCERT_CONFIGURATION_HPP