security: Add appropriate hooks in Validator

This commit add three hooks in validation process, so that sub-classes can extend the process
1. preCertificateValidation: process received certificate before validation.
2. onTimeout: process interest timeout
3. afterCheckPolicy: process validation requests.

Change-Id: I23d9eae7087ff6c69639b332a424636ca7bc2841
diff --git a/src/security/validation-request.hpp b/src/security/validation-request.hpp
index b141e02..d9aae80 100644
--- a/src/security/validation-request.hpp
+++ b/src/security/validation-request.hpp
@@ -41,18 +41,26 @@
 typedef function<void(const shared_ptr<const Data>&,
                       const std::string&)> OnDataValidationFailed;
 
-
+/**
+ * @brief ValidationRequest contains information related to further validation.
+ *
+ * During a validation process, validator may not have retrieved the corresponding public
+ * key of the signature in a packet. ValidationRequest contains the interest for the
+ * certificate that carries the public key and also contains the context for the certificate
+ * including how to proceed when the public key is authenticated or not, the number of
+ * validation steps that have been performed, and how to handle interest timeout.
+ */
 class ValidationRequest
 {
 public:
   ValidationRequest(const Interest& interest,
-                    const OnDataValidated& onValidated,
-                    const OnDataValidationFailed& onDataValidated,
-                    int nRetrials, int nSteps)
+                    const OnDataValidated& onDataValidated,
+                    const OnDataValidationFailed& onDataValidationFailed,
+                    int nRetries, int nSteps)
     : m_interest(interest)
-    , m_onValidated(onValidated)
     , m_onDataValidated(onDataValidated)
-    , m_nRetrials(nRetrials)
+    , m_onDataValidationFailed(onDataValidationFailed)
+    , m_nRetries(nRetries)
     , m_nSteps(nSteps)
   {
   }
@@ -62,11 +70,16 @@
   {
   }
 
-  Interest m_interest;                      // Interest for the requested data.
-  OnDataValidated m_onValidated;            // Callback function on validated certificate.
-  OnDataValidationFailed m_onDataValidated; // Callback function on validation failure.
-  int m_nRetrials;                          // The number of retrials when interest timeout.
-  int m_nSteps;                             // The stepCount of next step.
+  /// @brief the Interest for the requested data/certificate.
+  Interest m_interest;
+  /// @brief callback when the retrieved certificate is authenticated.
+  OnDataValidated m_onDataValidated;
+  /// @brief callback when the retrieved certificate cannot be authenticated.
+  OnDataValidationFailed m_onDataValidationFailed;
+  /// @brief the number of retries when the interest times out.
+  int m_nRetries;
+  /// @brief the number of validation steps that have been performed.
+  int m_nSteps;
 };
 
 } // namespace ndn
diff --git a/src/security/validator.cpp b/src/security/validator.cpp
index df7b0e6..1b9d92a 100644
--- a/src/security/validator.cpp
+++ b/src/security/validator.cpp
@@ -55,31 +55,23 @@
   std::vector<shared_ptr<ValidationRequest> > nextSteps;
   checkPolicy(interest, nSteps, onValidated, onValidationFailed, nextSteps);
 
-  if (!nextSteps.empty())
-    {
-      if (!m_hasFace)
-        {
-          onValidationFailed(interest.shared_from_this(),
-                             "Require more information to validate the interest!");
-          return;
-        }
-
-      std::vector<shared_ptr<ValidationRequest> >::const_iterator it = nextSteps.begin();
-      OnFailure onFailure = bind(onValidationFailed, interest.shared_from_this(), _1);
-      for (; it != nextSteps.end(); it++)
-        m_face.expressInterest((*it)->m_interest,
-                               bind(&Validator::onData, this, _1, _2, *it),
-                               bind(&Validator::onTimeout,
-                                    this, _1, (*it)->m_nRetrials,
-                                    onFailure,
-                                    *it));
-    }
-  else
+  if (nextSteps.empty())
     {
       // If there is no nextStep,
       // that means InterestPolicy has already been able to verify the Interest.
       // No more further processes.
+      return;
     }
+
+  if (!m_hasFace)
+    {
+      onValidationFailed(interest.shared_from_this(),
+                         "Require more information to validate the interest!");
+      return;
+    }
+
+  OnFailure onFailure = bind(onValidationFailed, interest.shared_from_this(), _1);
+  afterCheckPolicy(nextSteps, onFailure);
 }
 
 void
@@ -91,30 +83,23 @@
   std::vector<shared_ptr<ValidationRequest> > nextSteps;
   checkPolicy(data, nSteps, onValidated, onValidationFailed, nextSteps);
 
-  if (!nextSteps.empty())
-    {
-      if (!m_hasFace)
-        {
-          onValidationFailed(data.shared_from_this(),
-                             "Require more information to validate the data!");
-        }
-
-      std::vector<shared_ptr<ValidationRequest> >::const_iterator it = nextSteps.begin();
-      OnFailure onFailure = bind(onValidationFailed, data.shared_from_this(), _1);
-      for (; it != nextSteps.end(); it++)
-        m_face.expressInterest((*it)->m_interest,
-                               bind(&Validator::onData, this, _1, _2, *it),
-                               bind(&Validator::onTimeout,
-                                    this, _1, (*it)->m_nRetrials,
-                                    onFailure,
-                                    *it));
-    }
-  else
+  if (nextSteps.empty())
     {
       // If there is no nextStep,
       // that means Data Policy has already been able to verify the Interest.
       // No more further processes.
+      return;
     }
+
+  if (!m_hasFace)
+    {
+      onValidationFailed(data.shared_from_this(),
+                         "Require more information to validate the data!");
+      return;
+    }
+
+  OnFailure onFailure = bind(onValidationFailed, data.shared_from_this(), _1);
+  afterCheckPolicy(nextSteps, onFailure);
 }
 
 void
@@ -122,23 +107,15 @@
                   const Data& data,
                   const shared_ptr<ValidationRequest>& nextStep)
 {
-  validate(data, nextStep->m_onValidated, nextStep->m_onDataValidated, nextStep->m_nSteps);
-}
+  shared_ptr<const Data> certificateData = preCertificateValidation(data);
 
-void
-Validator::onTimeout(const Interest& interest,
-                     int nRetrials,
-                     const OnFailure& onFailure,
-                     const shared_ptr<ValidationRequest>& nextStep)
-{
-  if (nRetrials > 0)
-    // Issue the same expressInterest except decrement nRetrials.
-    m_face.expressInterest(interest,
-                            bind(&Validator::onData, this, _1, _2, nextStep),
-                            bind(&Validator::onTimeout, this, _1,
-                                 nRetrials - 1, onFailure, nextStep));
-  else
-    onFailure("Cannot fetch cert: " + interest.getName().toUri());
+  if (!static_cast<bool>(certificateData))
+    return nextStep->m_onDataValidationFailed(data.shared_from_this(),
+                                              "Cannot decode cert: " + data.getName().toUri());
+
+  validate(*certificateData,
+           nextStep->m_onDataValidated, nextStep->m_onDataValidationFailed,
+           nextStep->m_nSteps);
 }
 
 bool
@@ -352,4 +329,37 @@
     }
 }
 
+void
+Validator::onTimeout(const Interest& interest,
+                     int remainingRetries,
+                     const OnFailure& onFailure,
+                     const shared_ptr<ValidationRequest>& validationRequest)
+{
+  if (remainingRetries > 0)
+    // Issue the same expressInterest except decrement nRetrials.
+    m_face.expressInterest(interest,
+                           bind(&Validator::onData, this, _1, _2, validationRequest),
+                           bind(&Validator::onTimeout, this, _1,
+                                remainingRetries - 1, onFailure, validationRequest));
+  else
+    onFailure("Cannot fetch cert: " + interest.getName().toUri());
+}
+
+
+void
+Validator::afterCheckPolicy(const std::vector<shared_ptr<ValidationRequest> >& nextSteps,
+                            const OnFailure& onFailure)
+{
+  for (std::vector<shared_ptr<ValidationRequest> >::const_iterator it = nextSteps.begin();
+       it != nextSteps.end(); it++)
+    {
+      m_face.expressInterest((*it)->m_interest,
+                             bind(&Validator::onData, this, _1, _2, *it),
+                             bind(&Validator::onTimeout,
+                                  this, _1, (*it)->m_nRetries,
+                                  onFailure,
+                                  *it));
+    }
+}
+
 } // namespace ndn
diff --git a/src/security/validator.hpp b/src/security/validator.hpp
index 87c2bfd..b95c5ad 100644
--- a/src/security/validator.hpp
+++ b/src/security/validator.hpp
@@ -236,13 +236,6 @@
          const Data& data,
          const shared_ptr<ValidationRequest>& nextStep);
 
-  /// @brief Re-express the interest if it times out.
-  void
-  onTimeout(const Interest& interest,
-            int retry,
-            const OnFailure& onFailure,
-            const shared_ptr<ValidationRequest>& nextStep);
-
   void
   validate(const Data& data,
            const OnDataValidated& onValidated,
@@ -255,6 +248,57 @@
            const OnInterestValidationFailed& onValidationFailed,
            int nSteps);
 
+  /// Hooks
+
+  /**
+   * @brief trigger before validating requested certificate.
+   *
+   * The Data:
+   * - matches the interest in the validation-request.
+   * - may be certificate or a data encapsulating certificate.
+   *
+   * This method returns a data (actually certificate) that is will be passed as Data into:
+   * Validator::validate(const Data& data,
+   *                     const OnDataValidated& onValidated,
+   *                     const OnDataValidationFailed& onValidationFailed,
+   *                     int nSteps);
+   */
+  virtual shared_ptr<const Data>
+  preCertificateValidation(const Data& data)
+  {
+    return data.shared_from_this();
+  }
+
+  /**
+   * @brief trigger when interest for certificate times out.
+   *
+   * Validator can decide how to handle the timeout, either call onFailure, or retry.
+   *
+   * @param interest The interest that times out.
+   * @param nRemainingRetries The number of retries left.
+   * @param onFailure Failure callback when there is no more retries remaining.
+   * @param validationRequest The validationRequest containing the context of the interest.
+   */
+
+  virtual void
+  onTimeout(const Interest& interest,
+            int nRemainingRetries,
+            const OnFailure& onFailure,
+            const shared_ptr<ValidationRequest>& validationRequest);
+
+  /**
+   * @brief trigger after checkPolicy is done.
+   *
+   * Validator can decide how to handle the set of validation requests according to
+   * the trust model.
+   *
+   * @param nextSteps A set of validation request made by checkPolicy.
+   * @param onFailure Failure callback when errors happen in processing nextSteps.
+   */
+  virtual void
+  afterCheckPolicy(const std::vector<shared_ptr<ValidationRequest> >& nextSteps,
+                   const OnFailure& onFailure);
+
 protected:
   bool m_hasFace;
   Face& m_face;