Boolean match functors, policy context to manage lifetime and references.
authorScott Cantor <cantor.2@osu.edu>
Mon, 7 May 2007 15:57:48 +0000 (15:57 +0000)
committerScott Cantor <cantor.2@osu.edu>
Mon, 7 May 2007 15:57:48 +0000 (15:57 +0000)
16 files changed:
shibsp/Makefile.am
shibsp/SPConfig.h
shibsp/attribute/Attribute.h
shibsp/attribute/NameIDAttribute.h
shibsp/attribute/ScopedAttribute.h
shibsp/attribute/filtering/FilterPolicyContext.h [new file with mode: 0644]
shibsp/attribute/filtering/MatchFunctor.h
shibsp/attribute/filtering/impl/AndMatchFunctor.cpp [new file with mode: 0644]
shibsp/attribute/filtering/impl/AnyMatchFunctor.cpp [new file with mode: 0644]
shibsp/attribute/filtering/impl/MatchFunctor.cpp
shibsp/attribute/filtering/impl/NotMatchFunctor.cpp [new file with mode: 0644]
shibsp/attribute/filtering/impl/OrMatchFunctor.cpp [new file with mode: 0644]
shibsp/attribute/filtering/impl/XMLAttributeFilter.cpp
shibsp/shibsp.vcproj
shibsp/util/SPConstants.cpp
shibsp/util/SPConstants.h

index 61b152d..2ad3d3f 100644 (file)
@@ -49,6 +49,7 @@ attrfiltinclude_HEADERS = \
        attribute/filtering/AttributeFilter.h \
        attribute/filtering/BasicFilteringContext.h \
        attribute/filtering/FilteringContext.h \
+       attribute/filtering/FilterPolicyContext.h \
        attribute/filtering/MatchFunctor.h
 
 attrresinclude_HEADERS = \
@@ -100,8 +101,12 @@ libshibsp_la_SOURCES = \
        attribute/StringAttributeDecoder.cpp \
        attribute/filtering/AttributeFilter.cpp \
        attribute/filtering/ChainingAttributeFilter.cpp \
-       attribute/filtering/MatchFunctor.cpp \
        attribute/filtering/XMLAttributeFilter.cpp \
+       attribute/filtering/MatchFunctor.cpp \
+       attribute/filtering/AndMatchFunctor.cpp \
+       attribute/filtering/AnyMatchFunctor.cpp \
+       attribute/filtering/NotMatchFunctor.cpp \
+       attribute/filtering/OrMatchFunctor.cpp \
        attribute/resolver/impl/ChainingAttributeResolver.cpp \
        attribute/resolver/impl/QueryAttributeResolver.cpp \
        attribute/resolver/impl/XMLAttributeExtractor.cpp \
index 4e62b8c..7de91c5 100644 (file)
@@ -39,6 +39,7 @@ namespace shibsp {
     class SHIBSP_API AttributeExtractor;
     class SHIBSP_API AttributeFilter;
     class SHIBSP_API AttributeResolver;
+    class SHIBSP_API FilterPolicyContext;
     class SHIBSP_API Handler;
     class SHIBSP_API ListenerService;
     class SHIBSP_API MatchFunctor;
@@ -208,7 +209,7 @@ namespace shibsp {
         /**
          * Manages factories for MatchFunctor plugins.
          */
-        xmltooling::PluginManager<MatchFunctor,xmltooling::QName,const xercesc::DOMElement*> MatchFunctorManager;
+        xmltooling::PluginManager< MatchFunctor,xmltooling::QName,std::pair<const FilterPolicyContext*,const xercesc::DOMElement*> > MatchFunctorManager;
 
         /**
          * Manages factories for Handler plugins that implement ManageNameIDService functionality.
index 0b282ad..401749f 100644 (file)
@@ -142,6 +142,16 @@ namespace shibsp {
         virtual void clearSerializedValues()=0;
         
         /**
+         * Removes the value at the specified position (starting from zero).
+         *
+         * @param index position of value to remove
+         */
+        virtual void removeValue(size_t index) {
+            if (index < m_serialized.size())
+                m_serialized.erase(m_serialized.begin() + index);
+        }
+
+        /**
          * Marshalls an Attribute for remoting.
          * 
          * <p>This allows Attribute objects to be communicated across process boundaries
index d2decee..0ba4ab7 100644 (file)
@@ -116,7 +116,13 @@ namespace shibsp {
         void clearSerializedValues() {
             m_serialized.clear();
         }
-        
+
+        void removeValue(size_t index) {
+            Attribute::removeValue(index);
+            if (index < m_values.size())
+                m_values.erase(m_values.begin() + index);
+        }
+
         const std::vector<std::string>& getSerializedValues() const {
             if (m_serialized.empty()) {
                 for (std::vector<Value>::const_iterator i=m_values.begin(); i!=m_values.end(); ++i) {
index 4baab6e..9fb81e2 100644 (file)
@@ -90,6 +90,12 @@ namespace shibsp {
             m_serialized.clear();
         }
         
+        void removeValue(size_t index) {
+            Attribute::removeValue(index);
+            if (index < m_values.size())
+                m_values.erase(m_values.begin() + index);
+        }
+
         const std::vector<std::string>& getSerializedValues() const {
             if (m_serialized.empty()) {
                 for (std::vector< std::pair<std::string,std::string> >::const_iterator i=m_values.begin(); i!=m_values.end(); ++i)
diff --git a/shibsp/attribute/filtering/FilterPolicyContext.h b/shibsp/attribute/filtering/FilterPolicyContext.h
new file mode 100644 (file)
index 0000000..2fff8ae
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *  Copyright 2001-2007 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file shibsp/attribute/filtering/FilterPolicyContext.h
+ * 
+ * Context for lookup of instantiated MatchFunctor objects.
+ */
+
+#ifndef __shibsp_filtpolctx_h__
+#define __shibsp_filtpolctx_h__
+
+#include <shibsp/attribute/filtering/MatchFunctor.h>
+
+#include <map>
+#include <string>
+
+namespace shibsp {
+
+    /**
+     * Context for lookup of instantiated MatchFunctor objects.
+     */
+    class SHIBSP_API FilterPolicyContext
+    {
+        MAKE_NONCOPYABLE(FilterPolicyContext);
+    public:
+        /**
+         * Constructor.
+         * 
+         * @param functors  reference to a map of id/functor pairs
+         */
+        FilterPolicyContext(std::multimap<std::string,MatchFunctor*>& functors) : m_functors(functors) {
+        }
+
+        virtual ~FilterPolicyContext() {}
+
+        /**
+         * Gets a mutable map to store id/functor pairs.
+         * 
+         * <p>When storing new instances, use an empty string for unnamed objects.
+         *
+         * @return  reference to a mutable map containing available MatchFunctors 
+         */
+        std::multimap<std::string,MatchFunctor*>& getMatchFunctors() const {
+            return m_functors;
+        }
+    
+    private:
+        std::multimap<std::string,MatchFunctor*>& m_functors;
+    };
+
+};
+
+#endif /* __shibsp_filtpolctx_h__ */
index 373aa01..db18391 100644 (file)
@@ -64,6 +64,18 @@ namespace shibsp {
         virtual bool evaluatePermitValue(const FilteringContext& filterContext, const Attribute& attribute, size_t index) const=0;\r
     };
 
+    /** Always evaluates to true. */
+    extern SHIBSP_API xmltooling::QName AnyMatchFunctorType;
+
+    /** Conjunction MatchFunctor. */
+    extern SHIBSP_API xmltooling::QName AndMatchFunctorType;
+
+    /** Disjunction MatchFunctor. */
+    extern SHIBSP_API xmltooling::QName OrMatchFunctorType;
+
+    /** Negating MatchFunctor. */
+    extern SHIBSP_API xmltooling::QName NotMatchFunctorType;
+
     /**
      * Registers MatchFunctor classes into the runtime.
      */
diff --git a/shibsp/attribute/filtering/impl/AndMatchFunctor.cpp b/shibsp/attribute/filtering/impl/AndMatchFunctor.cpp
new file mode 100644 (file)
index 0000000..b1645b8
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ *  Copyright 2001-2007 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * AndMatchFunctor.cpp
+ * 
+ * A MatchFunctor that logical ANDs the results of contained functors.
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "attribute/filtering/FilterPolicyContext.h"
+#include "util/SPConstants.h"
+
+#include <xercesc/util/XMLUniDefs.hpp>
+#include <xmltooling/util/XMLHelper.h>
+
+using namespace shibsp;
+using namespace xmltooling;
+using namespace std;
+
+namespace shibsp {
+
+    /**
+     * A MatchFunctor that logical ANDs the results of contained functors.
+     */
+    class SHIBSP_DLLLOCAL AndMatchFunctor : public MatchFunctor
+    {
+    public:
+        AndMatchFunctor(const pair<const FilterPolicyContext*,const DOMElement*>& p);
+
+        bool evaluatePolicyRequirement(const FilteringContext& filterContext) const {
+            if (m_functors.empty())
+                return false;
+            for (vector<const MatchFunctor*>::const_iterator mf = m_functors.begin(); mf!=m_functors.end(); ++mf)
+                if (!(*mf)->evaluatePolicyRequirement(filterContext))
+                    return false;
+            return true;
+        }
+
+        bool evaluatePermitValue(const FilteringContext& filterContext, const Attribute& attribute, size_t index) const {
+            if (m_functors.empty())
+                return false;
+            for (vector<const MatchFunctor*>::const_iterator mf = m_functors.begin(); mf!=m_functors.end(); ++mf)
+                if (!(*mf)->evaluatePermitValue(filterContext, attribute, index))
+                    return false;
+            return true;
+        }
+
+    private:
+        MatchFunctor* buildFunctor(const DOMElement* e, const FilterPolicyContext* functorMap);
+
+        vector<const MatchFunctor*> m_functors;
+    };
+
+    MatchFunctor* SHIBSP_DLLLOCAL AndFunctorFactory(const pair<const FilterPolicyContext*,const DOMElement*>& p)
+    {
+        return new AndMatchFunctor(p);
+    }
+
+    static XMLCh _id[] =            UNICODE_LITERAL_2(i,d);
+    static XMLCh _ref[] =           UNICODE_LITERAL_3(r,e,f);
+    static XMLCh Rule[] =           UNICODE_LITERAL_4(R,u,l,e);
+    static XMLCh RuleReference[] =  UNICODE_LITERAL_13(R,u,l,e,R,e,f,e,r,e,n,c,e);
+};
+
+AndMatchFunctor::AndMatchFunctor(const pair<const FilterPolicyContext*,const DOMElement*>& p)
+{
+    MatchFunctor* func;
+    const DOMElement* e = XMLHelper::getFirstChildElement(p.second);
+    while (e) {
+        func = NULL;
+        if (XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_MF_BASIC_NS, Rule)) {
+            func = buildFunctor(e, p.first);
+        }
+        else if (XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_MF_BASIC_NS, RuleReference)) {
+            auto_ptr_char ref(e->getAttributeNS(NULL, _ref));
+            if (ref.get() && *ref.get()) {
+                multimap<string,MatchFunctor*>::const_iterator rule = p.first->getMatchFunctors().find(ref.get());
+                func = (rule!=p.first->getMatchFunctors().end()) ? rule->second : NULL;
+            }
+        }
+
+        if (func)
+            m_functors.push_back(func);
+
+        e = XMLHelper::getNextSiblingElement(e);
+    }
+}
+
+MatchFunctor* AndMatchFunctor::buildFunctor(const DOMElement* e, const FilterPolicyContext* functorMap)
+{
+    // We'll track and map IDs just for consistency, but don't require them or worry about dups.
+    auto_ptr_char temp(e->getAttributeNS(NULL,_id));
+    const char* id = (temp.get() && *temp.get()) ? temp.get() : "";
+    if (*id && functorMap->getMatchFunctors().count(id))
+        id = "";
+
+    auto_ptr<QName> type(XMLHelper::getXSIType(e));
+    if (!type.get())
+        throw ConfigurationException("Child Rule found with no xsi:type.");
+
+    MatchFunctor* func = SPConfig::getConfig().MatchFunctorManager.newPlugin(*type.get(), make_pair(functorMap,e));
+    functorMap->getMatchFunctors().insert(make_pair(id, func));
+    return func;
+}
diff --git a/shibsp/attribute/filtering/impl/AnyMatchFunctor.cpp b/shibsp/attribute/filtering/impl/AnyMatchFunctor.cpp
new file mode 100644 (file)
index 0000000..ac352d8
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  Copyright 2001-2007 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * AnyMatchFunctor.cpp
+ * 
+ * A match function that returns true to evaluations.
+ */
+
+#include "internal.h"
+#include "attribute/filtering/FilterPolicyContext.h"
+
+using namespace shibsp;
+
+namespace shibsp {
+
+    /**
+     * A match function that returns true to evaluations. Note, the result may still be negated.
+     */
+    class SHIBSP_DLLLOCAL AnyMatchFunctor : public MatchFunctor
+    {
+    public:
+        bool evaluatePolicyRequirement(const FilteringContext& filterContext) const {
+            return true;
+        }
+
+        bool evaluatePermitValue(const FilteringContext& filterContext, const Attribute& attribute, size_t index) const {
+            return true;
+        }
+    };
+
+    MatchFunctor* SHIBSP_DLLLOCAL AnyFunctorFactory(const std::pair<const FilterPolicyContext*,const DOMElement*>& p)
+    {
+        return new AnyMatchFunctor();
+    }
+
+};
index 2f81f89..ce6526e 100644 (file)
 
 #include "internal.h"
 #include "attribute/filtering/MatchFunctor.h"
+#include "util/SPConstants.h"
+
+#include <xercesc/util/XMLUniDefs.hpp>
 
 using namespace shibsp;
 using namespace xmltooling;
 using namespace std;
 
 namespace shibsp {
-    //SHIBSP_DLLLOCAL PluginManager<MatchFunctor,QName,const DOMElement*>::Factory FunctorFactory;
+    SHIBSP_DLLLOCAL PluginManager< MatchFunctor,QName,pair<const FilterPolicyContext*,const DOMElement*> >::Factory AnyFunctorFactory;
+    SHIBSP_DLLLOCAL PluginManager< MatchFunctor,QName,pair<const FilterPolicyContext*,const DOMElement*> >::Factory AndFunctorFactory;
+    SHIBSP_DLLLOCAL PluginManager< MatchFunctor,QName,pair<const FilterPolicyContext*,const DOMElement*> >::Factory OrFunctorFactory;
+    SHIBSP_DLLLOCAL PluginManager< MatchFunctor,QName,pair<const FilterPolicyContext*,const DOMElement*> >::Factory NotFunctorFactory;
+
+    static const XMLCh ANY[] =                  UNICODE_LITERAL_3(A,N,Y);
+    static const XMLCh AND[] =                  UNICODE_LITERAL_3(A,N,D);
+    static const XMLCh OR[] =                   UNICODE_LITERAL_2(O,R);
+    static const XMLCh NOT[] =                  UNICODE_LITERAL_3(N,O,T);
 };
 
+QName shibsp::AnyMatchFunctorType(shibspconstants::SHIB2ATTRIBUTEFILTER_MF_BASIC_NS, ANY);
+QName shibsp::AndMatchFunctorType(shibspconstants::SHIB2ATTRIBUTEFILTER_MF_BASIC_NS, AND);
+QName shibsp::OrMatchFunctorType(shibspconstants::SHIB2ATTRIBUTEFILTER_MF_BASIC_NS, OR);
+QName shibsp::NotMatchFunctorType(shibspconstants::SHIB2ATTRIBUTEFILTER_MF_BASIC_NS, NOT);
+
 void SHIBSP_API shibsp::registerMatchFunctors()
 {
     SPConfig& conf = SPConfig::getConfig();
-    //conf.MatchFunctorManager.registerFactory("", FunctorFactory);
+    conf.MatchFunctorManager.registerFactory(AnyMatchFunctorType, AnyFunctorFactory);
+    conf.MatchFunctorManager.registerFactory(AndMatchFunctorType, AndFunctorFactory);
+    conf.MatchFunctorManager.registerFactory(OrMatchFunctorType, OrFunctorFactory);
+    conf.MatchFunctorManager.registerFactory(NotMatchFunctorType, NotFunctorFactory);
 }
diff --git a/shibsp/attribute/filtering/impl/NotMatchFunctor.cpp b/shibsp/attribute/filtering/impl/NotMatchFunctor.cpp
new file mode 100644 (file)
index 0000000..6d2797e
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ *  Copyright 2001-2007 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * NotMatchFunctor.cpp
+ * 
+ * A MatchFunctor that negates the result of a contained functor.
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "attribute/filtering/FilterPolicyContext.h"
+#include "util/SPConstants.h"
+
+#include <xercesc/util/XMLUniDefs.hpp>
+#include <xmltooling/util/XMLHelper.h>
+
+using namespace shibsp;
+using namespace xmltooling;
+using namespace std;
+
+namespace shibsp {
+
+    /**
+     * A MatchFunctor that negates the result of a contained functor.
+     */
+    class SHIBSP_DLLLOCAL NotMatchFunctor : public MatchFunctor
+    {
+    public:
+        NotMatchFunctor(const pair<const FilterPolicyContext*,const DOMElement*>& p);
+
+        bool evaluatePolicyRequirement(const FilteringContext& filterContext) const {\r
+            if (m_functor)\r
+                return !(m_functor->evaluatePolicyRequirement(filterContext));\r
+            return false;\r
+        }\r
+\r
+        bool evaluatePermitValue(const FilteringContext& filterContext, const Attribute& attribute, size_t index) const {\r
+            if (m_functor)\r
+                return !(m_functor->evaluatePermitValue(filterContext, attribute, index));\r
+            return false;\r
+        }\r
+
+    private:
+        MatchFunctor* buildFunctor(const DOMElement* e, const FilterPolicyContext* functorMap);
+
+        const MatchFunctor* m_functor;
+    };
+
+    MatchFunctor* SHIBSP_DLLLOCAL NotFunctorFactory(const pair<const FilterPolicyContext*,const DOMElement*>& p)
+    {
+        return new NotMatchFunctor(p);
+    }
+
+    static XMLCh _id[] =            UNICODE_LITERAL_2(i,d);
+    static XMLCh _ref[] =           UNICODE_LITERAL_3(r,e,f);
+    static XMLCh Rule[] =           UNICODE_LITERAL_4(R,u,l,e);
+    static XMLCh RuleReference[] =  UNICODE_LITERAL_13(R,u,l,e,R,e,f,e,r,e,n,c,e);
+};
+
+NotMatchFunctor::NotMatchFunctor(const pair<const FilterPolicyContext*,const DOMElement*>& p) : m_functor(NULL)
+{
+    const DOMElement* e = XMLHelper::getFirstChildElement(p.second);
+    if (e) {
+        if (XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_MF_BASIC_NS, Rule)) {
+            m_functor = buildFunctor(e, p.first);
+        }
+        else if (XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_MF_BASIC_NS, RuleReference)) {
+            auto_ptr_char ref(e->getAttributeNS(NULL, _ref));
+            if (ref.get() && *ref.get()) {
+                multimap<string,MatchFunctor*>::const_iterator rule = p.first->getMatchFunctors().find(ref.get());
+                m_functor = (rule!=p.first->getMatchFunctors().end()) ? rule->second : NULL;
+            }
+        }
+    }
+
+    if (!m_functor)
+        throw ConfigurationException("No child Rule installed into NotMatchFunctor.");
+}
+
+MatchFunctor* NotMatchFunctor::buildFunctor(const DOMElement* e, const FilterPolicyContext* functorMap)
+{
+    // We'll track and map IDs just for consistency, but don't require them or worry about dups.
+    auto_ptr_char temp(e->getAttributeNS(NULL,_id));
+    const char* id = (temp.get() && *temp.get()) ? temp.get() : "";
+    if (*id && functorMap->getMatchFunctors().count(id))
+        id = "";
+
+    auto_ptr<QName> type(XMLHelper::getXSIType(e));
+    if (!type.get())
+        throw ConfigurationException("Child Rule found with no xsi:type.");
+
+    MatchFunctor* func = SPConfig::getConfig().MatchFunctorManager.newPlugin(*type.get(), make_pair(functorMap,e));
+    functorMap->getMatchFunctors().insert(make_pair(id, func));
+    return func;
+}
diff --git a/shibsp/attribute/filtering/impl/OrMatchFunctor.cpp b/shibsp/attribute/filtering/impl/OrMatchFunctor.cpp
new file mode 100644 (file)
index 0000000..32c6f2a
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *  Copyright 2001-2007 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * OrMatchFunctor.cpp
+ * 
+ * A MatchFunctor that logical ORs the results of contained functors.
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "attribute/filtering/FilterPolicyContext.h"
+#include "util/SPConstants.h"
+
+#include <xercesc/util/XMLUniDefs.hpp>
+#include <xmltooling/util/XMLHelper.h>
+
+using namespace shibsp;
+using namespace xmltooling;
+using namespace std;
+
+namespace shibsp {
+
+    /**
+     * A MatchFunctor that logical ORs the results of contained functors.
+     */
+    class SHIBSP_DLLLOCAL OrMatchFunctor : public MatchFunctor
+    {
+    public:
+        OrMatchFunctor(const pair<const FilterPolicyContext*,const DOMElement*>& p);
+
+        bool evaluatePolicyRequirement(const FilteringContext& filterContext) const {
+            for (vector<const MatchFunctor*>::const_iterator mf = m_functors.begin(); mf!=m_functors.end(); ++mf)
+                if ((*mf)->evaluatePolicyRequirement(filterContext))
+                    return true;
+            return false;
+        }
+
+        bool evaluatePermitValue(const FilteringContext& filterContext, const Attribute& attribute, size_t index) const {
+            for (vector<const MatchFunctor*>::const_iterator mf = m_functors.begin(); mf!=m_functors.end(); ++mf)
+                if ((*mf)->evaluatePermitValue(filterContext, attribute, index))
+                    return true;
+            return false;
+        }
+
+    private:
+        MatchFunctor* buildFunctor(const DOMElement* e, const FilterPolicyContext* functorMap);
+
+        vector<const MatchFunctor*> m_functors;
+    };
+
+    MatchFunctor* SHIBSP_DLLLOCAL OrFunctorFactory(const pair<const FilterPolicyContext*,const DOMElement*>& p)
+    {
+        return new OrMatchFunctor(p);
+    }
+
+    static XMLCh _id[] =            UNICODE_LITERAL_2(i,d);
+    static XMLCh _ref[] =           UNICODE_LITERAL_3(r,e,f);
+    static XMLCh Rule[] =           UNICODE_LITERAL_4(R,u,l,e);
+    static XMLCh RuleReference[] =  UNICODE_LITERAL_13(R,u,l,e,R,e,f,e,r,e,n,c,e);
+};
+
+OrMatchFunctor::OrMatchFunctor(const pair<const FilterPolicyContext*,const DOMElement*>& p)
+{
+    MatchFunctor* func;
+    const DOMElement* e = XMLHelper::getFirstChildElement(p.second);
+    while (e) {
+        func = NULL;
+        if (XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_MF_BASIC_NS, Rule)) {
+            func = buildFunctor(e, p.first);
+        }
+        else if (XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_MF_BASIC_NS, RuleReference)) {
+            auto_ptr_char ref(e->getAttributeNS(NULL, _ref));
+            if (ref.get() && *ref.get()) {
+                multimap<string,MatchFunctor*>::const_iterator rule = p.first->getMatchFunctors().find(ref.get());
+                func = (rule!=p.first->getMatchFunctors().end()) ? rule->second : NULL;
+            }
+        }
+
+        if (func)
+            m_functors.push_back(func);
+
+        e = XMLHelper::getNextSiblingElement(e);
+    }
+}
+
+MatchFunctor* OrMatchFunctor::buildFunctor(const DOMElement* e, const FilterPolicyContext* functorMap)
+{
+    // We'll track and map IDs just for consistency, but don't require them or worry about dups.
+    auto_ptr_char temp(e->getAttributeNS(NULL,_id));
+    const char* id = (temp.get() && *temp.get()) ? temp.get() : "";
+    if (*id && functorMap->getMatchFunctors().count(id))
+        id = "";
+
+    auto_ptr<QName> type(XMLHelper::getXSIType(e));
+    if (!type.get())
+        throw ConfigurationException("Child Rule found with no xsi:type.");
+
+    MatchFunctor* func = SPConfig::getConfig().MatchFunctorManager.newPlugin(*type.get(), make_pair(functorMap,e));
+    functorMap->getMatchFunctors().insert(make_pair(id, func));
+    return func;
+}
index 3b8fe52..8184431 100644 (file)
@@ -25,7 +25,7 @@
 #include "ServiceProvider.h"
 #include "attribute/Attribute.h"
 #include "attribute/filtering/AttributeFilter.h"
-#include "attribute/filtering/MatchFunctor.h"
+#include "attribute/filtering/FilterPolicyContext.h"
 #include "util/SPConstants.h"
 
 #include <xmltooling/util/NDC.h>
@@ -74,9 +74,9 @@ namespace shibsp {
 
     private:
         MatchFunctor* buildFunctor(
-            const DOMElement* e, multimap<string,MatchFunctor*>& functorMap, const char* logname, bool standalone
+            const DOMElement* e, const FilterPolicyContext& functorMap, const char* logname, bool standalone
             );
-        pair<string,const MatchFunctor*> buildAttributeRule(const DOMElement* e, bool standalone);
+        pair<string,const MatchFunctor*> buildAttributeRule(const DOMElement* e, const FilterPolicyContext& functorMap, bool standalone);
 
         Category& m_log;
         DOMDocument* m_document;
@@ -138,22 +138,25 @@ XMLFilterImpl::XMLFilterImpl(const DOMElement* e, Category& log) : m_log(log), m
     if (!XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeFilterPolicyGroup))
         throw ConfigurationException("XML AttributeFilter requires afp:AttributeFilterPolicyGroup at root of configuration.");
 
+    FilterPolicyContext reqFunctors(m_policyReqRules);
+    FilterPolicyContext valFunctors(m_permitValRules);
+
     DOMElement* child = XMLHelper::getFirstChildElement(e);
     while (child) {
         if (XMLHelper::isNodeNamed(child, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PolicyRequirementRule)) {
-            buildFunctor(child, m_policyReqRules, "PolicyRequirementRule", true);
+            buildFunctor(child, reqFunctors, "PolicyRequirementRule", true);
         }
         else if (XMLHelper::isNodeNamed(child, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PermitValueRule)) {
-            buildFunctor(child, m_permitValRules, "PermitValueRule", true);
+            buildFunctor(child, valFunctors, "PermitValueRule", true);
         }
         else if (XMLHelper::isNodeNamed(child, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeRule)) {
-            buildAttributeRule(child, true);
+            buildAttributeRule(child, valFunctors, true);
         }
         else if (XMLHelper::isNodeNamed(child, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeFilterPolicy)) {
             e = XMLHelper::getFirstChildElement(child);
-            MatchFunctor* func;
+            MatchFunctor* func = NULL;
             if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PolicyRequirementRule)) {
-                func = buildFunctor(e, m_policyReqRules, "PolicyRequirementRule", false);
+                func = buildFunctor(e, reqFunctors, "PolicyRequirementRule", false);
             }
             else if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PolicyRequirementRuleReference)) {
                 auto_ptr_char ref(e->getAttributeNS(NULL, _ref));
@@ -168,7 +171,7 @@ XMLFilterImpl::XMLFilterImpl(const DOMElement* e, Category& log) : m_log(log), m
                 e = XMLHelper::getNextSiblingElement(e);
                 while (e) {
                     if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeRule)) {
-                        pair<string,const MatchFunctor*> rule = buildAttributeRule(e, false);
+                        pair<string,const MatchFunctor*> rule = buildAttributeRule(e, valFunctors, false);
                         if (rule.second)
                             m_policies.back().m_rules.insert(rule);
                     }
@@ -194,7 +197,7 @@ XMLFilterImpl::XMLFilterImpl(const DOMElement* e, Category& log) : m_log(log), m
 }
 
 MatchFunctor* XMLFilterImpl::buildFunctor(
-    const DOMElement* e, multimap<string,MatchFunctor*>& functorMap, const char* logname, bool standalone
+    const DOMElement* e, const FilterPolicyContext& functorMap, const char* logname, bool standalone
     )
 {
     auto_ptr_char temp(e->getAttributeNS(NULL,_id));
@@ -204,7 +207,7 @@ MatchFunctor* XMLFilterImpl::buildFunctor(
         m_log.warn("skipping stand-alone %s with no id", logname);
         return NULL;
     }
-    else if (*id && functorMap.count(id)) {
+    else if (*id && functorMap.getMatchFunctors().count(id)) {
         if (standalone) {
             m_log.warn("skipping duplicate stand-alone %s with id (%s)", logname, id);
             return NULL;
@@ -216,8 +219,8 @@ MatchFunctor* XMLFilterImpl::buildFunctor(
     auto_ptr<QName> type(XMLHelper::getXSIType(e));
     if (type.get()) {
         try {
-            MatchFunctor* func = SPConfig::getConfig().MatchFunctorManager.newPlugin(*type.get(), e);
-            functorMap.insert(make_pair(id, func));
+            MatchFunctor* func = SPConfig::getConfig().MatchFunctorManager.newPlugin(*type.get(), make_pair(&functorMap,e));
+            functorMap.getMatchFunctors().insert(make_pair(id, func));
             return func;
         }
         catch (exception& ex) {
@@ -232,7 +235,7 @@ MatchFunctor* XMLFilterImpl::buildFunctor(
     return NULL;
 }
 
-pair<string,const MatchFunctor*> XMLFilterImpl::buildAttributeRule(const DOMElement* e, bool standalone)
+pair<string,const MatchFunctor*> XMLFilterImpl::buildAttributeRule(const DOMElement* e, const FilterPolicyContext& functorMap, bool standalone)
 {
     auto_ptr_char temp(e->getAttributeNS(NULL,_id));
     const char* id = (temp.get() && *temp.get()) ? temp.get() : "";
@@ -257,7 +260,7 @@ pair<string,const MatchFunctor*> XMLFilterImpl::buildAttributeRule(const DOMElem
     e = XMLHelper::getFirstChildElement(e);
     MatchFunctor* func=NULL;
     if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PermitValueRule)) {
-        func = buildFunctor(e, m_permitValRules, "PermitValueRule", false);
+        func = buildFunctor(e, functorMap, "PermitValueRule", false);
     }
     else if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PermitValueRuleReference)) {
         auto_ptr_char ref(e->getAttributeNS(NULL, _ref));
@@ -280,16 +283,16 @@ pair<string,const MatchFunctor*> XMLFilterImpl::buildAttributeRule(const DOMElem
 
 void XMLFilterImpl::filterAttributes(const FilteringContext& context, multimap<string,Attribute*>& attributes) const
 {
-    auto_ptr_char issuer(context.getAttributeIssuer());\r
-\r
-    m_log.debug("filtering %lu attribute(s) from (%s)", attributes.size(), issuer.get() ? issuer.get() : "unknown source");\r
-\r
-    if (m_policies.empty()) {\r
-        m_log.warn("no filter policies were loaded, filtering out all attributes from (%s)", issuer.get() ? issuer.get() : "unknown source");\r
-        for_each(attributes.begin(), attributes.end(), cleanup_pair<string,Attribute>());\r
-        attributes.clear();\r
-        return;\r
-    }\r
+    auto_ptr_char issuer(context.getAttributeIssuer());
+
+    m_log.debug("filtering %lu attribute(s) from (%s)", attributes.size(), issuer.get() ? issuer.get() : "unknown source");
+
+    if (m_policies.empty()) {
+        m_log.warn("no filter policies were loaded, filtering out all attributes from (%s)", issuer.get() ? issuer.get() : "unknown source");
+        for_each(attributes.begin(), attributes.end(), cleanup_pair<string,Attribute>());
+        attributes.clear();
+        return;
+    }
 
     size_t count,index;
 
@@ -301,24 +304,31 @@ void XMLFilterImpl::filterAttributes(const FilteringContext& context, multimap<s
                 pair<Policy::rules_t::const_iterator,Policy::rules_t::const_iterator> rules = p->m_rules.equal_range(a->second->getId());
                 if (rules.first == rules.second) {
                     // No rule found, so we're filtering it out.
-                    m_log.warn(\r
-                        "no rule found, filtering out values of attribute (%s) from (%s)", a->second->getId(), issuer.get() ? issuer.get() : "unknown source"\r
-                        );\r
-                    multimap<string,Attribute*>::iterator dead = a++;\r
-                    delete dead->second;\r
-                    attributes.erase(dead);\r
+                    m_log.warn(
+                        "no rule found, filtering out values of attribute (%s) from (%s)", a->second->getId(), issuer.get() ? issuer.get() : "unknown source"
+                        );
+                    multimap<string,Attribute*>::iterator dead = a++;
+                    delete dead->second;
+                    attributes.erase(dead);
                 }
                 else {
                     // Run each rule in sequence.
-                    m_log.debug("filtering values of attribute (%s) from (%s)", a->second->getId(), issuer.get() ? issuer.get() : "unknown source");\r
+                    m_log.debug("filtering values of attribute (%s) from (%s)", a->second->getId(), issuer.get() ? issuer.get() : "unknown source");
                     for (; rules.first!=rules.second; ++rules.first) {
                         count = a->second->valueCount();
                         for (index=0; index < count;) {
                             // The return value tells us whether to index past the accepted value, or stay put and decrement the count.
-                            if (rules.first->second->evaluatePermitValue(context, *(a->second), index))
+                            if (rules.first->second->evaluatePermitValue(context, *(a->second), index)) {
                                 index++;
-                            else
+                            }
+                            else {
+                                m_log.warn(
+                                    "filtered value at position (%lu) of attribute (%s) from (%s)",
+                                    index, a->second->getId(), issuer.get() ? issuer.get() : "unknown source"
+                                    );
+                                a->second->removeValue(index);
                                 count--;
+                            }
                         }
                     }
                     // See if any values are left, delete if not.
@@ -326,9 +336,9 @@ void XMLFilterImpl::filterAttributes(const FilteringContext& context, multimap<s
                         ++a;
                     }
                     else {
-                        multimap<string,Attribute*>::iterator dead = a++;\r
-                        delete dead->second;\r
-                        attributes.erase(dead);\r
+                        multimap<string,Attribute*>::iterator dead = a++;
+                        delete dead->second;
+                        attributes.erase(dead);
                     }
                 }
             }
index 74398a7..f551daf 100644 (file)
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath=".\attribute\filtering\impl\AndMatchFunctor.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\attribute\filtering\impl\AnyMatchFunctor.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\Application.cpp"\r
                                >\r
                        </File>\r
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath=".\attribute\filtering\impl\NotMatchFunctor.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\attribute\filtering\impl\OrMatchFunctor.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\ServiceProvider.cpp"\r
                                >\r
                        </File>\r
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath=".\attribute\filtering\FilterPolicyContext.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\internal.h"\r
                                >\r
                        </File>\r
index 890e6b0..48d991c 100644 (file)
@@ -62,6 +62,20 @@ const XMLCh shibspconstants::SHIB2ATTRIBUTEFILTER_NS[] = // urn:mace:shibboleth:
   chDigit_2, chPeriod, chDigit_0, chColon, chLatin_a, chLatin_f, chLatin_p, chNull\r
 };\r
 \r
+const XMLCh shibspconstants::SHIB2ATTRIBUTEFILTER_MF_BASIC_NS[] = // urn:mace:shibboleth:2.0:afp:mf:basic\r
+{ chLatin_u, chLatin_r, chLatin_n, chColon, chLatin_m, chLatin_a, chLatin_c, chLatin_e, chColon,\r
+  chLatin_s, chLatin_h, chLatin_i, chLatin_b, chLatin_b, chLatin_o, chLatin_l, chLatin_e, chLatin_t, chLatin_h, chColon,\r
+  chDigit_2, chPeriod, chDigit_0, chColon, chLatin_a, chLatin_f, chLatin_p, chColon, chLatin_m, chLatin_f, chColon,\r
+  chLatin_b, chLatin_a, chLatin_s, chLatin_i, chLatin_c, chNull\r
+};\r
+\r
+const XMLCh shibspconstants::SHIB2ATTRIBUTEFILTER_MF_SAML_NS[] = // urn:mace:shibboleth:2.0:afp:mf:saml\r
+{ chLatin_u, chLatin_r, chLatin_n, chColon, chLatin_m, chLatin_a, chLatin_c, chLatin_e, chColon,\r
+  chLatin_s, chLatin_h, chLatin_i, chLatin_b, chLatin_b, chLatin_o, chLatin_l, chLatin_e, chLatin_t, chLatin_h, chColon,\r
+  chDigit_2, chPeriod, chDigit_0, chColon, chLatin_a, chLatin_f, chLatin_p, chColon, chLatin_m, chLatin_f, chColon,\r
+  chLatin_s, chLatin_a, chLatin_m, chLatin_l, chNull\r
+};\r
+\r
 const XMLCh shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI[] = // urn:mace:shibboleth:1.0:attributeNamespace:uri\r
 { chLatin_u, chLatin_r, chLatin_n, chColon, chLatin_m, chLatin_a, chLatin_c, chLatin_e, chColon,\r
   chLatin_s, chLatin_h, chLatin_i, chLatin_b, chLatin_b, chLatin_o, chLatin_l, chLatin_e, chLatin_t, chLatin_h, chColon,\r
index 00cd146..be5eda2 100644 (file)
@@ -46,6 +46,12 @@ namespace shibspconstants {
     /** Shibboleth 2.0 attribute filter policy namespace ("urn:mace:shibboleth:2.0:afp") */
     extern SHIBSP_API const XMLCh SHIB2ATTRIBUTEFILTER_NS[];
 
+    /** Shibboleth 2.0 basic matching function namespace ("urn:mace:shibboleth:2.0:afp:mf:basic") */
+    extern SHIBSP_API const XMLCh SHIB2ATTRIBUTEFILTER_MF_BASIC_NS[];
+
+    /** Shibboleth 2.0 SAML matching function namespace ("urn:mace:shibboleth:2.0:afp:mf:saml") */
+    extern SHIBSP_API const XMLCh SHIB2ATTRIBUTEFILTER_MF_SAML_NS[];
+
     /** Shibboleth 1.x Protocol Enumeration constant ("urn:mace:shibboleth:1.0") */
     extern SHIBSP_API const XMLCh SHIB1_PROTOCOL_ENUM[];