From: Scott Cantor Date: Thu, 19 Oct 2006 21:28:16 +0000 (+0000) Subject: Revamped encoders to produce the actual HTTP responses. X-Git-Tag: 2.0-alpha1~169 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-opensaml.git;a=commitdiff_plain;h=b0c11eb8bfd9daa93de903f1ab94f0f34df46c2e Revamped encoders to produce the actual HTTP responses. --- diff --git a/saml/binding/MessageDecoder.h b/saml/binding/MessageDecoder.h index 535dfc4..a55f0a7 100644 --- a/saml/binding/MessageDecoder.h +++ b/saml/binding/MessageDecoder.h @@ -57,9 +57,11 @@ namespace opensaml { /** * Interface to caller-supplied shim for accessing HTTP request context. * - * To supply information from the surrounding web server environment, + *

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. + * + *

This interface need not be threadsafe. */ class SAML_API HTTPRequest { MAKE_NONCOPYABLE(HTTPRequest); @@ -90,6 +92,14 @@ namespace opensaml { * @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. @@ -111,6 +121,21 @@ namespace opensaml { virtual std::vector::size_type getParameters( const char* name, std::vector& 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; }; /** diff --git a/saml/binding/MessageEncoder.h b/saml/binding/MessageEncoder.h index 4d23033..536acf4 100644 --- a/saml/binding/MessageEncoder.h +++ b/saml/binding/MessageEncoder.h @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -47,6 +48,59 @@ namespace opensaml { virtual ~MessageEncoder() {} /** + * Interface to caller-supplied shim for issuing an HTTP response. + * + *

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. + * + *

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 @@ -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. * @@ -100,27 +154,21 @@ namespace opensaml { * binding-specific manner. The CredentialResolver MUST * be locked by the caller. * - *

An embedded URLEncoder instance may be required by some bindings - * in order to produce predictable signature input. - * *

Artifact-based bindings require an ArtifactGenerator be set to * produce an artifact suitable for the intended recipient. * - *

Note that the name/value pairs resulting from the encoding operation are - * NOT 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 */ - virtual void encode( - std::map& outputFields, + virtual long encode( + HTTPResponse& httpResponse, xmltooling::XMLObject* xmlObject, + const char* destination, const char* recipientID=NULL, const char* relayState=NULL, const xmlsignature::CredentialResolver* credResolver=NULL, diff --git a/saml/saml1/binding/SAML1ArtifactEncoder.h b/saml/saml1/binding/SAML1ArtifactEncoder.h index 3bd1cdd..15f0ed1 100644 --- a/saml/saml1/binding/SAML1ArtifactEncoder.h +++ b/saml/saml1/binding/SAML1ArtifactEncoder.h @@ -35,9 +35,10 @@ namespace opensaml { SAML1ArtifactEncoder(const DOMElement* e); virtual ~SAML1ArtifactEncoder(); - void encode( - std::map& outputFields, + long encode( + HTTPResponse& httpResponse, xmltooling::XMLObject* xmlObject, + const char* destination, const char* recipientID=NULL, const char* relayState=NULL, const xmlsignature::CredentialResolver* credResolver=NULL, diff --git a/saml/saml1/binding/SAML1POSTEncoder.h b/saml/saml1/binding/SAML1POSTEncoder.h index c99c38d..4ab47bf 100644 --- a/saml/saml1/binding/SAML1POSTEncoder.h +++ b/saml/saml1/binding/SAML1POSTEncoder.h @@ -35,15 +35,20 @@ namespace opensaml { SAML1POSTEncoder(const DOMElement* e); virtual ~SAML1POSTEncoder(); - void encode( - std::map& outputFields, + long encode( + HTTPResponse& httpResponse, xmltooling::XMLObject* xmlObject, + const char* destination, 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; + }; }; }; diff --git a/saml/saml1/binding/impl/SAML1ArtifactEncoder.cpp b/saml/saml1/binding/impl/SAML1ArtifactEncoder.cpp index cc76f7c..b747201 100644 --- a/saml/saml1/binding/impl/SAML1ArtifactEncoder.cpp +++ b/saml/saml1/binding/impl/SAML1ArtifactEncoder.cpp @@ -22,8 +22,9 @@ #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" @@ -51,9 +52,10 @@ SAML1ArtifactEncoder::SAML1ArtifactEncoder(const DOMElement* e) {} SAML1ArtifactEncoder::~SAML1ArtifactEncoder() {} -void SAML1ArtifactEncoder::encode( - map& outputFields, +long SAML1ArtifactEncoder::encode( + HTTPResponse& httpResponse, XMLObject* xmlObject, + const char* destination, 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"); - outputFields.clear(); if (xmlObject->getParent()) throw BindingException("Cannot encode XML content with parent."); Assertion* assertion = dynamic_cast(xmlObject); @@ -87,13 +88,15 @@ void SAML1ArtifactEncoder::encode( log.debug("obtaining new artifact for relying party (%s)", recipientID ? recipientID : "unknown"); auto_ptr 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); - 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()); } diff --git a/saml/saml1/binding/impl/SAML1POSTEncoder.cpp b/saml/saml1/binding/impl/SAML1POSTEncoder.cpp index 5b0704f..ccc5510 100644 --- a/saml/saml1/binding/impl/SAML1POSTEncoder.cpp +++ b/saml/saml1/binding/impl/SAML1POSTEncoder.cpp @@ -25,9 +25,12 @@ #include "saml1/binding/SAML1POSTEncoder.h" #include "saml1/core/Protocols.h" +#include +#include #include #include #include +#include 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() {} -void SAML1POSTEncoder::encode( - map& outputFields, +long SAML1POSTEncoder::encode( + HTTPResponse& httpResponse, XMLObject* xmlObject, + const char* destination, 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"); - outputFields.clear(); if (xmlObject->getParent()) throw BindingException("Cannot encode XML content with parent."); Response* response = dynamic_cast(xmlObject); @@ -108,13 +122,24 @@ void SAML1POSTEncoder::encode( 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 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; - - log.debug("message encoded"); + return ret; } diff --git a/saml/saml2/binding/SAML2ArtifactEncoder.h b/saml/saml2/binding/SAML2ArtifactEncoder.h index ecbdae2..01057f8 100644 --- a/saml/saml2/binding/SAML2ArtifactEncoder.h +++ b/saml/saml2/binding/SAML2ArtifactEncoder.h @@ -35,15 +35,20 @@ namespace opensaml { SAML2ArtifactEncoder(const DOMElement* e); virtual ~SAML2ArtifactEncoder(); - void encode( - std::map& outputFields, + long encode( + HTTPResponse& httpResponse, xmltooling::XMLObject* xmlObject, + const char* destination, 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; + }; }; }; diff --git a/saml/saml2/binding/SAML2POSTEncoder.h b/saml/saml2/binding/SAML2POSTEncoder.h index 6074890..3f325e4 100644 --- a/saml/saml2/binding/SAML2POSTEncoder.h +++ b/saml/saml2/binding/SAML2POSTEncoder.h @@ -35,15 +35,20 @@ namespace opensaml { SAML2POSTEncoder(const DOMElement* e); virtual ~SAML2POSTEncoder(); - void encode( - std::map& outputFields, + long encode( + HTTPResponse& httpResponse, xmltooling::XMLObject* xmlObject, + const char* destination, 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; + }; }; }; diff --git a/saml/saml2/binding/impl/SAML2ArtifactEncoder.cpp b/saml/saml2/binding/impl/SAML2ArtifactEncoder.cpp index eec06cb..048eeb7 100644 --- a/saml/saml2/binding/impl/SAML2ArtifactEncoder.cpp +++ b/saml/saml2/binding/impl/SAML2ArtifactEncoder.cpp @@ -22,13 +22,17 @@ #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 +#include #include #include +#include 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() {} -void SAML2ArtifactEncoder::encode( - map& outputFields, - XMLObject* xmlObject, +long SAML2ArtifactEncoder::encode( + HTTPResponse& httpResponse, + xmltooling::XMLObject* xmlObject, + const char* destination, 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"); - 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."); @@ -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); - 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 params; + params["action"] = destination; + params["SAMLart"] = artifact->encode(); + if (relayState) + params["RelayState"] = relayState; + stringstream s; + engine->run(infile, s, params); + return httpResponse.sendResponse(s); + } } diff --git a/saml/saml2/binding/impl/SAML2POSTEncoder.cpp b/saml/saml2/binding/impl/SAML2POSTEncoder.cpp index 72d6ba8..9a4e7df 100644 --- a/saml/saml2/binding/impl/SAML2POSTEncoder.cpp +++ b/saml/saml2/binding/impl/SAML2POSTEncoder.cpp @@ -25,9 +25,12 @@ #include "saml2/binding/SAML2POSTEncoder.h" #include "saml2/core/Protocols.h" +#include +#include #include #include #include +#include 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() {} -void SAML2POSTEncoder::encode( - map& outputFields, +long SAML2POSTEncoder::encode( + HTTPResponse& httpResponse, XMLObject* xmlObject, + const char* destination, 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"); - outputFields.clear(); 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."); } - // 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 params; + params["action"] = destination; + params[request ? "SAMLRequest" : "SAMLResponse"] = xmlbuf; 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; - - log.debug("message encoded"); + return ret; } diff --git a/samltest/binding.h b/samltest/binding.h index 474e882..15aa249 100644 --- a/samltest/binding.h +++ b/samltest/binding.h @@ -19,19 +19,22 @@ #include #include #include +#include #include #include 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 m_fields; + map m_headers; + string m_method,m_url; public: void setUp() { @@ -39,6 +42,9 @@ public: 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"; @@ -84,8 +90,38 @@ public: 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::const_iterator i=m_headers.find(name); + return i==m_headers.end() ? "" : i->second; + } + const char* getParameter(const char* name) const { map::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(); } + + // 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,"<",4)) { + decoded+='<'; ch+=4; + } + else if (!strncmp(ch,">",4)) { + decoded+='>'; ch+=4; + } + else if (!strncmp(ch,""",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," + + SAML Binding + + +

+ + + + + + + + + + + + +
+ + diff --git a/samltest/saml1/binding/SAML1ArtifactTest.h b/samltest/saml1/binding/SAML1ArtifactTest.h index a133cf1..68edcfc 100644 --- a/samltest/saml1/binding/SAML1ArtifactTest.h +++ b/samltest/saml1/binding/SAML1ArtifactTest.h @@ -29,12 +29,10 @@ class SAML1ArtifactTest : public CxxTest::TestSuite, public SAMLBindingBaseTestCase, public MessageEncoder::ArtifactGenerator, public MessageDecoder::ArtifactResolver { public: void setUp() { - m_fields.clear(); SAMLBindingBaseTestCase::setUp(); } void tearDown() { - m_fields.clear(); SAMLBindingBaseTestCase::tearDown(); } @@ -55,7 +53,7 @@ public: 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. @@ -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/")); } diff --git a/samltest/saml1/binding/SAML1POSTTest.h b/samltest/saml1/binding/SAML1POSTTest.h index 4b26224..73a17ec 100644 --- a/samltest/saml1/binding/SAML1POSTTest.h +++ b/samltest/saml1/binding/SAML1POSTTest.h @@ -24,12 +24,10 @@ using namespace opensaml::saml1; class SAML1POSTTest : public CxxTest::TestSuite, public SAMLBindingBaseTestCase { public: void setUp() { - m_fields.clear(); SAMLBindingBaseTestCase::setUp(); } void tearDown() { - m_fields.clear(); SAMLBindingBaseTestCase::tearDown(); } @@ -49,10 +47,20 @@ public: 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 janitor2(encoder_config); + encoder_config->appendChild(encoder_config->createElementNS(NULL,lit1.get())); + encoder_config->getDocumentElement()->setAttributeNS(NULL,lit2.get(),lit3.get()); auto_ptr 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. @@ -101,10 +109,20 @@ public: 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 janitor2(encoder_config); + encoder_config->appendChild(encoder_config->createElementNS(NULL,lit1.get())); + encoder_config->getDocumentElement()->setAttributeNS(NULL,lit2.get(),lit3.get()); auto_ptr 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. @@ -140,16 +158,4 @@ public: throw; } } - - const char* getMethod() const { - return "POST"; - } - - const char* getRequestURL() const { - return "https://sp.example.org/SAML/POST"; - } - - const char* getQueryString() const { - return NULL; - } }; diff --git a/samltest/saml2/binding/SAML2ArtifactTest.h b/samltest/saml2/binding/SAML2ArtifactTest.h index c785bd3..c8764cd 100644 --- a/samltest/saml2/binding/SAML2ArtifactTest.h +++ b/samltest/saml2/binding/SAML2ArtifactTest.h @@ -28,12 +28,10 @@ class SAML2ArtifactTest : public CxxTest::TestSuite, public SAMLBindingBaseTestCase, public MessageEncoder::ArtifactGenerator, public MessageDecoder::ArtifactResolver { public: void setUp() { - m_fields.clear(); SAMLBindingBaseTestCase::setUp(); } void tearDown() { - m_fields.clear(); SAMLBindingBaseTestCase::tearDown(); } @@ -57,7 +55,7 @@ public: 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. @@ -94,18 +92,6 @@ public: 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."); diff --git a/samltest/saml2/binding/SAML2POSTTest.h b/samltest/saml2/binding/SAML2POSTTest.h index 77cd153..b52b228 100644 --- a/samltest/saml2/binding/SAML2POSTTest.h +++ b/samltest/saml2/binding/SAML2POSTTest.h @@ -24,12 +24,10 @@ using namespace opensaml::saml2; class SAML2POSTTest : public CxxTest::TestSuite, public SAMLBindingBaseTestCase { public: void setUp() { - m_fields.clear(); SAMLBindingBaseTestCase::setUp(); } void tearDown() { - m_fields.clear(); SAMLBindingBaseTestCase::tearDown(); } @@ -49,10 +47,20 @@ public: 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 janitor2(encoder_config); + encoder_config->appendChild(encoder_config->createElementNS(NULL,lit1.get())); + encoder_config->getDocumentElement()->setAttributeNS(NULL,lit2.get(),lit3.get()); auto_ptr 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. @@ -101,10 +109,20 @@ public: 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 janitor2(encoder_config); + encoder_config->appendChild(encoder_config->createElementNS(NULL,lit1.get())); + encoder_config->getDocumentElement()->setAttributeNS(NULL,lit2.get(),lit3.get()); auto_ptr 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. @@ -140,16 +158,4 @@ public: throw; } } - - const char* getMethod() const { - return "POST"; - } - - const char* getRequestURL() const { - return "https://sp.example.org/SAML/POST"; - } - - const char* getQueryString() const { - return NULL; - } }; diff --git a/samltest/samltest.h b/samltest/samltest.h index a65544b..e6283d9 100644 --- a/samltest/samltest.h +++ b/samltest/samltest.h @@ -20,6 +20,7 @@ #include #include #include +#include //#define SAML_LEAKCHECK @@ -33,6 +34,7 @@ public: 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")) diff --git a/samltest/samltest.vcproj b/samltest/samltest.vcproj index 8970b8d..cd29fdf 100644 --- a/samltest/samltest.vcproj +++ b/samltest/samltest.vcproj @@ -588,14 +588,6 @@ - - - - + + + +