security: Add configuration based validator

configuration file format can be found at: http://redmine.named-data.net/projects/ndn-cpp-dev/wiki/CommandValidatorConf

Change-Id: Icc2725f349aed7513f35f2cccdcd4463fadeef31
diff --git a/src/security/conf/filter.hpp b/src/security/conf/filter.hpp
new file mode 100644
index 0000000..1db7498
--- /dev/null
+++ b/src/security/conf/filter.hpp
@@ -0,0 +1,224 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Yingdi Yu <yingdi@cs.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_SECURITY_CONF_FILTER_HPP
+#define NDN_SECURITY_CONF_FILTER_HPP
+
+#include "../../common.hpp"
+#include "../../data.hpp"
+#include "../../interest.hpp"
+#include "../../util/regex.hpp"
+#include <boost/algorithm/string.hpp>
+
+#include "common.hpp"
+
+namespace ndn {
+namespace security {
+namespace conf {
+
+class Filter
+{
+public:
+  virtual
+  ~Filter()
+  {
+  }
+
+  virtual bool
+  match(const Data& data) = 0;
+
+  virtual bool
+  match(const Interest& interest) = 0;
+};
+
+class RelationNameFilter : public Filter
+{
+public:
+  enum Relation
+    {
+      RELATION_EQUAL,
+      RELATION_IS_PREFIX_OF,
+      RELATION_IS_STRICT_PREFIX_OF,
+    };
+
+  RelationNameFilter(const Name& name, Relation relation)
+    : m_name(name)
+    , m_relation(relation)
+  {
+  }
+
+  virtual
+  ~RelationNameFilter()
+  {
+  }
+
+  virtual bool
+  match(const Data& data)
+  {
+    return match(data.getName());
+  }
+
+  virtual bool
+  match(const Interest& interest)
+  {
+    if (interest.getName().size() < 2)
+      return false;
+
+    Name signedName = interest.getName().getPrefix(-2);
+    return match(signedName);
+  }
+
+private:
+  bool
+  match(const Name& name)
+  {
+    switch (m_relation)
+      {
+      case RELATION_EQUAL:
+        return (name == m_name);
+      case RELATION_IS_PREFIX_OF:
+        return m_name.isPrefixOf(name);
+      case RELATION_IS_STRICT_PREFIX_OF:
+        return (m_name.isPrefixOf(name) && m_name != name);
+      default:
+        return false;
+      }
+  }
+
+private:
+  Name m_name;
+  Relation m_relation;
+};
+
+class RegexNameFilter : public Filter
+{
+public:
+  explicit
+  RegexNameFilter(const Regex& regex)
+    : m_regex(regex)
+  {
+  }
+
+  virtual
+  ~RegexNameFilter()
+  {
+  }
+
+  virtual bool
+  match(const Data& data)
+  {
+    return m_regex.match(data.getName());
+  }
+
+  virtual bool
+  match(const Interest& interest)
+  {
+    if (interest.getName().size() < 2)
+      return false;
+
+    Name signedName = interest.getName().getPrefix(-2);
+    return m_regex.match(signedName);
+  }
+
+private:
+  Regex m_regex;
+};
+
+class FilterFactory
+{
+public:
+  static shared_ptr<Filter>
+  create(const ConfigSection& configSection)
+  {
+    ConfigSection::const_iterator propertyIt = configSection.begin();
+
+    if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
+      throw Error("Expect <filter.type>!");
+
+    std::string type = propertyIt->second.data();
+
+    if (boost::iequals(type, "name"))
+      return createNameFilter(configSection);
+    else
+      throw Error("Unsupported filter.type: " + type);
+  }
+private:
+  static shared_ptr<Filter>
+  createNameFilter(const ConfigSection& configSection)
+  {
+    ConfigSection::const_iterator propertyIt = configSection.begin();
+    propertyIt++;
+
+    if (propertyIt == configSection.end())
+      throw Error("Expect more properties for filter(name)");
+
+    if (boost::iequals(propertyIt->first, "name"))
+      {
+        // Get filter.name
+        Name name;
+        try
+          {
+            name = Name(propertyIt->second.data());
+          }
+        catch (Name::Error& e)
+          {
+            throw Error("Wrong filter.name: " + propertyIt->second.data());
+          }
+
+        propertyIt++;
+
+        // Get filter.relation
+        if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation"))
+          throw Error("Expect <filter.relation>!");
+
+        std::string relationString = propertyIt->second.data();
+        propertyIt++;
+
+        RelationNameFilter::Relation relation;
+        if (boost::iequals(relationString, "equal"))
+          relation = RelationNameFilter::RELATION_EQUAL;
+        else if (boost::iequals(relationString, "is-prefix-of"))
+          relation = RelationNameFilter::RELATION_IS_PREFIX_OF;
+        else if (boost::iequals(relationString, "is-strict-prefix-of"))
+          relation = RelationNameFilter::RELATION_IS_STRICT_PREFIX_OF;
+        else
+          throw Error("Unsupported relation: " + relationString);
+
+
+        if (propertyIt != configSection.end())
+          throw Error("Expect the end of filter!");
+
+        return make_shared<RelationNameFilter>(boost::cref(name),
+                                               boost::cref(relation));
+      }
+    else if (boost::iequals(propertyIt->first, "regex"))
+      {
+        std::string regexString = propertyIt->second.data();
+        propertyIt++;
+
+        if (propertyIt != configSection.end())
+          throw Error("Expect the end of filter!");
+
+        try
+          {
+            return shared_ptr<RegexNameFilter>(new RegexNameFilter(regexString));
+          }
+        catch (const Regex::Error& e)
+          {
+            throw Error("Wrong filter.regex: " + regexString);
+          }
+      }
+    else
+      throw Error("Wrong filter(name) properties");
+  }
+};
+
+} // namespace conf
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_CONF_FILTER_HPP