Add log4shib version to remaining version strings.
[shibboleth/sp.git] / shibsp / impl / XMLServiceProvider.cpp
index 5ae535f..3179637 100644 (file)
@@ -107,7 +107,7 @@ namespace {
     class SHIBSP_DLLLOCAL XMLApplication : public Application, public Remoted, public DOMPropertySet, public DOMNodeFilter
     {
     public:
-        XMLApplication(const ServiceProvider*, const ProtocolProvider*, const DOMElement*, const XMLApplication* base=nullptr);
+        XMLApplication(const ServiceProvider*, const ProtocolProvider*, DOMElement*, const XMLApplication* base=nullptr);
         ~XMLApplication() { cleanup(); }
 
         const char* getHash() const {return m_hash.c_str();}
@@ -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,
+            DOMElement* e,
+            Category& log
+            );
         void doAttributeInfo();
         void doHandlers(const ProtocolProvider*, const DOMElement*, Category&);
         void doSSO(const ProtocolProvider&, set<string>&, DOMElement*, Category&);
@@ -208,7 +216,7 @@ namespace {
         string m_hash;
         std::pair<std::string,std::string> m_attributePrefix;
 #ifndef SHIBSP_LITE
-        void doAttributePlugins(const DOMElement* e, Category& log);
+        void doAttributePlugins(DOMElement* e, Category& log);
         MetadataProvider* m_metadata;
         TrustEngine* m_trust;
         AttributeExtractor* m_attrExtractor;
@@ -508,7 +516,7 @@ namespace shibsp {
 XMLApplication::XMLApplication(
     const ServiceProvider* sp,
     const ProtocolProvider* pp,
-    const DOMElement* e,
+    DOMElement* e,
     const XMLApplication* base
     ) : Application(sp), m_base(base),
 #ifndef SHIBSP_LITE
@@ -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,52 @@ XMLApplication::XMLApplication(
 #endif
 }
 
+template <class T> T* XMLApplication::doChainedPlugins(
+    PluginManager<T,string,const DOMElement*>& pluginMgr,
+    const char* pluginType,
+    const char* chainingType,
+    const XMLCh* localName,
+    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;
+            e->appendChild(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.
@@ -1275,60 +1302,18 @@ void XMLApplication::doArtifactResolution(const ProtocolProvider& pp, const char
 }
 
 #ifndef SHIBSP_LITE
-void XMLApplication::doAttributePlugins(const DOMElement* e, Category& log)
+void XMLApplication::doAttributePlugins(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;
@@ -1747,11 +1732,11 @@ void XMLConfigImpl::doCaching(const DOMElement* e, Category& log)
 #ifndef SHIBSP_LITE
     SAMLConfig& samlConf = SAMLConfig::getConfig();
 #endif
-    XMLToolingConfig& xmlConf = XMLToolingConfig::getConfig();
 
     DOMElement* child;
 #ifndef SHIBSP_LITE
     if (conf.isEnabled(SPConfig::OutOfProcess)) {
+        XMLToolingConfig& xmlConf = XMLToolingConfig::getConfig();
         // First build any StorageServices.
         child = XMLHelper::getFirstChildElement(e, _StorageService);
         while (child) {
@@ -1853,9 +1838,6 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o
 
     try {
         SPConfig& conf=SPConfig::getConfig();
-#ifndef SHIBSP_LITE
-        SAMLConfig& samlConf=SAMLConfig::getConfig();
-#endif
         XMLToolingConfig& xmlConf=XMLToolingConfig::getConfig();
         const DOMElement* SHAR=XMLHelper::getFirstChildElement(e, OutOfProcess);
         const DOMElement* SHIRE=XMLHelper::getFirstChildElement(e, InProcess);
@@ -1894,12 +1876,26 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o
         log.info("Shibboleth SP Version %s", PACKAGE_VERSION);
 #ifndef SHIBSP_LITE
         log.info(
-            "Library versions: Xerces-C %s, XML-Security-C %s, XMLTooling-C %s, OpenSAML-C %s, Shibboleth %s",
+            "Library versions: %s %s, Xerces-C %s, XML-Security-C %s, XMLTooling-C %s, OpenSAML-C %s, Shibboleth %s",
+# if defined(LOG4SHIB_VERSION)
+        "log4shib", LOG4SHIB_VERSION,
+# elif defined(LOG4CPP_VERSION)
+        "log4cpp", LOG4CPP_VERSION,
+# else
+        "", "",
+# endif
             XERCES_FULLVERSIONDOT, XSEC_FULLVERSIONDOT, XMLTOOLING_FULLVERSIONDOT, OPENSAML_FULLVERSIONDOT, SHIBSP_FULLVERSIONDOT
             );
 #else
         log.info(
-            "Library versions: Xerces-C %s, XMLTooling-C %s, Shibboleth %s",
+            "Library versions: %s %s, Xerces-C %s, XMLTooling-C %s, Shibboleth %s",
+# if defined(LOG4SHIB_VERSION)
+        "log4shib", LOG4SHIB_VERSION,
+# elif defined(LOG4CPP_VERSION)
+        "log4cpp", LOG4CPP_VERSION,
+# else
+        "", "",
+# endif
             XERCES_FULLVERSIONDOT, XMLTOOLING_FULLVERSIONDOT, SHIBSP_FULLVERSIONDOT
             );
 #endif
@@ -2002,20 +1998,22 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o
         }
 
         if (first) {
-#ifdef SHIBSP_XMLSEC_WHITELISTING
-            vector<xstring>::const_iterator alg;
             if (!m_policy->getAlgorithmBlacklist().empty()) {
-                for (alg = m_policy->getAlgorithmBlacklist().begin(); alg != m_policy->getAlgorithmBlacklist().end(); ++alg)
+#ifdef SHIBSP_XMLSEC_WHITELISTING
+                for (vector<xstring>::const_iterator alg = m_policy->getAlgorithmBlacklist().begin(); alg != m_policy->getAlgorithmBlacklist().end(); ++alg)
                     XSECPlatformUtils::blacklistAlgorithm(alg->c_str());
+#else
+                log.crit("XML-Security-C library prior to 1.6.0 does not support algorithm white/blacklists");
+#endif
             }
             else if (!m_policy->getAlgorithmWhitelist().empty()) {
-                for (alg = m_policy->getAlgorithmWhitelist().begin(); alg != m_policy->getAlgorithmWhitelist().end(); ++alg)
+#ifdef SHIBSP_XMLSEC_WHITELISTING
+                for (vector<xstring>::const_iterator alg = m_policy->getAlgorithmWhitelist().begin(); alg != m_policy->getAlgorithmWhitelist().end(); ++alg)
                     XSECPlatformUtils::whitelistAlgorithm(alg->c_str());
-            }
 #else
-            log.fatal("XML-Security-C library prior to 1.6.0 does not support algorithm white/blacklists");
-            throw ConfigurationException("XML-Security-C library prior to 1.6.0 does not support algorithm white/blacklists.");
+                log.crit("XML-Security-C library prior to 1.6.0 does not support algorithm white/blacklists");
 #endif
+            }
         }
 
         // Process TransportOption elements.