Auto-wrap chained Application plugins, relax order child elements, add some logging.
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Fri, 20 Aug 2010 19:21:24 +0000 (19:21 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Fri, 20 Aug 2010 19:21:24 +0000 (19:21 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/branches/REL_2@3302 cb58f699-b61c-0410-a6fe-9272a202ed29

configs/example-shibboleth2.xml
configs/shibboleth2.xml
configs/win-shibboleth2.xml
schemas/shibboleth-2.0-native-sp-config.xsd
shibsp/attribute/filtering/impl/ChainingAttributeFilter.cpp
shibsp/attribute/resolver/impl/ChainingAttributeExtractor.cpp
shibsp/attribute/resolver/impl/ChainingAttributeResolver.cpp
shibsp/impl/XMLServiceProvider.cpp

index 69f2821..0dc0da9 100644 (file)
         <RelyingParty Name="SpecialFederation" keyName="SpecialKey"/>\r
         -->\r
 \r
-        <!-- Chains together all your metadata sources. -->\r
-        <MetadataProvider type="Chaining">\r
-            <!-- Example of remotely supplied batch of signed metadata. -->\r
-            <!--\r
-            <MetadataProvider type="XML" uri="http://federation.org/federation-metadata.xml"\r
-                 backingFilePath="federation-metadata.xml" reloadInterval="7200">\r
-               <MetadataFilter type="RequireValidUntil" maxValidityInterval="2419200"/>\r
-               <MetadataFilter type="Signature" certificate="fedsigner.pem"/>\r
-            </MetadataProvider>\r
-            -->\r
-\r
-            <!-- Example of locally maintained metadata. -->\r
-            <!--\r
-            <MetadataProvider type="XML" file="partner-metadata.xml"/>\r
-            -->\r
+        <!-- Example of remotely supplied batch of signed metadata. -->\r
+        <!--\r
+        <MetadataProvider type="XML" uri="http://federation.org/federation-metadata.xml"\r
+              backingFilePath="federation-metadata.xml" reloadInterval="7200">\r
+            <MetadataFilter type="RequireValidUntil" maxValidityInterval="2419200"/>\r
+            <MetadataFilter type="Signature" certificate="fedsigner.pem"/>\r
         </MetadataProvider>\r
+        -->\r
+\r
+        <!-- Example of locally maintained metadata. -->\r
+        <!--\r
+        <MetadataProvider type="XML" file="partner-metadata.xml"/>\r
+        -->\r
 \r
-        <!-- Chain the two built-in trust engines together. -->\r
-        <TrustEngine type="Chaining">\r
-            <TrustEngine type="ExplicitKey"/>\r
-            <TrustEngine type="PKIX"/>\r
-        </TrustEngine>\r
+        <!-- TrustEngines run in order to evaluate peer keys and certificates. -->\r
+        <TrustEngine type="ExplicitKey"/>\r
+        <TrustEngine type="PKIX"/>\r
 \r
         <!-- Map to extract attributes from SAML assertions. -->\r
         <AttributeExtractor type="XML" validate="true" path="attribute-map.xml"/>\r
index f33e05b..6d6eb7d 100644 (file)
             logoLocation="/shibboleth-sp/logo.jpg"
             styleSheet="/shibboleth-sp/main.css"/>
         
-        <!-- Chains together all your metadata sources. -->
-        <MetadataProvider type="Chaining">
-            <!-- Example of remotely supplied batch of signed metadata. -->
-            <!--
-            <MetadataProvider type="XML" uri="http://federation.org/federation-metadata.xml"
-                 backingFilePath="federation-metadata.xml" reloadInterval="7200">
-               <MetadataFilter type="RequireValidUntil" maxValidityInterval="2419200"/>
-               <MetadataFilter type="Signature" certificate="fedsigner.pem"/>
-            </MetadataProvider>
-            -->
-
-            <!-- Example of locally maintained metadata. -->
-            <!--
-            <MetadataProvider type="XML" file="partner-metadata.xml"/>
-            -->
+        <!-- Example of remotely supplied batch of signed metadata. -->
+        <!--
+        <MetadataProvider type="XML" uri="http://federation.org/federation-metadata.xml"
+              backingFilePath="federation-metadata.xml" reloadInterval="7200">
+            <MetadataFilter type="RequireValidUntil" maxValidityInterval="2419200"/>
+            <MetadataFilter type="Signature" certificate="fedsigner.pem"/>
         </MetadataProvider>
+        -->
+
+        <!-- Example of locally maintained metadata. -->
+        <!--
+        <MetadataProvider type="XML" file="partner-metadata.xml"/>
+        -->
 
         <!-- Map to extract attributes from SAML assertions. -->
         <AttributeExtractor type="XML" validate="true" path="attribute-map.xml"/>
index 23e9fcb..1a9a9b5 100644 (file)
             logoLocation="/shibboleth-sp/logo.jpg"\r
             styleSheet="/shibboleth-sp/main.css"/>\r
         \r
-        <!-- Chains together all your metadata sources. -->\r
-        <MetadataProvider type="Chaining">\r
-            <!-- Example of remotely supplied batch of signed metadata. -->\r
-            <!--\r
-            <MetadataProvider type="XML" uri="http://federation.org/federation-metadata.xml"\r
-                 backingFilePath="federation-metadata.xml" reloadInterval="7200">\r
-               <MetadataFilter type="RequireValidUntil" maxValidityInterval="2419200"/>\r
-               <MetadataFilter type="Signature" certificate="fedsigner.pem"/>\r
-            </MetadataProvider>\r
-            -->\r
-\r
-            <!-- Example of locally maintained metadata. -->\r
-            <!--\r
-            <MetadataProvider type="XML" file="partner-metadata.xml"/>\r
-            -->\r
+        <!-- Example of remotely supplied batch of signed metadata. -->\r
+        <!--\r
+        <MetadataProvider type="XML" uri="http://federation.org/federation-metadata.xml"\r
+              backingFilePath="federation-metadata.xml" reloadInterval="7200">\r
+            <MetadataFilter type="RequireValidUntil" maxValidityInterval="2419200"/>\r
+            <MetadataFilter type="Signature" certificate="fedsigner.pem"/>\r
         </MetadataProvider>\r
+        -->\r
+\r
+        <!-- Example of locally maintained metadata. -->\r
+        <!--\r
+        <MetadataProvider type="XML" file="partner-metadata.xml"/>\r
+        -->\r
 \r
         <!-- Map to extract attributes from SAML assertions. -->\r
         <AttributeExtractor type="XML" validate="true" path="attribute-map.xml"/>\r
index b49f37b..f7b3758 100644 (file)
     <sequence>
       <element name="Sessions" type="conf:SessionsType"/>
       <element name="Errors" type="conf:ErrorsType" minOccurs="0"/>
-      <element name="RelyingParty" type="conf:RelyingPartyType" minOccurs="0" maxOccurs="unbounded"/>
-      <element name="Notify" type="conf:NotifyType" minOccurs="0" maxOccurs="unbounded"/>
-      <element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>
-      <element name="MetadataProvider" type="conf:PluggableType"/>
-      <element name="TrustEngine" type="conf:PluggableType" minOccurs="0"/>
-      <element name="AttributeExtractor" type="conf:PluggableType" minOccurs="0"/>
-      <element name="AttributeResolver" type="conf:PluggableType" minOccurs="0"/>
-      <element name="AttributeFilter" type="conf:PluggableType" minOccurs="0"/>
-      <element name="CredentialResolver" type="conf:PluggableType" minOccurs="0"/>
-      <element name="ApplicationOverride" type="conf:ApplicationOverrideType" minOccurs="0" maxOccurs="unbounded"/>
+      <choice minOccurs="0" maxOccurs="unbounded">
+        <element name="RelyingParty" type="conf:RelyingPartyType"/>
+        <element name="Notify" type="conf:NotifyType"/>
+        <element ref="saml:Audience"/>
+        <element name="MetadataProvider" type="conf:PluggableType"/>
+        <element name="TrustEngine" type="conf:PluggableType"/>
+        <element name="AttributeExtractor" type="conf:PluggableType"/>
+        <element name="AttributeResolver" type="conf:PluggableType"/>
+        <element name="AttributeFilter" type="conf:PluggableType"/>
+        <element name="CredentialResolver" type="conf:PluggableType"/>
+        <element name="ApplicationOverride" type="conf:ApplicationOverrideType"/>
+      </choice>
     </sequence>
     <attribute name="id" type="conf:string" fixed="default"/>
     <attribute name="entityID" type="anyURI" use="required"/>
     <sequence>
       <element name="Sessions" type="conf:SessionsType" minOccurs="0"/>
       <element name="Errors" type="conf:ErrorsType" minOccurs="0"/>
-      <element name="RelyingParty" type="conf:RelyingPartyType" minOccurs="0" maxOccurs="unbounded"/>
-      <element name="Notify" type="conf:NotifyType" minOccurs="0" maxOccurs="unbounded"/>
-      <element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>
-      <element name="MetadataProvider" type="conf:PluggableType" minOccurs="0"/>
-      <element name="TrustEngine" type="conf:PluggableType" minOccurs="0"/>
-      <element name="AttributeExtractor" type="conf:PluggableType" minOccurs="0"/>
-      <element name="AttributeResolver" type="conf:PluggableType" minOccurs="0"/>
-      <element name="AttributeFilter" type="conf:PluggableType" minOccurs="0"/>
-      <element name="CredentialResolver" type="conf:PluggableType" minOccurs="0"/>
+      <choice minOccurs="0" maxOccurs="unbounded">
+        <element name="RelyingParty" type="conf:RelyingPartyType"/>
+        <element name="Notify" type="conf:NotifyType"/>
+        <element ref="saml:Audience"/>
+        <element name="MetadataProvider" type="conf:PluggableType"/>
+        <element name="TrustEngine" type="conf:PluggableType"/>
+        <element name="AttributeExtractor" type="conf:PluggableType"/>
+        <element name="AttributeResolver" type="conf:PluggableType"/>
+        <element name="AttributeFilter" type="conf:PluggableType"/>
+        <element name="CredentialResolver" type="conf:PluggableType"/>
+      </choice>
     </sequence>
     <attribute name="id" type="conf:string" use="required"/>
     <attribute name="entityID" type="anyURI"/>
index d0023b7..ee4201e 100644 (file)
@@ -77,10 +77,13 @@ ChainingAttributeFilter::ChainingAttributeFilter(const DOMElement* e)
         string t(XMLHelper::getAttrString(e, nullptr, _type));
         if (!t.empty()) {
             try {
+                Category::getInstance(SHIBSP_LOGCAT".AttributeFilter.Chaining").info(
+                    "building AttributeFilter of type (%s)...", t.c_str()
+                    );
                 m_filters.push_back(conf.AttributeFilterManager.newPlugin(t.c_str(), e));
             }
             catch (exception& ex) {
-                Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").error(
+                Category::getInstance(SHIBSP_LOGCAT".AttributeFilter.Chaining").error(
                     "caught exception processing embedded AttributeFilter element: %s", ex.what()
                     );
             }
index 986bf39..c0f5983 100644 (file)
@@ -106,6 +106,9 @@ ChainingAttributeExtractor::ChainingAttributeExtractor(const DOMElement* e)
         string t(XMLHelper::getAttrString(e, nullptr, _type));
         if (!t.empty()) {
             try {
+                Category::getInstance(SHIBSP_LOGCAT".AttributeExtractor.Chaining").info(
+                    "building AttributeExtractor of type (%s)...", t.c_str()
+                    );
                 m_extractors.push_back(conf.AttributeExtractorManager.newPlugin(t.c_str(), e));
             }
             catch (exception& ex) {
index 6718113..fa268cf 100644 (file)
@@ -176,6 +176,9 @@ ChainingAttributeResolver::ChainingAttributeResolver(const DOMElement* e)
         string t(XMLHelper::getAttrString(e, nullptr, _type));
         if (!t.empty()) {
             try {
+                Category::getInstance(SHIBSP_LOGCAT".AttributeResolver.Chaining").info(
+                    "building AttributeResolver of type (%s)...", t.c_str()
+                    );
                 m_resolvers.push_back(conf.AttributeResolverManager.newPlugin(t.c_str(), e));
             }
             catch (exception& ex) {
index 5ae535f..2c31593 100644 (file)
@@ -197,6 +197,14 @@ namespace {
         acceptNode(const DOMNode* node) const;
 
     private:
+        template <class T> T* doChainedPlugins(
+            PluginManager<T,string,const DOMElement*>& pluginMgr,
+            const char* pluginType,
+            const char* chainingType,
+            const XMLCh* localName,
+            const DOMElement* e,
+            Category& log
+            );
         void doAttributeInfo();
         void doHandlers(const ProtocolProvider*, const DOMElement*, Category&);
         void doSSO(const ProtocolProvider&, set<string>&, DOMElement*, Category&);
@@ -531,7 +539,6 @@ XMLApplication::XMLApplication(
 
         SPConfig& conf=SPConfig::getConfig();
 #ifndef SHIBSP_LITE
-        SAMLConfig& samlConf=SAMLConfig::getConfig();
         XMLToolingConfig& xmlConf=XMLToolingConfig::getConfig();
 #endif
 
@@ -573,49 +580,31 @@ XMLApplication::XMLApplication(
                     m_audiences.push_back(nlist->item(i)->getFirstChild()->getNodeValue());
         }
 
-        const DOMElement* child;
-
         if (conf.isEnabled(SPConfig::Metadata)) {
-            child = XMLHelper::getFirstChildElement(e, _MetadataProvider);
-            if (child) {
-                string t(XMLHelper::getAttrString(child, nullptr, _type));
-                try {
-                    if (!t.empty()) {
-                        log.info("building MetadataProvider of type %s...", t.c_str());
-                        auto_ptr<MetadataProvider> mp(samlConf.MetadataProviderManager.newPlugin(t.c_str(), child));
-                        mp->init();
-                        m_metadata = mp.release();
-                    }
-                    else {
-                        throw ConfigurationException("MetadataProvider element had no type attribute.");
-                    }
+            auto_ptr<MetadataProvider> mp(
+                doChainedPlugins(
+                    SAMLConfig::getConfig().MetadataProviderManager, "MetadataProvider", CHAINING_METADATA_PROVIDER, _MetadataProvider, e, log
+                    )
+                );
+            try {
+                if (mp.get()) {
+                    mp->init();
+                    m_metadata = mp.release();
                 }
-                catch (exception& ex) {
-                    log.crit("error building/initializing MetadataProvider: %s", ex.what());
+                else if (!m_base) {
+                    log.crit("no MetadataProvider available, configuration is probably unusable");
                 }
             }
+            catch (exception& ex) {
+                log.crit("error initializing MetadataProvider: %s", ex.what());
+            }
         }
 
         if (conf.isEnabled(SPConfig::Trust)) {
-            child = XMLHelper::getFirstChildElement(e, _TrustEngine);
-            if (child) {
-                string t(XMLHelper::getAttrString(child, nullptr, _type));
-                try {
-                    if (!t.empty()) {
-                        log.info("building TrustEngine of type %s...", t.c_str());
-                        m_trust = xmlConf.TrustEngineManager.newPlugin(t.c_str(), child);
-                    }
-                    else {
-                        throw ConfigurationException("TrustEngine element had no type attribute.");
-                    }
-                }
-                catch (exception& ex) {
-                    log.crit("error building TrustEngine: %s", ex.what());
-                }
-            }
-            else if (!m_base) {
+            m_trust = doChainedPlugins(xmlConf.TrustEngineManager, "TrustEngine", CHAINING_TRUSTENGINE, _TrustEngine, e, log);
+            if (!m_trust && !m_base) {
                 log.info(
-                    "no TrustEngine specified, using default chain {%s, %s}",
+                    "no TrustEngine specified or installed, using default chain {%s, %s}",
                     EXPLICIT_KEY_TRUSTENGINE, SHIBBOLETH_PKIX_TRUSTENGINE
                     );
                 m_trust = xmlConf.TrustEngineManager.newPlugin(CHAINING_TRUSTENGINE, nullptr);
@@ -631,21 +620,13 @@ XMLApplication::XMLApplication(
             doAttributePlugins(e, log);
 
         if (conf.isEnabled(SPConfig::Credentials)) {
-            child = XMLHelper::getFirstChildElement(e,_CredentialResolver);
-            if (child) {
-                auto_ptr_char type(child->getAttributeNS(nullptr,_type));
-                log.info("building CredentialResolver of type %s...",type.get());
-                try {
-                    m_credResolver = xmlConf.CredentialResolverManager.newPlugin(type.get(),child);
-                }
-                catch (exception& ex) {
-                    log.crit("error building CredentialResolver: %s", ex.what());
-                }
-            }
+            m_credResolver = doChainedPlugins(
+                xmlConf.CredentialResolverManager, "CredentialResolver", CHAINING_CREDENTIAL_RESOLVER, _CredentialResolver, e, log
+                );
         }
 
         // Finally, load relying parties.
-        child = XMLHelper::getFirstChildElement(e, RelyingParty);
+        const DOMElement* child = XMLHelper::getFirstChildElement(e, RelyingParty);
         while (child) {
             if (child->hasAttributeNS(nullptr, saml2::Attribute::NAME_ATTRIB_NAME)) {
                 auto_ptr<DOMPropertySet> rp(new DOMPropertySet());
@@ -695,6 +676,51 @@ XMLApplication::XMLApplication(
 #endif
 }
 
+template <class T> T* XMLApplication::doChainedPlugins(
+    PluginManager<T,string,const DOMElement*>& pluginMgr,
+    const char* pluginType,
+    const char* chainingType,
+    const XMLCh* localName,
+    const DOMElement* e,
+    Category& log
+    )
+{
+    string t;
+    DOMElement* child = XMLHelper::getFirstChildElement(e, localName);
+    if (child) {
+        // Check for multiple.
+        if (XMLHelper::getNextSiblingElement(child, localName)) {
+            log.info("multiple %s plugins, wrapping in a chain", pluginType);
+            DOMElement* chain = child->getOwnerDocument()->createElementNS(nullptr, localName);
+            while (child) {
+                chain->appendChild(child);
+                child = XMLHelper::getFirstChildElement(e, localName);
+            }
+            t = chainingType;
+            child = chain;
+        }
+        else {
+            // Only a single one.
+            t = XMLHelper::getAttrString(child, nullptr, _type);
+        }
+
+        try {
+            if (!t.empty()) {
+                log.info("building %s of type %s...", pluginType, t.c_str());
+                return pluginMgr.newPlugin(t.c_str(), child);
+            }
+            else {
+                throw ConfigurationException("$1 element had no type attribute.", params(1, pluginType));
+            }
+        }
+        catch (exception& ex) {
+            log.crit("error building %s: %s", pluginType, ex.what());
+        }
+    }
+
+    return nullptr;
+}
+
 void XMLApplication::doAttributeInfo()
 {
     // Populate prefix pair.
@@ -1279,56 +1305,14 @@ void XMLApplication::doAttributePlugins(const DOMElement* e, Category& log)
 {
     SPConfig& conf = SPConfig::getConfig();
 
-    DOMElement* child = XMLHelper::getFirstChildElement(e, _AttributeExtractor);
-    if (child) {
-        string t(XMLHelper::getAttrString(child, nullptr, _type));
-        try {
-            if (!t.empty()) {
-                log.info("building AttributeExtractor of type %s...", t.c_str());
-                m_attrExtractor = conf.AttributeExtractorManager.newPlugin(t.c_str(), child);
-            }
-            else {
-                throw ConfigurationException("AttributeExtractor element had no type attribute.");
-            }
-        }
-        catch (exception& ex) {
-            log.crit("error building AttributeExtractor: %s", ex.what());
-        }
-    }
+    m_attrExtractor =
+        doChainedPlugins(conf.AttributeExtractorManager, "AttributeExtractor", CHAINING_ATTRIBUTE_EXTRACTOR, _AttributeExtractor, e, log);
 
-    child = XMLHelper::getFirstChildElement(e, _AttributeFilter);
-    if (child) {
-        string t(XMLHelper::getAttrString(child, nullptr, _type));
-        try {
-            if (!t.empty()) {
-                log.info("building AttributeFilter of type %s...", t.c_str());
-                m_attrFilter = conf.AttributeFilterManager.newPlugin(t.c_str(), child);
-            }
-            else {
-                throw ConfigurationException("AttributeFilter element had no type attribute.");
-            }
-        }
-        catch (exception& ex) {
-            log.crit("error building AttributeFilter: %s", ex.what());
-        }
-    }
+    m_attrFilter =
+        doChainedPlugins(conf.AttributeFilterManager, "AttributeFilter", CHAINING_ATTRIBUTE_FILTER, _AttributeFilter, e, log);
 
-    child = XMLHelper::getFirstChildElement(e, _AttributeResolver);
-    if (child) {
-        string t(XMLHelper::getAttrString(child, nullptr, _type));
-        try {
-            if (!t.empty()) {
-                log.info("building AttributeResolver of type %s...", t.c_str());
-                m_attrResolver = conf.AttributeResolverManager.newPlugin(t.c_str(), child);
-            }
-            else {
-                throw ConfigurationException("AttributeResolver element had no type attribute.");
-            }
-        }
-        catch (exception& ex) {
-            log.crit("error building AttributeResolver: %s", ex.what());
-        }
-    }
+    m_attrResolver =
+        doChainedPlugins(conf.AttributeResolverManager, "AttributeResolver", CHAINING_ATTRIBUTE_RESOLVER, _AttributeResolver, e, log);
 
     if (m_unsetHeaders.empty()) {
         vector<string> unsetHeaders;