Artifact mapper implementation
authorScott Cantor <cantor.2@osu.edu>
Mon, 21 Feb 2005 04:31:51 +0000 (04:31 +0000)
committerScott Cantor <cantor.2@osu.edu>
Mon, 21 Feb 2005 04:31:51 +0000 (04:31 +0000)
shib-target/ArtifactMapper.cpp [new file with mode: 0644]
shib-target/Makefile.am
shib-target/internal.h
shib-target/shib-ccache.cpp
shib-target/shib-ini.cpp
shib-target/shib-target.h
shib-target/shibrpc-server.cpp

diff --git a/shib-target/ArtifactMapper.cpp b/shib-target/ArtifactMapper.cpp
new file mode 100644 (file)
index 0000000..35145b8
--- /dev/null
@@ -0,0 +1,177 @@
+/* 
+ * The Shibboleth License, Version 1. 
+ * Copyright (c) 2002 
+ * University Corporation for Advanced Internet Development, Inc. 
+ * All rights reserved
+ * 
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice, this 
+ * list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice, 
+ * this list of conditions and the following disclaimer in the documentation 
+ * and/or other materials provided with the distribution, if any, must include 
+ * the following acknowledgment: "This product includes software developed by 
+ * the University Corporation for Advanced Internet Development 
+ * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement 
+ * may appear in the software itself, if and wherever such third-party 
+ * acknowledgments normally appear.
+ * 
+ * Neither the name of Shibboleth nor the names of its contributors, nor 
+ * Internet2, nor the University Corporation for Advanced Internet Development, 
+ * Inc., nor UCAID may be used to endorse or promote products derived from this 
+ * software without specific prior written permission. For written permission, 
+ * please contact shibboleth@shibboleth.org
+ * 
+ * Products derived from this software may not be called Shibboleth, Internet2, 
+ * UCAID, or the University Corporation for Advanced Internet Development, nor 
+ * may Shibboleth appear in their name, without prior written permission of the 
+ * University Corporation for Advanced Internet Development.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
+ * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK 
+ * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. 
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY 
+ * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, 
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* ArtifactMapper.cpp - a ShibTarget-aware SAML artifact->binding mapper
+
+   Scott Cantor
+   2/20/05
+
+   $History:$
+*/
+
+#include "internal.h"
+
+#include <log4cpp/Category.hh>
+
+using namespace std;
+using namespace log4cpp;
+using namespace saml;
+using namespace shibboleth;
+using namespace shibtarget;
+
+SAMLBrowserProfile::ArtifactMapper::ArtifactMapperResponse STArtifactMapper::map(const SAMLArtifact* artifact)
+{
+    Category& log=Category::getInstance("shibtarget.ArtifactMapper");
+    
+    // First do a search for the issuer.
+    const IEntityDescriptor* entity=m_metadata.lookup(artifact);
+    if (!entity) {
+        log.error(
+            "metadata lookup failed, unable to determine issuer of artifact (0x%s)",
+            SAMLArtifact::toHex(artifact->getBytes()).c_str()
+            );
+        throw MetadataException("ArtifactMapper::map() metadata lookup failed, unable to determine artifact issuer");
+    }
+    
+    if (log.isInfoEnabled()) {
+        auto_ptr_char issuer(entity->getId());
+        log.info("lookup succeeded, artifact issued by (%s)", issuer.get());
+    }
+    
+    SAMLBrowserProfile::ArtifactMapper::ArtifactMapperResponse amr;
+
+    // Depends on type of artifact.
+    const SAMLArtifactType0001* type1=dynamic_cast<const SAMLArtifactType0001*>(artifact);
+    if (type1) {
+        // With type 01, any endpoint will do. Try SAML 1.1 first.
+        const IIDPSSODescriptor* idp=entity->getIDPSSODescriptor(saml::XML::SAML11_PROTOCOL_ENUM);
+        if (idp) {
+            const IEndpointManager* mgr=idp->getArtifactResolutionServiceManager();
+            Iterator<const IEndpoint*> eps=mgr ? mgr->getEndpoints() : EMPTY(const IEndpoint*);
+            while (eps.hasNext()) {
+                const IEndpoint* ep=eps.next();
+                amr.binding = m_app->getBinding(ep->getBinding());
+                if (amr.binding) {
+                    auto_ptr_char loc(ep->getLocation());
+                    amr.endpoint = loc.get();
+                    amr.callCtx = new ShibHTTPHook::ShibHTTPHookCallContext(m_app->getTLSCred(entity),idp);
+                    return amr;
+                }
+            }
+        }
+        
+        // No compatible 1.1 binding, try 1.0...
+        idp=entity->getIDPSSODescriptor(saml::XML::SAML10_PROTOCOL_ENUM);
+        if (idp) {
+            const IEndpointManager* mgr=idp->getArtifactResolutionServiceManager();
+            Iterator<const IEndpoint*> eps=mgr ? mgr->getEndpoints() : EMPTY(const IEndpoint*);
+            while (eps.hasNext()) {
+                const IEndpoint* ep=eps.next();
+                amr.binding = m_app->getBinding(ep->getBinding());
+                if (amr.binding) {
+                    auto_ptr_char loc(ep->getLocation());
+                    amr.endpoint = loc.get();
+                    amr.callCtx = new ShibHTTPHook::ShibHTTPHookCallContext(m_app->getTLSCred(entity),idp);
+                    return amr;
+                }
+            }
+        }
+    }
+    else {
+        const SAMLArtifactType0002* type2=dynamic_cast<const SAMLArtifactType0002*>(artifact);
+        if (type2) {
+            // With type 02, we have to find the matching location. Try SAML 1.1 first.
+            const IIDPSSODescriptor* idp=entity->getIDPSSODescriptor(saml::XML::SAML11_PROTOCOL_ENUM);
+            if (idp) {
+                const IEndpointManager* mgr=idp->getArtifactResolutionServiceManager();
+                Iterator<const IEndpoint*> eps=mgr ? mgr->getEndpoints() : EMPTY(const IEndpoint*);
+                while (eps.hasNext()) {
+                    const IEndpoint* ep=eps.next();
+                    auto_ptr_char loc(ep->getLocation());
+                    if (!strcmp(loc.get(),type2->getSourceLocation())) {
+                        amr.binding = m_app->getBinding(ep->getBinding());
+                        if (amr.binding) {
+                            amr.endpoint = loc.get();
+                            amr.callCtx = new ShibHTTPHook::ShibHTTPHookCallContext(m_app->getTLSCred(entity),idp);
+                            return amr;
+                        }
+                    }
+                }
+            }
+
+            // No match for 1.1, try 1.0...
+            idp=entity->getIDPSSODescriptor(saml::XML::SAML10_PROTOCOL_ENUM);
+            if (idp) {
+                const IEndpointManager* mgr=idp->getArtifactResolutionServiceManager();
+                Iterator<const IEndpoint*> eps=mgr ? mgr->getEndpoints() : EMPTY(const IEndpoint*);
+                while (eps.hasNext()) {
+                    const IEndpoint* ep=eps.next();
+                    auto_ptr_char loc(ep->getLocation());
+                    if (!strcmp(loc.get(),type2->getSourceLocation())) {
+                        amr.binding = m_app->getBinding(ep->getBinding());
+                        if (amr.binding) {
+                            amr.endpoint = loc.get();
+                            amr.callCtx = new ShibHTTPHook::ShibHTTPHookCallContext(m_app->getTLSCred(entity),idp);
+                            return amr;
+                        }
+                    }
+                }
+            }
+        }
+        else {
+            log.error("unrecognized artifact type (0x%s)", SAMLArtifact::toHex(artifact->getTypeCode()).c_str());
+            throw UnsupportedExtensionException(
+                string("ArtifactMapper::map() unrecognized artifact type (0x") + SAMLArtifact::toHex(artifact->getTypeCode()) + ")"
+                );
+        }
+    }
+    
+    log.error("unable to locate acceptable binding endpoint to resolve artifact");
+    throw MetadataException("ArtifactMapper::map() unable to locate acceptable binding endpoint to resolve artifact");
+}
index eaf436e..6856553 100644 (file)
@@ -18,6 +18,7 @@ libshib_target_HEADERS = shib-target.h shibrpc.h shib-paths.h
 noinst_HEADERS = internal.h
 
 libshib_target_la_SOURCES = \
+       ArtifactMapper.cpp \
        shib-ccache.cpp \
        shib-config.cpp \
        shib-ini.cpp \
index 1eee2c1..77b39ff 100644 (file)
@@ -160,6 +160,22 @@ namespace shibtarget {
         std::map<std::string,std::pair<char*,const XMLCh*> > m_map;
         std::map<std::string,IPropertySet*> m_nested;
     };
+
+    // ST-aware class that maps SAML artifacts to appropriate binding information
+    class STArtifactMapper : public virtual saml::SAMLBrowserProfile::ArtifactMapper
+    {
+    public:
+        STArtifactMapper(const IApplication* application)
+            : m_app(application), m_metadata(application->getMetadataProviders()), m_ctx(NULL) {}
+        virtual ~STArtifactMapper() {delete m_ctx;}
+    
+        saml::SAMLBrowserProfile::ArtifactMapper::ArtifactMapperResponse map(const saml::SAMLArtifact* artifact);
+    
+    private:
+        const IApplication* m_app;
+        shibboleth::Metadata m_metadata;    // scopes lock around use of role descriptor by hook context
+        shibboleth::ShibHTTPHook::ShibHTTPHookCallContext* m_ctx;
+    };
     
     class STConfig : public ShibTargetConfig
     {
index 09be57e..0a69bea 100644 (file)
@@ -689,7 +689,7 @@ SAMLResponse* InternalCCacheEntry::getNewResponse()
             providerID.second,
             application->getAttributeDesignators().clone()
             );
-        auto_ptr<SAMLRequest> req(new SAMLRequest(q,EMPTY(QName)));
+        auto_ptr<SAMLRequest> req(new SAMLRequest(q));
         
         // Sign it? Highly doubtful we'll ever use this, but just for fun...
         if (signRequest.first && signRequest.second) {
index 0dc40d6..6bc77b3 100644 (file)
@@ -98,6 +98,7 @@ namespace shibtarget {
         const SAMLBrowserProfile* getBrowserProfile() const {return m_profile;}
         const SAMLBinding* getBinding(const XMLCh* binding) const
             {return XMLString::compareString(SAMLBinding::SOAP,binding) ? NULL : m_binding;}
+        SAMLBrowserProfile::ArtifactMapper* getArtifactMapper() const {return new STArtifactMapper(this);}
         
         // Provides filter to exclude special config elements.
         short acceptNode(const DOMNode* node) const;
index e8d4525..9fe3aef 100644 (file)
@@ -194,9 +194,11 @@ namespace shibtarget {
         virtual saml::Iterator<const XMLCh*> getAudiences() const=0;
         virtual const char* getTLSCred(const shibboleth::IEntityDescriptor* provider) const=0;
         virtual const char* getSigningCred(const shibboleth::IEntityDescriptor* provider) const=0;
+        // caller is borrowing object, must use within scope of config lock
         virtual const saml::SAMLBrowserProfile* getBrowserProfile() const=0;
-        //virtual saml::SAMLBrowserProfile::ArtifactMapper* newArtifactMapper() const=0;
         virtual const saml::SAMLBinding* getBinding(const XMLCh* binding) const=0;
+        // caller is given ownership of object, must use and delete within scope of config lock
+        virtual saml::SAMLBrowserProfile::ArtifactMapper* getArtifactMapper() const=0;
         virtual ~IApplication() {}
     };
 
index 7694d38..b240055 100644 (file)
@@ -331,6 +331,8 @@ shibrpc_new_session_2_svc(
       
     try
     {
+      auto_ptr<SAMLBrowserProfile::ArtifactMapper> artifactMapper(app->getArtifactMapper());
+      
       // Try and run the profile.
       log.debug ("Executing browser profile...");
       bpr=app->getBrowserProfile()->receive(
@@ -338,7 +340,8 @@ shibrpc_new_session_2_svc(
         argp->packet,
         recipient.get(),
         SAMLBrowserProfile::Post,   // For now, we only handle POST.
-        (!checkReplay.first || checkReplay.second) ? conf->getReplayCache() : NULL
+        (!checkReplay.first || checkReplay.second) ? conf->getReplayCache() : NULL,
+        artifactMapper.get()
         );
 
       // Try and map to metadata for support purposes.