Attribute filtering code.
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Sun, 6 May 2007 23:44:32 +0000 (23:44 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Sun, 6 May 2007 23:44:32 +0000 (23:44 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@2232 cb58f699-b61c-0410-a6fe-9272a202ed29

21 files changed:
.cdtproject
schemas/shibboleth-2.0-afp.xsd
shibsp/Application.h
shibsp/Makefile.am
shibsp/SPConfig.cpp
shibsp/SPConfig.h
shibsp/attribute/filtering/AttributeFilter.h [new file with mode: 0644]
shibsp/attribute/filtering/BasicFilteringContext.h [new file with mode: 0644]
shibsp/attribute/filtering/FilteringContext.h [new file with mode: 0644]
shibsp/attribute/filtering/MatchFunctor.h [new file with mode: 0644]
shibsp/attribute/filtering/impl/AttributeFilter.cpp [new file with mode: 0644]
shibsp/attribute/filtering/impl/ChainingAttributeFilter.cpp [new file with mode: 0644]
shibsp/attribute/filtering/impl/MatchFunctor.cpp [new file with mode: 0644]
shibsp/attribute/filtering/impl/XMLAttributeFilter.cpp [new file with mode: 0644]
shibsp/attribute/resolver/impl/QueryAttributeResolver.cpp
shibsp/handler/impl/SAML1Consumer.cpp
shibsp/handler/impl/SAML2Consumer.cpp
shibsp/impl/XMLServiceProvider.cpp
shibsp/shibsp.vcproj
shibsp/util/SPConstants.cpp
shibsp/util/SPConstants.h

index 10a5b0a..78aae40 100644 (file)
@@ -8,8 +8,10 @@
         
     <item id="org.eclipse.cdt.core.pathentry">
 <pathentry kind="out" path=""/>
-<pathentry excluding="util/|impl/|security/|metadata/|remoting/|remoting/impl/|attribute/|binding/|binding/impl/|attribute/resolver/|attribute/resolver/impl/|handler/|handler/impl/" kind="src" path="shibsp"/>
-<pathentry excluding="resolver/|resolver/impl/" kind="src" path="shibsp/attribute"/>
+<pathentry excluding="util/|impl/|security/|metadata/|remoting/|remoting/impl/|attribute/|binding/|binding/impl/|attribute/resolver/|attribute/resolver/impl/|handler/|handler/impl/|attribute/filtering/|attribute/filtering/impl/" kind="src" path="shibsp"/>
+<pathentry excluding="resolver/|resolver/impl/|filtering/|filtering/impl/" kind="src" path="shibsp/attribute"/>
+<pathentry excluding="impl/" kind="src" path="shibsp/attribute/filtering"/>
+<pathentry kind="src" path="shibsp/attribute/filtering/impl"/>
 <pathentry excluding="impl/" kind="src" path="shibsp/attribute/resolver"/>
 <pathentry kind="src" path="shibsp/attribute/resolver/impl"/>
 <pathentry excluding="impl/" kind="src" path="shibsp/binding"/>
index 9d3ad12..857729e 100644 (file)
@@ -18,7 +18,7 @@
     </element>
     <complexType name="AttributeFilterPolicyGroupType">
         <complexContent>
-            <extension base="afp:IndentityType">
+            <extension base="afp:IdentityType">
                 <sequence>
                     <element ref="afp:PolicyRequirementRule" minOccurs="0" maxOccurs="unbounded">
                         <annotation>
                             </documentation>
                         </annotation>
                     </element>
-                    <element ref="afp:AttributeRule" minOccurs="0" maxOccurs="unbounded">
+                    <element ref="afp:PermitValueRule" minOccurs="0" maxOccurs="unbounded">
                         <annotation>
                             <documentation>
-                                Defines an attribute rule that may be reused across multiple filter policies.
+                                Defines an attribute value filter that may be reused across multiple attribute rules.
                             </documentation>
                         </annotation>
-                    </element>
-                    <element ref="afp:PermitValueRule" minOccurs="0" maxOccurs="unbounded">
+                    </element>\r
+                    <element ref="afp:AttributeRule" minOccurs="0" maxOccurs="unbounded">
                         <annotation>
                             <documentation>
-                                Defines an attribute value filter that may be reused across multiple attribtue rules.
+                                Defines an attribute rule that may be reused across multiple filter policies.
                             </documentation>
                         </annotation>
-                    </element>\r
+                    </element>
                     <element ref="afp:AttributeFilterPolicy" minOccurs="0" maxOccurs="unbounded">
                         <annotation>
                             <documentation>
@@ -73,7 +73,7 @@
     </element>
     <complexType name="AttributeFilterPolicyType">
         <complexContent>
-            <extension base="afp:IndentityType">
+            <extension base="afp:IdentityType">
                 <sequence>
                     <choice>
                         <element ref="afp:PolicyRequirementRule">
     </element>\r
     <complexType name="AttributeRuleType">
         <complexContent>
-            <extension base="afp:IndentityType">
+            <extension base="afp:IdentityType">
                 <choice>
                     <element ref="afp:PermitValueRule">
                         <annotation>
     </element>
     <complexType name="MatchFunctorType" abstract="true">
         <complexContent>
-            <extension base="afp:IndentityType" />
+            <extension base="afp:IdentityType" />
         </complexContent>
     </complexType>
 
-    <complexType name="IndentityType">
+    <complexType name="IdentityType">
         <attribute name="id" type="string">
             <annotation>
                 <documentation>An ID, unique within the policy and component type.</documentation>
index 1ad17bd..a60d5b8 100644 (file)
@@ -31,6 +31,7 @@
 namespace shibsp {
     
     class SHIBSP_API AttributeExtractor;
+    class SHIBSP_API AttributeFilter;
     class SHIBSP_API AttributeResolver;
     class SHIBSP_API Handler;
     class SHIBSP_API ServiceProvider;
@@ -101,6 +102,13 @@ namespace shibsp {
         virtual AttributeExtractor* getAttributeExtractor() const=0;
 
         /**
+         * Returns an AttributeFilter for use with this Application.
+         * 
+         * @return  an AttributeFilter, or NULL
+         */
+        virtual AttributeFilter* getAttributeFilter() const=0;
+
+        /**
          * Returns an AttributeResolver for use with this Application.
          * 
          * @return  an AttributeResolver, or NULL
index 5795bef..61b152d 100644 (file)
@@ -45,6 +45,12 @@ attrinclude_HEADERS = \
        attribute/ScopedAttribute.h \
        attribute/SimpleAttribute.h
 
+attrfiltinclude_HEADERS = \
+       attribute/filtering/AttributeFilter.h \
+       attribute/filtering/BasicFilteringContext.h \
+       attribute/filtering/FilteringContext.h \
+       attribute/filtering/MatchFunctor.h
+
 attrresinclude_HEADERS = \
        attribute/resolver/AttributeExtractor.h \
        attribute/resolver/AttributeResolver.h \
@@ -92,6 +98,10 @@ libshibsp_la_SOURCES = \
        attribute/NameIDAttributeDecoder.cpp \
        attribute/ScopedAttributeDecoder.cpp \
        attribute/StringAttributeDecoder.cpp \
+       attribute/filtering/AttributeFilter.cpp \
+       attribute/filtering/ChainingAttributeFilter.cpp \
+       attribute/filtering/MatchFunctor.cpp \
+       attribute/filtering/XMLAttributeFilter.cpp \
        attribute/resolver/impl/ChainingAttributeResolver.cpp \
        attribute/resolver/impl/QueryAttributeResolver.cpp \
        attribute/resolver/impl/XMLAttributeExtractor.cpp \
index e01a617..ff26b4a 100644 (file)
@@ -29,6 +29,8 @@
 #include "SessionCache.h"
 #include "SPConfig.h"
 #include "attribute/AttributeDecoder.h"
+#include "attribute/filtering/AttributeFilter.h"
+#include "attribute/filtering/MatchFunctor.h"
 #include "attribute/resolver/AttributeExtractor.h"
 #include "attribute/resolver/AttributeResolver.h"
 #include "binding/ArtifactResolver.h"
@@ -108,21 +110,35 @@ bool SPInternalConfig::init(const char* catalog_path)
     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(ConfigurationException,shibsp);
     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(ListenerException,shibsp);
     
-    registerMetadataExtClasses();
-    registerPKIXTrustEngine();
+    if (isEnabled(Metadata))
+        registerMetadataExtClasses();
+    if (isEnabled(Trust))
+        registerPKIXTrustEngine();
 
-    registerAccessControls();
-    registerAttributeDecoders();
-    registerAttributeExtractors();
     registerAttributeFactories();
-    registerAttributeResolvers();
     registerHandlers();
     registerSessionInitiators();
-    registerListenerServices();
-    registerRequestMappers();
-    registerSessionCaches();
     registerServiceProviders();
 
+    if (isEnabled(AttributeResolution)) {
+        registerAttributeDecoders();
+        registerAttributeExtractors();
+        registerAttributeFilters();
+        registerAttributeResolvers();
+        registerMatchFunctors();
+    }
+
+    if (isEnabled(Listener))
+        registerListenerServices();
+
+    if (isEnabled(RequestMapping)) {
+        registerAccessControls();
+        registerRequestMappers();
+    }
+
+    if (isEnabled(Caching))
+        registerSessionCaches();
+
     if (isEnabled(OutOfProcess))
         m_artifactResolver = new ArtifactResolver();
     
@@ -145,17 +161,28 @@ void SPInternalConfig::term()
     ManageNameIDServiceManager.deregisterFactories();
     SessionInitiatorManager.deregisterFactories();
     SingleLogoutServiceManager.deregisterFactories();
-    
-    ServiceProviderManager.deregisterFactories();
-    SessionCacheManager.deregisterFactories();
-    RequestMapperManager.deregisterFactories();
-    ListenerServiceManager.deregisterFactories();
     HandlerManager.deregisterFactories();
-    AttributeDecoderManager.deregisterFactories();
-    AttributeExtractorManager.deregisterFactories();
-    AttributeResolverManager.deregisterFactories();
+    ServiceProviderManager.deregisterFactories();
     Attribute::deregisterFactories();
-    AccessControlManager.deregisterFactories();
+
+    if (isEnabled(AttributeResolution)) {
+        MatchFunctorManager.deregisterFactories();
+        AttributeDecoderManager.deregisterFactories();
+        AttributeFilterManager.deregisterFactories();
+        AttributeExtractorManager.deregisterFactories();
+        AttributeResolverManager.deregisterFactories();
+    }
+
+    if (isEnabled(Listener))
+        ListenerServiceManager.deregisterFactories();
+
+    if (isEnabled(RequestMapping)) {
+        AccessControlManager.deregisterFactories();
+        RequestMapperManager.deregisterFactories();
+    }
+
+    if (isEnabled(Caching))
+        SessionCacheManager.deregisterFactories();
 
     SAMLConfig::getConfig().term();
     log.info("library shutdown complete");
index 4abaaa5..4e62b8c 100644 (file)
@@ -37,9 +37,11 @@ namespace shibsp {
     class SHIBSP_API AccessControl;
     class SHIBSP_API AttributeDecoder;
     class SHIBSP_API AttributeExtractor;
+    class SHIBSP_API AttributeFilter;
     class SHIBSP_API AttributeResolver;
     class SHIBSP_API Handler;
     class SHIBSP_API ListenerService;
+    class SHIBSP_API MatchFunctor;
     class SHIBSP_API RequestMapper;
     class SHIBSP_API ServiceProvider;
     class SHIBSP_API SessionCache;
@@ -179,6 +181,11 @@ namespace shibsp {
         xmltooling::PluginManager<AttributeExtractor,std::string,const xercesc::DOMElement*> AttributeExtractorManager;
 
         /**
+         * Manages factories for AttributeFilter plugins.
+         */
+        xmltooling::PluginManager<AttributeFilter,std::string,const xercesc::DOMElement*> AttributeFilterManager;
+
+        /**
          * Manages factories for AttributeResolver plugins.
          */
         xmltooling::PluginManager<AttributeResolver,std::string,const xercesc::DOMElement*> AttributeResolverManager;
@@ -199,6 +206,11 @@ namespace shibsp {
         xmltooling::PluginManager<ListenerService,std::string,const xercesc::DOMElement*> ListenerServiceManager;
 
         /**
+         * Manages factories for MatchFunctor plugins.
+         */
+        xmltooling::PluginManager<MatchFunctor,xmltooling::QName,const xercesc::DOMElement*> MatchFunctorManager;
+
+        /**
          * Manages factories for Handler plugins that implement ManageNameIDService functionality.
          */
         xmltooling::PluginManager< Handler,std::string,std::pair<const xercesc::DOMElement*,const char*> > ManageNameIDServiceManager;
diff --git a/shibsp/attribute/filtering/AttributeFilter.h b/shibsp/attribute/filtering/AttributeFilter.h
new file mode 100644 (file)
index 0000000..7eeb63d
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  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/AttributeFilter.h
+ * 
+ * Engine for filtering attribute values.
+ */
+
+#ifndef __shibsp_attrfilt_h__
+#define __shibsp_attrfilt_h__
+
+#include <shibsp/attribute/filtering/FilteringContext.h>
+
+#include <xmltooling/Lockable.h>
+
+namespace shibsp {
+
+    /**
+     * Engine for filtering attribute values.
+     */
+    class SHIBSP_API AttributeFilter : public virtual xmltooling::Lockable
+    {
+        MAKE_NONCOPYABLE(AttributeFilter);
+    protected:
+        AttributeFilter() {}
+    public:
+        virtual ~AttributeFilter() {}
+
+        /**
+         * Filters values out of a set of attributes.
+         * 
+         * @param context       a FilteringContext interface
+         * @param attributes    a mutable map containing the attributes to filter
+         * 
+         * @throws AttributeFileringException thrown if there is a problem filtering attributes
+         */
+        virtual void filterAttributes(const FilteringContext& context, std::multimap<std::string,Attribute*>& attributes) const=0;
+    };
+
+    /**
+     * Registers AttributeFilter classes into the runtime.
+     */
+    void SHIBSP_API registerAttributeFilters();
+
+    /** AttributeFilter based on an XML mapping schema. */
+    #define XML_ATTRIBUTE_FILTER "XML"
+
+    /** AttributeFilter based on chaining together other filters. */
+    #define CHAINING_ATTRIBUTE_FILTER "Chaining"
+};
+
+#endif /* __shibsp_attrfilt_h__ */
diff --git a/shibsp/attribute/filtering/BasicFilteringContext.h b/shibsp/attribute/filtering/BasicFilteringContext.h
new file mode 100644 (file)
index 0000000..c671b4e
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  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/BasicFilteringContext.h
+ * 
+ * A trivial FilteringContext implementation.
+ */
+
+#ifndef __shibsp_basicfiltctx_h__
+#define __shibsp_basicfiltctx_h__
+
+#include <shibsp/attribute/filtering/FilteringContext.h>
+
+namespace shibsp {
+
+    class SHIBSP_API BasicFilteringContext : public FilteringContext
+    {
+    public:
+        /**
+         * Constructor.
+         *
+         * @param app   reference to Application
+         * @param role  metadata role of attribute issuer, if any
+         */
+        BasicFilteringContext(const Application& app, const opensaml::saml2md::RoleDescriptor* role)
+                : m_app(app), m_role(role), m_issuer(NULL) {
+            if (role)
+                m_issuer = dynamic_cast<opensaml::saml2md::EntityDescriptor*>(role->getParent())->getEntityID();
+        }
+
+        virtual ~BasicFilteringContext() {}
+
+        const Application& getApplication() const {
+            return m_app;
+        }
+        const XMLCh* getAttributeRequester() const {
+            return m_app.getXMLString("entityID").second;
+        }
+        const XMLCh* getAttributeIssuer() const {
+            return m_issuer;
+        }
+        const opensaml::saml2md::RoleDescriptor* getAttributeRequesterMetadata() const {
+            return NULL;
+        }
+        const opensaml::saml2md::RoleDescriptor* getAttributeIssuerMetadata() const {
+            return m_role;
+        }
+
+    private:
+        const Application& m_app;
+        const opensaml::saml2md::RoleDescriptor* m_role;
+        const XMLCh* m_issuer;
+    };
+};
+
+#endif /* __shibsp_basicfiltctx_h__ */
diff --git a/shibsp/attribute/filtering/FilteringContext.h b/shibsp/attribute/filtering/FilteringContext.h
new file mode 100644 (file)
index 0000000..34e29cd
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *  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/FilteringContext.h
+ * 
+ * Context for attribute filtering operations.
+ */
+
+#ifndef __shibsp_filtctx_h__
+#define __shibsp_filtctx_h__
+
+#include <shibsp/base.h>
+
+#include <saml/saml2/metadata/Metadata.h>
+
+namespace shibsp {
+
+    class SHIBSP_API Application;
+    class SHIBSP_API Attribute;
+
+    /**
+     * Context for attribute filtering operations.
+     */
+    class SHIBSP_API FilteringContext
+    {
+        MAKE_NONCOPYABLE(FilteringContext);
+    protected:
+        FilteringContext() {}
+    public:
+        virtual ~FilteringContext() {}
+
+        /**
+         * Gets the Application doing the filtering.
+         *
+         * @return  reference to an Application
+         */
+        virtual const Application& getApplication() const=0;
+
+        /**
+         * Gets the ID of the requester of the attributes, if known.
+         * 
+         * @return requester of the attributes, or NULL
+         */
+        virtual const XMLCh* getAttributeRequester() const=0;
+        
+        /**
+         * Gets the ID of the issuer of the attributes, if known.
+         * 
+         * @return ID of the issuer of the attributes, or NULL
+         */
+        virtual const XMLCh* getAttributeIssuer() const=0;
+
+        /**
+         * Gets the SAML metadata for the attribute requesting role, if available.
+         * 
+         * @return SAML metadata for the attribute requesting role, or NULL
+         */
+        virtual const opensaml::saml2md::RoleDescriptor* getAttributeRequesterMetadata() const=0;
+        
+        /**
+         * Gets the SAML metadata for the attribute issuing role, if available.
+         * 
+         * @return SAML metadata for the attribute issuing role, or NULL
+         */
+        virtual const opensaml::saml2md::RoleDescriptor* getAttributeIssuerMetadata() const=0;
+    };
+};
+
+#endif /* __shibsp_filtctx_h__ */
diff --git a/shibsp/attribute/filtering/MatchFunctor.h b/shibsp/attribute/filtering/MatchFunctor.h
new file mode 100644 (file)
index 0000000..373aa01
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  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/MatchFunctor.h
+ * 
+ * A function that evaluates whether an expressed criteria is met by the current filter context.
+ */
+
+#ifndef __shibsp_matchfunc_h__
+#define __shibsp_matchfunc_h__
+
+#include <shibsp/base.h>
+
+namespace shibsp {
+
+    class SHIBSP_API Attribute;
+    class SHIBSP_API FilteringContext;
+
+    /**
+     * A function that evaluates whether an expressed criteria is met by the current filter context.
+     */
+    class SHIBSP_API MatchFunctor
+    {
+        MAKE_NONCOPYABLE(MatchFunctor);
+    protected:
+        MatchFunctor() {}
+    public:
+        virtual ~MatchFunctor() {}
+
+        /**\r
+         * Evaluates this matching criteria. This evaluation is used when a filtering engine determines policy\r
+         * applicability.\r
+         * \r
+         * @param filterContext current filtering context\r
+         * @return true if the criteria for this matching function are met\r
+         * @throws AttributeFilteringException thrown if the function can not be evaluated\r
+         */\r
+        virtual bool evaluatePolicyRequirement(const FilteringContext& filterContext) const=0;\r
+\r
+        /**\r
+         * Evaluates this matching criteria. This evaluation is used when a filtering engine is filtering attribute\r
+         * values.\r
+         * \r
+         * @param filterContext the current filtering context\r
+         * @param attribute     the attribute being evaluated\r
+         * @param index         the index of the attribute value being evaluated\r
+         * @return true if the criteria for this matching function are met\r
+         * @throws AttributeFilteringException thrown if the function can not be evaluated\r
+         */\r
+        virtual bool evaluatePermitValue(const FilteringContext& filterContext, const Attribute& attribute, size_t index) const=0;\r
+    };
+
+    /**
+     * Registers MatchFunctor classes into the runtime.
+     */
+    void SHIBSP_API registerMatchFunctors();
+};
+
+#endif /* __shibsp_matchfunc_h__ */
diff --git a/shibsp/attribute/filtering/impl/AttributeFilter.cpp b/shibsp/attribute/filtering/impl/AttributeFilter.cpp
new file mode 100644 (file)
index 0000000..ad21399
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  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.
+ */
+
+/**
+ * AttributeFilter.cpp
+ * 
+ * Engine for filtering attribute values.
+ */
+
+#include "internal.h"
+#include "attribute/filtering/AttributeFilter.h"
+
+using namespace shibsp;
+using namespace xmltooling;
+using namespace std;
+
+namespace shibsp {
+    SHIBSP_DLLLOCAL PluginManager<AttributeFilter,string,const DOMElement*>::Factory XMLAttributeFilterFactory;
+    SHIBSP_DLLLOCAL PluginManager<AttributeFilter,string,const DOMElement*>::Factory ChainingAttributeFilterFactory;
+};
+
+void SHIBSP_API shibsp::registerAttributeFilters()
+{
+    SPConfig& conf = SPConfig::getConfig();
+    conf.AttributeFilterManager.registerFactory(XML_ATTRIBUTE_FILTER, XMLAttributeFilterFactory);
+    conf.AttributeFilterManager.registerFactory(CHAINING_ATTRIBUTE_FILTER, ChainingAttributeFilterFactory);
+}
diff --git a/shibsp/attribute/filtering/impl/ChainingAttributeFilter.cpp b/shibsp/attribute/filtering/impl/ChainingAttributeFilter.cpp
new file mode 100644 (file)
index 0000000..3069ffd
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *  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.
+ */
+
+/**
+ * ChainingAttributeFilter.cpp
+ * 
+ * Chains together multiple AttributeFilter plugins.
+ */
+
+#include "internal.h"
+#include "attribute/filtering/AttributeFilter.h"
+#include "attribute/filtering/FilteringContext.h"
+
+#include <log4cpp/Category.hh>
+#include <xercesc/util/XMLUniDefs.hpp>
+#include <xmltooling/util/XMLHelper.h>
+
+using namespace shibsp;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace shibsp {
+
+    class SHIBSP_DLLLOCAL ChainingAttributeFilter : public AttributeFilter
+    {
+    public:
+        ChainingAttributeFilter(const DOMElement* e);
+        virtual ~ChainingAttributeFilter() {
+            for_each(m_filters.begin(), m_filters.end(), xmltooling::cleanup<AttributeFilter>());
+        }
+        
+        Lockable* lock() {
+            return this;
+        }
+        void unlock() {
+        }
+        
+        void filterAttributes(const FilteringContext& context, multimap<string,Attribute*>& attributes) const {
+            for (vector<AttributeFilter*>::const_iterator i=m_filters.begin(); i!=m_filters.end(); ++i) {
+                Locker locker(*i);
+                (*i)->filterAttributes(context, attributes);
+            }
+        }
+
+    private:
+        vector<AttributeFilter*> m_filters;
+    };
+
+    static const XMLCh _AttributeFilter[] = UNICODE_LITERAL_15(A,t,t,r,i,b,u,t,e,F,i,l,t,e,r);
+    static const XMLCh _type[] =            UNICODE_LITERAL_4(t,y,p,e);
+
+    AttributeFilter* SHIBSP_DLLLOCAL ChainingAttributeFilterFactory(const DOMElement* const & e)
+    {
+        return new ChainingAttributeFilter(e);
+    }
+};
+
+ChainingAttributeFilter::ChainingAttributeFilter(const DOMElement* e)
+{
+    SPConfig& conf = SPConfig::getConfig();
+
+    // Load up the chain of handlers.
+    e = e ? XMLHelper::getFirstChildElement(e, _AttributeFilter) : NULL;
+    while (e) {
+        auto_ptr_char type(e->getAttributeNS(NULL,_type));
+        if (type.get() && *(type.get())) {
+            try {
+                m_filters.push_back(conf.AttributeFilterManager.newPlugin(type.get(),e));
+            }
+            catch (exception& ex) {
+                Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").error(
+                    "caught exception processing embedded AttributeFilter element: %s", ex.what()
+                    );
+            }
+        }
+        e = XMLHelper::getNextSiblingElement(e, _AttributeFilter);
+    }
+}
diff --git a/shibsp/attribute/filtering/impl/MatchFunctor.cpp b/shibsp/attribute/filtering/impl/MatchFunctor.cpp
new file mode 100644 (file)
index 0000000..2f81f89
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  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.
+ */
+
+/**
+ * MatchFunctor.cpp
+ * 
+ * A function that evaluates whether an expressed criteria is met by the current filter context.
+ */
+
+#include "internal.h"
+#include "attribute/filtering/MatchFunctor.h"
+
+using namespace shibsp;
+using namespace xmltooling;
+using namespace std;
+
+namespace shibsp {
+    //SHIBSP_DLLLOCAL PluginManager<MatchFunctor,QName,const DOMElement*>::Factory FunctorFactory;
+};
+
+void SHIBSP_API shibsp::registerMatchFunctors()
+{
+    SPConfig& conf = SPConfig::getConfig();
+    //conf.MatchFunctorManager.registerFactory("", FunctorFactory);
+}
diff --git a/shibsp/attribute/filtering/impl/XMLAttributeFilter.cpp b/shibsp/attribute/filtering/impl/XMLAttributeFilter.cpp
new file mode 100644 (file)
index 0000000..3b8fe52
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ *  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.
+ */
+
+/**
+ * XMLAttributeFilter.cpp
+ * 
+ * AttributeFilter based on an XML policy language.
+ */
+
+#include "internal.h"
+#include "Application.h"
+#include "ServiceProvider.h"
+#include "attribute/Attribute.h"
+#include "attribute/filtering/AttributeFilter.h"
+#include "attribute/filtering/MatchFunctor.h"
+#include "util/SPConstants.h"
+
+#include <xmltooling/util/NDC.h>
+#include <xmltooling/util/ReloadableXMLFile.h>
+#include <xmltooling/util/XMLHelper.h>
+#include <xercesc/util/XMLUniDefs.hpp>
+
+using namespace shibsp;
+using namespace opensaml::saml2md;
+using namespace opensaml;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace shibsp {
+
+#if defined (_MSC_VER)
+    #pragma warning( push )
+    #pragma warning( disable : 4250 )
+#endif
+
+    struct SHIBSP_DLLLOCAL Policy
+    {
+        Policy() : m_applies(NULL) {}
+        const MatchFunctor* m_applies;
+        typedef multimap<string,const MatchFunctor*> rules_t;
+        rules_t m_rules;
+    };
+
+    class SHIBSP_DLLLOCAL XMLFilterImpl
+    {
+    public:
+        XMLFilterImpl(const DOMElement* e, Category& log);
+        ~XMLFilterImpl() {
+            if (m_document)
+                m_document->release();
+            for_each(m_policyReqRules.begin(), m_policyReqRules.end(), cleanup_pair<string,MatchFunctor>());
+            for_each(m_permitValRules.begin(), m_permitValRules.end(), cleanup_pair<string,MatchFunctor>());
+        }
+
+        void setDocument(DOMDocument* doc) {
+            m_document = doc;
+        }
+
+        void filterAttributes(const FilteringContext& context, multimap<string,Attribute*>& attributes) const;
+
+    private:
+        MatchFunctor* buildFunctor(
+            const DOMElement* e, multimap<string,MatchFunctor*>& functorMap, const char* logname, bool standalone
+            );
+        pair<string,const MatchFunctor*> buildAttributeRule(const DOMElement* e, bool standalone);
+
+        Category& m_log;
+        DOMDocument* m_document;
+        vector<Policy> m_policies;
+        map< string,pair<string,const MatchFunctor*> > m_attrRules;
+        multimap<string,MatchFunctor*> m_policyReqRules;
+        multimap<string,MatchFunctor*> m_permitValRules;
+    };
+    
+    class SHIBSP_DLLLOCAL XMLFilter : public AttributeFilter, public ReloadableXMLFile
+    {
+    public:
+        XMLFilter(const DOMElement* e) : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT".AttributeFilter")), m_impl(NULL) {
+            load();
+        }
+        ~XMLFilter() {
+            delete m_impl;
+        }
+        
+        void filterAttributes(const FilteringContext& context, multimap<string,Attribute*>& attributes) const {
+            m_impl->filterAttributes(context, attributes);
+        }
+
+    protected:
+        pair<bool,DOMElement*> load();
+
+    private:
+        XMLFilterImpl* m_impl;
+    };
+
+#if defined (_MSC_VER)
+    #pragma warning( pop )
+#endif
+
+    AttributeFilter* SHIBSP_DLLLOCAL XMLAttributeFilterFactory(const DOMElement* const & e)
+    {
+        return new XMLFilter(e);
+    }
+    
+    static const XMLCh AttributeFilterPolicyGroup[] =   UNICODE_LITERAL_26(A,t,t,r,i,b,u,t,e,F,i,l,t,e,r,P,o,l,i,c,y,G,r,o,u,p);
+    static const XMLCh AttributeFilterPolicy[] =        UNICODE_LITERAL_21(A,t,t,r,i,b,u,t,e,F,i,l,t,e,r,P,o,l,i,c,y);
+    static const XMLCh AttributeRule[] =                UNICODE_LITERAL_13(A,t,t,r,i,b,u,t,e,R,u,l,e);
+    static const XMLCh AttributeRuleReference[] =       UNICODE_LITERAL_22(A,t,t,r,i,b,u,t,e,R,u,l,e,R,e,f,e,r,e,n,c,e);
+    static const XMLCh PermitValueRule[] =              UNICODE_LITERAL_15(P,e,r,m,i,t,V,a,l,u,e,R,u,l,e);
+    static const XMLCh PermitValueRuleReference[] =     UNICODE_LITERAL_24(P,e,r,m,i,t,V,a,l,u,e,R,u,l,e,R,e,f,e,r,e,n,c,e);
+    static const XMLCh PolicyRequirementRule[] =        UNICODE_LITERAL_21(P,o,l,i,c,y,R,e,q,u,i,r,e,m,e,n,t,R,u,l,e);
+    static const XMLCh PolicyRequirementRuleReference[]=UNICODE_LITERAL_30(P,o,l,i,c,y,R,e,q,u,i,r,e,m,e,n,t,R,u,l,e,R,e,f,e,r,e,n,c,e);
+    static const XMLCh attributeId[] =                  UNICODE_LITERAL_11(a,t,t,r,i,b,u,t,e,I,d);
+    static const XMLCh _id[] =                          UNICODE_LITERAL_2(i,d);
+    static const XMLCh _ref[] =                         UNICODE_LITERAL_3(r,e,f);
+};
+
+XMLFilterImpl::XMLFilterImpl(const DOMElement* e, Category& log) : m_log(log), m_document(NULL)
+{
+#ifdef _DEBUG
+    xmltooling::NDC ndc("XMLFilterImpl");
+#endif
+    
+    if (!XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeFilterPolicyGroup))
+        throw ConfigurationException("XML AttributeFilter requires afp:AttributeFilterPolicyGroup at root of configuration.");
+
+    DOMElement* child = XMLHelper::getFirstChildElement(e);
+    while (child) {
+        if (XMLHelper::isNodeNamed(child, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PolicyRequirementRule)) {
+            buildFunctor(child, m_policyReqRules, "PolicyRequirementRule", true);
+        }
+        else if (XMLHelper::isNodeNamed(child, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PermitValueRule)) {
+            buildFunctor(child, m_permitValRules, "PermitValueRule", true);
+        }
+        else if (XMLHelper::isNodeNamed(child, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeRule)) {
+            buildAttributeRule(child, true);
+        }
+        else if (XMLHelper::isNodeNamed(child, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeFilterPolicy)) {
+            e = XMLHelper::getFirstChildElement(child);
+            MatchFunctor* func;
+            if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PolicyRequirementRule)) {
+                func = buildFunctor(e, m_policyReqRules, "PolicyRequirementRule", false);
+            }
+            else if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PolicyRequirementRuleReference)) {
+                auto_ptr_char ref(e->getAttributeNS(NULL, _ref));
+                if (ref.get() && *ref.get()) {
+                    multimap<string,MatchFunctor*>::const_iterator prr = m_policyReqRules.find(ref.get());
+                    func = (prr!=m_policyReqRules.end()) ? prr->second : NULL;
+                }
+            }
+            if (func) {
+                m_policies.push_back(Policy());
+                m_policies.back().m_applies = func;
+                e = XMLHelper::getNextSiblingElement(e);
+                while (e) {
+                    if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeRule)) {
+                        pair<string,const MatchFunctor*> rule = buildAttributeRule(e, false);
+                        if (rule.second)
+                            m_policies.back().m_rules.insert(rule);
+                    }
+                    else if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeRuleReference)) {
+                        auto_ptr_char ref(e->getAttributeNS(NULL, _ref));
+                        if (ref.get() && *ref.get()) {
+                            map< string,pair<string,const MatchFunctor*> >::const_iterator ar = m_attrRules.find(ref.get());
+                            if (ar != m_attrRules.end())
+                                m_policies.back().m_rules.insert(ar->second);
+                            else
+                                m_log.warn("skipping invalid AttributeRuleReference (%s)", ref.get());
+                        }
+                    }
+                    e = XMLHelper::getNextSiblingElement(e);
+                }
+            }
+            else {
+                m_log.warn("skipping AttributeFilterPolicy, PolicyRequirementRule invalid or missing");
+            }
+        }
+        child = XMLHelper::getNextSiblingElement(child);
+    }
+}
+
+MatchFunctor* XMLFilterImpl::buildFunctor(
+    const DOMElement* e, multimap<string,MatchFunctor*>& functorMap, const char* logname, bool standalone
+    )
+{
+    auto_ptr_char temp(e->getAttributeNS(NULL,_id));
+    const char* id = (temp.get() && *temp.get()) ? temp.get() : "";
+
+    if (standalone && !*id) {
+        m_log.warn("skipping stand-alone %s with no id", logname);
+        return NULL;
+    }
+    else if (*id && functorMap.count(id)) {
+        if (standalone) {
+            m_log.warn("skipping duplicate stand-alone %s with id (%s)", logname, id);
+            return NULL;
+        }
+        else
+            id = "";
+    }
+
+    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));
+            return func;
+        }
+        catch (exception& ex) {
+            m_log.error("error building %s with type (%s): %s", logname, type->toString().c_str(), ex.what());
+        }
+    }
+    else if (standalone)
+        m_log.warn("skipping stand-alone %s with no xsi:type", logname);
+    else
+        m_log.error("%s with no xsi:type", logname);
+
+    return NULL;
+}
+
+pair<string,const MatchFunctor*> XMLFilterImpl::buildAttributeRule(const DOMElement* e, bool standalone)
+{
+    auto_ptr_char temp(e->getAttributeNS(NULL,_id));
+    const char* id = (temp.get() && *temp.get()) ? temp.get() : "";
+
+    if (standalone && !*id) {
+        m_log.warn("skipping stand-alone AttributeRule with no id");
+        return make_pair(string(),(MatchFunctor*)NULL);
+    }
+    else if (*id && m_attrRules.count(id)) {
+        if (standalone) {
+            m_log.warn("skipping duplicate stand-alone AttributeRule with id (%s)", id);
+            return make_pair(string(),(MatchFunctor*)NULL);
+        }
+        else
+            id = "";
+    }
+
+    auto_ptr_char attrId(e->getAttributeNS(NULL,attributeId));
+    if (!attrId.get() || !*attrId.get())
+        m_log.warn("skipping AttributeRule with no attributeId");
+
+    e = XMLHelper::getFirstChildElement(e);
+    MatchFunctor* func=NULL;
+    if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PermitValueRule)) {
+        func = buildFunctor(e, m_permitValRules, "PermitValueRule", false);
+    }
+    else if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PermitValueRuleReference)) {
+        auto_ptr_char ref(e->getAttributeNS(NULL, _ref));
+        if (ref.get() && *ref.get()) {
+            multimap<string,MatchFunctor*>::const_iterator pvr = m_permitValRules.find(ref.get());
+            func = (pvr!=m_permitValRules.end()) ? pvr->second : NULL;
+        }
+    }
+
+    if (func) {
+        if (*id)
+            return m_attrRules[id] = make_pair(attrId.get(), func);
+        else
+            return make_pair(attrId.get(), func);
+    }
+
+    m_log.warn("skipping AttributeRule (%s), PermitValueRule invalid or missing", id);
+    return make_pair(string(),(MatchFunctor*)NULL);
+}
+
+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
+
+    size_t count,index;
+
+    // Test each Policy.
+    for (vector<Policy>::const_iterator p=m_policies.begin(); p!=m_policies.end(); ++p) {
+        if (p->m_applies->evaluatePolicyRequirement(context)) {
+            // Loop over the attributes and look for possible rules to run.
+            for (multimap<string,Attribute*>::iterator a=attributes.begin(); a!=attributes.end();) {
+                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
+                }
+                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
+                    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))
+                                index++;
+                            else
+                                count--;
+                        }
+                    }
+                    // See if any values are left, delete if not.
+                    if (count>0) {
+                        ++a;
+                    }
+                    else {
+                        multimap<string,Attribute*>::iterator dead = a++;\r
+                        delete dead->second;\r
+                        attributes.erase(dead);\r
+                    }
+                }
+            }
+        }
+    }
+}
+
+pair<bool,DOMElement*> XMLFilter::load()
+{
+    // Load from source using base class.
+    pair<bool,DOMElement*> raw = ReloadableXMLFile::load();
+    
+    // If we own it, wrap it.
+    XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL);
+
+    XMLFilterImpl* impl = new XMLFilterImpl(raw.second, m_log);
+    
+    // If we held the document, transfer it to the impl. If we didn't, it's a no-op.
+    impl->setDocument(docjanitor.release());
+
+    delete m_impl;
+    m_impl = impl;
+
+    return make_pair(false,(DOMElement*)NULL);
+}
index 33250ed..b873757 100644 (file)
@@ -25,6 +25,8 @@
 #include "ServiceProvider.h"
 #include "SessionCache.h"
 #include "attribute/Attribute.h"
+#include "attribute/filtering/AttributeFilter.h"
+#include "attribute/filtering/BasicFilteringContext.h"
 #include "attribute/resolver/AttributeExtractor.h"
 #include "attribute/resolver/AttributeResolver.h"
 #include "attribute/resolver/ResolutionContext.h"
@@ -321,9 +323,18 @@ bool QueryResolver::SAML1Query(QueryContext& ctx) const
             Locker extlocker(extractor);
             extractor->extractAttributes(ctx.getApplication(), AA, *newtoken, ctx.getResolvedAttributes());
         }
+
+        AttributeFilter* filter = ctx.getApplication().getAttributeFilter();
+        if (filter) {
+            BasicFilteringContext fc(ctx.getApplication(), AA);
+            Locker filtlocker(filter);
+            filter->filterAttributes(fc, ctx.getResolvedAttributes());
+        }
     }
     catch (exception& ex) {
         m_log.error("caught exception extracting/filtering attributes from query result: %s", ex.what());
+        for_each(ctx.getResolvedAttributes().begin(), ctx.getResolvedAttributes().end(), cleanup_pair<string,shibsp::Attribute>());
+        ctx.getResolvedAttributes().clear();
     }
 
     return true;
@@ -423,9 +434,18 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
             Locker extlocker(extractor);
             extractor->extractAttributes(ctx.getApplication(), AA, *newtoken, ctx.getResolvedAttributes());
         }
+
+        AttributeFilter* filter = ctx.getApplication().getAttributeFilter();
+        if (filter) {
+            BasicFilteringContext fc(ctx.getApplication(), AA);
+            Locker filtlocker(filter);
+            filter->filterAttributes(fc, ctx.getResolvedAttributes());
+        }
     }
     catch (exception& ex) {
         m_log.error("caught exception extracting/filtering attributes from query result: %s", ex.what());
+        for_each(ctx.getResolvedAttributes().begin(), ctx.getResolvedAttributes().end(), cleanup_pair<string,shibsp::Attribute>());
+        ctx.getResolvedAttributes().clear();
     }
 
     return true;
index c7caeb9..7ef4eb7 100644 (file)
@@ -26,6 +26,8 @@
 #include "ServiceProvider.h"
 #include "SessionCache.h"
 #include "attribute/Attribute.h"
+#include "attribute/filtering/AttributeFilter.h"
+#include "attribute/filtering/BasicFilteringContext.h"
 #include "attribute/resolver/AttributeExtractor.h"
 #include "attribute/resolver/ResolutionContext.h"
 #include "handler/AssertionConsumerService.h"
@@ -209,6 +211,21 @@ string SAML1Consumer::implementProtocol(
                 m_log.error("caught exception extracting attributes: %s", ex.what());
             }
         }
+
+        AttributeFilter* filter = application.getAttributeFilter();
+        if (filter && !resolvedAttributes.empty()) {
+            BasicFilteringContext fc(application, policy.getIssuerMetadata());
+            Locker filtlocker(filter);
+            try {
+                filter->filterAttributes(fc, resolvedAttributes);
+            }
+            catch (exception& ex) {
+                m_log.error("caught exception filtering attributes: %s", ex.what());
+                m_log.error("dumping extracted attributes due to filtering exception");
+                for_each(resolvedAttributes.begin(), resolvedAttributes.end(), cleanup_pair<string,shibsp::Attribute>());
+                resolvedAttributes.clear();
+            }
+        }
     }
 
     // First, normalize the SAML 1.x NameIdentifier...
index d1a0f27..fac1fc0 100644 (file)
@@ -26,6 +26,8 @@
 #include "ServiceProvider.h"
 #include "SessionCache.h"
 #include "attribute/Attribute.h"
+#include "attribute/filtering/AttributeFilter.h"
+#include "attribute/filtering/BasicFilteringContext.h"
 #include "attribute/resolver/AttributeExtractor.h"
 #include "attribute/resolver/ResolutionContext.h"
 #include "handler/AssertionConsumerService.h"
@@ -333,6 +335,21 @@ string SAML2Consumer::implementProtocol(
         }
     }
 
+    AttributeFilter* filter = application.getAttributeFilter();
+    if (filter && !resolvedAttributes.empty()) {
+        BasicFilteringContext fc(application, policy.getIssuerMetadata());
+        Locker filtlocker(filter);
+        try {
+            filter->filterAttributes(fc, resolvedAttributes);
+        }
+        catch (exception& ex) {
+            m_log.error("caught exception filtering attributes: %s", ex.what());
+            m_log.error("dumping extracted attributes due to filtering exception");
+            for_each(resolvedAttributes.begin(), resolvedAttributes.end(), cleanup_pair<string,shibsp::Attribute>());
+            resolvedAttributes.clear();
+        }
+    }
+
     try {
         const EntityDescriptor* issuerMetadata =
             policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL;
index 2d3fa74..d24a5d7 100644 (file)
@@ -30,6 +30,7 @@
 #include "SPConfig.h"\r
 #include "SPRequest.h"\r
 #include "TransactionLog.h"\r
+#include "attribute/filtering/AttributeFilter.h"\r
 #include "attribute/resolver/AttributeExtractor.h"\r
 #include "attribute/resolver/AttributeResolver.h"\r
 #include "handler/SessionInitiator.h"\r
@@ -90,6 +91,9 @@ namespace {
         AttributeExtractor* getAttributeExtractor() const {\r
             return (!m_attrExtractor && m_base) ? m_base->getAttributeExtractor() : m_attrExtractor;\r
         }\r
+        AttributeFilter* getAttributeFilter() const {\r
+            return (!m_attrFilter && m_base) ? m_base->getAttributeFilter() : m_attrFilter;\r
+        }\r
         AttributeResolver* getAttributeResolver() const {\r
             return (!m_attrResolver && m_base) ? m_base->getAttributeResolver() : m_attrResolver;\r
         }\r
@@ -120,6 +124,7 @@ namespace {
         MetadataProvider* m_metadata;\r
         TrustEngine* m_trust;\r
         AttributeExtractor* m_attrExtractor;\r
+        AttributeFilter* m_attrFilter;\r
         AttributeResolver* m_attrResolver;\r
         CredentialResolver* m_credResolver;\r
         vector<const XMLCh*> m_audiences;\r
@@ -341,7 +346,7 @@ XMLApplication::XMLApplication(
     const ServiceProvider* sp,\r
     const DOMElement* e,\r
     const XMLApplication* base\r
-    ) : m_sp(sp), m_base(base), m_metadata(NULL), m_trust(NULL), m_attrExtractor(NULL), m_attrResolver(NULL),\r
+    ) : m_sp(sp), m_base(base), m_metadata(NULL), m_trust(NULL), m_attrExtractor(NULL), m_attrFilter(NULL), m_attrResolver(NULL),\r
         m_credResolver(NULL), m_partyDefault(NULL), m_sessionInitDefault(NULL), m_acsDefault(NULL)\r
 {\r
 #ifdef _DEBUG\r
@@ -522,6 +527,18 @@ XMLApplication::XMLApplication(
                 }\r
             }\r
 \r
+            child = XMLHelper::getFirstChildElement(e,_AttributeFilter);\r
+            if (child) {\r
+                auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
+                log.info("building AttributeFilter of type %s...",type.get());\r
+                try {\r
+                    m_attrFilter = conf.AttributeFilterManager.newPlugin(type.get(),child);\r
+                }\r
+                catch (exception& ex) {\r
+                    log.crit("error building AttributeFilter: %s", ex.what());\r
+                }\r
+            }\r
+\r
             child = XMLHelper::getFirstChildElement(e,_AttributeResolver);\r
             if (child) {\r
                 auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
@@ -592,6 +609,7 @@ void XMLApplication::cleanup()
     for_each(m_handlers.begin(),m_handlers.end(),xmltooling::cleanup<Handler>());\r
     delete m_credResolver;\r
     delete m_attrResolver;\r
+    delete m_attrFilter;\r
     delete m_attrExtractor;\r
     delete m_trust;\r
     delete m_metadata;\r
index 8fc3389..74398a7 100644 (file)
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath=".\attribute\filtering\impl\AttributeFilter.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\attribute\filtering\impl\ChainingAttributeFilter.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\attribute\filtering\impl\MatchFunctor.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\ServiceProvider.cpp"\r
                                >\r
                        </File>\r
                                RelativePath=".\SPConfig.cpp"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\attribute\filtering\impl\XMLAttributeFilter.cpp"\r
+                               >\r
+                       </File>\r
                        <Filter\r
                                Name="util"\r
                                >\r
                                                </File>\r
                                        </Filter>\r
                                </Filter>\r
+                               <Filter\r
+                                       Name="filtering"\r
+                                       >\r
+                                       <Filter\r
+                                               Name="impl"\r
+                                               >\r
+                                       </Filter>\r
+                               </Filter>\r
                        </Filter>\r
                        <Filter\r
                                Name="binding"\r
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath=".\attribute\filtering\BasicFilteringContext.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\exceptions.h"\r
                                >\r
                        </File>\r
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath=".\attribute\filtering\MatchFunctor.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\RequestMapper.h"\r
                                >\r
                        </File>\r
                                                >\r
                                        </File>\r
                                </Filter>\r
+                               <Filter\r
+                                       Name="filtering"\r
+                                       >\r
+                                       <File\r
+                                               RelativePath=".\attribute\filtering\AttributeFilter.h"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
+                                               RelativePath=".\attribute\filtering\FilteringContext.h"\r
+                                               >\r
+                                       </File>\r
+                               </Filter>\r
                        </Filter>\r
                        <Filter\r
                                Name="binding"\r
index c069e02..890e6b0 100644 (file)
@@ -56,6 +56,12 @@ const XMLCh shibspconstants::SHIB2ATTRIBUTEMAP_NS[] = // urn:mace:shibboleth:2.0
   chLatin_m, chLatin_a, chLatin_p, chNull\r
 };\r
 \r
+const XMLCh shibspconstants::SHIB2ATTRIBUTEFILTER_NS[] = // urn:mace:shibboleth:2.0:afp\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, 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 d0e39ea..00cd146 100644 (file)
@@ -43,6 +43,9 @@ namespace shibspconstants {
     /** Shibboleth 2.0 attribute mapping namespace ("urn:mace:shibboleth:2.0:attribute-map") */
     extern SHIBSP_API const XMLCh SHIB2ATTRIBUTEMAP_NS[];
 
+    /** Shibboleth 2.0 attribute filter policy namespace ("urn:mace:shibboleth:2.0:afp") */
+    extern SHIBSP_API const XMLCh SHIB2ATTRIBUTEFILTER_NS[];
+
     /** Shibboleth 1.x Protocol Enumeration constant ("urn:mace:shibboleth:1.0") */
     extern SHIBSP_API const XMLCh SHIB1_PROTOCOL_ENUM[];