+ // Look for "shorthand" elements first.
+ set<string> protocols;
+ DOMElement* child = sessions ? XMLHelper::getFirstChildElement(sessions->getElement()) : nullptr;
+ while (child) {
+ if (XMLHelper::isNodeNamed(child, shibspconstants::SHIB2SPCONFIG_NS, SSO)) {
+ if (pp)
+ doSSO(*pp, protocols, child, log);
+ else
+ log.error("no ProtocolProvider, SSO auto-configure unsupported");
+ }
+ else if (XMLHelper::isNodeNamed(child, shibspconstants::SHIB2SPCONFIG_NS, Logout)) {
+ if (pp)
+ doLogout(*pp, protocols, child, log);
+ else
+ log.error("no ProtocolProvider, Logout auto-configure unsupported");
+ }
+ else if (XMLHelper::isNodeNamed(child, shibspconstants::SHIB2SPCONFIG_NS, NameIDMgmt)) {
+ if (pp)
+ doNameIDMgmt(*pp, protocols, child, log);
+ else
+ log.error("no ProtocolProvider, NameIDMgmt auto-configure unsupported");
+ }
+ else {
+ break; // drop into next while loop
+ }
+ child = XMLHelper::getNextSiblingElement(child);
+ }
+
+ // Process other handlers.
+ bool hardACS=false, hardSessionInit=false, hardArt=false;
+ while (child) {
+ if (!child->hasAttributeNS(nullptr, Location)) {
+ auto_ptr_char hclass(child->getLocalName());
+ log.error("%s handler with no Location property cannot be processed", hclass.get());
+ child = XMLHelper::getNextSiblingElement(child);
+ continue;
+ }
+ try {
+ if (XMLString::equals(child->getLocalName(), _AssertionConsumerService)) {
+ string bindprop(XMLHelper::getAttrString(child, nullptr, Binding));
+ if (bindprop.empty()) {
+ log.error("AssertionConsumerService element has no Binding attribute, skipping it...");
+ child = XMLHelper::getNextSiblingElement(child);
+ continue;
+ }
+ handler = conf.AssertionConsumerServiceManager.newPlugin(bindprop.c_str(), make_pair(child, getId()));
+ // Map by binding and protocol (may be > 1 per protocol and binding)
+ m_acsBindingMap[handler->getXMLString("Binding").second].push_back(handler);
+ const XMLCh* protfamily = handler->getProtocolFamily();
+ if (protfamily)
+ m_acsProtocolMap[protfamily].push_back(handler);
+ m_acsIndexMap[handler->getUnsignedInt("index").second] = handler;
+
+ if (!hardACS) {
+ pair<bool,bool> defprop = handler->getBool("isDefault");
+ if (defprop.first) {
+ if (defprop.second) {
+ hardACS = true;
+ m_acsDefault = handler;
+ }
+ }
+ else if (!m_acsDefault)
+ m_acsDefault = handler;
+ }
+ }
+ else if (XMLString::equals(child->getLocalName(), _SessionInitiator)) {
+ string t(XMLHelper::getAttrString(child, nullptr, _type));
+ if (t.empty()) {
+ log.error("SessionInitiator element has no type attribute, skipping it...");
+ child = XMLHelper::getNextSiblingElement(child);
+ continue;
+ }
+ SessionInitiator* sihandler = conf.SessionInitiatorManager.newPlugin(t.c_str(), make_pair(child, getId()));
+ handler = sihandler;
+ pair<bool,const char*> si_id = handler->getString("id");
+ if (si_id.first && si_id.second)
+ m_sessionInitMap[si_id.second] = sihandler;
+ if (!hardSessionInit) {
+ pair<bool,bool> defprop = handler->getBool("isDefault");
+ if (defprop.first) {
+ if (defprop.second) {
+ hardSessionInit = true;
+ m_sessionInitDefault = sihandler;
+ }
+ }
+ else if (!m_sessionInitDefault) {
+ m_sessionInitDefault = sihandler;
+ }
+ }
+ }
+ else if (XMLString::equals(child->getLocalName(), _LogoutInitiator)) {
+ string t(XMLHelper::getAttrString(child, nullptr, _type));
+ if (t.empty()) {
+ log.error("LogoutInitiator element has no type attribute, skipping it...");
+ child = XMLHelper::getNextSiblingElement(child);
+ continue;
+ }
+ handler = conf.LogoutInitiatorManager.newPlugin(t.c_str(), make_pair(child, getId()));
+ }
+ else if (XMLString::equals(child->getLocalName(), _ArtifactResolutionService)) {
+ string bindprop(XMLHelper::getAttrString(child, nullptr, Binding));
+ if (bindprop.empty()) {
+ log.error("ArtifactResolutionService element has no Binding attribute, skipping it...");
+ child = XMLHelper::getNextSiblingElement(child);
+ continue;
+ }
+ handler = conf.ArtifactResolutionServiceManager.newPlugin(bindprop.c_str(), make_pair(child, getId()));
+
+ if (!hardArt) {
+ pair<bool,bool> defprop = handler->getBool("isDefault");
+ if (defprop.first) {
+ if (defprop.second) {
+ hardArt = true;
+ m_artifactResolutionDefault = handler;
+ }
+ }
+ else if (!m_artifactResolutionDefault)
+ m_artifactResolutionDefault = handler;
+ }
+ }
+ else if (XMLString::equals(child->getLocalName(), _SingleLogoutService)) {
+ string bindprop(XMLHelper::getAttrString(child, nullptr, Binding));
+ if (bindprop.empty()) {
+ log.error("SingleLogoutService element has no Binding attribute, skipping it...");
+ child = XMLHelper::getNextSiblingElement(child);
+ continue;
+ }
+ handler = conf.SingleLogoutServiceManager.newPlugin(bindprop.c_str(), make_pair(child, getId()));
+ }
+ else if (XMLString::equals(child->getLocalName(), _ManageNameIDService)) {
+ string bindprop(XMLHelper::getAttrString(child, nullptr, Binding));
+ if (bindprop.empty()) {
+ log.error("ManageNameIDService element has no Binding attribute, skipping it...");
+ child = XMLHelper::getNextSiblingElement(child);
+ continue;
+ }
+ handler = conf.ManageNameIDServiceManager.newPlugin(bindprop.c_str(), make_pair(child, getId()));
+ }
+ else {
+ string t(XMLHelper::getAttrString(child, nullptr, _type));
+ if (t.empty()) {
+ log.error("Handler element has no type attribute, skipping it...");
+ child = XMLHelper::getNextSiblingElement(child);
+ continue;
+ }
+ handler = conf.HandlerManager.newPlugin(t.c_str(), make_pair(child, getId()));
+ }
+
+ m_handlers.push_back(handler);
+
+ // Insert into location map.
+ location = handler->getString("Location");
+ if (location.first && *location.second == '/')
+ m_handlerMap[location.second] = handler;
+ else if (location.first)
+ m_handlerMap[string("/") + location.second] = handler;
+ }
+ catch (exception& ex) {
+ log.error("caught exception processing handler element: %s", ex.what());
+ }
+
+ child = XMLHelper::getNextSiblingElement(child);
+ }
+}
+
+void XMLApplication::doSSO(const ProtocolProvider& pp, set<string>& protocols, DOMElement* e, Category& log)
+{
+ if (!e->hasChildNodes())
+ return;
+
+ SPConfig& conf = SPConfig::getConfig();
+
+ // Tokenize the protocol list inside the element.
+ const XMLCh* protlist = e->getFirstChild()->getNodeValue();
+ XMLStringTokenizer prottokens(protlist);
+ while (prottokens.hasMoreTokens()) {
+ auto_ptr_char prot(prottokens.nextToken());
+
+ // Look for initiator.
+ const PropertySet* initiator = pp.getInitiator(prot.get(), "SSO");
+ if (initiator) {
+ log.info("auto-configuring SSO initiation for protocol (%s)", prot.get());
+ pair<bool,const XMLCh*> inittype = initiator->getXMLString("id");
+ if (inittype.first) {
+ // Append a session initiator element of the designated type to the root element.
+ DOMElement* sidom = e->getOwnerDocument()->createElementNS(shibspconstants::SHIB2SPCONFIG_NS, _SessionInitiator);
+ sidom->setAttributeNS(nullptr, _type, inittype.second);
+ e->appendChild(sidom);
+ log.info("adding SessionInitiator of type (%s) to chain (/Login)", initiator->getString("id").second);
+
+ doArtifactResolution(pp, prot.get(), e, log);
+ protocols.insert(prot.get());
+ }
+ else {
+ log.error("missing id property on Initiator element, check config for protocol (%s)", prot.get());
+ }
+ }
+
+ // Look for incoming bindings.
+ const vector<const PropertySet*>& bindings = pp.getBindings(prot.get(), "SSO");
+ if (!bindings.empty()) {
+ log.info("auto-configuring SSO endpoints for protocol (%s)", prot.get());
+ int index = 0;
+ pair<bool,const XMLCh*> idprop,pathprop;
+ for (vector<const PropertySet*>::const_iterator b = bindings.begin(); b != bindings.end(); ++b, ++index) {
+ idprop = (*b)->getXMLString("id");
+ pathprop = (*b)->getXMLString("path");
+ if (idprop.first && pathprop.first) {
+ DOMElement* acsdom = e->getOwnerDocument()->createElementNS(samlconstants::SAML20MD_NS, _AssertionConsumerService);
+ acsdom->setAttributeNS(nullptr, Binding, idprop.second);
+ acsdom->setAttributeNS(nullptr, Location, pathprop.second);
+ xstring indexbuf(chDigit_1 + (index % 10), 1);
+ if (index / 10)
+ indexbuf = (XMLCh)(chDigit_1 + (index / 10)) + indexbuf;
+ acsdom->setAttributeNS(nullptr, _index, indexbuf.c_str());
+
+ log.info("adding AssertionConsumerService for Binding (%s) at (%s)", (*b)->getString("id").second, (*b)->getString("path").second);
+ Handler* handler = conf.AssertionConsumerServiceManager.newPlugin((*b)->getString("id").second, make_pair(acsdom, getId()));
+ m_handlers.push_back(handler);
+
+ // Setup maps and defaults.
+ m_acsBindingMap[handler->getXMLString("Binding").second].push_back(handler);
+ const XMLCh* protfamily = handler->getProtocolFamily();
+ if (protfamily)
+ m_acsProtocolMap[protfamily].push_back(handler);
+ m_acsIndexMap[handler->getUnsignedInt("index").second] = handler;
+ if (!m_acsDefault)
+ m_acsDefault = handler;
+
+ // Insert into location map.
+ pair<bool,const char*> location = handler->getString("Location");
+ if (location.first && *location.second == '/')
+ m_handlerMap[location.second] = handler;
+ else if (location.first)
+ m_handlerMap[string("/") + location.second] = handler;
+ }
+ else {
+ log.error("missing id or path property on Binding element, check config for protocol (%s)", prot.get());
+ }
+ }
+ }
+
+ if (!initiator && bindings.empty()) {
+ log.error("no SSO Initiator or Binding config for protocol (%s)", prot.get());
+ }
+ }
+
+ // Handle discovery.
+ static const XMLCh discoveryProtocol[] = UNICODE_LITERAL_17(d,i,s,c,o,v,e,r,y,P,r,o,t,o,c,o,l);
+ static const XMLCh discoveryURL[] = UNICODE_LITERAL_12(d,i,s,c,o,v,e,r,y,U,R,L);
+ static const XMLCh _URL[] = UNICODE_LITERAL_3(U,R,L);
+ const XMLCh* discop = e->getAttributeNS(nullptr, discoveryProtocol);
+ if (discop && *discop) {
+ const XMLCh* discou = e->getAttributeNS(nullptr, discoveryURL);
+ if (discou && *discou) {
+ // Append a session initiator element of the designated type to the root element.
+ DOMElement* sidom = e->getOwnerDocument()->createElementNS(shibspconstants::SHIB2SPCONFIG_NS, _SessionInitiator);
+ sidom->setAttributeNS(nullptr, _type, discop);
+ sidom->setAttributeNS(nullptr, _URL, discou);
+ e->appendChild(sidom);
+ if (log.isInfoEnabled()) {
+ auto_ptr_char dp(discop);
+ log.info("adding SessionInitiator of type (%s) to chain (/Login)", dp.get());
+ }
+ }
+ else {
+ log.error("SSO discoveryProtocol specified without discoveryURL");
+ }
+ }
+
+ // Attach default Location to SSO element.
+ static const XMLCh _loc[] = { chForwardSlash, chLatin_L, chLatin_o, chLatin_g, chLatin_i, chLatin_n, chNull };
+ e->setAttributeNS(nullptr, Location, _loc);
+
+ // Instantiate Chaining initiator around the SSO element.
+ SessionInitiator* chain = conf.SessionInitiatorManager.newPlugin(CHAINING_SESSION_INITIATOR, make_pair(e, getId()));
+ m_handlers.push_back(chain);
+ m_sessionInitDefault = chain;
+ m_handlerMap["/Login"] = chain;
+}
+
+void XMLApplication::doLogout(const ProtocolProvider& pp, set<string>& protocols, DOMElement* e, Category& log)
+{
+ if (!e->hasChildNodes())
+ return;
+
+ SPConfig& conf = SPConfig::getConfig();
+
+ // Tokenize the protocol list inside the element.
+ const XMLCh* protlist = e->getFirstChild()->getNodeValue();
+ XMLStringTokenizer prottokens(protlist);
+ while (prottokens.hasMoreTokens()) {
+ auto_ptr_char prot(prottokens.nextToken());
+
+ // Look for initiator.
+ const PropertySet* initiator = pp.getInitiator(prot.get(), "Logout");
+ if (initiator) {
+ log.info("auto-configuring Logout initiation for protocol (%s)", prot.get());
+ pair<bool,const XMLCh*> inittype = initiator->getXMLString("id");
+ if (inittype.first) {
+ // Append a logout initiator element of the designated type to the root element.
+ DOMElement* lidom = e->getOwnerDocument()->createElementNS(shibspconstants::SHIB2SPCONFIG_NS, _LogoutInitiator);
+ lidom->setAttributeNS(nullptr, _type, inittype.second);
+ e->appendChild(lidom);
+ log.info("adding LogoutInitiator of type (%s) to chain (/Logout)", initiator->getString("id").second);
+
+ if (protocols.count(prot.get()) == 0) {
+ doArtifactResolution(pp, prot.get(), e, log);
+ protocols.insert(prot.get());
+ }
+ }
+ else {
+ log.error("missing id property on Initiator element, check config for protocol (%s)", prot.get());
+ }
+ }
+
+ // Look for incoming bindings.
+ const vector<const PropertySet*>& bindings = pp.getBindings(prot.get(), "Logout");
+ if (!bindings.empty()) {
+ log.info("auto-configuring Logout endpoints for protocol (%s)", prot.get());
+ pair<bool,const XMLCh*> idprop,pathprop;
+ for (vector<const PropertySet*>::const_iterator b = bindings.begin(); b != bindings.end(); ++b) {
+ idprop = (*b)->getXMLString("id");
+ pathprop = (*b)->getXMLString("path");
+ if (idprop.first && pathprop.first) {
+ DOMElement* slodom = e->getOwnerDocument()->createElementNS(samlconstants::SAML20MD_NS, _SingleLogoutService);
+ slodom->setAttributeNS(nullptr, Binding, idprop.second);
+ slodom->setAttributeNS(nullptr, Location, pathprop.second);
+
+ log.info("adding SingleLogoutService for Binding (%s) at (%s)", (*b)->getString("id").second, (*b)->getString("path").second);
+ Handler* handler = conf.SingleLogoutServiceManager.newPlugin((*b)->getString("id").second, make_pair(slodom, getId()));
+ m_handlers.push_back(handler);
+
+ // Insert into location map.
+ pair<bool,const char*> location = handler->getString("Location");
+ if (location.first && *location.second == '/')
+ m_handlerMap[location.second] = handler;
+ else if (location.first)
+ m_handlerMap[string("/") + location.second] = handler;
+ }
+ else {
+ log.error("missing id or path property on Binding element, check config for protocol (%s)", prot.get());
+ }
+ }
+
+ if (protocols.count(prot.get()) == 0) {
+ doArtifactResolution(pp, prot.get(), e, log);
+ protocols.insert(prot.get());
+ }
+ }
+
+ if (!initiator && bindings.empty()) {
+ log.error("no Logout Initiator or Binding config for protocol (%s)", prot.get());
+ }
+ }
+
+ // Attach default Location to Logout element.
+ static const XMLCh _loc[] = { chForwardSlash, chLatin_L, chLatin_o, chLatin_g, chLatin_o, chLatin_u, chLatin_t, chNull };
+ e->setAttributeNS(nullptr, Location, _loc);
+
+ // Instantiate Chaining initiator around the SSO element.
+ Handler* chain = conf.LogoutInitiatorManager.newPlugin(CHAINING_LOGOUT_INITIATOR, make_pair(e, getId()));
+ m_handlers.push_back(chain);
+ m_handlerMap["/Logout"] = chain;
+}
+
+void XMLApplication::doNameIDMgmt(const ProtocolProvider& pp, set<string>& protocols, DOMElement* e, Category& log)
+{
+ if (!e->hasChildNodes())
+ return;
+
+ SPConfig& conf = SPConfig::getConfig();
+
+ // Tokenize the protocol list inside the element.
+ const XMLCh* protlist = e->getFirstChild()->getNodeValue();
+ XMLStringTokenizer prottokens(protlist);
+ while (prottokens.hasMoreTokens()) {
+ auto_ptr_char prot(prottokens.nextToken());
+
+ // Look for incoming bindings.
+ const vector<const PropertySet*>& bindings = pp.getBindings(prot.get(), "NameIDMgmt");
+ if (!bindings.empty()) {
+ log.info("auto-configuring NameIDMgmt endpoints for protocol (%s)", prot.get());
+ pair<bool,const XMLCh*> idprop,pathprop;
+ for (vector<const PropertySet*>::const_iterator b = bindings.begin(); b != bindings.end(); ++b) {
+ idprop = (*b)->getXMLString("id");
+ pathprop = (*b)->getXMLString("path");
+ if (idprop.first && pathprop.first) {
+ DOMElement* nimdom = e->getOwnerDocument()->createElementNS(samlconstants::SAML20MD_NS, _ManageNameIDService);
+ nimdom->setAttributeNS(nullptr, Binding, idprop.second);
+ nimdom->setAttributeNS(nullptr, Location, pathprop.second);
+
+ log.info("adding ManageNameIDService for Binding (%s) at (%s)", (*b)->getString("id").second, (*b)->getString("path").second);
+ Handler* handler = conf.ManageNameIDServiceManager.newPlugin((*b)->getString("id").second, make_pair(nimdom, getId()));
+ m_handlers.push_back(handler);
+
+ // Insert into location map.
+ pair<bool,const char*> location = handler->getString("Location");
+ if (location.first && *location.second == '/')
+ m_handlerMap[location.second] = handler;
+ else if (location.first)
+ m_handlerMap[string("/") + location.second] = handler;
+ }
+ else {
+ log.error("missing id or path property on Binding element, check config for protocol (%s)", prot.get());
+ }
+ }
+
+ if (protocols.count(prot.get()) == 0) {
+ doArtifactResolution(pp, prot.get(), e, log);
+ protocols.insert(prot.get());
+ }
+ }
+ else {
+ log.error("no NameIDMgmt Binding config for protocol (%s)", prot.get());
+ }
+ }
+}
+
+void XMLApplication::doArtifactResolution(const ProtocolProvider& pp, const char* protocol, DOMElement* e, Category& log)
+{
+ SPConfig& conf = SPConfig::getConfig();
+
+ // Look for incoming bindings.
+ const vector<const PropertySet*>& bindings = pp.getBindings(protocol, "ArtifactResolution");
+ if (!bindings.empty()) {
+ log.info("auto-configuring ArtifactResolution endpoints for protocol (%s)", protocol);
+ int index = 0;
+ pair<bool,const XMLCh*> idprop,pathprop;
+ for (vector<const PropertySet*>::const_iterator b = bindings.begin(); b != bindings.end(); ++b) {
+ idprop = (*b)->getXMLString("id");
+ pathprop = (*b)->getXMLString("path");
+ if (idprop.first && pathprop.first) {
+ DOMElement* artdom = e->getOwnerDocument()->createElementNS(samlconstants::SAML20MD_NS, _ArtifactResolutionService);
+ artdom->setAttributeNS(nullptr, Binding, idprop.second);
+ artdom->setAttributeNS(nullptr, Location, pathprop.second);
+ xstring indexbuf(chDigit_1 + (index % 10), 1);
+ if (index / 10)
+ indexbuf = (XMLCh)(chDigit_1 + (index / 10)) + indexbuf;
+ artdom->setAttributeNS(nullptr, _index, indexbuf.c_str());
+
+ log.info("adding ArtifactResolutionService for Binding (%s) at (%s)", (*b)->getString("id").second, (*b)->getString("path").second);
+ Handler* handler = conf.ArtifactResolutionServiceManager.newPlugin((*b)->getString("id").second, make_pair(artdom, getId()));
+ m_handlers.push_back(handler);
+
+ if (!m_artifactResolutionDefault)
+ m_artifactResolutionDefault = handler;
+
+ // Insert into location map.
+ pair<bool,const char*> location = handler->getString("Location");
+ if (location.first && *location.second == '/')
+ m_handlerMap[location.second] = handler;
+ else if (location.first)
+ m_handlerMap[string("/") + location.second] = handler;
+ }
+ else {
+ log.error("missing id or path property on Binding element, check config for protocol (%s)", protocol);
+ }
+ }
+ }
+}
+
+#ifndef SHIBSP_LITE
+void XMLApplication::doAttributePlugins(DOMElement* e, Category& log)
+{
+ SPConfig& conf = SPConfig::getConfig();
+
+ m_attrExtractor =
+ doChainedPlugins(conf.AttributeExtractorManager, "AttributeExtractor", CHAINING_ATTRIBUTE_EXTRACTOR, _AttributeExtractor, e, log);
+
+ m_attrFilter =
+ doChainedPlugins(conf.AttributeFilterManager, "AttributeFilter", CHAINING_ATTRIBUTE_FILTER, _AttributeFilter, e, log);
+
+ m_attrResolver =
+ doChainedPlugins(conf.AttributeResolverManager, "AttributeResolver", CHAINING_ATTRIBUTE_RESOLVER, _AttributeResolver, e, log);
+
+ if (m_unsetHeaders.empty()) {
+ vector<string> unsetHeaders;
+ if (m_attrExtractor) {
+ Locker extlock(m_attrExtractor);
+ m_attrExtractor->getAttributeIds(unsetHeaders);
+ }
+ else if (m_base && m_base->m_attrExtractor) {
+ Locker extlock(m_base->m_attrExtractor);
+ m_base->m_attrExtractor->getAttributeIds(unsetHeaders);
+ }
+ if (m_attrResolver) {
+ Locker reslock(m_attrResolver);
+ m_attrResolver->getAttributeIds(unsetHeaders);
+ }
+ else if (m_base && m_base->m_attrResolver) {
+ Locker extlock(m_base->m_attrResolver);
+ m_base->m_attrResolver->getAttributeIds(unsetHeaders);
+ }
+ if (!unsetHeaders.empty()) {
+ string transformedprefix(m_attributePrefix.second);
+ const char* pch;
+ pair<bool,const char*> prefix = getString("metadataAttributePrefix");
+ if (prefix.first) {
+ pch = prefix.second;
+ while (*pch) {
+ transformedprefix += (isalnum(*pch) ? toupper(*pch) : '_');
+ pch++;
+ }
+ }
+ for (vector<string>::const_iterator hdr = unsetHeaders.begin(); hdr!=unsetHeaders.end(); ++hdr) {
+ string transformed;
+ pch = hdr->c_str();
+ while (*pch) {
+ transformed += (isalnum(*pch) ? toupper(*pch) : '_');
+ pch++;
+ }
+ m_unsetHeaders.push_back(pair<string,string>(m_attributePrefix.first + *hdr, m_attributePrefix.second + transformed));
+ if (prefix.first)
+ m_unsetHeaders.push_back(pair<string,string>(m_attributePrefix.first + prefix.second + *hdr, transformedprefix + transformed));
+ }
+ }
+ m_unsetHeaders.push_back(pair<string,string>(m_attributePrefix.first + "Shib-Application-ID", m_attributePrefix.second + "SHIB_APPLICATION_ID"));
+ }
+}
+#endif
+
+void XMLApplication::cleanup()
+{
+ ListenerService* listener=getServiceProvider().getListenerService(false);
+ if (listener && SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess) && !SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
+ string addr=string(getId()) + "::getHeaders::Application";
+ listener->unregListener(addr.c_str(),this);
+ }
+ for_each(m_handlers.begin(),m_handlers.end(),xmltooling::cleanup<Handler>());
+ m_handlers.clear();
+#ifndef SHIBSP_LITE
+ for_each(m_partyMap.begin(),m_partyMap.end(),cleanup_pair<xstring,PropertySet>());
+ m_partyMap.clear();
+ delete m_credResolver;
+ m_credResolver = nullptr;
+ delete m_attrResolver;
+ m_attrResolver = nullptr;
+ delete m_attrFilter;
+ m_attrFilter = nullptr;
+ delete m_attrExtractor;
+ m_attrExtractor = nullptr;
+ delete m_trust;
+ m_trust = nullptr;
+ delete m_metadata;
+ m_metadata = nullptr;
+#endif
+}
+
+#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE
+short
+#else
+DOMNodeFilter::FilterAction
+#endif
+XMLApplication::acceptNode(const DOMNode* node) const
+{
+ const XMLCh* name=node->getLocalName();
+ if (XMLString::equals(name,ApplicationOverride) ||
+ XMLString::equals(name,_Audience) ||
+ XMLString::equals(name,Notify) ||
+ XMLString::equals(name,_Handler) ||
+ XMLString::equals(name,_AssertionConsumerService) ||
+ XMLString::equals(name,_ArtifactResolutionService) ||
+ XMLString::equals(name,Logout) ||
+ XMLString::equals(name,_LogoutInitiator) ||
+ XMLString::equals(name,_ManageNameIDService) ||
+ XMLString::equals(name,NameIDMgmt) ||
+ XMLString::equals(name,_SessionInitiator) ||
+ XMLString::equals(name,_SingleLogoutService) ||
+ XMLString::equals(name,SSO) ||
+ XMLString::equals(name,RelyingParty) ||
+ XMLString::equals(name,_MetadataProvider) ||
+ XMLString::equals(name,_TrustEngine) ||
+ XMLString::equals(name,_CredentialResolver) ||
+ XMLString::equals(name,_AttributeFilter) ||
+ XMLString::equals(name,_AttributeExtractor) ||
+ XMLString::equals(name,_AttributeResolver))
+ return FILTER_REJECT;
+
+ return FILTER_ACCEPT;
+}
+
+#ifndef SHIBSP_LITE
+
+const PropertySet* XMLApplication::getRelyingParty(const EntityDescriptor* provider) const
+{
+ if (!provider)
+ return this;
+
+ map<xstring,PropertySet*>::const_iterator i=m_partyMap.find(provider->getEntityID());
+ if (i!=m_partyMap.end())
+ return i->second;
+ const EntitiesDescriptor* group=dynamic_cast<const EntitiesDescriptor*>(provider->getParent());
+ while (group) {
+ if (group->getName()) {
+ i=m_partyMap.find(group->getName());
+ if (i!=m_partyMap.end())
+ return i->second;
+ }
+ group=dynamic_cast<const EntitiesDescriptor*>(group->getParent());
+ }
+ return this;
+}
+
+const PropertySet* XMLApplication::getRelyingParty(const XMLCh* entityID) const
+{
+ if (!entityID)
+ return this;
+
+ map<xstring,PropertySet*>::const_iterator i=m_partyMap.find(entityID);
+ if (i!=m_partyMap.end())
+ return i->second;
+ return this;
+}
+
+#endif
+
+string XMLApplication::getNotificationURL(const char* resource, bool front, unsigned int index) const
+{
+ const vector<string>& locs = front ? m_frontLogout : m_backLogout;
+ if (locs.empty())
+ return m_base ? m_base->getNotificationURL(resource, front, index) : string();
+ else if (index >= locs.size())
+ return string();
+
+#ifdef HAVE_STRCASECMP
+ if (!resource || (strncasecmp(resource,"http://",7) && strncasecmp(resource,"https://",8)))
+#else
+ if (!resource || (strnicmp(resource,"http://",7) && strnicmp(resource,"https://",8)))