Attempt at a metadata generation handler.
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Sun, 30 Sep 2007 03:44:01 +0000 (03:44 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Sun, 30 Sep 2007 03:44:01 +0000 (03:44 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@2518 cb58f699-b61c-0410-a6fe-9272a202ed29

16 files changed:
adfs/adfs.cpp
configs/shibboleth2.xml.in
schemas/shibboleth-2.0-native-sp-config.xsd
shibsp/Application.h
shibsp/Makefile.am
shibsp/handler/AssertionConsumerService.h
shibsp/handler/Handler.h
shibsp/handler/impl/AbstractHandler.cpp
shibsp/handler/impl/AssertionConsumerService.cpp
shibsp/handler/impl/MetadataGenerator.cpp [new file with mode: 0644]
shibsp/handler/impl/SAML1Consumer.cpp
shibsp/handler/impl/SAML2Consumer.cpp
shibsp/handler/impl/SAML2Logout.cpp
shibsp/impl/XMLServiceProvider.cpp
shibsp/shibsp-lite.vcproj
shibsp/shibsp.vcproj

index 116fa02..6403441 100644 (file)
@@ -153,8 +153,15 @@ namespace {
             {}
         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,
@@ -162,7 +169,6 @@ namespace {
             const PropertySet* settings,
             const XMLObject& xmlObject
             ) const;
-        auto_ptr_XMLCh m_protocol;
 #endif
     };
 
@@ -220,6 +226,22 @@ namespace {
 
         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;
     };
index 7cc75e4..5825d7f 100644 (file)
                        <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>
 
                <!--
index acc5d02..b8450d4 100644 (file)
                                                                        <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
index c941c89..d9bd87c 100644 (file)
@@ -253,6 +253,13 @@ namespace shibsp {
          * @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)
index 983b6ae..847380f 100644 (file)
@@ -113,6 +113,7 @@ common_sources = \
        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 \
index b8154b9..9cf5f48 100644 (file)
@@ -64,6 +64,8 @@ namespace shibsp {
         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.
          * 
@@ -85,16 +87,16 @@ namespace shibsp {
             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,
index 94ccefa..7c92a53 100644 (file)
@@ -24,6 +24,9 @@
 #define __shibsp_handler_h__
 
 #include <shibsp/util/PropertySet.h>
+#ifndef SHIBSP_LITE
+# include <saml/saml2/metadata/Metadata.h>
+#endif
 
 namespace shibsp {
 
@@ -51,6 +54,19 @@ 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. */
index d087e0d..fa7a032 100644 (file)
@@ -58,11 +58,12 @@ namespace shibsp {
     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()
@@ -78,6 +79,7 @@ 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);
index 0a220f7..18ef907 100644 (file)
@@ -42,6 +42,7 @@
 using namespace samlconstants;
 using opensaml::saml2md::EntityDescriptor;
 using opensaml::saml2md::IDPSSODescriptor;
+using opensaml::saml2md::SPSSODescriptor;
 #else
 # include "lite/CommonDomainCookie.h"
 #endif
@@ -250,6 +251,20 @@ void AssertionConsumerService::checkAddress(
 
 #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:
@@ -409,19 +424,19 @@ void AssertionConsumerService::extractMessageDetails(const Assertion& assertion,
 
     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());
+        }
     }
 }
 
diff --git a/shibsp/handler/impl/MetadataGenerator.cpp b/shibsp/handler/impl/MetadataGenerator.cpp
new file mode 100644 (file)
index 0000000..ef48f81
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ *  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
+}
index d9cb975..71a53cb 100644 (file)
@@ -39,6 +39,7 @@ using namespace opensaml;
 using saml2::NameID;
 using saml2::NameIDBuilder;
 using saml2md::EntityDescriptor;
+using saml2md::SPSSODescriptor;
 using saml2md::MetadataException;
 #else
 # include "lite/SAMLConstants.h"
@@ -66,8 +67,14 @@ namespace shibsp {
         }
         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,
index 9b1c3ec..83f8ea9 100644 (file)
@@ -61,8 +61,13 @@ namespace shibsp {
         }
         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,
index 4674931..2b0c5d0 100644 (file)
@@ -72,6 +72,22 @@ namespace shibsp {
         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
index cf5dd81..c350e9b 100644 (file)
@@ -141,6 +141,7 @@ namespace {
         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.
@@ -178,7 +179,7 @@ namespace {
         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
@@ -1106,6 +1107,17 @@ const Handler* XMLApplication::getHandler(const char* path) const
     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))
index bb6d2ed..573c172 100644 (file)
                                                >\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
index dcdac56..523f209 100644 (file)
                                                >\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