security: Allow reloading ValidationPolicyConfig / ValidatorConfig

Change-Id: Idba53c0b4e2cf645d3d0e6c76c57a1b54995462a
Refs: #4261
diff --git a/src/security/v2/certificate-cache.cpp b/src/security/v2/certificate-cache.cpp
index b9d15aa..be2b084 100644
--- a/src/security/v2/certificate-cache.cpp
+++ b/src/security/v2/certificate-cache.cpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -58,6 +58,12 @@
   m_certs.insert(Entry(cert, removalTime));
 }
 
+void
+CertificateCache::clear()
+{
+  m_certs.clear();
+}
+
 const Certificate*
 CertificateCache::find(const Name& certPrefix) const
 {
diff --git a/src/security/v2/certificate-cache.hpp b/src/security/v2/certificate-cache.hpp
index f649776..a5109a8 100644
--- a/src/security/v2/certificate-cache.hpp
+++ b/src/security/v2/certificate-cache.hpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -63,6 +63,12 @@
   insert(const Certificate& cert);
 
   /**
+   * @brief Remove all certificates from cache
+   */
+  void
+  clear();
+
+  /**
    * @brief Get certificate given key name
    * @param certPrefix  Certificate prefix for searching the certificate.
    * @return The found certificate, nullptr if not found.
diff --git a/src/security/v2/certificate-storage.cpp b/src/security/v2/certificate-storage.cpp
index 89869fa..d1638d9 100644
--- a/src/security/v2/certificate-storage.cpp
+++ b/src/security/v2/certificate-storage.cpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -65,12 +65,24 @@
 }
 
 void
+CertificateStorage::resetAnchors()
+{
+  m_trustAnchors.clear();
+}
+
+void
 CertificateStorage::cacheVerifiedCert(Certificate&& cert)
 {
   m_verifiedCertCache.insert(std::move(cert));
 }
 
 void
+CertificateStorage::resetVerifiedCerts()
+{
+  m_verifiedCertCache.clear();
+}
+
+void
 CertificateStorage::cacheUnverifiedCert(Certificate&& cert)
 {
   m_unverifiedCertCache.insert(std::move(cert));
diff --git a/src/security/v2/certificate-storage.hpp b/src/security/v2/certificate-storage.hpp
index ff54ae2..5f3e608 100644
--- a/src/security/v2/certificate-storage.hpp
+++ b/src/security/v2/certificate-storage.hpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -110,6 +110,12 @@
              time::nanoseconds refreshPeriod, bool isDir = false);
 
   /**
+   * @brief remove any previously loaded static or dynamic trust anchor
+   */
+  void
+  resetAnchors();
+
+  /**
    * @brief Cache verified certificate a period of time (1 hour)
    * @param cert  The certificate packet
    *
@@ -118,6 +124,12 @@
   void
   cacheVerifiedCert(Certificate&& cert);
 
+  /**
+   * @brief Remove any cached verified certificates
+   */
+  void
+  resetVerifiedCerts();
+
 protected:
   TrustAnchorContainer m_trustAnchors;
   CertificateCache m_verifiedCertCache;
diff --git a/src/security/v2/trust-anchor-container.cpp b/src/security/v2/trust-anchor-container.cpp
index efb272f..80ef5cc 100644
--- a/src/security/v2/trust-anchor-container.cpp
+++ b/src/security/v2/trust-anchor-container.cpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -40,6 +40,12 @@
 }
 
 void
+TrustAnchorContainer::AnchorContainer::clear()
+{
+  AnchorContainerBase::clear();
+}
+
+void
 TrustAnchorContainer::insert(const std::string& groupId, Certificate&& cert)
 {
   auto group = m_groups.find(groupId);
@@ -64,6 +70,13 @@
   m_groups.insert(make_shared<DynamicTrustAnchorGroup>(m_anchors, groupId, path, refreshPeriod, isDir));
 }
 
+void
+TrustAnchorContainer::clear()
+{
+  m_groups.clear();
+  m_anchors.clear();
+}
+
 const Certificate*
 TrustAnchorContainer::find(const Name& keyName) const
 {
diff --git a/src/security/v2/trust-anchor-container.hpp b/src/security/v2/trust-anchor-container.hpp
index 49e4999..f935571 100644
--- a/src/security/v2/trust-anchor-container.hpp
+++ b/src/security/v2/trust-anchor-container.hpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -96,6 +96,12 @@
          time::nanoseconds refreshPeriod, bool isDir = false);
 
   /**
+   * @brief Remove all static or dynamic anchors
+   */
+  void
+  clear();
+
+  /**
    * @brief Search for certificate across all groups (longest prefix match)
    * @param keyName  Key name prefix for searching the certificate.
    * @return The found certificate, nullptr if not found.
@@ -155,6 +161,9 @@
 
     void
     remove(const Name& certName) final;
+
+    void
+    clear();
   };
 
   using GroupContainer = boost::multi_index::multi_index_container<
diff --git a/src/security/v2/validation-policy-config.cpp b/src/security/v2/validation-policy-config.cpp
index ba87a23..c41a47f 100644
--- a/src/security/v2/validation-policy-config.cpp
+++ b/src/security/v2/validation-policy-config.cpp
@@ -83,7 +83,12 @@
                              const std::string& filename)
 {
   if (m_isConfigured) {
-    BOOST_THROW_EXCEPTION(std::logic_error("ValidationPolicyConfig can be configured only once"));
+    m_shouldBypass = false;
+    m_dataRules.clear();
+    m_interestRules.clear();
+
+    m_validator->resetAnchors();
+    m_validator->resetVerifiedCertificates();
   }
   m_isConfigured = true;
 
diff --git a/src/security/v2/validator.cpp b/src/security/v2/validator.cpp
index 638d12d..aa651b1 100644
--- a/src/security/v2/validator.cpp
+++ b/src/security/v2/validator.cpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -195,11 +195,23 @@
 }
 
 void
+Validator::resetAnchors()
+{
+  CertificateStorage::resetAnchors();
+}
+
+void
 Validator::cacheVerifiedCertificate(Certificate&& cert)
 {
   CertificateStorage::cacheVerifiedCert(std::move(cert));
 }
 
+void
+Validator::resetVerifiedCertificates()
+{
+  CertificateStorage::resetVerifiedCerts();
+}
+
 } // namespace v2
 } // namespace security
 } // namespace ndn
diff --git a/src/security/v2/validator.hpp b/src/security/v2/validator.hpp
index 6dfe8a8..14e9c7f 100644
--- a/src/security/v2/validator.hpp
+++ b/src/security/v2/validator.hpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -137,6 +137,12 @@
              time::nanoseconds refreshPeriod, bool isDir = false);
 
   /**
+   * @brief remove any previously loaded static or dynamic trust anchor
+   */
+  void
+  resetAnchors();
+
+  /**
    * @brief Cache verified @p cert a period of time (1 hour)
    *
    * @todo Add ability to customize time period
@@ -144,6 +150,12 @@
   void
   cacheVerifiedCertificate(Certificate&& cert);
 
+  /**
+   * @brief Remove any cached verified certificates
+   */
+  void
+  resetVerifiedCertificates();
+
 private: // Common validator operations
   /**
    * @brief Recursive validation of the certificate in the certification chain
diff --git a/tests/unit-tests/security/v2/validation-policy-config.t.cpp b/tests/unit-tests/security/v2/validation-policy-config.t.cpp
index 308b0fe..7808700 100644
--- a/tests/unit-tests/security/v2/validation-policy-config.t.cpp
+++ b/tests/unit-tests/security/v2/validation-policy-config.t.cpp
@@ -377,6 +377,66 @@
   VALIDATE_FAILURE(packet, "Should fail, because subSelfSignedIdentity is not a trust anchor");
 }
 
+BOOST_FIXTURE_TEST_CASE(Reload, HierarchicalValidatorFixture<ValidationPolicyConfig>)
+{
+  BOOST_CHECK_EQUAL(this->policy.m_isConfigured, false);
+  this->policy.load(R"CONF(
+      rule
+      {
+        id test-rule-data-id
+        for data
+        filter
+        {
+          type name
+          name /foo/bar
+          relation is-prefix-of
+        }
+        checker
+        {
+          type hierarchical
+          sig-type rsa-sha256
+        }
+      }
+      rule
+      {
+        id test-rule-interest-id
+        for interest
+        filter
+        {
+          type name
+          name /foo/bar
+          relation is-prefix-of
+        }
+        checker
+        {
+          type hierarchical
+          sig-type rsa-sha256
+        }
+      }
+      trust-anchor
+      {
+        type dir
+        dir keys
+        refresh 1h
+      }
+    )CONF", "test-config");
+  BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true);
+  BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, false);
+  BOOST_CHECK_EQUAL(this->policy.m_dataRules.size(), 1);
+  BOOST_CHECK_EQUAL(this->policy.m_interestRules.size(), 1);
+
+  this->policy.load(R"CONF(
+      trust-anchor
+      {
+        type any
+      }
+    )CONF", "test-config");
+  BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true);
+  BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, true);
+  BOOST_CHECK_EQUAL(this->policy.m_dataRules.size(), 0);
+  BOOST_CHECK_EQUAL(this->policy.m_interestRules.size(), 0);
+}
+
 using Packets = boost::mpl::vector<Interest, Data>;
 
 BOOST_FIXTURE_TEST_CASE_TEMPLATE(TrustAnchorWildcard, Packet, Packets, ValidationPolicyConfigFixture<Packet>)
@@ -419,22 +479,22 @@
   VALIDATE_SUCCESS(packet, "Policy should accept everything");
 }
 
-using ReloadedPolicies = boost::mpl::vector<Refresh1h, Refresh1m, Refresh1s>;
+using RefreshPolicies = boost::mpl::vector<Refresh1h, Refresh1m, Refresh1s>;
 
 // Somehow, didn't work without this wrapper
-template<typename ReloadPolicy>
-class ReloadPolicyFixture : public LoadStringWithDirAnchor<Data, ReloadPolicy>
+template<typename RefreshPolicy>
+class RefreshPolicyFixture : public LoadStringWithDirAnchor<Data, RefreshPolicy>
 {
 public:
 };
 
-BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateReload, Reload, ReloadedPolicies, ReloadPolicyFixture<Reload>)
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateRefresh, Refresh, RefreshPolicies, RefreshPolicyFixture<Refresh>)
 {
   using Packet = Data;
   Packet unsignedPacket("/Security/V2/ValidatorFixture/Sub1/Sub2/Packet");
 
   boost::filesystem::remove(this->path / "keys" / "identity.ndncert");
-  this->advanceClocks(Reload::getRefreshTime(), 3);
+  this->advanceClocks(Refresh::getRefreshTime(), 3);
 
   Packet packet = unsignedPacket;
   this->m_keyChain.sign(packet, signingByIdentity(this->identity));
diff --git a/tests/unit-tests/security/v2/validator.t.cpp b/tests/unit-tests/security/v2/validator.t.cpp
index 42bcf2a..bb545e1 100644
--- a/tests/unit-tests/security/v2/validator.t.cpp
+++ b/tests/unit-tests/security/v2/validator.t.cpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -100,7 +100,6 @@
   BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
 }
 
-
 BOOST_AUTO_TEST_CASE(ExpiredCert)
 {
   Data expiredCert = subIdentity.getDefaultKey().getDefaultCertificate();
@@ -127,6 +126,15 @@
   BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
 }
 
+BOOST_AUTO_TEST_CASE(ResetAnchors)
+{
+  validator.resetAnchors();
+
+  Data data("/Security/V2/ValidatorFixture/Sub1/Sub2/Data");
+  m_keyChain.sign(data, signingByIdentity(subIdentity));
+  VALIDATE_FAILURE(data, "Should fail, as no anchors configured");
+}
+
 BOOST_AUTO_TEST_CASE(TrustedCertCaching)
 {
   Data data("/Security/V2/ValidatorFixture/Sub1/Sub2/Data");
@@ -149,6 +157,21 @@
   face.sentInterests.clear();
 }
 
+BOOST_AUTO_TEST_CASE(ResetVerifiedCertificates)
+{
+  Data data("/Security/V2/ValidatorFixture/Sub1/Sub2/Data");
+  m_keyChain.sign(data, signingByIdentity(subIdentity));
+  VALIDATE_SUCCESS(data, "Should get accepted, as signed by the policy-compliant cert");
+
+  // reset anchors
+  validator.resetAnchors();
+  VALIDATE_SUCCESS(data, "Should get accepted, as signed by the cert in trusted cache");
+
+  // reset trusted cache
+  validator.resetVerifiedCertificates();
+  VALIDATE_FAILURE(data, "Should fail, as no trusted cache or anchors");
+}
+
 BOOST_AUTO_TEST_CASE(UntrustedCertCaching)
 {
   Data data("/Security/V2/ValidatorFixture/Sub1/Sub2/Data");
diff --git a/tests/unit-tests/security/validator-config.t.cpp b/tests/unit-tests/security/validator-config.t.cpp
index 37f2cff..7dd65f5 100644
--- a/tests/unit-tests/security/validator-config.t.cpp
+++ b/tests/unit-tests/security/validator-config.t.cpp
@@ -86,14 +86,20 @@
 {
   validator.load(configFile);
   BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true);
-  BOOST_CHECK_THROW(validator.load(configFile), std::logic_error);
+
+  // should reload policy
+  validator.load(configFile);
+  BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true);
 }
 
 BOOST_AUTO_TEST_CASE(FromString)
 {
   validator.load(config, "config-file-from-string");
   BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true);
-  BOOST_CHECK_THROW(validator.load(configFile), std::logic_error);
+
+  // should reload policy
+  validator.load(config, "config-file-from-string");
+  BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true);
 }
 
 BOOST_AUTO_TEST_CASE(FromIstream)
@@ -101,14 +107,21 @@
   std::istringstream is(config);
   validator.load(is, "config-file-from-istream");
   BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true);
-  BOOST_CHECK_THROW(validator.load(configFile), std::logic_error);
+
+  // should reload policy
+  std::istringstream is2(config);
+  validator.load(is2, "config-file-from-istream");
+  BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true);
 }
 
 BOOST_AUTO_TEST_CASE(FromSection)
 {
   validator.load(v2::validator_config::tests::makeSection(config), "config-file-from-section");
   BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true);
-  BOOST_CHECK_THROW(validator.load(configFile), std::logic_error);
+
+  // should reload policy
+  validator.load(v2::validator_config::tests::makeSection(config), "config-file-from-section");
+  BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true);
 }
 
 BOOST_AUTO_TEST_SUITE_END() // Loads