{}
virtual ~ADFSConsumer() {}
- private:
#ifndef SHIBSP_LITE
+ void generateMetadata(SPSSODescriptor& role, const char* handlerURL) const {
+ AssertionConsumerService::generateMetadata(role, handlerURL);
+ role.addSupport(m_protocol.get());
+ }
+
+ auto_ptr_XMLCh m_protocol;
+
+ private:
string implementProtocol(
const Application& application,
const HTTPRequest& httpRequest,
const PropertySet* settings,
const XMLObject& xmlObject
) const;
- auto_ptr_XMLCh m_protocol;
#endif
};
pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
+#ifndef SHIBSP_LITE
+ void generateMetadata(SPSSODescriptor& role, const char* handlerURL) const {
+ m_login.generateMetadata(role, handlerURL);
+ const char* loc = getString("Location").second;
+ string hurl(handlerURL);
+ if (*loc != '/')
+ hurl += '/';
+ hurl += loc;
+ auto_ptr_XMLCh widen(hurl.c_str());
+ SingleLogoutService* ep = SingleLogoutServiceBuilder::buildSingleLogoutService();
+ ep->setLocation(widen.get());
+ ep->setBinding(m_login.m_protocol.get());
+ role.getSingleLogoutServices().push_back(ep);
+ }
+#endif
+
private:
ADFSConsumer m_login;
};
<md:ArtifactResolutionService Location="/Artifact/SOAP" index="1"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"/>
+ <!-- Extension service that generates "approximate" metadata based on SP configuration. -->
+ <Handler type="MetadataGenerator" Location="/Metadata" signing="true"/>
+
</Sessions>
<!--
<any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
</sequence>\r
<attribute name="Location" type="anyURI" use="required"/>\r
+ <anyAttribute namespace="##any" processContents="lax"/>\r
</restriction>\r
</complexContent>\r
</complexType>\r
* @return the mapped Handler, or NULL
*/
virtual const Handler* getHandler(const char* path) const=0;
+
+ /**
+ * Returns all registered Handlers.
+ *
+ * @param handlers array to populate
+ */
+ virtual void getHandlers(std::vector<const Handler*>& handlers) const=0;
};
#if defined (_MSC_VER)
handler/impl/ChainingSessionInitiator.cpp \
handler/impl/LocalLogoutInitiator.cpp \
handler/impl/LogoutHandler.cpp \
+ handler/impl/MetadataGenerator.cpp \
handler/impl/RemotedHandler.cpp \
handler/impl/SAML1Consumer.cpp \
handler/impl/SAML2Consumer.cpp \
AssertionConsumerService(const xercesc::DOMElement* e, const char* appId, xmltooling::logging::Category& log);
#ifndef SHIBSP_LITE
+ void generateMetadata(opensaml::saml2md::SPSSODescriptor& role, const char* handlerURL) const;
+
/**
* Implement protocol-specific handling of the incoming decoded message.
*
const xmltooling::XMLObject& xmlObject
) const=0;
- /**\r
- * Extracts policy-relevant assertion details.\r
- * \r
- * @param assertion the incoming assertion\r
- * @param protocol the protocol family in use\r
- * @param policy SecurityPolicy to provide various components and track message data\r
- */\r
- virtual void extractMessageDetails(\r
- const opensaml::Assertion& assertion, const XMLCh* protocol, opensaml::SecurityPolicy& policy\r
- ) const;\r
+ /**
+ * Extracts policy-relevant assertion details.
+ *
+ * @param assertion the incoming assertion
+ * @param protocol the protocol family in use
+ * @param policy SecurityPolicy to provide various components and track message data
+ */
+ virtual void extractMessageDetails(
+ const opensaml::Assertion& assertion, const XMLCh* protocol, opensaml::SecurityPolicy& policy
+ ) const;
/**
* Attempt SSO-initiated attribute resolution using the supplied information,
#define __shibsp_handler_h__
#include <shibsp/util/PropertySet.h>
+#ifndef SHIBSP_LITE
+# include <saml/saml2/metadata/Metadata.h>
+#endif
namespace shibsp {
* @return a pair containing a "request completed" indicator and a server-specific response code
*/
virtual std::pair<bool,long> run(SPRequest& request, bool isHandler=true) const=0;
+
+#ifndef SHIBSP_LITE
+ /**
+ * Generates and/or modifies metadata reflecting the handler.
+ *
+ * <p>The default implementation does nothing.
+ *
+ * @param role metadata role to decorate
+ * @param handlerURL base location of handler's endpoint
+ */
+ virtual void generateMetadata(opensaml::saml2md::SPSSODescriptor& role, const char* handlerURL) const {
+ }
+#endif
};
/** Registers Handler implementations. */
SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML1ConsumerFactory;
SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2ConsumerFactory;
SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2ArtifactResolutionFactory;
- SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory AssertionLookupFactory;
SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory ChainingLogoutInitiatorFactory;
SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory LocalLogoutInitiatorFactory;
SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2LogoutInitiatorFactory;
SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2LogoutFactory;
+ SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory AssertionLookupFactory;
+ SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory MetadataGeneratorFactory;
};
void SHIBSP_API shibsp::registerHandlers()
conf.ArtifactResolutionServiceManager.registerFactory(SAML20_BINDING_SOAP, SAML2ArtifactResolutionFactory);
conf.HandlerManager.registerFactory(SAML20_BINDING_URI, AssertionLookupFactory);
+ conf.HandlerManager.registerFactory("MetadataGenerator", MetadataGeneratorFactory);
conf.LogoutInitiatorManager.registerFactory(CHAINING_LOGOUT_INITIATOR, ChainingLogoutInitiatorFactory);
conf.LogoutInitiatorManager.registerFactory(LOCAL_LOGOUT_INITIATOR, LocalLogoutInitiatorFactory);
using namespace samlconstants;
using opensaml::saml2md::EntityDescriptor;
using opensaml::saml2md::IDPSSODescriptor;
+using opensaml::saml2md::SPSSODescriptor;
#else
# include "lite/CommonDomainCookie.h"
#endif
#ifndef SHIBSP_LITE
+void AssertionConsumerService::generateMetadata(SPSSODescriptor& role, const char* handlerURL) const {
+ const char* loc = getString("Location").second;
+ string hurl(handlerURL);
+ if (*loc != '/')
+ hurl += '/';
+ hurl += loc;
+ auto_ptr_XMLCh widen(hurl.c_str());
+ saml2md::AssertionConsumerService* ep = saml2md::AssertionConsumerServiceBuilder::buildAssertionConsumerService();
+ ep->setLocation(widen.get());
+ ep->setBinding(getXMLString("Binding").second);
+ ep->setIndex(getXMLString("index").second);
+ role.getAssertionConsumerServices().push_back(ep);
+}
+
class SHIBSP_DLLLOCAL DummyContext : public ResolutionContext
{
public:
if (policy.getIssuer() && !policy.getIssuerMetadata() && policy.getMetadataProvider()) {
m_log.debug("searching metadata for assertion issuer...");
- const EntityDescriptor* entity = policy.getMetadataProvider()->getEntityDescriptor(policy.getIssuer()->getName());\r
- if (entity) {\r
- m_log.debug("matched assertion issuer against metadata, searching for applicable role...");\r
- const IDPSSODescriptor* idp=entity->getIDPSSODescriptor(protocol);\r
- if (idp)\r
- policy.setIssuerMetadata(idp);\r
- else if (m_log.isWarnEnabled())\r
- m_log.warn("unable to find compatible IdP role in metadata");\r
- }\r
- else if (m_log.isWarnEnabled()) {\r
- auto_ptr_char iname(policy.getIssuer()->getName());\r
- m_log.warn("no metadata found, can't establish identity of issuer (%s)", iname.get());\r
- }\r
+ const EntityDescriptor* entity = policy.getMetadataProvider()->getEntityDescriptor(policy.getIssuer()->getName());
+ if (entity) {
+ m_log.debug("matched assertion issuer against metadata, searching for applicable role...");
+ const IDPSSODescriptor* idp=entity->getIDPSSODescriptor(protocol);
+ if (idp)
+ policy.setIssuerMetadata(idp);
+ else if (m_log.isWarnEnabled())
+ m_log.warn("unable to find compatible IdP role in metadata");
+ }
+ else if (m_log.isWarnEnabled()) {
+ auto_ptr_char iname(policy.getIssuer()->getName());
+ m_log.warn("no metadata found, can't establish identity of issuer (%s)", iname.get());
+ }
}
}
--- /dev/null
+/*
+ * 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.
+ */
+
+/**
+ * MetadataGenerator.cpp
+ *
+ * Handler for generating "approximate" metadata based on SP configuration.
+ */
+
+#include "internal.h"
+#include "Application.h"
+#include "exceptions.h"
+#include "ServiceProvider.h"
+#include "handler/AbstractHandler.h"
+#include "handler/RemotedHandler.h"
+
+#include <xercesc/framework/LocalFileInputSource.hpp>
+#include <xercesc/framework/Wrapper4InputSource.hpp>
+
+using namespace shibsp;
+#ifndef SHIBSP_LITE
+using namespace opensaml::saml2md;
+using namespace opensaml;
+using namespace xmlsignature;
+#endif
+using namespace xmltooling;
+using namespace std;
+
+namespace shibsp {
+
+#if defined (_MSC_VER)
+ #pragma warning( push )
+ #pragma warning( disable : 4250 )
+#endif
+
+ class SHIBSP_DLLLOCAL Blocker : public DOMNodeFilter
+ {
+ public:
+ short acceptNode(const DOMNode* node) const {
+ return FILTER_REJECT;
+ }
+ };
+
+ static SHIBSP_DLLLOCAL Blocker g_Blocker;
+
+ class SHIBSP_API MetadataGenerator : public AbstractHandler, public RemotedHandler
+ {
+ public:
+ MetadataGenerator(const DOMElement* e, const char* appId);
+ virtual ~MetadataGenerator() {}
+
+ pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
+ void receive(DDF& in, ostream& out);
+
+ private:
+ pair<bool,long> processMessage(const Application& application, const char* handlerURL, HTTPResponse& httpResponse) const;
+
+ set<string> m_acl;
+#ifndef SHIBSP_LITE
+ vector<string> m_bases;
+#endif
+ };
+
+#if defined (_MSC_VER)
+ #pragma warning( pop )
+#endif
+
+ Handler* SHIBSP_DLLLOCAL MetadataGeneratorFactory(const pair<const DOMElement*,const char*>& p)
+ {
+ return new MetadataGenerator(p.first, p.second);
+ }
+
+};
+
+MetadataGenerator::MetadataGenerator(const DOMElement* e, const char* appId)
+ : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".MetadataGenerator"), &g_Blocker)
+{
+ string address(appId);
+ address += getString("Location").second;
+ setAddress(address.c_str());
+ if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
+ pair<bool,const char*> acl = getString("acl");
+ if (acl.first) {
+ string aclbuf=acl.second;
+ int j = 0;
+ for (unsigned int i=0; i < aclbuf.length(); i++) {
+ if (aclbuf.at(i)==' ') {
+ m_acl.insert(aclbuf.substr(j, i-j));
+ j = i+1;
+ }
+ }
+ m_acl.insert(aclbuf.substr(j, aclbuf.length()-j));
+ }
+ }
+
+#ifndef SHIBSP_LITE
+ static XMLCh EndpointBase[] = UNICODE_LITERAL_12(E,n,d,p,o,i,n,t,B,a,s,e);
+ e = XMLHelper::getFirstChildElement(e, EndpointBase);
+ while (e) {
+ if (e->hasChildNodes()) {
+ auto_ptr_char base(e->getFirstChild()->getNodeValue());
+ if (base.get() && *base.get())
+ m_bases.push_back(base.get());
+ }
+ e = XMLHelper::getNextSiblingElement(e, EndpointBase);
+ }
+#endif
+}
+
+pair<bool,long> MetadataGenerator::run(SPRequest& request, bool isHandler) const
+{
+ string relayState;
+ SPConfig& conf = SPConfig::getConfig();
+ if (conf.isEnabled(SPConfig::InProcess)) {
+ if (!m_acl.empty() && m_acl.count(request.getRemoteAddr()) == 0) {
+ m_log.error("request for metadata blocked from invalid address (%s)", request.getRemoteAddr().c_str());
+ istringstream msg("Metadata Request Blocked");
+ return make_pair(true,request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_FORBIDDEN));
+ }
+ }
+
+ try {
+ if (conf.isEnabled(SPConfig::OutOfProcess)) {
+ // When out of process, we run natively and directly process the message.
+ return processMessage(request.getApplication(), request.getHandlerURL(), request);
+ }
+ else {
+ // When not out of process, we remote all the message processing.
+ DDF out,in = DDF(m_address.c_str());
+ in.addmember("application_id").string(request.getApplication().getId());
+ in.addmember("handler_url").string(request.getHandlerURL());
+ DDFJanitor jin(in), jout(out);
+
+ out=request.getServiceProvider().getListenerService()->send(in);
+ return unwrap(request, out);
+ }
+ }
+ catch (exception& ex) {
+ m_log.error("error while processing request: %s", ex.what());
+ istringstream msg("Metadata Request Failed");
+ return make_pair(true,request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_ERROR));
+ }
+}
+
+void MetadataGenerator::receive(DDF& in, ostream& out)
+{
+ // Find application.
+ const char* aid=in["application_id"].string();
+ const char* hurl=in["handler_url"].string();
+ const Application* app=aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : NULL;
+ if (!app) {
+ // Something's horribly wrong.
+ m_log.error("couldn't find application (%s) for metadata request", aid ? aid : "(missing)");
+ throw ConfigurationException("Unable to locate application for metadata request, deleted?");
+ }
+ else if (!hurl) {
+ throw ConfigurationException("Missing handler_url parameter in remoted method call.");
+ }
+
+ // Wrap a response shim.
+ DDF ret(NULL);
+ DDFJanitor jout(ret);
+ auto_ptr<HTTPResponse> resp(getResponse(ret));
+
+ // Since we're remoted, the result should either be a throw, a false/0 return,
+ // which we just return as an empty structure, or a response/redirect,
+ // which we capture in the facade and send back.
+ processMessage(*app, hurl, *resp.get());
+ out << ret;
+}
+
+pair<bool,long> MetadataGenerator::processMessage(const Application& application, const char* handlerURL, HTTPResponse& httpResponse) const
+{
+#ifndef SHIBSP_LITE
+ m_log.debug("processing metadata request");
+
+ EntityDescriptor* entity;
+ pair<bool,const char*> prop = getString("template");
+ if (prop.first) {
+ // Load a template to use for our metadata.
+ LocalFileInputSource src(getXMLString("template").second);
+ Wrapper4InputSource dsrc(&src,false);
+ DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(dsrc);
+ XercesJanitor<DOMDocument> docjan(doc);
+ auto_ptr<XMLObject> xmlobj(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true));
+ entity = dynamic_cast<EntityDescriptor*>(xmlobj.get());
+ if (!entity)
+ throw ConfigurationException("Template file ($1) did not contain an EntityDescriptor", params(1, prop.second));
+ xmlobj.release();
+ }
+ else {
+ entity = EntityDescriptorBuilder::buildEntityDescriptor();
+ }
+
+ auto_ptr<EntityDescriptor> wrapper(entity);
+ pair<bool,unsigned int> cache = getUnsignedInt("cacheDuration");
+ if (cache.first)
+ entity->setValidUntil(time(NULL) + cache.second);
+ entity->setEntityID(application.getXMLString("entityID").second);
+
+ SPSSODescriptor* role;
+ if (entity->getSPSSODescriptors().empty()) {
+ role = SPSSODescriptorBuilder::buildSPSSODescriptor();
+ entity->getSPSSODescriptors().push_back(role);
+ }
+ else {
+ role = entity->getSPSSODescriptors().front();
+ }
+
+ vector<const Handler*> handlers;
+ application.getHandlers(handlers);
+ for (vector<const Handler*>::const_iterator h = handlers.begin(); h != handlers.end(); ++h) {
+ (*h)->generateMetadata(*role, handlerURL);
+ for (vector<string>::const_iterator b = m_bases.begin(); b != m_bases.end(); ++b)
+ (*h)->generateMetadata(*role, b->c_str());
+ }
+
+ CredentialResolver* credResolver=application.getCredentialResolver();
+ if (credResolver) {
+ Locker credLocker(credResolver);
+ CredentialCriteria cc;
+ cc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL);
+ vector<const Credential*> creds;
+ credResolver->resolve(creds,&cc);
+ for (vector<const Credential*>::const_iterator c = creds.begin(); c != creds.end(); ++c) {
+ KeyInfo* kinfo = (*c)->getKeyInfo();
+ if (kinfo) {
+ KeyDescriptor* kd = KeyDescriptorBuilder::buildKeyDescriptor();
+ kd->setUse(KeyDescriptor::KEYTYPE_SIGNING);
+ kd->setKeyInfo(kinfo);
+ role->getKeyDescriptors().push_back(kd);
+ }
+ }
+
+ cc.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
+ creds.clear();
+ credResolver->resolve(creds,&cc);
+ for (vector<const Credential*>::const_iterator c = creds.begin(); c != creds.end(); ++c) {
+ KeyInfo* kinfo = (*c)->getKeyInfo();
+ if (kinfo) {
+ KeyDescriptor* kd = KeyDescriptorBuilder::buildKeyDescriptor();
+ kd->setUse(KeyDescriptor::KEYTYPE_ENCRYPTION);
+ kd->setKeyInfo(kinfo);
+ role->getKeyDescriptors().push_back(kd);
+ }
+ }
+ }
+
+ // Self-sign it?
+ pair<bool,bool> flag = getBool("signing");
+ if (flag.first && flag.second) {
+ if (credResolver) {
+ Locker credLocker(credResolver);
+ // Fill in criteria to use.
+ CredentialCriteria cc;
+ cc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL);
+ prop = getString("keyName");
+ if (prop.first)
+ cc.getKeyNames().insert(prop.second);
+ pair<bool,const XMLCh*> sigalg = getXMLString("signingAlg");
+ pair<bool,const XMLCh*> digalg = getXMLString("digestAlg");
+ if (sigalg.first)
+ cc.setXMLAlgorithm(sigalg.second);
+ const Credential* cred = credResolver->resolve(&cc);
+ if (!cred)
+ throw XMLSecurityException("Unable to obtain signing credential to use.");
+ Signature* sig = SignatureBuilder::buildSignature();
+ entity->setSignature(sig);
+ if (sigalg.first)
+ sig->setSignatureAlgorithm(sigalg.second);
+ if (digalg.first) {
+ opensaml::ContentReference* cr = dynamic_cast<opensaml::ContentReference*>(sig->getContentReference());
+ if (cr)
+ cr->setDigestAlgorithm(digalg.second);
+ }
+
+ // Sign response while marshalling.
+ vector<Signature*> sigs(1,sig);
+ entity->marshall((DOMDocument*)NULL,&sigs,cred);
+ }
+ }
+
+ stringstream s;
+ s << *entity;
+ httpResponse.setContentType("application/samlmetadata+xml");
+ return make_pair(true, httpResponse.sendResponse(s));
+#else
+ return make_pair(false,0);
+#endif
+}
using saml2::NameID;
using saml2::NameIDBuilder;
using saml2md::EntityDescriptor;
+using saml2md::SPSSODescriptor;
using saml2md::MetadataException;
#else
# include "lite/SAMLConstants.h"
}
virtual ~SAML1Consumer() {}
- private:
#ifndef SHIBSP_LITE
+ void generateMetadata(SPSSODescriptor& role, const char* handlerURL) const {
+ AssertionConsumerService::generateMetadata(role, handlerURL);
+ role.addSupport(samlconstants::SAML11_PROTOCOL_ENUM);
+ role.addSupport(samlconstants::SAML10_PROTOCOL_ENUM);
+ }
+
+ private:
string implementProtocol(
const Application& application,
const HTTPRequest& httpRequest,
}
virtual ~SAML2Consumer() {}
- private:
#ifndef SHIBSP_LITE
+ void generateMetadata(SPSSODescriptor& role, const char* handlerURL) const {
+ AssertionConsumerService::generateMetadata(role, handlerURL);
+ role.addSupport(samlconstants::SAML20P_NS);
+ }
+
+ private:
string implementProtocol(
const Application& application,
const HTTPRequest& httpRequest,
void receive(DDF& in, ostream& out);
pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
+#ifndef SHIBSP_LITE
+ void generateMetadata(SPSSODescriptor& role, const char* handlerURL) const {
+ const char* loc = getString("Location").second;
+ string hurl(handlerURL);
+ if (*loc != '/')
+ hurl += '/';
+ hurl += loc;
+ auto_ptr_XMLCh widen(hurl.c_str());
+ SingleLogoutService* ep = SingleLogoutServiceBuilder::buildSingleLogoutService();
+ ep->setLocation(widen.get());
+ ep->setBinding(getXMLString("Binding").second);
+ role.getSingleLogoutServices().push_back(ep);
+ role.addSupport(samlconstants::SAML20P_NS);
+ }
+#endif
+
private:
pair<bool,long> doRequest(
const Application& application, const char* session_id, const HTTPRequest& httpRequest, HTTPResponse& httpResponse
const Handler* getAssertionConsumerServiceByIndex(unsigned short index) const;
const vector<const Handler*>& getAssertionConsumerServicesByBinding(const XMLCh* binding) const;
const Handler* getHandler(const char* path) const;
+ void getHandlers(vector<const Handler*>& handlers) const;
void receive(DDF& in, ostream& out) {
// Only current function is to return the headers to clear.
map<const XMLCh*,PropertySet*> m_partyMap;
#endif
#endif
- std::set<std::string> m_remoteUsers;
+ set<string> m_remoteUsers;
vector<string> m_frontLogout,m_backLogout;
// manage handler objects
return m_base ? m_base->getHandler(path) : NULL;
}
+void XMLApplication::getHandlers(vector<const Handler*>& handlers) const
+{
+ handlers.insert(handlers.end(), m_handlers.begin(), m_handlers.end());
+ if (m_base) {
+ for (map<string,const Handler*>::const_iterator h = m_base->m_handlerMap.begin(); h != m_base->m_handlerMap.end(); ++h) {
+ if (m_handlerMap.count(h->first) == 0)
+ handlers.push_back(h->second);
+ }
+ }
+}
+
short XMLConfigImpl::acceptNode(const DOMNode* node) const
{
if (!XMLString::equals(node->getNamespaceURI(),shibspconstants::SHIB2SPCONFIG_NS))
>\r
</File>\r
<File\r
+ RelativePath=".\handler\impl\MetadataGenerator.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\handler\impl\RemotedHandler.cpp"\r
>\r
</File>\r
>\r
</File>\r
<File\r
+ RelativePath=".\handler\impl\MetadataGenerator.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\handler\impl\RemotedHandler.cpp"\r
>\r
</File>\r