Revamped encoders to produce the actual HTTP responses.
authorScott Cantor <cantor.2@osu.edu>
Thu, 19 Oct 2006 21:28:16 +0000 (21:28 +0000)
committerScott Cantor <cantor.2@osu.edu>
Thu, 19 Oct 2006 21:28:16 +0000 (21:28 +0000)
18 files changed:
saml/binding/MessageDecoder.h
saml/binding/MessageEncoder.h
saml/saml1/binding/SAML1ArtifactEncoder.h
saml/saml1/binding/SAML1POSTEncoder.h
saml/saml1/binding/impl/SAML1ArtifactEncoder.cpp
saml/saml1/binding/impl/SAML1POSTEncoder.cpp
saml/saml2/binding/SAML2ArtifactEncoder.h
saml/saml2/binding/SAML2POSTEncoder.h
saml/saml2/binding/impl/SAML2ArtifactEncoder.cpp
saml/saml2/binding/impl/SAML2POSTEncoder.cpp
samltest/binding.h
samltest/data/binding/template.html [new file with mode: 0644]
samltest/saml1/binding/SAML1ArtifactTest.h
samltest/saml1/binding/SAML1POSTTest.h
samltest/saml2/binding/SAML2ArtifactTest.h
samltest/saml2/binding/SAML2POSTTest.h
samltest/samltest.h
samltest/samltest.vcproj

index 535dfc4..a55f0a7 100644 (file)
@@ -57,9 +57,11 @@ namespace opensaml {
         /**
          * Interface to caller-supplied shim for accessing HTTP request context.
          * 
         /**
          * Interface to caller-supplied shim for accessing HTTP request context.
          * 
-         * To supply information from the surrounding web server environment,
+         * <p>To supply information from the surrounding web server environment,
          * a shim must be supplied in the form of this interface to adapt the
          * library to different proprietary server APIs.
          * a shim must be supplied in the form of this interface to adapt the
          * library to different proprietary server APIs.
+         * 
+         * <p>This interface need not be threadsafe.
          */
         class SAML_API HTTPRequest {
             MAKE_NONCOPYABLE(HTTPRequest);
          */
         class SAML_API HTTPRequest {
             MAKE_NONCOPYABLE(HTTPRequest);
@@ -90,6 +92,14 @@ namespace opensaml {
              * @return the query string
              */
             virtual const char* getQueryString() const=0;
              * @return the query string
              */
             virtual const char* getQueryString() const=0;
+
+            /**
+             * Returns the raw HTTP request body. Used to access the body
+             * of a POST that is not in URL-encoded form.
+             * 
+             * @return the request body, or NULL
+             */
+            virtual const char* getRequestBody() const=0;
             
             /**
              * Returns a decoded named parameter value from the query string or form body.
             
             /**
              * Returns a decoded named parameter value from the query string or form body.
@@ -111,6 +121,21 @@ namespace opensaml {
             virtual std::vector<const char*>::size_type getParameters(
                 const char* name, std::vector<const char*>& values
                 ) const=0;
             virtual std::vector<const char*>::size_type getParameters(
                 const char* name, std::vector<const char*>& values
                 ) const=0;
+
+            /**
+             * Returns the authenticated identity associated with the request
+             * 
+             * @return the authenticated username or an empty string
+             */
+            virtual std::string getRemoteUser() const=0;
+
+            /**
+             * Returns a request header value.
+             * 
+             * @param name  the name of the header to return
+             * @return the header's value, or an empty string
+             */
+            virtual std::string getHeader(const char* name) const=0;
         };
 
         /**
         };
 
         /**
index 4d23033..536acf4 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <map>
 #include <string>
 
 #include <map>
 #include <string>
+#include <istream>
 #include <xmltooling/XMLObject.h>
 #include <xmltooling/signature/CredentialResolver.h>
 
 #include <xmltooling/XMLObject.h>
 #include <xmltooling/signature/CredentialResolver.h>
 
@@ -47,6 +48,59 @@ namespace opensaml {
         virtual ~MessageEncoder() {}
 
         /**
         virtual ~MessageEncoder() {}
 
         /**
+         * Interface to caller-supplied shim for issuing an HTTP response.
+         * 
+         * <p>To supply information to the surrounding web server environment,
+         * a shim must be supplied in the form of this interface to adapt the
+         * library to different proprietary server APIs.
+         * 
+         * <p>This interface need not be threadsafe.
+         */
+        class SAML_API HTTPResponse {
+            MAKE_NONCOPYABLE(HTTPResponse);
+        protected:
+            HTTPResponse() {}
+        public:
+            virtual ~HTTPResponse() {}
+            
+            /**
+             * Sets or clears a response header.
+             * 
+             * @param name  header name
+             * @param value value to set, or NULL to clear
+             */
+            virtual void setHeader(const char* name, const char* value)=0;
+
+            /**
+             * Sets a client cookie.
+             * 
+             * @param name  cookie name
+             * @param value value to set, or NULL to clear
+             */
+            virtual void setCookie(const char* name, const char* value)=0;
+            
+            /**
+             * Redirect the client to the specified URL and complete the response.
+             * Any headers previously set will be sent ahead of the redirect.
+             * 
+             * @param url   location to redirect client
+             * @return a result code to return from the calling MessageEncoder
+             */
+            virtual long sendRedirect(const char* url)=0;
+
+            /**
+             * Sends a completed response to the client. Any headers previously set
+             * will be sent ahead of the data.
+             * 
+             * @param inputStream   reference to source of response data
+             * @param status        HTTP status code to return
+             * @param contentType   Content-Type header to return
+             * @return a result code to return from the calling MessageEncoder
+             */
+            virtual long sendResponse(std::istream& inputStream, int status = 200, const char* contentType = "text/html")=0;
+        };
+
+        /**
          * Interface to caller-supplied artifact generation mechanism.
          * 
          * Generating an artifact for storage and retrieval requires knowledge of
          * Interface to caller-supplied artifact generation mechanism.
          * 
          * Generating an artifact for storage and retrieval requires knowledge of
@@ -92,7 +146,7 @@ namespace opensaml {
         }
         
         /**
         }
         
         /**
-         * Encodes an XML object/message into a set of binding-specific data "fields".
+         * Encodes an XML object/message into a binding-specific HTTP response.
          * The XML content cannot have a parent object, and any existing references to
          * the content will be invalidated if the encode method returns successfully.
          * 
          * The XML content cannot have a parent object, and any existing references to
          * the content will be invalidated if the encode method returns successfully.
          * 
@@ -100,27 +154,21 @@ namespace opensaml {
          * binding-specific manner. The CredentialResolver <strong>MUST</strong>
          * be locked by the caller. 
          * 
          * binding-specific manner. The CredentialResolver <strong>MUST</strong>
          * be locked by the caller. 
          * 
-         * <p>An embedded URLEncoder instance may be required by some bindings
-         * in order to produce predictable signature input.
-         * 
          * <p>Artifact-based bindings require an ArtifactGenerator be set to
          * produce an artifact suitable for the intended recipient.
          * 
          * <p>Artifact-based bindings require an ArtifactGenerator be set to
          * produce an artifact suitable for the intended recipient.
          * 
-         * <p>Note that the name/value pairs resulting from the encoding operation are
-         * <strong>NOT</strong> URL-encoded or otherwise transformed. It is the caller's
-         * responsibility to apply any necessary encoding when preparing the data for
-         * transport.
-         * 
-         * @param outputFields      name/value pairs containing the results of encoding the message
-         * @param xmlObject         XML object/message to encode
+         * @param httpResponse      reference to interface for sending encoded response to client      
+         * @param xmlObject         XML message to encode
+         * @param destination       destination URL for message
          * @param recipientID       optional entityID of message recipient
          * @param relayState        optional RelayState value to accompany message
          * @param credResolver      optional CredentialResolver instance to supply signing material
          * @param sigAlgorithm      optional signature algorithm identifier
          */
          * @param recipientID       optional entityID of message recipient
          * @param relayState        optional RelayState value to accompany message
          * @param credResolver      optional CredentialResolver instance to supply signing material
          * @param sigAlgorithm      optional signature algorithm identifier
          */
-        virtual void encode(
-            std::map<std::string,std::string>& outputFields,
+        virtual long encode(
+            HTTPResponse& httpResponse,
             xmltooling::XMLObject* xmlObject,
             xmltooling::XMLObject* xmlObject,
+            const char* destination,
             const char* recipientID=NULL,
             const char* relayState=NULL,
             const xmlsignature::CredentialResolver* credResolver=NULL,
             const char* recipientID=NULL,
             const char* relayState=NULL,
             const xmlsignature::CredentialResolver* credResolver=NULL,
index 3bd1cdd..15f0ed1 100644 (file)
@@ -35,9 +35,10 @@ namespace opensaml {
             SAML1ArtifactEncoder(const DOMElement* e);
             virtual ~SAML1ArtifactEncoder();
             
             SAML1ArtifactEncoder(const DOMElement* e);
             virtual ~SAML1ArtifactEncoder();
             
-            void encode(
-                std::map<std::string,std::string>& outputFields,
+            long encode(
+                HTTPResponse& httpResponse,
                 xmltooling::XMLObject* xmlObject,
                 xmltooling::XMLObject* xmlObject,
+                const char* destination,
                 const char* recipientID=NULL,
                 const char* relayState=NULL,
                 const xmlsignature::CredentialResolver* credResolver=NULL,
                 const char* recipientID=NULL,
                 const char* relayState=NULL,
                 const xmlsignature::CredentialResolver* credResolver=NULL,
index c99c38d..4ab47bf 100644 (file)
@@ -35,15 +35,20 @@ namespace opensaml {
             SAML1POSTEncoder(const DOMElement* e);
             virtual ~SAML1POSTEncoder();
             
             SAML1POSTEncoder(const DOMElement* e);
             virtual ~SAML1POSTEncoder();
             
-            void encode(
-                std::map<std::string,std::string>& outputFields,
+            long encode(
+                HTTPResponse& httpResponse,
                 xmltooling::XMLObject* xmlObject,
                 xmltooling::XMLObject* xmlObject,
+                const char* destination,
                 const char* recipientID=NULL,
                 const char* relayState=NULL,
                 const xmlsignature::CredentialResolver* credResolver=NULL,
                 const XMLCh* sigAlgorithm=NULL
                 ) const;
                 const char* recipientID=NULL,
                 const char* relayState=NULL,
                 const xmlsignature::CredentialResolver* credResolver=NULL,
                 const XMLCh* sigAlgorithm=NULL
                 ) const;
-        };                
+
+        protected:
+            /** Pathname of HTML template for transmission of message via POST. */
+            std::string m_template;
+        };
 
     };
 };
 
     };
 };
index cc76f7c..b747201 100644 (file)
@@ -22,8 +22,9 @@
 
 #include "internal.h"
 #include "exceptions.h"
 
 #include "internal.h"
 #include "exceptions.h"
-#include "saml/binding/ArtifactMap.h"
-#include "saml/binding/SAMLArtifact.h"
+#include "binding/ArtifactMap.h"
+#include "binding/SAMLArtifact.h"
+#include "binding/URLEncoder.h"
 #include "saml1/binding/SAML1ArtifactEncoder.h"
 #include "saml1/core/Assertions.h"
 
 #include "saml1/binding/SAML1ArtifactEncoder.h"
 #include "saml1/core/Assertions.h"
 
@@ -51,9 +52,10 @@ SAML1ArtifactEncoder::SAML1ArtifactEncoder(const DOMElement* e) {}
 
 SAML1ArtifactEncoder::~SAML1ArtifactEncoder() {}
 
 
 SAML1ArtifactEncoder::~SAML1ArtifactEncoder() {}
 
-void SAML1ArtifactEncoder::encode(
-    map<string,string>& outputFields,
+long SAML1ArtifactEncoder::encode(
+    HTTPResponse& httpResponse,
     XMLObject* xmlObject,
     XMLObject* xmlObject,
+    const char* destination,
     const char* recipientID,
     const char* relayState,
     const CredentialResolver* credResolver,
     const char* recipientID,
     const char* relayState,
     const CredentialResolver* credResolver,
@@ -66,7 +68,6 @@ void SAML1ArtifactEncoder::encode(
     Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML1Artifact");
     log.debug("validating input");
     
     Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML1Artifact");
     log.debug("validating input");
     
-    outputFields.clear();
     if (xmlObject->getParent())
         throw BindingException("Cannot encode XML content with parent.");
     Assertion* assertion = dynamic_cast<Assertion*>(xmlObject);
     if (xmlObject->getParent())
         throw BindingException("Cannot encode XML content with parent.");
     Assertion* assertion = dynamic_cast<Assertion*>(xmlObject);
@@ -87,13 +88,15 @@ void SAML1ArtifactEncoder::encode(
     log.debug("obtaining new artifact for relying party (%s)", recipientID ? recipientID : "unknown");
     auto_ptr<SAMLArtifact> artifact(m_artifactGenerator->generateSAML1Artifact(recipientID));
     
     log.debug("obtaining new artifact for relying party (%s)", recipientID ? recipientID : "unknown");
     auto_ptr<SAMLArtifact> artifact(m_artifactGenerator->generateSAML1Artifact(recipientID));
     
-    // Pass back output fields.
-    outputFields["SAMLart"] = artifact->encode();
-    outputFields["TARGET"] = relayState;
-
     // Store the assertion. Last step in storage will be to delete the XML.
     log.debug("storing artifact and content in map");
     mapper->storeContent(xmlObject, artifact.get(), recipientID);
 
     // Store the assertion. Last step in storage will be to delete the XML.
     log.debug("storing artifact and content in map");
     mapper->storeContent(xmlObject, artifact.get(), recipientID);
 
-    log.debug("message encoded");
+    // Generate redirect.
+    string loc = destination;
+    loc += (strchr(destination,'?') ? '&' : '?');
+    URLEncoder* escaper = SAMLConfig::getConfig().getURLEncoder();
+    loc = loc + "SAMLart=" + escaper->encode(artifact->encode().c_str()) + "&TARGET=" + escaper->encode(relayState);
+    log.debug("message encoded, sending redirect to client");
+    return httpResponse.sendRedirect(loc.c_str());
 }
 }
index 5b0704f..ccc5510 100644 (file)
 #include "saml1/binding/SAML1POSTEncoder.h"
 #include "saml1/core/Protocols.h"
 
 #include "saml1/binding/SAML1POSTEncoder.h"
 #include "saml1/core/Protocols.h"
 
+#include <fstream>
+#include <sstream>
 #include <log4cpp/Category.hh>
 #include <xercesc/util/Base64.hpp>
 #include <xmltooling/util/NDC.h>
 #include <log4cpp/Category.hh>
 #include <xercesc/util/Base64.hpp>
 #include <xmltooling/util/NDC.h>
+#include <xmltooling/util/TemplateEngine.h>
 
 using namespace opensaml::saml1p;
 using namespace opensaml;
 
 using namespace opensaml::saml1p;
 using namespace opensaml;
@@ -45,13 +48,25 @@ namespace opensaml {
     };
 };
 
     };
 };
 
-SAML1POSTEncoder::SAML1POSTEncoder(const DOMElement* e) {}
+static const XMLCh templat[] = UNICODE_LITERAL_8(t,e,m,p,l,a,t,e);
+
+SAML1POSTEncoder::SAML1POSTEncoder(const DOMElement* e)
+{
+    if (e) {
+        auto_ptr_char t(e->getAttributeNS(NULL, templat));
+        if (t.get())
+            m_template = t.get();
+    }
+    if (m_template.empty())
+        throw XMLToolingException("SAML1POSTEncoder requires template attribute.");
+}
 
 SAML1POSTEncoder::~SAML1POSTEncoder() {}
 
 
 SAML1POSTEncoder::~SAML1POSTEncoder() {}
 
-void SAML1POSTEncoder::encode(
-    map<string,string>& outputFields,
+long SAML1POSTEncoder::encode(
+    HTTPResponse& httpResponse,
     XMLObject* xmlObject,
     XMLObject* xmlObject,
+    const char* destination,
     const char* recipientID,
     const char* relayState,
     const CredentialResolver* credResolver,
     const char* recipientID,
     const char* relayState,
     const CredentialResolver* credResolver,
@@ -64,7 +79,6 @@ void SAML1POSTEncoder::encode(
     Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML1POST");
     log.debug("validating input");
     
     Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML1POST");
     log.debug("validating input");
     
-    outputFields.clear();
     if (xmlObject->getParent())
         throw BindingException("Cannot encode XML content with parent.");
     Response* response = dynamic_cast<Response*>(xmlObject);
     if (xmlObject->getParent())
         throw BindingException("Cannot encode XML content with parent.");
     Response* response = dynamic_cast<Response*>(xmlObject);
@@ -108,13 +122,24 @@ void SAML1POSTEncoder::encode(
     else {
         throw BindingException("Base64 encoding of XML failed.");
     }
     else {
         throw BindingException("Base64 encoding of XML failed.");
     }
-    
-    // Pass back output fields.
-    outputFields["SAMLResponse"] = xmlbuf;
-    outputFields["TARGET"] = relayState;
+
+    // Push message into template and send result to client.
+    log.debug("message encoded, sending HTML form template to client");
+    TemplateEngine* engine = XMLToolingConfig::getConfig().getTemplateEngine();
+    if (!engine)
+        throw BindingException("Encoding response using POST requires a TemplateEngine instance.");
+    ifstream infile(m_template.c_str());
+    if (!infile)
+        throw BindingException("Failed to open HTML template for POST response ($1).", params(1,m_template.c_str()));
+    map<string,string> params;
+    params["action"] = destination;
+    params["SAMLResponse"] = xmlbuf;
+    params["TARGET"] = relayState;
+    stringstream s;
+    engine->run(infile, s, params);
+    long ret = httpResponse.sendResponse(s);
 
     // Cleanup by destroying XML.
     delete xmlObject;
 
     // Cleanup by destroying XML.
     delete xmlObject;
-
-    log.debug("message encoded");
+    return ret;
 }
 }
index ecbdae2..01057f8 100644 (file)
@@ -35,15 +35,20 @@ namespace opensaml {
             SAML2ArtifactEncoder(const DOMElement* e);
             virtual ~SAML2ArtifactEncoder();
             
             SAML2ArtifactEncoder(const DOMElement* e);
             virtual ~SAML2ArtifactEncoder();
             
-            void encode(
-                std::map<std::string,std::string>& outputFields,
+            long encode(
+                HTTPResponse& httpResponse,
                 xmltooling::XMLObject* xmlObject,
                 xmltooling::XMLObject* xmlObject,
+                const char* destination,
                 const char* recipientID=NULL,
                 const char* relayState=NULL,
                 const xmlsignature::CredentialResolver* credResolver=NULL,
                 const XMLCh* sigAlgorithm=NULL
                 ) const;
                 const char* recipientID=NULL,
                 const char* relayState=NULL,
                 const xmlsignature::CredentialResolver* credResolver=NULL,
                 const XMLCh* sigAlgorithm=NULL
                 ) const;
-        };                
+        
+        protected:
+            /** Pathname of HTML template for transmission of message via POST. */
+            std::string m_template; 
+        };
 
     };
 };
 
     };
 };
index 6074890..3f325e4 100644 (file)
@@ -35,15 +35,20 @@ namespace opensaml {
             SAML2POSTEncoder(const DOMElement* e);
             virtual ~SAML2POSTEncoder();
             
             SAML2POSTEncoder(const DOMElement* e);
             virtual ~SAML2POSTEncoder();
             
-            void encode(
-                std::map<std::string,std::string>& outputFields,
+            long encode(
+                HTTPResponse& httpResponse,
                 xmltooling::XMLObject* xmlObject,
                 xmltooling::XMLObject* xmlObject,
+                const char* destination,
                 const char* recipientID=NULL,
                 const char* relayState=NULL,
                 const xmlsignature::CredentialResolver* credResolver=NULL,
                 const XMLCh* sigAlgorithm=NULL
                 ) const;
                 const char* recipientID=NULL,
                 const char* relayState=NULL,
                 const xmlsignature::CredentialResolver* credResolver=NULL,
                 const XMLCh* sigAlgorithm=NULL
                 ) const;
-        };                
+
+        protected:        
+            /** Pathname of HTML template for transmission of message via POST. */
+            std::string m_template;
+        };
 
     };
 };
 
     };
 };
index eec06cb..048eeb7 100644 (file)
 
 #include "internal.h"
 #include "exceptions.h"
 
 #include "internal.h"
 #include "exceptions.h"
-#include "saml/binding/ArtifactMap.h"
+#include "binding/ArtifactMap.h"
+#include "binding/URLEncoder.h"
 #include "saml2/binding/SAML2Artifact.h"
 #include "saml2/binding/SAML2ArtifactEncoder.h"
 #include "saml2/core/Protocols.h"
 
 #include "saml2/binding/SAML2Artifact.h"
 #include "saml2/binding/SAML2ArtifactEncoder.h"
 #include "saml2/core/Protocols.h"
 
+#include <fstream>
+#include <sstream>
 #include <log4cpp/Category.hh>
 #include <xmltooling/util/NDC.h>
 #include <log4cpp/Category.hh>
 #include <xmltooling/util/NDC.h>
+#include <xmltooling/util/TemplateEngine.h>
 
 using namespace opensaml::saml2p;
 using namespace opensaml;
 
 using namespace opensaml::saml2p;
 using namespace opensaml;
@@ -46,13 +50,23 @@ namespace opensaml {
     };
 };
 
     };
 };
 
-SAML2ArtifactEncoder::SAML2ArtifactEncoder(const DOMElement* e) {}
+static const XMLCh templat[] = UNICODE_LITERAL_8(t,e,m,p,l,a,t,e);
+
+SAML2ArtifactEncoder::SAML2ArtifactEncoder(const DOMElement* e)
+{
+    if (e) {
+        auto_ptr_char t(e->getAttributeNS(NULL, templat));
+        if (t.get())
+            m_template = t.get();
+    }
+}
 
 SAML2ArtifactEncoder::~SAML2ArtifactEncoder() {}
 
 
 SAML2ArtifactEncoder::~SAML2ArtifactEncoder() {}
 
-void SAML2ArtifactEncoder::encode(
-    map<string,string>& outputFields,
-    XMLObject* xmlObject,
+long SAML2ArtifactEncoder::encode(
+    HTTPResponse& httpResponse,
+    xmltooling::XMLObject* xmlObject,
+    const char* destination,
     const char* recipientID,
     const char* relayState,
     const CredentialResolver* credResolver,
     const char* recipientID,
     const char* relayState,
     const CredentialResolver* credResolver,
@@ -65,7 +79,9 @@ void SAML2ArtifactEncoder::encode(
     Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML2Artifact");
     log.debug("validating input");
     
     Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML2Artifact");
     log.debug("validating input");
     
-    outputFields.clear();
+    if (relayState && strlen(relayState)>80)
+        throw BindingException("RelayState cannot exceed 80 bytes in length.");
+    
     if (xmlObject->getParent())
         throw BindingException("Cannot encode XML content with parent.");
 
     if (xmlObject->getParent())
         throw BindingException("Cannot encode XML content with parent.");
 
@@ -106,14 +122,37 @@ void SAML2ArtifactEncoder::encode(
         }
     }
     
         }
     }
     
-    // Pass back output fields.
-    outputFields["SAMLart"] = artifact->encode();
-    if (relayState)
-        outputFields["RelayState"] = relayState;
-
     // Store the message. Last step in storage will be to delete the XML.
     log.debug("storing artifact and content in map");
     mapper->storeContent(xmlObject, artifact.get(), recipientID);
 
     // Store the message. Last step in storage will be to delete the XML.
     log.debug("storing artifact and content in map");
     mapper->storeContent(xmlObject, artifact.get(), recipientID);
 
-    log.debug("message encoded");
+    if (m_template.empty()) {
+        // Generate redirect.
+        string loc = destination;
+        loc += (strchr(destination,'?') ? '&' : '?');
+        URLEncoder* escaper = SAMLConfig::getConfig().getURLEncoder();
+        loc = loc + "SAMLart=" + escaper->encode(artifact->encode().c_str());
+        if (relayState)
+            loc = loc + "&RelayState=" + escaper->encode(relayState);
+        log.debug("message encoded, sending redirect to client");
+        return httpResponse.sendRedirect(loc.c_str());
+    }
+    else {
+        // Push message into template and send result to client. 
+        log.debug("message encoded, sending HTML form template to client");
+        TemplateEngine* engine = XMLToolingConfig::getConfig().getTemplateEngine();
+        if (!engine)
+            throw BindingException("Encoding artifact using POST requires a TemplateEngine instance.");
+        ifstream infile(m_template.c_str());
+        if (!infile)
+            throw BindingException("Failed to open HTML template for POST response ($1).", params(1,m_template.c_str()));
+        map<string,string> params;
+        params["action"] = destination;
+        params["SAMLart"] = artifact->encode();
+        if (relayState)
+            params["RelayState"] = relayState;
+        stringstream s;
+        engine->run(infile, s, params);
+        return httpResponse.sendResponse(s);
+    }
 }
 }
index 72d6ba8..9a4e7df 100644 (file)
 #include "saml2/binding/SAML2POSTEncoder.h"
 #include "saml2/core/Protocols.h"
 
 #include "saml2/binding/SAML2POSTEncoder.h"
 #include "saml2/core/Protocols.h"
 
+#include <fstream>
+#include <sstream>
 #include <log4cpp/Category.hh>
 #include <xercesc/util/Base64.hpp>
 #include <xmltooling/util/NDC.h>
 #include <log4cpp/Category.hh>
 #include <xercesc/util/Base64.hpp>
 #include <xmltooling/util/NDC.h>
+#include <xmltooling/util/TemplateEngine.h>
 
 using namespace opensaml::saml2p;
 using namespace opensaml;
 
 using namespace opensaml::saml2p;
 using namespace opensaml;
@@ -45,13 +48,25 @@ namespace opensaml {
     };
 };
 
     };
 };
 
-SAML2POSTEncoder::SAML2POSTEncoder(const DOMElement* e) {}
+static const XMLCh templat[] = UNICODE_LITERAL_8(t,e,m,p,l,a,t,e);
+
+SAML2POSTEncoder::SAML2POSTEncoder(const DOMElement* e)
+{
+    if (e) {
+        auto_ptr_char t(e->getAttributeNS(NULL, templat));
+        if (t.get())
+            m_template = t.get();
+    }
+    if (m_template.empty())
+        throw XMLToolingException("SAML2POSTEncoder requires template attribute.");
+}
 
 SAML2POSTEncoder::~SAML2POSTEncoder() {}
 
 
 SAML2POSTEncoder::~SAML2POSTEncoder() {}
 
-void SAML2POSTEncoder::encode(
-    map<string,string>& outputFields,
+long SAML2POSTEncoder::encode(
+    HTTPResponse& httpResponse,
     XMLObject* xmlObject,
     XMLObject* xmlObject,
+    const char* destination,
     const char* recipientID,
     const char* relayState,
     const CredentialResolver* credResolver,
     const char* recipientID,
     const char* relayState,
     const CredentialResolver* credResolver,
@@ -64,7 +79,6 @@ void SAML2POSTEncoder::encode(
     Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML2POST");
     log.debug("validating input");
     
     Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML2POST");
     log.debug("validating input");
     
-    outputFields.clear();
     if (xmlObject->getParent())
         throw BindingException("Cannot encode XML content with parent.");
     
     if (xmlObject->getParent())
         throw BindingException("Cannot encode XML content with parent.");
     
@@ -114,13 +128,24 @@ void SAML2POSTEncoder::encode(
         throw BindingException("Base64 encoding of XML failed.");
     }
     
         throw BindingException("Base64 encoding of XML failed.");
     }
     
-    // Pass back output fields.
-    outputFields[request ? "SAMLRequest" : "SAMLResponse"] = xmlbuf;
+    // Push message into template and send result to client.
+    log.debug("message encoded, sending HTML form template to client");
+    TemplateEngine* engine = XMLToolingConfig::getConfig().getTemplateEngine();
+    if (!engine)
+        throw BindingException("Encoding message using POST requires a TemplateEngine instance.");
+    ifstream infile(m_template.c_str());
+    if (!infile)
+        throw BindingException("Failed to open HTML template for POST message ($1).", params(1,m_template.c_str()));
+    map<string,string> params;
+    params["action"] = destination;
+    params[request ? "SAMLRequest" : "SAMLResponse"] = xmlbuf;
     if (relayState)
     if (relayState)
-        outputFields["RelayState"] = relayState;
+        params["RelayState"] = relayState;
+    stringstream s;
+    engine->run(infile, s, params);
+    long ret = httpResponse.sendResponse(s);
 
     // Cleanup by destroying XML.
     delete xmlObject;
 
     // Cleanup by destroying XML.
     delete xmlObject;
-
-    log.debug("message encoded");
+    return ret;
 }
 }
index 474e882..15aa249 100644 (file)
 #include <saml/SAMLConfig.h>
 #include <saml/binding/MessageDecoder.h>
 #include <saml/binding/MessageEncoder.h>
 #include <saml/SAMLConfig.h>
 #include <saml/binding/MessageDecoder.h>
 #include <saml/binding/MessageEncoder.h>
+#include <saml/binding/URLEncoder.h>
 #include <saml/saml2/metadata/MetadataProvider.h>
 #include <saml/security/X509TrustEngine.h>
 
 using namespace saml2md;
 using namespace xmlsignature;
 
 #include <saml/saml2/metadata/MetadataProvider.h>
 #include <saml/security/X509TrustEngine.h>
 
 using namespace saml2md;
 using namespace xmlsignature;
 
-class SAMLBindingBaseTestCase : public MessageDecoder::HTTPRequest
+class SAMLBindingBaseTestCase : public MessageDecoder::HTTPRequest, public MessageEncoder::HTTPResponse
 {
 protected:
     CredentialResolver* m_creds; 
     MetadataProvider* m_metadata;
     opensaml::X509TrustEngine* m_trust;
     map<string,string> m_fields;
 {
 protected:
     CredentialResolver* m_creds; 
     MetadataProvider* m_metadata;
     opensaml::X509TrustEngine* m_trust;
     map<string,string> m_fields;
+    map<string,string> m_headers;
+    string m_method,m_url;
 
 public:
     void setUp() {
 
 public:
     void setUp() {
@@ -39,6 +42,9 @@ public:
         m_metadata=NULL;
         m_trust=NULL;
         m_fields.clear();
         m_metadata=NULL;
         m_trust=NULL;
         m_fields.clear();
+        m_headers.clear();
+        m_method.erase();
+        m_url.erase();
 
         try {
             string config = data_path + "binding/ExampleMetadataProvider.xml";
 
         try {
             string config = data_path + "binding/ExampleMetadataProvider.xml";
@@ -84,8 +90,38 @@ public:
         m_metadata=NULL;
         m_trust=NULL;
         m_fields.clear();
         m_metadata=NULL;
         m_trust=NULL;
         m_fields.clear();
+        m_headers.clear();
+        m_method.erase();
+        m_url.erase();
     }
 
     }
 
+    // HTTPRequest methods
+
+    const char* getMethod() const {
+        return m_method.c_str();
+    } 
+
+    const char* getRequestURL() const {
+        return m_url.c_str();
+    }
+    
+    const char* getRequestBody() const {
+        return NULL;
+    }
+    
+    const char* getQueryString() const {
+        return NULL;
+    }
+    
+    string getRemoteUser() const {
+        return "";
+    }
+
+    string getHeader(const char* name) const {
+        map<string,string>::const_iterator i=m_headers.find(name);
+        return i==m_headers.end() ? "" : i->second;
+    }
+    
     const char* getParameter(const char* name) const {
         map<string,string>::const_iterator i=m_fields.find(name);
         return i==m_fields.end() ? NULL : i->second.c_str();
     const char* getParameter(const char* name) const {
         map<string,string>::const_iterator i=m_fields.find(name);
         return i==m_fields.end() ? NULL : i->second.c_str();
@@ -98,4 +134,87 @@ public:
             values.push_back(i->second.c_str());
         return values.size();
     }
             values.push_back(i->second.c_str());
         return values.size();
     }
+    
+    // HTTPResponse methods
+    
+    void setHeader(const char* name, const char* value) {
+        m_headers[name] = value ? value : "";
+    }
+    
+    void setCookie(const char* name, const char* value) {
+        m_headers["Set-Cookie"] = string(name) + "=" + (value ? value : "");
+    }
+    
+    // The amount of error checking missing from this is incredible, but as long
+    // as the test data isn't unexpected or malformed, it should work.
+    
+    long sendRedirect(const char* url) {
+        m_method = "GET";
+        char* dup = strdup(url);
+        char* pch = strchr(dup,'?');
+        if (pch) {
+            *pch++=0;
+            char* name=pch;
+            while (name && *name) {
+                pch=strchr(pch,'=');
+                *pch++=0;
+                char* value=pch;
+                pch=strchr(pch,'&');
+                if (pch)
+                    *pch++=0;
+                SAMLConfig::getConfig().getURLEncoder()->decode(value);
+                m_fields[name] = value;
+                name = pch; 
+            }
+        }
+        m_url = dup;
+        free(dup);
+        return m_fields.size();
+    }
+    
+    string html_decode(const string& s) const {
+        string decoded;
+        const char* ch=s.c_str();
+        while (*ch) {
+            if (*ch=='&') {
+                if (!strncmp(ch,"&lt;",4)) {
+                    decoded+='<'; ch+=4;
+                }
+                else if (!strncmp(ch,"&gt;",4)) {
+                    decoded+='>'; ch+=4;
+                }
+                else if (!strncmp(ch,"&quot;",6)) {
+                    decoded+='"'; ch+=6;
+                }
+                else if (*++ch=='#') {
+                    decoded+=(char)atoi(++ch);
+                    ch=strchr(ch,';')+1;
+                }
+            }
+            else {
+                decoded+=*ch++;
+            }
+        }
+        return decoded;
+    }
+    
+    long sendResponse(std::istream& inputStream, int status = 200, const char* contentType = "text/html") {
+        m_method="POST";
+        string page,line;
+        while (getline(inputStream,line))
+            page += line + '\n';
+            
+        const char* pch=strstr(page.c_str(),"action=\"");
+        pch+=strlen("action=\"");
+        m_url = html_decode(page.substr(pch-page.c_str(),strchr(pch,'"')-pch));
+
+        while (pch=strstr(pch,"<input type=\"hidden\" name=\"")) {
+            pch+=strlen("<input type=\"hidden\" name=\"");
+            string name = page.substr(pch-page.c_str(),strchr(pch,'"')-pch);
+            pch=strstr(pch,"value=\"");
+            pch+=strlen("value=\"");
+            m_fields[name] = html_decode(page.substr(pch-page.c_str(),strchr(pch,'"')-pch));
+        }
+        return m_fields.size();
+    }
 };
 };
diff --git a/samltest/data/binding/template.html b/samltest/data/binding/template.html
new file mode 100644 (file)
index 0000000..83215a8
--- /dev/null
@@ -0,0 +1,21 @@
+<html>
+       <head>
+               <title>SAML Binding</title>
+       </head>
+       <body>
+               <form method="POST" action="<mlp action/>">
+               <mlpif TARGET>
+                       <input type="hidden" name="TARGET" value="<mlp TARGET/>"/>
+               </mlpif>
+               <mlpif RelayState>
+                       <input type="hidden" name="RelayState" value="<mlp RelayState/>"/>
+               </mlpif>
+               <mlpif SAMLRequest>
+                       <input type="hidden" name="SAMLRequest" value="<mlp SAMLRequest/>"/>
+               </mlpif>
+               <mlpif SAMLResponse>
+                       <input type="hidden" name="SAMLResponse" value="<mlp SAMLResponse/>"/>
+               </mlpif>
+               </form>
+       </body>
+</html>
index a133cf1..68edcfc 100644 (file)
@@ -29,12 +29,10 @@ class SAML1ArtifactTest : public CxxTest::TestSuite,
     public SAMLBindingBaseTestCase, public MessageEncoder::ArtifactGenerator, public MessageDecoder::ArtifactResolver {
 public:
     void setUp() {
     public SAMLBindingBaseTestCase, public MessageEncoder::ArtifactGenerator, public MessageDecoder::ArtifactResolver {
 public:
     void setUp() {
-        m_fields.clear();
         SAMLBindingBaseTestCase::setUp();
     }
 
     void tearDown() {
         SAMLBindingBaseTestCase::setUp();
     }
 
     void tearDown() {
-        m_fields.clear();
         SAMLBindingBaseTestCase::tearDown();
     }
 
         SAMLBindingBaseTestCase::tearDown();
     }
 
@@ -55,7 +53,7 @@ public:
                 SAMLConfig::getConfig().MessageEncoderManager.newPlugin(SAMLConstants::SAML1_PROFILE_BROWSER_ARTIFACT, NULL)
                 );
             encoder->setArtifactGenerator(this);
                 SAMLConfig::getConfig().MessageEncoderManager.newPlugin(SAMLConstants::SAML1_PROFILE_BROWSER_ARTIFACT, NULL)
                 );
             encoder->setArtifactGenerator(this);
-            encoder->encode(m_fields,toSend.get(),"https://sp.example.org/","state",m_creds);
+            encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/Artifact","https://sp.example.org/","state",m_creds);
             toSend.release();
             
             // Decode message.
             toSend.release();
             
             // Decode message.
@@ -93,18 +91,6 @@ public:
         }
     }
 
         }
     }
 
-    const char* getMethod() const {
-        return "GET";
-    } 
-
-    const char* getRequestURL() const {
-        return "https://sp.example.org/SAML/Artifact";
-    }
-    
-    const char* getQueryString() const {
-        return NULL;
-    }
-    
     SAMLArtifact* generateSAML1Artifact(const char* relyingParty) const {
         return new SAMLArtifactType0001(SAMLConfig::getConfig().hashSHA1("https://idp.example.org/"));
     }
     SAMLArtifact* generateSAML1Artifact(const char* relyingParty) const {
         return new SAMLArtifactType0001(SAMLConfig::getConfig().hashSHA1("https://idp.example.org/"));
     }
index 4b26224..73a17ec 100644 (file)
@@ -24,12 +24,10 @@ using namespace opensaml::saml1;
 class SAML1POSTTest : public CxxTest::TestSuite, public SAMLBindingBaseTestCase {
 public:
     void setUp() {
 class SAML1POSTTest : public CxxTest::TestSuite, public SAMLBindingBaseTestCase {
 public:
     void setUp() {
-        m_fields.clear();
         SAMLBindingBaseTestCase::setUp();
     }
 
     void tearDown() {
         SAMLBindingBaseTestCase::setUp();
     }
 
     void tearDown() {
-        m_fields.clear();
         SAMLBindingBaseTestCase::tearDown();
     }
 
         SAMLBindingBaseTestCase::tearDown();
     }
 
@@ -49,10 +47,20 @@ public:
             toSend->setIssueInstant(time(NULL));
     
             // Encode message.
             toSend->setIssueInstant(time(NULL));
     
             // Encode message.
+            auto_ptr_XMLCh lit1("MessageEncoder");
+            auto_ptr_XMLCh lit2("template");
+            path = data_path + "binding/template.html";
+            auto_ptr_XMLCh lit3(path.c_str());
+            DOMDocument* encoder_config = XMLToolingConfig::getConfig().getParser().newDocument();
+            XercesJanitor<DOMDocument> janitor2(encoder_config);
+            encoder_config->appendChild(encoder_config->createElementNS(NULL,lit1.get()));
+            encoder_config->getDocumentElement()->setAttributeNS(NULL,lit2.get(),lit3.get());
             auto_ptr<MessageEncoder> encoder(
             auto_ptr<MessageEncoder> encoder(
-                SAMLConfig::getConfig().MessageEncoderManager.newPlugin(SAMLConstants::SAML1_PROFILE_BROWSER_POST, NULL)
+                SAMLConfig::getConfig().MessageEncoderManager.newPlugin(
+                    SAMLConstants::SAML1_PROFILE_BROWSER_POST, encoder_config->getDocumentElement()
+                    )
                 );
                 );
-            encoder->encode(m_fields,toSend.get(),"https://sp.example.org/","state",m_creds);
+            encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/POST","https://sp.example.org/","state",m_creds);
             toSend.release();
             
             // Decode message.
             toSend.release();
             
             // Decode message.
@@ -101,10 +109,20 @@ public:
             toSend->setResponseID(NULL);
     
             // Encode message.
             toSend->setResponseID(NULL);
     
             // Encode message.
+            auto_ptr_XMLCh lit1("MessageEncoder");
+            auto_ptr_XMLCh lit2("template");
+            path = data_path + "binding/template.html";
+            auto_ptr_XMLCh lit3(path.c_str());
+            DOMDocument* encoder_config = XMLToolingConfig::getConfig().getParser().newDocument();
+            XercesJanitor<DOMDocument> janitor2(encoder_config);
+            encoder_config->appendChild(encoder_config->createElementNS(NULL,lit1.get()));
+            encoder_config->getDocumentElement()->setAttributeNS(NULL,lit2.get(),lit3.get());
             auto_ptr<MessageEncoder> encoder(
             auto_ptr<MessageEncoder> encoder(
-                SAMLConfig::getConfig().MessageEncoderManager.newPlugin(SAMLConstants::SAML1_PROFILE_BROWSER_POST, NULL)
+                SAMLConfig::getConfig().MessageEncoderManager.newPlugin(
+                    SAMLConstants::SAML1_PROFILE_BROWSER_POST, encoder_config->getDocumentElement()
+                    )
                 );
                 );
-            encoder->encode(m_fields,toSend.get(),"https://sp.example.org/","state");
+            encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/POST","https://sp.example.org/","state");
             toSend.release();
             
             // Decode message.
             toSend.release();
             
             // Decode message.
@@ -140,16 +158,4 @@ public:
             throw;
         }
     }
             throw;
         }
     }
-
-    const char* getMethod() const {
-        return "POST";
-    } 
-
-    const char* getRequestURL() const {
-        return "https://sp.example.org/SAML/POST";
-    }
-    
-    const char* getQueryString() const {
-        return NULL;
-    }
 };
 };
index c785bd3..c8764cd 100644 (file)
@@ -28,12 +28,10 @@ class SAML2ArtifactTest : public CxxTest::TestSuite,
     public SAMLBindingBaseTestCase, public MessageEncoder::ArtifactGenerator, public MessageDecoder::ArtifactResolver {
 public:
     void setUp() {
     public SAMLBindingBaseTestCase, public MessageEncoder::ArtifactGenerator, public MessageDecoder::ArtifactResolver {
 public:
     void setUp() {
-        m_fields.clear();
         SAMLBindingBaseTestCase::setUp();
     }
 
     void tearDown() {
         SAMLBindingBaseTestCase::setUp();
     }
 
     void tearDown() {
-        m_fields.clear();
         SAMLBindingBaseTestCase::tearDown();
     }
 
         SAMLBindingBaseTestCase::tearDown();
     }
 
@@ -57,7 +55,7 @@ public:
                 SAMLConfig::getConfig().MessageEncoderManager.newPlugin(SAMLConstants::SAML20_BINDING_HTTP_ARTIFACT, NULL)
                 );
             encoder->setArtifactGenerator(this);
                 SAMLConfig::getConfig().MessageEncoderManager.newPlugin(SAMLConstants::SAML20_BINDING_HTTP_ARTIFACT, NULL)
                 );
             encoder->setArtifactGenerator(this);
-            encoder->encode(m_fields,toSend.get(),"https://sp.example.org/","state",m_creds);
+            encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/Artifact","https://sp.example.org/","state",m_creds);
             toSend.release();
             
             // Decode message.
             toSend.release();
             
             // Decode message.
@@ -94,18 +92,6 @@ public:
             throw;
         }
     }
             throw;
         }
     }
-
-    const char* getMethod() const {
-        return "GET";
-    } 
-
-    const char* getRequestURL() const {
-        return "https://sp.example.org/SAML/Artifact";
-    }
-    
-    const char* getQueryString() const {
-        return NULL;
-    }
     
     SAMLArtifact* generateSAML1Artifact(const char* relyingParty) const {
         throw BindingException("Not implemented.");
     
     SAMLArtifact* generateSAML1Artifact(const char* relyingParty) const {
         throw BindingException("Not implemented.");
index 77cd153..b52b228 100644 (file)
@@ -24,12 +24,10 @@ using namespace opensaml::saml2;
 class SAML2POSTTest : public CxxTest::TestSuite, public SAMLBindingBaseTestCase {
 public:
     void setUp() {
 class SAML2POSTTest : public CxxTest::TestSuite, public SAMLBindingBaseTestCase {
 public:
     void setUp() {
-        m_fields.clear();
         SAMLBindingBaseTestCase::setUp();
     }
 
     void tearDown() {
         SAMLBindingBaseTestCase::setUp();
     }
 
     void tearDown() {
-        m_fields.clear();
         SAMLBindingBaseTestCase::tearDown();
     }
 
         SAMLBindingBaseTestCase::tearDown();
     }
 
@@ -49,10 +47,20 @@ public:
             toSend->setIssueInstant(time(NULL));
     
             // Encode message.
             toSend->setIssueInstant(time(NULL));
     
             // Encode message.
+            auto_ptr_XMLCh lit1("MessageEncoder");
+            auto_ptr_XMLCh lit2("template");
+            path = data_path + "binding/template.html";
+            auto_ptr_XMLCh lit3(path.c_str());
+            DOMDocument* encoder_config = XMLToolingConfig::getConfig().getParser().newDocument();
+            XercesJanitor<DOMDocument> janitor2(encoder_config);
+            encoder_config->appendChild(encoder_config->createElementNS(NULL,lit1.get()));
+            encoder_config->getDocumentElement()->setAttributeNS(NULL,lit2.get(),lit3.get());
             auto_ptr<MessageEncoder> encoder(
             auto_ptr<MessageEncoder> encoder(
-                SAMLConfig::getConfig().MessageEncoderManager.newPlugin(SAMLConstants::SAML20_BINDING_HTTP_POST, NULL)
+                SAMLConfig::getConfig().MessageEncoderManager.newPlugin(
+                    SAMLConstants::SAML20_BINDING_HTTP_POST, encoder_config->getDocumentElement()
+                    )
                 );
                 );
-            encoder->encode(m_fields,toSend.get(),"https://sp.example.org/","state",m_creds);
+            encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/POST","https://sp.example.org/","state",m_creds);
             toSend.release();
             
             // Decode message.
             toSend.release();
             
             // Decode message.
@@ -101,10 +109,20 @@ public:
             toSend->setID(NULL);
     
             // Encode message.
             toSend->setID(NULL);
     
             // Encode message.
+            auto_ptr_XMLCh lit1("MessageEncoder");
+            auto_ptr_XMLCh lit2("template");
+            path = data_path + "binding/template.html";
+            auto_ptr_XMLCh lit3(path.c_str());
+            DOMDocument* encoder_config = XMLToolingConfig::getConfig().getParser().newDocument();
+            XercesJanitor<DOMDocument> janitor2(encoder_config);
+            encoder_config->appendChild(encoder_config->createElementNS(NULL,lit1.get()));
+            encoder_config->getDocumentElement()->setAttributeNS(NULL,lit2.get(),lit3.get());
             auto_ptr<MessageEncoder> encoder(
             auto_ptr<MessageEncoder> encoder(
-                SAMLConfig::getConfig().MessageEncoderManager.newPlugin(SAMLConstants::SAML20_BINDING_HTTP_POST, NULL)
+                SAMLConfig::getConfig().MessageEncoderManager.newPlugin(
+                    SAMLConstants::SAML20_BINDING_HTTP_POST, encoder_config->getDocumentElement()
+                    )
                 );
                 );
-            encoder->encode(m_fields,toSend.get(),"https://sp.example.org/","state");
+            encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/POST","https://sp.example.org/","state");
             toSend.release();
             
             // Decode message.
             toSend.release();
             
             // Decode message.
@@ -140,16 +158,4 @@ public:
             throw;
         }
     }
             throw;
         }
     }
-
-    const char* getMethod() const {
-        return "POST";
-    } 
-
-    const char* getRequestURL() const {
-        return "https://sp.example.org/SAML/POST";
-    }
-    
-    const char* getQueryString() const {
-        return NULL;
-    }
 };
 };
index a65544b..e6283d9 100644 (file)
@@ -20,6 +20,7 @@
 #include <saml/SAMLConfig.h>
 #include <saml/binding/ArtifactMap.h>
 #include <xmltooling/util/ReplayCache.h>
 #include <saml/SAMLConfig.h>
 #include <saml/binding/ArtifactMap.h>
 #include <xmltooling/util/ReplayCache.h>
+#include <xmltooling/util/TemplateEngine.h>
 
 //#define SAML_LEAKCHECK
 
 
 //#define SAML_LEAKCHECK
 
@@ -33,6 +34,7 @@ public:
         if (!SAMLConfig::getConfig().init())
             return false;
         XMLToolingConfig::getConfig().setReplayCache(new ReplayCache());
         if (!SAMLConfig::getConfig().init())
             return false;
         XMLToolingConfig::getConfig().setReplayCache(new ReplayCache());
+        XMLToolingConfig::getConfig().setTemplateEngine(new TemplateEngine());
         SAMLConfig::getConfig().setArtifactMap(new ArtifactMap());
 
         if (getenv("SAMLTEST_DATA"))
         SAMLConfig::getConfig().setArtifactMap(new ArtifactMap());
 
         if (getenv("SAMLTEST_DATA"))
index 8970b8d..cd29fdf 100644 (file)
                                </FileConfiguration>\r
                        </File>\r
                        <File\r
                                </FileConfiguration>\r
                        </File>\r
                        <File\r
-                               RelativePath=".\binding.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\internal.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
                                RelativePath=".\SAMLArtifactCreationTest.h"\r
                                >\r
                                <FileConfiguration\r
                                RelativePath=".\SAMLArtifactCreationTest.h"\r
                                >\r
                                <FileConfiguration\r
                        UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
                        >\r
                </Filter>\r
                        UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
                        >\r
                </Filter>\r
+               <File\r
+                       RelativePath=".\binding.h"\r
+                       >\r
+               </File>\r
+               <File\r
+                       RelativePath=".\internal.h"\r
+                       >\r
+               </File>\r
        </Files>\r
        <Globals>\r
        </Globals>\r
        </Files>\r
        <Globals>\r
        </Globals>\r