security: Add Validator

Change-Id: Ib97bbb1a95f43684f14f02d0e50b1b6b6f93979b
diff --git a/tests/test_data_fetch_and_publish.cc b/tests/test-data-fetch-and-publish.cc
similarity index 100%
rename from tests/test_data_fetch_and_publish.cc
rename to tests/test-data-fetch-and-publish.cc
diff --git a/tests/test_digest.cc b/tests/test-digest.cc
similarity index 100%
rename from tests/test_digest.cc
rename to tests/test-digest.cc
diff --git a/tests/test_interest_table.cc b/tests/test-interest-table.cc
similarity index 100%
rename from tests/test_interest_table.cc
rename to tests/test-interest-table.cc
diff --git a/tests/test_leaf.cc b/tests/test-leaf.cc
similarity index 100%
rename from tests/test_leaf.cc
rename to tests/test-leaf.cc
diff --git a/tests/test_pit.cc b/tests/test-pit.cc
similarity index 100%
rename from tests/test_pit.cc
rename to tests/test-pit.cc
diff --git a/tests/test_scheduler.cc.tmp b/tests/test-scheduler.cc.tmp
similarity index 100%
rename from tests/test_scheduler.cc.tmp
rename to tests/test-scheduler.cc.tmp
diff --git a/tests/test_socket.cc b/tests/test-socket.cc
similarity index 78%
rename from tests/test_socket.cc
rename to tests/test-socket.cc
index 60a87f3..e4791c2 100644
--- a/tests/test_socket.cc
+++ b/tests/test-socket.cc
@@ -29,6 +29,7 @@
 
 #include "sync-logging.h"
 #include "sync-socket.h"
+#include "sync-validator.h"
 #include <ndn-cpp-dev/security/validator-null.hpp>
 
 extern "C" {
@@ -138,21 +139,48 @@
 class TestSet1{
 public:
   TestSet1(ndn::shared_ptr<boost::asio::io_service> ioService)
-    : m_validator(new ndn::ValidatorNull())
-    , m_face1(new ndn::Face(ioService))
+    : m_face1(new ndn::Face(ioService))
     , m_face2(new ndn::Face(ioService))
     , m_face3(new ndn::Face(ioService))
     , m_p1("/irl.cs.ucla.edu")
     , m_p2("/yakshi.org")
     , m_p3("/google.com")
     , m_syncPrefix("/let/us/sync")
-  {}
+  {
+    ndn::KeyChain keyChain;
+    m_name1 = m_p1;
+    m_name1.append(boost::lexical_cast<std::string>(ndn::time::now()));
+    ndn::Name certName1 = keyChain.createIdentity(m_name1);
+    m_id1 = keyChain.getCertificate(certName1);
+
+    m_name2 = m_p2;
+    m_name2.append(boost::lexical_cast<std::string>(ndn::time::now()));
+    ndn::Name certName2 = keyChain.createIdentity(m_name2);
+    m_id2 = keyChain.getCertificate(certName2);
+
+    m_name3 = m_p3;
+    m_name3.append(boost::lexical_cast<std::string>(ndn::time::now()));
+    ndn::Name certName3 = keyChain.createIdentity(m_name3);
+    m_id3 = keyChain.getCertificate(certName3);
+
+    ndn::shared_ptr<ndn::SecRuleRelative> rule = ndn::make_shared<ndn::SecRuleRelative>("^(<>*)<><>$",
+                                                                                        "^(<>*)<><KEY><ksk-.*><ID-CERT>$",
+                                                                                        "==", "\\1", "\\1", true);
+
+    m_v1 = ndn::make_shared<SyncValidator>(m_syncPrefix, *m_id1, m_face1, rule);
+    m_v1->addParticipant(*m_id2);
+    m_v2 = ndn::make_shared<SyncValidator>(m_syncPrefix, *m_id2, m_face2, rule);
+    m_v2->addParticipant(*m_id1);
+    m_v2->addParticipant(*m_id3);
+    m_v3 = ndn::make_shared<SyncValidator>(m_syncPrefix, *m_id3, m_face3, rule);
+    m_v3->addParticipant(*m_id2);
+  }
 
   void
   createSyncSocket1()
   {
     _LOG_DEBUG ("s1");
-    m_s1 = make_shared<SyncSocket>(m_syncPrefix, m_validator, m_face1, 
+    m_s1 = ndn::make_shared<SyncSocket>(m_syncPrefix, m_name1, m_v1, m_face1, 
                                    bind(&TestSocketApp::fetchAll, &m_a1, _1, _2), 
                                    bind(&TestSocketApp::pass, &m_a1, _1));
   }
@@ -161,7 +189,7 @@
   createSyncSocket2()
   {
     _LOG_DEBUG ("s2");
-    m_s2 = make_shared<SyncSocket>(m_syncPrefix, m_validator, m_face2, 
+    m_s2 = ndn::make_shared<SyncSocket>(m_syncPrefix, m_name2, m_v2, m_face2, 
                                    bind(&TestSocketApp::fetchAll, &m_a2, _1, _2), 
                                    bind(&TestSocketApp::pass, &m_a2, _1));
   }
@@ -170,7 +198,7 @@
   createSyncSocket3()
   {
     _LOG_DEBUG ("s3");
-    m_s3 = make_shared<SyncSocket>(m_syncPrefix, m_validator, m_face3, 
+    m_s3 = ndn::make_shared<SyncSocket>(m_syncPrefix, m_name3, m_v3, m_face3, 
                                    bind(&TestSocketApp::fetchAll, &m_a3, _1, _2), 
                                    bind(&TestSocketApp::pass, &m_a3, _1));
   }
@@ -236,12 +264,23 @@
     m_s1.reset();
     m_s2.reset();
     m_s3.reset();
+    m_v1.reset();
+    m_v2.reset();
+    m_v3.reset();
+
+    ndn::KeyChain keyChain;
+    keyChain.deleteIdentity(m_name1);
+    keyChain.deleteIdentity(m_name2);
+    keyChain.deleteIdentity(m_name3);
+
   }
 
 
   TestSocketApp m_a1, m_a2, m_a3;
-  ndn::shared_ptr<ndn::ValidatorNull> m_validator;
+  ndn::shared_ptr<ndn::IdentityCertificate> m_id1, m_id2, m_id3;
+  ndn::shared_ptr<Sync::SyncValidator> m_v1, m_v2, m_v3;
   ndn::shared_ptr<ndn::Face> m_face1, m_face2, m_face3;
+  ndn::Name m_name1, m_name2, m_name3;
   ndn::Name m_p1, m_p2, m_p3;
   ndn::shared_ptr<SyncSocket> m_s1, m_s2, m_s3;
   ndn::Name m_syncPrefix;
@@ -250,19 +289,39 @@
 class TestSet2{
 public:
   TestSet2(ndn::shared_ptr<boost::asio::io_service> ioService)
-    : m_validator(new ndn::ValidatorNull())
-    , m_face1(new ndn::Face(ioService))
+    : m_face1(new ndn::Face(ioService))
     , m_face2(new ndn::Face(ioService))
     , m_p1("/xiaonei.com")
     , m_p2("/mitbbs.com")
     , m_syncPrefix("/this/is/the/prefix")
-  {}
+  {
+    ndn::KeyChain keyChain;
+    m_name1 = m_p1;
+    m_name1.append(boost::lexical_cast<string>(ndn::time::now()));
+    ndn::Name certName1 = keyChain.createIdentity(m_name1);
+    m_id1 = keyChain.getCertificate(certName1);
+
+    m_name2 = m_p2;
+    m_name2.append(boost::lexical_cast<string>(ndn::time::now()));
+    ndn::Name certName2 = keyChain.createIdentity(m_name2);
+    m_id2 = keyChain.getCertificate(certName2);
+
+    ndn::shared_ptr<ndn::SecRuleRelative> rule = ndn::make_shared<ndn::SecRuleRelative>("^(<>*)<><>$",
+                                                                                        "^(<>*)<><KEY><ksk-.*><ID-CERT>$",
+                                                                                        "==", "\\1", "\\1", true);
+
+    m_v1 = ndn::make_shared<SyncValidator>(m_syncPrefix, *m_id1, m_face1, rule);
+    m_v1->addParticipant(*m_id2);
+    m_v2 = ndn::make_shared<SyncValidator>(m_syncPrefix, *m_id2, m_face2, rule);
+    m_v2->addParticipant(*m_id1);
+
+  }
 
   void
   createSyncSocket1()
   {
     _LOG_DEBUG ("s1");
-    m_s1 = make_shared<SyncSocket>(m_syncPrefix, m_validator, m_face1, 
+    m_s1 = ndn::make_shared<SyncSocket>(m_syncPrefix, m_name1, m_v1, m_face1, 
                                    bind(&TestSocketApp::fetchNumbers, &m_a1, _1, _2), 
                                    bind(&TestSocketApp::pass, &m_a1, _1));
   }
@@ -271,7 +330,7 @@
   createSyncSocket2()
   {
     _LOG_DEBUG ("s2");
-    m_s2 = make_shared<SyncSocket>(m_syncPrefix, m_validator, m_face2, 
+    m_s2 = ndn::make_shared<SyncSocket>(m_syncPrefix, m_name2, m_v2, m_face2, 
                                    bind(&TestSocketApp::fetchNumbers, &m_a2, _1, _2), 
                                    bind(&TestSocketApp::pass, &m_a2, _1));
   }
@@ -319,12 +378,20 @@
   {
     m_s1.reset();
     m_s2.reset();
+    m_v1.reset();
+    m_v2.reset();
+
+    ndn::KeyChain keyChain;
+    keyChain.deleteIdentity(m_name1);
+    keyChain.deleteIdentity(m_name2);
   }
 
   TestSocketApp m_a1, m_a2;
-  ndn::shared_ptr<ndn::ValidatorNull> m_validator;
+  ndn::shared_ptr<ndn::IdentityCertificate> m_id1, m_id2;
+  ndn::shared_ptr<Sync::SyncValidator> m_v1, m_v2;
   ndn::shared_ptr<ndn::Face> m_face1, m_face2;
   ndn::Name m_p1, m_p2;
+  ndn::Name m_name1, m_name2;
   ndn::shared_ptr<SyncSocket> m_s1, m_s2;
   ndn::Name m_syncPrefix;
 };
diff --git a/tests/test_state.cc.outdated b/tests/test-state.cc.outdated
similarity index 100%
rename from tests/test_state.cc.outdated
rename to tests/test-state.cc.outdated
diff --git a/tests/test_sync_logic.cc b/tests/test-sync-logic.cc
similarity index 96%
rename from tests/test_sync_logic.cc
rename to tests/test-sync-logic.cc
index d2444e7..76c5fc5 100644
--- a/tests/test_sync_logic.cc
+++ b/tests/test-sync-logic.cc
@@ -101,8 +101,11 @@
   createSyncLogic(int index, 
                   ndn::shared_ptr<Handler> h)
   { 
+    ndn::Name identity("/tmp-" + boost::lexical_cast<std::string>(ndn::time::now()));
+    m_keyChain.createIdentity(identity);
     m_faces[index] = ndn::make_shared<ndn::Face>(m_ioService);
     m_l[index] = new SyncLogic(ndn::Name("/bcast"), 
+                               identity,
                                m_validator, m_faces[index], 
                                bind (&Handler::wrapper, &*h, _1), 
                                bind (&Handler::onRemove, &*h, _1)); 
@@ -140,6 +143,7 @@
 
 
 public:
+  ndn::KeyChain m_keyChain;
   ndn::shared_ptr<boost::asio::io_service> m_ioService;
   SyncLogic* m_l[2];
   ndn::shared_ptr<ndn::Face> m_faces[2];
diff --git a/tests/test-sync-validator.cc b/tests/test-sync-validator.cc
new file mode 100644
index 0000000..ca7078b
--- /dev/null
+++ b/tests/test-sync-validator.cc
@@ -0,0 +1,249 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ */
+
+#include <boost/test/unit_test.hpp>
+#include "sync-validator.h"
+
+BOOST_AUTO_TEST_SUITE(TestSyncValidator)
+
+void onValidated(const ndn::shared_ptr<const ndn::Data>& data)
+{
+  BOOST_CHECK(true);
+}
+
+void onValidationFailed(const ndn::shared_ptr<const ndn::Data>& data,
+			const std::string& failureInfo)
+{
+  BOOST_CHECK(false);
+}
+
+void onValidated2(const ndn::shared_ptr<const ndn::Data>& data)
+{
+  BOOST_CHECK(false);
+}
+
+void onValidationFailed2(const ndn::shared_ptr<const ndn::Data>& data,
+			const std::string& failureInfo)
+{
+  BOOST_CHECK(true);
+}
+
+BOOST_AUTO_TEST_CASE (Graph)
+{
+  using namespace Sync;
+  using namespace ndn;
+
+  Name prefix("/Sync/TestSyncValidator/AddEdge");
+  KeyChain keychain;
+
+  Name identity1("/TestSyncValidator/AddEdge-1/" + boost::lexical_cast<std::string>(time::now()));
+  Name certName1 = keychain.createIdentity(identity1);
+  shared_ptr<IdentityCertificate> anchor = keychain.getCertificate(certName1);
+
+  Name identity2("/TestSyncValidator/AddEdge-2/" + boost::lexical_cast<std::string>(time::now()));
+  Name certName2 = keychain.createIdentity(identity2);
+  shared_ptr<IdentityCertificate> introducer = keychain.getCertificate(certName2);
+
+  Name identity3("/TestSyncValidator/AddEdge-3/" + boost::lexical_cast<std::string>(time::now()));
+  Name certName3 = keychain.createIdentity(identity3);
+  shared_ptr<IdentityCertificate> introducee = keychain.getCertificate(certName3);
+
+  Name identity4("/TestSyncValidator/AddEdge-4/" + boost::lexical_cast<std::string>(time::now()));
+  Name certName4 = keychain.createIdentity(identity4);
+  shared_ptr<IdentityCertificate> introducer2 = keychain.getCertificate(certName4);
+
+  Name identity5("/TestSyncValidator/AddEdge-5/" + boost::lexical_cast<std::string>(time::now()));
+  Name certName5 = keychain.createIdentity(identity5);
+  shared_ptr<IdentityCertificate> introducee2 = keychain.getCertificate(certName5);
+
+  shared_ptr<boost::asio::io_service> ioService = make_shared<boost::asio::io_service>();
+  shared_ptr<Face> face = make_shared<Face>(ioService);
+  SyncValidator validator(prefix, *anchor, face);
+
+  validator.addParticipant(*introducer);
+  BOOST_CHECK(validator.canTrust(certName2));
+  
+  IntroCertificate introCert(prefix, *introducee, certName2.getPrefix(-1));
+  keychain.sign(introCert, certName2);
+  validator.addParticipant(introCert);
+  BOOST_CHECK(validator.canTrust(certName3));
+
+  IntroCertificate introCert1(prefix, *anchor, certName3.getPrefix(-1));
+  keychain.sign(introCert1, certName3);
+  validator.addParticipant(introCert1);
+  validator.setAnchor(*introducer);
+  BOOST_CHECK(validator.canTrust(certName2));
+  BOOST_CHECK(validator.canTrust(certName3));
+  BOOST_CHECK(validator.canTrust(certName1));
+
+  IntroCertificate introCert2(prefix, *introducee2, certName4.getPrefix(-1));
+  keychain.sign(introCert2, certName4);
+  validator.addParticipant(introCert2);
+  BOOST_CHECK(validator.canTrust(certName5) == false);
+  BOOST_CHECK(validator.canTrust(certName4) == false);
+
+  IntroCertificate introCert3(prefix, *introducee, certName5.getPrefix(-1));
+  keychain.sign(introCert3, certName5);
+  validator.addParticipant(introCert3);
+  BOOST_CHECK(validator.canTrust(certName5) == false);
+  BOOST_CHECK(validator.canTrust(certName4) == false);
+
+  validator.setAnchor(*introducee2);
+  BOOST_CHECK(validator.canTrust(certName1));
+  BOOST_CHECK(validator.canTrust(certName2));
+  BOOST_CHECK(validator.canTrust(certName3));
+  BOOST_CHECK(validator.canTrust(certName4) == false);
+  BOOST_CHECK(validator.canTrust(certName5));
+  
+
+  keychain.deleteIdentity(identity1);
+  keychain.deleteIdentity(identity2);
+  keychain.deleteIdentity(identity3);
+  keychain.deleteIdentity(identity4);
+  keychain.deleteIdentity(identity5);
+}
+
+BOOST_AUTO_TEST_CASE (OfflineValidate)
+{
+  using namespace Sync;
+  using namespace ndn;
+
+  Name prefix("/Sync/TestSyncValidator/OfflineValidate");
+  KeyChain keychain;
+
+  Name identity1("/TestSyncValidator/OfflineValidate-1/" + boost::lexical_cast<std::string>(time::now()));
+  Name certName1 = keychain.createIdentity(identity1);
+  shared_ptr<IdentityCertificate> anchor = keychain.getCertificate(certName1);
+
+  Name identity2("/TestSyncValidator/OfflineValidate-2/" + boost::lexical_cast<std::string>(time::now()));
+  Name certName2 = keychain.createIdentity(identity2);
+  shared_ptr<IdentityCertificate> introducer = keychain.getCertificate(certName2);
+
+  Name identity3("/TestSyncValidator/OfflineValidate-3/" + boost::lexical_cast<std::string>(time::now()));
+  Name certName3 = keychain.createIdentity(identity3);
+  shared_ptr<IdentityCertificate> introducee = keychain.getCertificate(certName3);
+
+  Name identity4("/TestSyncValidator/OfflineValidate-4/" + boost::lexical_cast<std::string>(time::now()));
+  Name certName4 = keychain.createIdentity(identity4);
+  shared_ptr<IdentityCertificate> introducer2 = keychain.getCertificate(certName4);
+
+  Name identity5("/TestSyncValidator/OfflineValidate-5/" + boost::lexical_cast<std::string>(time::now()));
+  Name certName5 = keychain.createIdentity(identity5);
+  shared_ptr<IdentityCertificate> introducee2 = keychain.getCertificate(certName5);
+
+  shared_ptr<boost::asio::io_service> ioService = make_shared<boost::asio::io_service>();
+  shared_ptr<Face> face = make_shared<Face>(ioService);
+  SyncValidator validator(prefix, *anchor, face);
+
+  validator.addParticipant(*introducer);
+  BOOST_CHECK(validator.canTrust(certName2));
+  
+  IntroCertificate introCert(prefix, *introducee, certName2.getPrefix(-1));
+  keychain.sign(introCert, certName2);
+  validator.addParticipant(introCert);
+  BOOST_CHECK(validator.canTrust(certName3));
+
+  IntroCertificate introCert2(prefix, *introducee2, certName4.getPrefix(-1));
+  keychain.sign(introCert2, certName4);
+  validator.addParticipant(introCert2);
+  BOOST_CHECK(validator.canTrust(certName5) == false);
+  BOOST_CHECK(validator.canTrust(certName4) == false);
+
+  validator.setAnchor(*introducer2);
+  BOOST_CHECK(validator.canTrust(certName1) == false);
+  BOOST_CHECK(validator.canTrust(certName2) == false);
+  BOOST_CHECK(validator.canTrust(certName3) == false);
+  BOOST_CHECK(validator.canTrust(certName4));
+  BOOST_CHECK(validator.canTrust(certName5));
+
+  Name dataName1 = prefix;
+  dataName1.append("data-1");
+  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
+  keychain.sign(*data1, certName5);
+
+  validator.validate(*data1,
+		     bind(&onValidated, _1),
+		     bind(&onValidationFailed, _1, _2));
+
+  Name dataName2 = prefix;
+  dataName2.append("data-2");
+  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
+  keychain.sign(*data2, certName1);
+
+  validator.validate(*data2,
+		     bind(&onValidated2, _1),
+		     bind(&onValidationFailed2, _1, _2));
+
+  ioService->run();
+
+  keychain.deleteIdentity(identity1);
+  keychain.deleteIdentity(identity2);
+  keychain.deleteIdentity(identity3);
+  keychain.deleteIdentity(identity4);
+  keychain.deleteIdentity(identity5);
+}
+
+BOOST_AUTO_TEST_CASE (OnlineValidate)
+{
+  using namespace Sync;
+  using namespace ndn;
+
+  Name prefix("/Sync/TestSyncValidator/OnlineValidate");
+  KeyChain keychain;
+
+  Name identity1("/TestSyncValidator/OnlineValidate-1/" + boost::lexical_cast<std::string>(time::now()));
+  Name certName1 = keychain.createIdentity(identity1);
+  shared_ptr<IdentityCertificate> anchor = keychain.getCertificate(certName1);
+
+  Name identity2("/TestSyncValidator/OnlineValidate-2/" + boost::lexical_cast<std::string>(time::now()));
+  Name certName2 = keychain.createIdentity(identity2);
+  shared_ptr<IdentityCertificate> introducer = keychain.getCertificate(certName2);
+
+  Name identity3("/TestSyncValidator/OnlineValidate-3/" + boost::lexical_cast<std::string>(time::now()));
+  Name certName3 = keychain.createIdentity(identity3);
+  shared_ptr<IdentityCertificate> introducee = keychain.getCertificate(certName3);
+
+  Name identity4("/TestSyncValidator/OfflineValidate-4/" + boost::lexical_cast<std::string>(time::now()));
+  Name certName4 = keychain.createIdentity(identity4);
+  shared_ptr<IdentityCertificate> introducee2 = keychain.getCertificate(certName4);
+
+  shared_ptr<boost::asio::io_service> ioService = make_shared<boost::asio::io_service>();
+  shared_ptr<Face> face = make_shared<Face>(ioService);
+  SyncValidator validator(prefix, *anchor, face);
+
+  validator.addParticipant(*introducer);
+  BOOST_CHECK(validator.canTrust(certName2));
+  
+  IntroCertificate introCert(prefix, *introducee, certName2.getPrefix(-1));
+  keychain.sign(introCert, certName2);
+  face->put(introCert);
+  BOOST_CHECK(validator.canTrust(certName3) == false);
+
+  IntroCertificate introCert2(prefix, *introducee2, certName3.getPrefix(-1));
+  keychain.sign(introCert2, certName3);
+  face->put(introCert2);
+  BOOST_CHECK(validator.canTrust(certName4) == false);
+
+  Name dataName1 = prefix;
+  dataName1.append("data-1");
+  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
+  keychain.sign(*data1, certName4);
+
+  validator.validate(*data1,
+		     bind(&onValidated, _1),
+		     bind(&onValidationFailed, _1, _2));
+
+  ioService->run();
+
+  BOOST_CHECK(validator.canTrust(certName3));
+  BOOST_CHECK(validator.canTrust(certName4));
+
+  keychain.deleteIdentity(identity1);
+  keychain.deleteIdentity(identity2);
+  keychain.deleteIdentity(identity3);
+  keychain.deleteIdentity(identity4);
+}
+
+BOOST_AUTO_TEST_SUITE_END()