Draft artifact resolver.
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Sun, 27 May 2007 03:27:51 +0000 (03:27 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Sun, 27 May 2007 03:27:51 +0000 (03:27 +0000)
Fixes and properties related to SOAP-based services.
Client certificate bridging for Apache and IIS.

git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@2263 cb58f699-b61c-0410-a6fe-9272a202ed29

17 files changed:
apache/mod_apache.cpp
configs/shibboleth.xml.in
isapi_shib/isapi_shib.cpp
isapi_shib/isapi_shib.vcproj
nsapi_shib/nsapi_shib.cpp
schemas/shibboleth-2.0-native-sp-config.xsd
shibsp/Makefile.am
shibsp/handler/AbstractHandler.h
shibsp/handler/AssertionConsumerService.h
shibsp/handler/impl/AbstractHandler.cpp
shibsp/handler/impl/AssertionConsumerService.cpp
shibsp/handler/impl/RemotedHandler.cpp
shibsp/handler/impl/SAML1Consumer.cpp
shibsp/handler/impl/SAML2ArtifactResolution.cpp [new file with mode: 0644]
shibsp/handler/impl/SAML2Consumer.cpp
shibsp/shibsp-lite.vcproj
shibsp/shibsp.vcproj

index ccbc0c3..91e196f 100644 (file)
@@ -271,7 +271,7 @@ class ShibTargetApache : public AbstractSPRequest
 {
   mutable string m_body;
   mutable bool m_gotBody;
-  vector<string> m_certs;
+  mutable vector<string> m_certs;
 
 public:
   request_rec* m_req;
@@ -419,13 +419,26 @@ public:
         in.read(buf,1024);
         ap_rwrite(buf,in.gcount(),m_req);
     }
-    return ((status==XMLTOOLING_HTTP_STATUS_OK) ? DONE : status);
+    if (status!=XMLTOOLING_HTTP_STATUS_OK)
+        m_req->status = status;
+    return DONE;
   }
   long sendRedirect(const char* url) {
     ap_table_set(m_req->headers_out, "Location", url);
     return REDIRECT;
   }
   const vector<string>& getClientCertificates() const {
+      if (m_certs.empty()) {
+          const char* cert = ap_table_get(m_req->subprocess_env, "SSL_CLIENT_CERT");
+          if (cert)
+              m_certs.push_back(cert);
+          int i = 0;
+          do {
+              cert = ap_table_get(m_req->subprocess_env, ap_psprintf(m_req->pool, "SSL_CLIENT_CERT_CHAIN_%d", i++));
+              if (cert)
+                  m_certs.push_back(cert);
+          } while (cert);
+      }
       return m_certs;
   }
   long returnDecline(void) { return DECLINED; }
index bceda8d..df65ed2 100644 (file)
                        logoLocation="/shibboleth-sp/logo.jpg"
                        styleSheet="/shibboleth-sp/main.css"/>
                
-               <!-- Configure handling of outgoing messages and SOAP client authentication. -->
-               <DefaultRelyingParty authType="TLS" signRequests="false" encryptRequests="true" artifactEndpointIndex="1">
+               <!-- Configure handling of outgoing messages and SOAP authentication. -->
+               <DefaultRelyingParty authType="TLS" artifactEndpointIndex="1"
+                       signRequests="true" encryptRequests="true" signResponses="true" encryptResponses="true">
                        <!-- Uncomment and modify to tweak settings for specific IdPs or groups. -->
                        <!--
                        <RelyingParty Name="SpecialFederation" keyName="SpecialKey"/>
index 9bc2e45..485e248 100644 (file)
@@ -34,6 +34,7 @@
 #include <xmltooling/util/NDC.h>
 #include <xmltooling/util/XMLConstants.h>
 #include <xmltooling/util/XMLHelper.h>
+#include <xercesc/util/Base64.hpp>
 #include <xercesc/util/XMLUniDefs.hpp>
 
 #include <set>
@@ -93,6 +94,7 @@ namespace {
     SPConfig* g_Config = NULL;
     map<string,site_t> g_Sites;
     bool g_bNormalizeRequest = true;
+    vector<string> g_NoCerts;
 }
 
 BOOL LogEvent(
@@ -191,7 +193,7 @@ extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
     // Access the implementation-specifics for site mappings.
     ServiceProvider* sp=g_Config->getServiceProvider();
     xmltooling::Locker locker(sp);
-    const PropertySet* props=sp->getPropertySet("Local");
+    const PropertySet* props=sp->getPropertySet("InProcess");
     if (props) {
         const DOMElement* impl=XMLHelper::getFirstChildElement(props->getElement(),Implementation);
         if (impl && (impl=XMLHelper::getFirstChildElement(impl,ISAPI))) {
@@ -340,7 +342,6 @@ class ShibTargetIsapiF : public AbstractSPRequest
   PHTTP_FILTER_CONTEXT m_pfc;
   PHTTP_FILTER_PREPROC_HEADERS m_pn;
   map<string,string> m_headers;
-  vector<string> m_certs;
   int m_port;
   string m_scheme,m_hostname,m_uri;
   mutable string m_remote_addr,m_content_type,m_method;
@@ -503,7 +504,7 @@ public:
   }
 
   const vector<string>& getClientCertificates() const {
-      return m_certs;
+      return g_NoCerts;
   }
   
   // The filter never processes the POST, so stub these methods.
@@ -616,12 +617,12 @@ class ShibTargetIsapiE : public AbstractSPRequest
 {
   LPEXTENSION_CONTROL_BLOCK m_lpECB;
   map<string,string> m_headers;
-  vector<string> m_certs;
+  mutable vector<string> m_certs;
   mutable string m_body;
   mutable bool m_gotBody;
   int m_port;
   string m_scheme,m_hostname,m_uri;
-  mutable string m_remote_addr;
+  mutable string m_remote_addr,m_remote_user;
   
 public:
   ShibTargetIsapiE(LPEXTENSION_CONTROL_BLOCK lpECB, const site_t& site) : m_lpECB(lpECB), m_gotBody(false) {
@@ -717,6 +718,15 @@ public:
   long getContentLength() const {
       return m_lpECB->cbTotalBytes;
   }
+  string getRemoteUser() const {
+    if (m_remote_user.empty()) {
+        dynabuf var(16);
+        GetServerVariable(m_lpECB, "REMOTE_USER", var, 32, false);
+        if (!var.empty())
+            m_remote_user = var;
+    }
+    return m_remote_user;
+  }
   string getRemoteAddr() const {
     if (m_remote_addr.empty()) {
         dynabuf var(16);
@@ -726,7 +736,7 @@ public:
     }
     return m_remote_addr;
   }
-  void log(SPLogLevel level, const string& msg) {
+  void log(SPLogLevel level, const string& msg) const {
       AbstractSPRequest::log(level,msg);
       if (level >= SPError)
           LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, msg.c_str());
@@ -826,6 +836,22 @@ public:
   }
 
   const vector<string>& getClientCertificates() const {
+      if (m_certs.empty()) {
+        char CertificateBuf[8192];
+        CERT_CONTEXT_EX ccex;
+        ccex.cbAllocated = sizeof(CertificateBuf);
+        ccex.CertContext.pbCertEncoded = (BYTE*)CertificateBuf;
+        DWORD dwSize = sizeof(ccex);
+
+        if (m_lpECB->ServerSupportFunction(m_lpECB->ConnID, HSE_REQ_GET_CERT_INFO_EX, (LPVOID)&ccex, (LPDWORD)dwSize, NULL)) {
+            if (ccex.CertContext.cbCertEncoded) {
+                unsigned int outlen;
+                XMLByte* serialized = Base64::encode(reinterpret_cast<XMLByte*>(CertificateBuf), ccex.CertContext.cbCertEncoded, &outlen);
+                m_certs.push_back(reinterpret_cast<char*>(serialized));
+                XMLString::release(&serialized);
+            }
+        }
+      }
       return m_certs;
   }
 
@@ -833,7 +859,6 @@ public:
   virtual void clearHeader(const char* name) { throw runtime_error("clearHeader not implemented"); }
   virtual void setHeader(const char* name, const char* value) { throw runtime_error("setHeader not implemented"); }
   virtual void setRemoteUser(const char* user) { throw runtime_error("setRemoteUser not implemented"); }
-  virtual string getRemoteUser() const { throw runtime_error("getRemoteUser not implemented"); }
 };
 
 extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)
index 2a786ef..b1324c7 100644 (file)
@@ -49,7 +49,7 @@
                                Optimization="2"
                                InlineFunctionExpansion="1"
                                AdditionalIncludeDirectories=".;..;&quot;..\..\cpp-xmltooling&quot;"
-                               PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;WIN32_LEAN_AND_MEAN"
+                               PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0400"
                                StringPooling="true"
                                RuntimeLibrary="2"
                                EnableFunctionLevelLinking="true"
                                Name="VCCLCompilerTool"
                                Optimization="0"
                                AdditionalIncludeDirectories=".;..;&quot;..\..\cpp-xmltooling&quot;"
-                               PreprocessorDefinitions="_WINDOWS;WIN32;_DEBUG;WIN32_LEAN_AND_MEAN"
+                               PreprocessorDefinitions="_WINDOWS;WIN32;_DEBUG;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0400"
                                BasicRuntimeChecks="3"
                                RuntimeLibrary="3"
                                RuntimeTypeInfo="true"
index 55a53da..e834762 100644 (file)
@@ -255,7 +255,7 @@ public:
   string getRemoteAddr() const {
     return pblock_findval("ip", m_sn->client);
   }
-  void log(SPLogLevel level, const string& msg) {
+  void log(SPLogLevel level, const string& msg) const {
     AbstractSPRequest::log(level,msg);
     if (level>=SPError)
         log_error(LOG_FAILURE, "nsapi_shib", m_sn, m_rq, const_cast<char*>(msg.c_str()));
index 7d27a38..ab2da76 100644 (file)
                <attribute name="authUsername" type="conf:string"/>\r
                <attribute name="authPassword" type="conf:string"/>\r
                <attribute name="signRequests" type="boolean"/>
+               <attribute name="signResponses" type="boolean"/>\r
                <attribute name="signatureAlg" type="anyURI"/>\r
                <attribute name="digestAlg" type="anyURI"/>\r
                <attribute name="encryptRequests" type="boolean"/>\r
+               <attribute name="encryptResponses" type="boolean"/>\r
                <attribute name="encryptionAlg" type="anyURI"/>\r
                <attribute name="keyName" type="conf:string"/>\r
                <attribute name="artifactEndpointIndex" type="unsignedShort"/>\r
index 3a4223a..4acf181 100644 (file)
@@ -107,6 +107,7 @@ common_sources = \
        handler/impl/RemotedHandler.cpp \
        handler/impl/SAML1Consumer.cpp \
        handler/impl/SAML2Consumer.cpp \
+       handler/impl/SAML2ArtifactResolution.cpp \
        handler/impl/SAML2SessionInitiator.cpp \
        handler/impl/SAMLDSSessionInitiator.cpp \
        handler/impl/SessionInitiator.cpp \
index 3fda7f8..5e12fc1 100644 (file)
@@ -27,7 +27,9 @@
 #include <shibsp/util/DOMPropertySet.h>
 
 #include <log4cpp/Category.hh>
-
+#ifndef SHIBSP_LITE
+# include <saml/saml2/core/Protocols.h>
+#endif
 #include <xmltooling/XMLObject.h>
 #include <xmltooling/io/HTTPRequest.h>
 #include <xmltooling/io/HTTPResponse.h>
@@ -72,6 +74,17 @@ namespace shibsp {
          * @param response      a response message of some known protocol
          */
         virtual void checkError(const xmltooling::XMLObject* response) const;
+
+        /**
+         * Prepares Status information in a SAML 2.0 response.
+         * 
+         * @param response  a SAML 2.0 response message
+         * @param code      SAML status code
+         * @param ex        optional message to pass back
+         */
+        void prepareResponse(
+            opensaml::saml2p::StatusResponseType& response, const XMLCh* code, const XMLCh* subcode=NULL, const char* msg=NULL
+            ) const;
 #endif
 
         /**
@@ -106,6 +119,9 @@ namespace shibsp {
         /** Logging object. */
         log4cpp::Category& m_log;
         
+        /** Configuration namespace for custom properties. */
+        xmltooling::auto_ptr_char m_configNS;
+
     public:
         virtual ~AbstractHandler() {}
     };
index e3e4987..e00dc8d 100644 (file)
@@ -137,7 +137,6 @@ namespace shibsp {
         opensaml::MessageDecoder* m_decoder;
         xmltooling::QName m_role;
 #endif
-        xmltooling::auto_ptr_char m_configNS;
     };
 
 #if defined (_MSC_VER)
index 6f449de..1054f4c 100644 (file)
@@ -27,6 +27,7 @@
 #include "SPRequest.h"
 #include "handler/AbstractHandler.h"
 #include "remoting/ListenerService.h"
+#include "util/SPConstants.h"
 
 #ifndef SHIBSP_LITE
 # include <saml/SAMLConfig.h>
@@ -53,6 +54,7 @@ using namespace std;
 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;
 };
 
 void SHIBSP_API shibsp::registerHandlers()
@@ -64,11 +66,13 @@ void SHIBSP_API shibsp::registerHandlers()
     conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_ARTIFACT, SAML2ConsumerFactory);
     conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_POST, SAML2ConsumerFactory);
     conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_POST_SIMPLESIGN, SAML2ConsumerFactory);
+
+    conf.ArtifactResolutionServiceManager.registerFactory(SAML20_BINDING_SOAP, SAML2ArtifactResolutionFactory);
 }
 
 AbstractHandler::AbstractHandler(
     const DOMElement* e, log4cpp::Category& log, DOMNodeFilter* filter, const map<string,string>* remapper
-    ) : m_log(log) {
+    ) : m_log(log), m_configNS(shibspconstants::SHIB2SPCONFIG_NS) {
     load(e,log,filter,remapper);
 }
 
@@ -120,6 +124,27 @@ void AbstractHandler::checkError(const XMLObject* response) const
         }
     }
 }
+
+void AbstractHandler::prepareResponse(saml2p::StatusResponseType& response, const XMLCh* code, const XMLCh* subcode, const char* msg) const
+{
+    saml2p::Status* status = saml2p::StatusBuilder::buildStatus();
+    saml2p::StatusCode* scode = saml2p::StatusCodeBuilder::buildStatusCode();
+    status->setStatusCode(scode);
+    scode->setValue(code);
+    if (subcode) {
+        saml2p::StatusCode* ssubcode = saml2p::StatusCodeBuilder::buildStatusCode();
+        scode->setStatusCode(ssubcode);
+        ssubcode->setValue(subcode);
+    }
+    if (msg) {
+        pair<bool,bool> flag = getBool("detailedErrors", m_configNS.get());
+        auto_ptr_XMLCh widemsg((flag.first && flag.second) ? msg : "Error processing request.");
+        saml2p::StatusMessage* sm = saml2p::StatusMessageBuilder::buildStatusMessage();
+        status->setStatusMessage(sm);
+        sm->setMessage(widemsg.get());
+    }
+    response.setStatus(status);
+}
 #endif
 
 void AbstractHandler::preserveRelayState(const Application& application, HTTPResponse& response, string& relayState) const
index 6c9b6fc..c176cf0 100644 (file)
@@ -48,12 +48,10 @@ using namespace log4cpp;
 using namespace std;
 
 AssertionConsumerService::AssertionConsumerService(const DOMElement* e, const char* appId, Category& log)
-    : AbstractHandler(e, log),
+    : AbstractHandler(e, log)
 #ifndef SHIBSP_LITE
-        m_decoder(NULL), m_role(samlconstants::SAML20MD_NS, opensaml::saml2md::IDPSSODescriptor::LOCAL_NAME),
+        ,m_decoder(NULL), m_role(samlconstants::SAML20MD_NS, opensaml::saml2md::IDPSSODescriptor::LOCAL_NAME)
 #endif
-        m_configNS(SHIB2SPCONFIG_NS)
-        
 {
     string address(appId);
     address += getString("Location").second;
index 402489e..b83ccfd 100644 (file)
@@ -153,11 +153,15 @@ std::vector<const char*>::size_type RemotedRequest::getParameters(const char* na
 const std::vector<XSECCryptoX509*>& RemotedRequest::getClientCertificates() const
 {
     if (m_certs.empty()) {
-        DDF cert = m_input["certificates"].first();
-        while (cert.isstring()) {
+        DDF certs = m_input["certificates"];
+        DDF cert = certs.first();
+        while (cert.string()) {
             try {
                 auto_ptr<XSECCryptoX509> x509(XSECPlatformUtils::g_cryptoProvider->X509());
-                x509->loadX509Base64Bin(cert.string(), cert.strlen());
+                if (strstr(cert.string(), "BEGIN"))
+                    x509->loadX509PEM(cert.string(), cert.strlen());
+                else
+                    x509->loadX509Base64Bin(cert.string(), cert.strlen());
                 m_certs.push_back(x509.release());
             }
             catch(XSECException& e) {
@@ -167,7 +171,7 @@ const std::vector<XSECCryptoX509*>& RemotedRequest::getClientCertificates() cons
             catch(XSECCryptoException& e) {
                 Category::getInstance(SHIBSP_LOGCAT".SPRequest").error("XML-Security exception loading client certificate: %s", e.getMsg());
             }
-            cert = cert.next();
+            cert = certs.next();
         }
     }
     return m_certs;
@@ -285,10 +289,16 @@ DDF RemotedHandler::wrap(const SPRequest& request, const vector<string>* headers
 pair<bool,long> RemotedHandler::unwrap(SPRequest& request, DDF& out) const
 {
     DDF h = out["headers"];
-    h = h.first();
-    while (h.isstring()) {
-        request.setResponseHeader(h.name(), h.string());
-        h = h.next();
+    DDF hdr = h.first();
+    while (hdr.isstring()) {
+#ifdef HAVE_STRCASECMP
+        if (!strcasecmp(hdr.name(), "Content-Type"))
+#else
+        if (!stricmp(hdr.name(), "Content-Type"))
+#endif
+            request.setContentType(hdr.string());
+        request.setResponseHeader(hdr.name(), hdr.string());
+        hdr = h.next();
     }
     h = out["redirect"];
     if (h.isstring())
index 13c1e1f..c2870ee 100644 (file)
@@ -63,7 +63,7 @@ namespace shibsp {
     {
     public:
         SAML1Consumer(const DOMElement* e, const char* appId)
-                : AssertionConsumerService(e, appId, Category::getInstance(SHIBSP_LOGCAT".SAML1")) {
+                : AssertionConsumerService(e, appId, Category::getInstance(SHIBSP_LOGCAT".SAML1SSO")) {
 #ifndef SHIBSP_LITE
             m_post = XMLString::equals(getString("Binding").second, samlconstants::SAML1_PROFILE_BROWSER_POST);
 #endif
diff --git a/shibsp/handler/impl/SAML2ArtifactResolution.cpp b/shibsp/handler/impl/SAML2ArtifactResolution.cpp
new file mode 100644 (file)
index 0000000..d2eb0aa
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ *  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.
+ */
+
+/**
+ * SAML2ArtifactResolution.cpp
+ * 
+ * Handler for resolving SAML 2.0 artifacts.
+ */
+
+#include "internal.h"
+#include "Application.h"
+#include "exceptions.h"
+#include "ServiceProvider.h"
+#include "handler/AbstractHandler.h"
+#include "handler/RemotedHandler.h"
+#include "util/SPConstants.h"
+
+#ifndef SHIBSP_LITE
+# include "security/SecurityPolicy.h"
+# include <saml/SAMLConfig.h>
+# include <saml/binding/ArtifactMap.h>
+# include <saml/binding/MessageEncoder.h>
+# include <saml/binding/MessageDecoder.h>
+# include <saml/binding/SAMLArtifact.h>
+# include <saml/saml2/core/Assertions.h>
+# include <saml/saml2/core/Protocols.h>
+# include <saml/saml2/metadata/Metadata.h>
+# include <saml/saml2/metadata/MetadataCredentialCriteria.h>
+using namespace opensaml::saml2md;
+using namespace opensaml::saml2p;
+using namespace opensaml::saml2;
+using namespace samlconstants;
+#endif
+
+#include <xmltooling/soap/SOAP.h>
+
+using namespace shibspconstants;
+using namespace shibsp;
+using namespace opensaml;
+using namespace soap11;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace shibsp {
+
+    class SHIBSP_API Attribute;
+    class SHIBSP_API ResolutionContext;
+
+#if defined (_MSC_VER)
+    #pragma warning( push )
+    #pragma warning( disable : 4250 )
+#endif
+
+    class SHIBSP_API SAML2ArtifactResolution : public AbstractHandler, public RemotedHandler 
+    {
+    public:
+        SAML2ArtifactResolution(const DOMElement* e, const char* appId);
+        virtual ~SAML2ArtifactResolution();
+
+        pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
+        void receive(DDF& in, ostream& out);
+
+    private:
+        pair<bool,long> processMessage(const Application& application, HTTPRequest& httpRequest, HTTPResponse& httpResponse) const;
+#ifndef SHIBSP_LITE
+        pair<bool,long> samlError(
+            const Application& app,
+            const ArtifactResolve& request,
+            HTTPResponse& httpResponse,
+            const XMLCh* code,
+            const XMLCh* subcode=NULL,
+            const char* msg=NULL
+            ) const;
+
+        MessageEncoder* m_encoder;
+        MessageDecoder* m_decoder;
+        QName m_role;
+#endif
+    };
+
+#if defined (_MSC_VER)
+    #pragma warning( pop )
+#endif
+
+    Handler* SHIBSP_DLLLOCAL SAML2ArtifactResolutionFactory(const pair<const DOMElement*,const char*>& p)
+    {
+        return new SAML2ArtifactResolution(p.first, p.second);
+    }
+
+};
+
+SAML2ArtifactResolution::SAML2ArtifactResolution(const DOMElement* e, const char* appId)
+    : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".SAML2ArtifactResolution"))
+#ifndef SHIBSP_LITE
+        ,m_encoder(NULL), m_decoder(NULL), m_role(samlconstants::SAML20MD_NS, opensaml::saml2md::IDPSSODescriptor::LOCAL_NAME)
+#endif
+{
+#ifndef SHIBSP_LITE
+    if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
+        try {
+            m_encoder = SAMLConfig::getConfig().MessageEncoderManager.newPlugin(getString("Binding").second,e);
+            m_decoder = SAMLConfig::getConfig().MessageDecoderManager.newPlugin(getString("Binding").second,e);
+        }
+        catch (exception& ex) {
+            m_log.error("error building MessageEncoder/Decoder pair for binding (%s)", getString("Binding").second);
+            delete m_encoder;
+            delete m_decoder;
+            throw;
+        }
+    }
+#endif
+    string address(appId);
+    address += getString("Location").second;
+    address += "::run::SAML2Artifact";
+    setAddress(address.c_str());
+}
+
+SAML2ArtifactResolution::~SAML2ArtifactResolution()
+{
+#ifndef SHIBSP_LITE
+    delete m_encoder;
+    delete m_decoder;
+#endif
+}
+
+pair<bool,long> SAML2ArtifactResolution::run(SPRequest& request, bool isHandler) const
+{
+    string relayState;
+    SPConfig& conf = SPConfig::getConfig();
+    
+    try {
+        if (conf.isEnabled(SPConfig::OutOfProcess)) {
+            // When out of process, we run natively and directly process the message.
+            string entityID;
+            return processMessage(request.getApplication(), request, request);
+        }
+        else {
+            // When not out of process, we remote all the message processing.
+            DDF out,in = wrap(request, NULL, true);
+            DDFJanitor jin(in), jout(out);
+            
+            in.addmember("application_id").string(request.getApplication().getId());
+            out=request.getServiceProvider().getListenerService()->send(in);
+            return unwrap(request, out);
+        }
+    }
+    catch (exception& ex) {
+        m_log.error("error while processing request: %s", ex.what());
+
+        // Build a SOAP fault around the error.
+        auto_ptr<Fault> fault(FaultBuilder::buildFault());
+        Faultcode* code = FaultcodeBuilder::buildFaultcode();
+        fault->setFaultcode(code);
+        code->setCode(&Faultcode::SERVER);
+        Faultstring* fs = FaultstringBuilder::buildFaultstring();
+        fault->setFaultstring(fs);
+        pair<bool,bool> flag = getBool("detailedErrors", m_configNS.get());
+        auto_ptr_XMLCh msg((flag.first && flag.second) ? ex.what() : "Error processing request.");
+        fs->setString(msg.get());
+#ifndef SHIBSP_LITE
+        // Use MessageEncoder to send back the fault.
+        long ret = m_encoder->encode(request, fault.get(), NULL);
+        fault.release();
+        return make_pair(true, ret);
+#else
+        // Brute force the fault to avoid library dependency.
+        auto_ptr<Envelope> env(EnvelopeBuilder::buildEnvelope());
+        Body* body = BodyBuilder::buildBody();
+        env->setBody(body);
+        body->getUnknownXMLObjects().push_back(fault.release());
+        string xmlbuf;
+        XMLHelper::serialize(env->marshall(), xmlbuf);
+        istringstream s(xmlbuf);
+        request.setContentType("text/xml");
+        return make_pair(true, request.sendError(s));
+#endif
+    }
+}
+
+void SAML2ArtifactResolution::receive(DDF& in, ostream& out)
+{
+    // Find application.
+    const char* aid=in["application_id"].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 artifact resolution", aid ? aid : "(missing)");
+        throw ConfigurationException("Unable to locate application for new session, deleted?");
+    }
+    
+    // Unpack the request.
+    auto_ptr<HTTPRequest> req(getRequest(in));
+    //m_log.debug("found %d client certificates", req->getClientCertificates().size());
+
+    // Wrap a response shim.
+    DDF ret(NULL);
+    DDFJanitor jout(ret);
+    auto_ptr<HTTPResponse> resp(getResponse(ret));
+        
+    try {
+        // 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, *req.get(), *resp.get());
+        out << ret;
+    }
+    catch (exception& ex) {
+#ifndef SHIBSP_LITE
+        m_log.error("error while processing request: %s", ex.what());
+
+        // Use MessageEncoder to send back a SOAP fault.
+        auto_ptr<Fault> fault(FaultBuilder::buildFault());
+        Faultcode* code = FaultcodeBuilder::buildFaultcode();
+        fault->setFaultcode(code);
+        code->setCode(&Faultcode::SERVER);
+        Faultstring* fs = FaultstringBuilder::buildFaultstring();
+        fault->setFaultstring(fs);
+        pair<bool,bool> flag = getBool("detailedErrors", m_configNS.get());
+        auto_ptr_XMLCh msg((flag.first && flag.second) ? ex.what() : "Error processing request.");
+        fs->setString(msg.get());
+        m_encoder->encode(*resp.get(), fault.get(), NULL);
+        fault.release();
+        out << ret;
+#else
+        throw;  // should never happen anyway
+#endif
+    }
+}
+
+pair<bool,long> SAML2ArtifactResolution::processMessage(const Application& application, HTTPRequest& httpRequest, HTTPResponse& httpResponse) const
+{
+#ifndef SHIBSP_LITE
+    m_log.debug("processing SAML 2.0 ArtifactResolve request");
+
+    ArtifactMap* artmap = SAMLConfig::getConfig().getArtifactMap();
+    if (!artmap)
+        throw ConfigurationException("No ArtifactMap instance installed.");
+
+    // Locate policy key.
+    pair<bool,const char*> policyId = getString("policyId", m_configNS.get());  // namespace-qualified if inside handler element
+    if (!policyId.first)
+        policyId = application.getString("policyId");   // unqualified in Application(s) element
+        
+    // Access policy properties.
+    const PropertySet* settings = application.getServiceProvider().getPolicySettings(policyId.second);
+    pair<bool,bool> validate = settings->getBool("validate");
+
+    // Lock metadata for use by policy.
+    Locker metadataLocker(application.getMetadataProvider());
+
+    // Create the policy.
+    shibsp::SecurityPolicy policy(application, &m_role, validate.first && validate.second);
+    
+    // Decode the message and verify that it's a secured ArtifactResolve request.
+    string relayState;
+    auto_ptr<XMLObject> msg(m_decoder->decode(relayState, httpRequest, policy));
+    if (!msg.get())
+        throw BindingException("Failed to decode a SAML request.");
+    const ArtifactResolve* req = dynamic_cast<const ArtifactResolve*>(msg.get());
+    if (!req)
+        throw FatalProfileException("Decoded message was not a samlp::ArtifactResolve request.");
+
+    try {
+        if (!policy.isSecure())
+            return samlError(application, *req, httpResponse, StatusCode::REQUESTER, StatusCode::AUTHN_FAILED, "Unable to authenticate request.");
+
+        auto_ptr_char artifact(req->getArtifact() ? req->getArtifact()->getArtifact() : NULL);
+        if (!artifact.get() || !*artifact.get())
+            return samlError(application, *req, httpResponse, StatusCode::REQUESTER, NULL, "Request did not contain an artifact to resolve.");
+        auto_ptr_char issuer(policy.getIssuer() ? policy.getIssuer()->getName() : NULL);
+
+        m_log.info("resolving artifact (%s) for (%s)", artifact.get(), issuer.get() ? issuer.get() : "unknown");
+
+        // Parse the artifact and retrieve the object.
+        auto_ptr<SAMLArtifact> artobj(SAMLArtifact::parse(artifact.get()));
+        auto_ptr<XMLObject> payload(artmap->retrieveContent(artobj.get(), issuer.get()));
+
+        m_log.debug("artifact resolved, preparing response");
+
+        // Wrap it in a response.
+        auto_ptr<ArtifactResponse> resp(ArtifactResponseBuilder::buildArtifactResponse());
+        resp->setInResponseTo(req->getID());
+        Issuer* me = IssuerBuilder::buildIssuer();
+        me->setName(application.getXMLString("entityID").second);
+        resp->setPayload(payload.release());
+
+        const EntityDescriptor* entity =
+            policy.getIssuerMetadata() ? dynamic_cast<EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL;
+        const PropertySet* relyingParty = application.getRelyingParty(entity);
+        pair<bool,bool> flag = relyingParty->getBool("signResponses");
+        if (flag.first && flag.second && policy.getIssuerMetadata()) {
+            CredentialResolver* credResolver=application.getCredentialResolver();
+            if (credResolver) {
+                Locker credLocker(credResolver);
+                // Fill in criteria to use.
+                MetadataCredentialCriteria mcc(*policy.getIssuerMetadata());
+                mcc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL);
+                pair<bool,const char*> keyName = relyingParty->getString("keyName");
+                if (keyName.first)
+                    mcc.getKeyNames().insert(keyName.second);
+                pair<bool,const XMLCh*> sigalg = relyingParty->getXMLString("signatureAlg");
+                if (sigalg.first)
+                    mcc.setXMLAlgorithm(sigalg.second);
+                const Credential* cred = credResolver->resolve(&mcc);
+                if (cred) {
+                    // Signed request.
+                    long ret = m_encoder->encode(
+                        httpResponse,
+                        resp.get(),
+                        NULL,
+                        entity,
+                        relayState.c_str(),
+                        NULL,
+                        cred,
+                        sigalg.second,
+                        relyingParty->getXMLString("digestAlg").second
+                        );
+                    resp.release();  // freed by encoder
+                    return make_pair(true,ret);
+                }
+                else {
+                    m_log.warn("no signing credential resolved, leaving response unsigned");
+                }
+            }
+        }
+
+        long ret = m_encoder->encode(httpResponse, resp.get(), NULL, entity, relayState.c_str());
+        resp.release();  // freed by encoder
+        return make_pair(true,ret);
+    }
+    catch (exception& ex) {
+        // Trap localized errors in a SAML Response.
+        m_log.error("error processing artifact request, returning SAML error: %s", ex.what());
+        return samlError(application, *req, httpResponse, StatusCode::RESPONDER, NULL, ex.what());
+    }
+#else
+    return make_pair(false,0);
+#endif
+}
+
+#ifndef SHIBSP_LITE
+pair<bool,long> SAML2ArtifactResolution::samlError(
+    const Application& app, const ArtifactResolve& request, HTTPResponse& httpResponse, const XMLCh* code, const XMLCh* subcode, const char* msg
+    ) const
+{
+    auto_ptr<ArtifactResponse> resp(ArtifactResponseBuilder::buildArtifactResponse());
+    resp->setInResponseTo(request.getID());
+    Issuer* me = IssuerBuilder::buildIssuer();
+    me->setName(app.getXMLString("entityID").second);
+    prepareResponse(*resp.get(), code, subcode, msg);
+    long ret = m_encoder->encode(httpResponse, resp.get(), NULL);
+    resp.release();  // freed by encoder
+    return make_pair(true,ret);
+}
+#endif
index cca120e..dfe89f5 100644 (file)
@@ -59,7 +59,7 @@ namespace shibsp {
     {
     public:
         SAML2Consumer(const DOMElement* e, const char* appId)
-            : AssertionConsumerService(e, appId, Category::getInstance(SHIBSP_LOGCAT".SAML2")) {
+            : AssertionConsumerService(e, appId, Category::getInstance(SHIBSP_LOGCAT".SAML2SSO")) {
         }
         virtual ~SAML2Consumer() {}
         
index ccd9121..cfbfdbe 100644 (file)
                                                >\r
                                        </File>\r
                                        <File\r
+                                               RelativePath=".\handler\impl\SAML2ArtifactResolution.cpp"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\handler\impl\SAML2Consumer.cpp"\r
                                                >\r
                                        </File>\r
index 5f514b5..f1da7e9 100644 (file)
                                                >\r
                                        </File>\r
                                        <File\r
+                                               RelativePath=".\handler\impl\SAML2ArtifactResolution.cpp"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\handler\impl\SAML2Consumer.cpp"\r
                                                >\r
                                        </File>\r