+ if (!e->hasChildNodes())
+ return;
+ DOMNamedNodeMap* sloprops = e->getAttributes();
+ XMLSize_t slopropslen = sloprops ? sloprops->getLength() : 0;
+
+ SPConfig& conf = SPConfig::getConfig();
+
+ // Tokenize the protocol list inside the element.
+ XMLStringTokenizer prottokens(e->getTextContent());
+ 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);
+
+ // Copy in any attributes from the <Logout> element so they can be accessed as properties in the SLO handler.
+ for (XMLSize_t p = 0; p < slopropslen; ++p) {
+ DOMNode* sloprop = sloprops->item(p);
+ if (sloprop->getNodeType() == DOMNode::ATTRIBUTE_NODE) {
+ slodom->setAttributeNS(
+ ((DOMAttr*)sloprop)->getNamespaceURI(),
+ ((DOMAttr*)sloprop)->getLocalName(),
+ ((DOMAttr*)sloprop)->getValue()
+ );
+ }
+ }
+
+ // Set necessary properties based on context.
+ slodom->setAttributeNS(nullptr, Binding, idprop.second);
+ slodom->setAttributeNS(nullptr, Location, pathprop.second);
+ if (e->hasAttributeNS(nullptr, _policyId))
+ slodom->setAttributeNS(shibspconstants::SHIB2SPCONFIG_NS, _policyId, e->getAttributeNS(nullptr, _policyId));
+
+ log.info("adding SingleLogoutService for Binding (%s) at (%s)", (*b)->getString("id").second, (*b)->getString("path").second);
+ boost::shared_ptr<Handler> handler(
+ conf.SingleLogoutServiceManager.newPlugin((*b)->getString("id").second, pair<const DOMElement*,const char*>(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.get();
+ else if (location.first)
+ m_handlerMap[string("/") + location.second] = handler.get();
+ }
+ 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.
+ boost::shared_ptr<Handler> chain(
+ conf.LogoutInitiatorManager.newPlugin(CHAINING_LOGOUT_INITIATOR, pair<const DOMElement*,const char*>(e, getId()))
+ );
+ m_handlers.push_back(chain);
+ m_handlerMap["/Logout"] = chain.get();
+}
+
+void XMLApplication::doNameIDMgmt(const ProtocolProvider& pp, set<string>& protocols, DOMElement* e, Category& log)
+{
+ if (!e->hasChildNodes())
+ return;
+ DOMNamedNodeMap* nimprops = e->getAttributes();
+ XMLSize_t nimpropslen = nimprops ? nimprops->getLength() : 0;
+
+ SPConfig& conf = SPConfig::getConfig();
+
+ // Tokenize the protocol list inside the element.
+ XMLStringTokenizer prottokens(e->getTextContent());
+ 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);
+
+ // Copy in any attributes from the <NameIDMgmt> element so they can be accessed as properties in the NIM handler.
+ for (XMLSize_t p = 0; p < nimpropslen; ++p) {
+ DOMNode* nimprop = nimprops->item(p);
+ if (nimprop->getNodeType() == DOMNode::ATTRIBUTE_NODE) {
+ nimdom->setAttributeNS(
+ ((DOMAttr*)nimprop)->getNamespaceURI(),
+ ((DOMAttr*)nimprop)->getLocalName(),
+ ((DOMAttr*)nimprop)->getValue()
+ );
+ }
+ }
+
+ // Set necessary properties based on context.
+ nimdom->setAttributeNS(nullptr, Binding, idprop.second);
+ nimdom->setAttributeNS(nullptr, Location, pathprop.second);
+ if (e->hasAttributeNS(nullptr, _policyId))
+ nimdom->setAttributeNS(shibspconstants::SHIB2SPCONFIG_NS, _policyId, e->getAttributeNS(nullptr, _policyId));
+
+ log.info("adding ManageNameIDService for Binding (%s) at (%s)", (*b)->getString("id").second, (*b)->getString("path").second);
+ boost::shared_ptr<Handler> handler(
+ conf.ManageNameIDServiceManager.newPlugin((*b)->getString("id").second, pair<const DOMElement*,const char*>(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.get();
+ else if (location.first)
+ m_handlerMap[string("/") + location.second] = handler.get();
+ }
+ 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();
+
+ int index = 0; // track indexes globally across all protocols
+
+ // 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);
+ 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* artdom = e->getOwnerDocument()->createElementNS(samlconstants::SAML20MD_NS, _ArtifactResolutionService);
+ artdom->setAttributeNS(nullptr, Binding, idprop.second);
+ artdom->setAttributeNS(nullptr, Location, pathprop.second);
+ xstring indexbuf(1, chDigit_1 + (index % 10));
+ 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);
+ boost::shared_ptr<Handler> handler(
+ conf.ArtifactResolutionServiceManager.newPlugin((*b)->getString("id").second, pair<const DOMElement*,const char*>(artdom, getId()))
+ );
+ m_handlers.push_back(handler);
+
+ if (!m_artifactResolutionDefault)
+ m_artifactResolutionDefault = handler.get();
+
+ // Insert into location map.
+ pair<bool,const char*> location = handler->getString("Location");
+ if (location.first && *location.second == '/')
+ m_handlerMap[location.second] = handler.get();
+ else if (location.first)
+ m_handlerMap[string("/") + location.second] = handler.get();
+ }
+ 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.reset(
+ doChainedPlugins(conf.AttributeExtractorManager, "AttributeExtractor", CHAINING_ATTRIBUTE_EXTRACTOR, _AttributeExtractor, e, log)
+ );
+
+ m_attrFilter.reset(
+ doChainedPlugins(conf.AttributeFilterManager, "AttributeFilter", CHAINING_ATTRIBUTE_FILTER, _AttributeFilter, e, log, DUMMY_ATTRIBUTE_FILTER)
+ );
+
+ m_attrResolver.reset(
+ doChainedPlugins(conf.AttributeResolverManager, "AttributeResolver", CHAINING_ATTRIBUTE_RESOLVER, _AttributeResolver, e, log)
+ );
+
+ if (m_unsetHeaders.empty()) {
+ vector<string> unsetHeaders;
+ if (m_attrExtractor) {
+ Locker extlock(m_attrExtractor.get());
+ m_attrExtractor->getAttributeIds(unsetHeaders);
+ }
+ else if (m_base && m_base->m_attrExtractor) {
+ Locker extlock(m_base->m_attrExtractor.get());
+ m_base->m_attrExtractor->getAttributeIds(unsetHeaders);
+ }
+ if (m_attrResolver) {
+ Locker reslock(m_attrResolver.get());
+ m_attrResolver->getAttributeIds(unsetHeaders);
+ }
+ else if (m_base && m_base->m_attrResolver) {
+ Locker extlock(m_base->m_attrResolver.get());
+ 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(make_pair(m_attributePrefix.first + *hdr, m_attributePrefix.second + transformed));
+ if (prefix.first)
+ m_unsetHeaders.push_back(make_pair(m_attributePrefix.first + prefix.second + *hdr, transformedprefix + transformed));
+ }
+ }
+ m_unsetHeaders.push_back(make_pair(m_attributePrefix.first + "Shib-Application-ID", m_attributePrefix.second + "SHIB_APPLICATION_ID"));
+ }
+}
+#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) ||