From: Scott Cantor Date: Sun, 12 Nov 2006 05:11:23 +0000 (+0000) Subject: First SOAP encoder. X-Git-Tag: 2.0-alpha1~145 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-opensaml.git;a=commitdiff_plain;h=8a21bb42163a78e9c324f840004fd9e9821ad745 First SOAP encoder. --- diff --git a/saml/Makefile.am b/saml/Makefile.am index 70fe4a7..78ae9b2 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -77,7 +77,8 @@ saml1bindinclude_HEADERS = \ saml1/binding/SAML1ArtifactEncoder.h \ saml1/binding/SAML1POSTDecoder.h \ saml1/binding/SAML1POSTEncoder.h \ - saml1/binding/SAML1SOAPDecoder.h + saml1/binding/SAML1SOAPDecoder.h \ + saml1/binding/SAML1SOAPEncoder.h saml2coreinclude_HEADERS = \ saml2/core/Assertions.h \ @@ -129,6 +130,7 @@ libsaml_la_SOURCES = \ saml1/binding/impl/SAML1POSTDecoder.cpp \ saml1/binding/impl/SAML1POSTEncoder.cpp \ saml1/binding/impl/SAML1SOAPDecoder.cpp \ + saml1/binding/impl/SAML1SOAPEncoder.cpp \ saml2/core/impl/Assertions20Impl.cpp \ saml2/core/impl/Assertions20SchemaValidators.cpp \ saml2/core/impl/Protocols20Impl.cpp \ diff --git a/saml/binding/GenericResponse.h b/saml/binding/GenericResponse.h index f955e5c..6947a37 100644 --- a/saml/binding/GenericResponse.h +++ b/saml/binding/GenericResponse.h @@ -49,6 +49,24 @@ namespace opensaml { virtual void setContentType(const char* type=NULL)=0; /** + * Sends a completed response to the client along with a + * transport-specific "OK" indication. Used for "normal" responses. + * + * @param inputStream reference to source of response data + * @return a result code to return from the calling MessageEncoder + */ + virtual long sendResponse(std::istream& inputStream)=0; + + /** + * Sends an "error" response to the client along with a + * transport-specific error indication. + * + * @param inputStream reference to source of response data + * @return a result code to return from the calling MessageEncoder + */ + virtual long sendError(std::istream& inputStream)=0; + + /** * Sends a completed response to the client. * * @param inputStream reference to source of response data diff --git a/saml/binding/HTTPResponse.h b/saml/binding/HTTPResponse.h index e77e17d..4a94e1d 100644 --- a/saml/binding/HTTPResponse.h +++ b/saml/binding/HTTPResponse.h @@ -71,7 +71,8 @@ namespace opensaml { /** Some common HTTP status codes. */ enum status_t { SAML_HTTP_STATUS_OK = 200, - SAML_HTTP_STATUS_MOVED = 302 + SAML_HTTP_STATUS_MOVED = 302, + SAML_HTTP_STATUS_ERROR = 500 }; }; }; diff --git a/saml/saml.vcproj b/saml/saml.vcproj index f8190eb..80d71c6 100644 --- a/saml/saml.vcproj +++ b/saml/saml.vcproj @@ -257,6 +257,10 @@ > + + @@ -640,6 +644,10 @@ > + + diff --git a/saml/saml1/binding/SAML1ArtifactDecoder.h b/saml/saml1/binding/SAML1ArtifactDecoder.h index c1e384b..d1e3e89 100644 --- a/saml/saml1/binding/SAML1ArtifactDecoder.h +++ b/saml/saml1/binding/SAML1ArtifactDecoder.h @@ -34,7 +34,7 @@ namespace opensaml { { public: SAML1ArtifactDecoder(const DOMElement* e); - virtual ~SAML1ArtifactDecoder(); + virtual ~SAML1ArtifactDecoder() {} Response* decode( std::string& relayState, diff --git a/saml/saml1/binding/SAML1ArtifactEncoder.h b/saml/saml1/binding/SAML1ArtifactEncoder.h index a4d4718..40ce726 100644 --- a/saml/saml1/binding/SAML1ArtifactEncoder.h +++ b/saml/saml1/binding/SAML1ArtifactEncoder.h @@ -33,7 +33,7 @@ namespace opensaml { { public: SAML1ArtifactEncoder(const DOMElement* e); - virtual ~SAML1ArtifactEncoder(); + virtual ~SAML1ArtifactEncoder() {} long encode( GenericResponse& genericResponse, diff --git a/saml/saml1/binding/SAML1POSTDecoder.h b/saml/saml1/binding/SAML1POSTDecoder.h index 9ed3334..ead184b 100644 --- a/saml/saml1/binding/SAML1POSTDecoder.h +++ b/saml/saml1/binding/SAML1POSTDecoder.h @@ -34,7 +34,7 @@ namespace opensaml { { public: SAML1POSTDecoder(const DOMElement* e); - virtual ~SAML1POSTDecoder(); + virtual ~SAML1POSTDecoder() {} Response* decode( std::string& relayState, diff --git a/saml/saml1/binding/SAML1POSTEncoder.h b/saml/saml1/binding/SAML1POSTEncoder.h index 1496aff..a5abad7 100644 --- a/saml/saml1/binding/SAML1POSTEncoder.h +++ b/saml/saml1/binding/SAML1POSTEncoder.h @@ -33,7 +33,7 @@ namespace opensaml { { public: SAML1POSTEncoder(const DOMElement* e); - virtual ~SAML1POSTEncoder(); + virtual ~SAML1POSTEncoder() {} long encode( GenericResponse& genericResponse, diff --git a/saml/saml1/binding/SAML1SOAPEncoder.h b/saml/saml1/binding/SAML1SOAPEncoder.h new file mode 100644 index 0000000..ca52837 --- /dev/null +++ b/saml/saml1/binding/SAML1SOAPEncoder.h @@ -0,0 +1,50 @@ +/* + * Copyright 2001-2006 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. + */ + +/** + * @file saml/saml1/binding/SAML1SOAPEncoder.h + * + * SAML 1.x SOAP binding message encoder + */ + +#include + + +namespace opensaml { + namespace saml1p { + + /** + * SAML 1.x POST binding/profile message encoder + */ + class SAML_API SAML1SOAPEncoder : public MessageEncoder + { + public: + SAML1SOAPEncoder(const DOMElement* e); + virtual ~SAML1SOAPEncoder() {} + + long encode( + GenericResponse& genericResponse, + xmltooling::XMLObject* xmlObject, + const char* destination, + const char* recipientID=NULL, + const char* relayState=NULL, + const xmlsignature::CredentialResolver* credResolver=NULL, + const XMLCh* sigAlgorithm=NULL + ) const; + }; + + }; +}; diff --git a/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp b/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp index 83cd7ba..70cee0f 100644 --- a/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp +++ b/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp @@ -50,8 +50,6 @@ namespace opensaml { SAML1ArtifactDecoder::SAML1ArtifactDecoder(const DOMElement* e) {} -SAML1ArtifactDecoder::~SAML1ArtifactDecoder() {} - Response* SAML1ArtifactDecoder::decode( string& relayState, const GenericRequest& genericRequest, diff --git a/saml/saml1/binding/impl/SAML1ArtifactEncoder.cpp b/saml/saml1/binding/impl/SAML1ArtifactEncoder.cpp index 7252831..d40f64c 100644 --- a/saml/saml1/binding/impl/SAML1ArtifactEncoder.cpp +++ b/saml/saml1/binding/impl/SAML1ArtifactEncoder.cpp @@ -51,8 +51,6 @@ namespace opensaml { SAML1ArtifactEncoder::SAML1ArtifactEncoder(const DOMElement* e) {} -SAML1ArtifactEncoder::~SAML1ArtifactEncoder() {} - long SAML1ArtifactEncoder::encode( GenericResponse& genericResponse, XMLObject* xmlObject, diff --git a/saml/saml1/binding/impl/SAML1POSTDecoder.cpp b/saml/saml1/binding/impl/SAML1POSTDecoder.cpp index 33ac05f..bccc690 100644 --- a/saml/saml1/binding/impl/SAML1POSTDecoder.cpp +++ b/saml/saml1/binding/impl/SAML1POSTDecoder.cpp @@ -52,8 +52,6 @@ namespace opensaml { SAML1POSTDecoder::SAML1POSTDecoder(const DOMElement* e) {} -SAML1POSTDecoder::~SAML1POSTDecoder() {} - Response* SAML1POSTDecoder::decode( string& relayState, const GenericRequest& genericRequest, diff --git a/saml/saml1/binding/impl/SAML1POSTEncoder.cpp b/saml/saml1/binding/impl/SAML1POSTEncoder.cpp index ce99ce1..5c15044 100644 --- a/saml/saml1/binding/impl/SAML1POSTEncoder.cpp +++ b/saml/saml1/binding/impl/SAML1POSTEncoder.cpp @@ -22,7 +22,6 @@ #include "internal.h" #include "exceptions.h" -#include "binding/HTTPResponse.h" #include "saml1/binding/SAML1POSTEncoder.h" #include "saml1/core/Protocols.h" @@ -62,8 +61,6 @@ SAML1POSTEncoder::SAML1POSTEncoder(const DOMElement* e) throw XMLToolingException("SAML1POSTEncoder requires template attribute."); } -SAML1POSTEncoder::~SAML1POSTEncoder() {} - long SAML1POSTEncoder::encode( GenericResponse& genericResponse, XMLObject* xmlObject, @@ -80,9 +77,6 @@ long SAML1POSTEncoder::encode( Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML1POST"); log.debug("validating input"); - HTTPResponse* httpResponse=dynamic_cast(&genericResponse); - if (!httpResponse) - throw BindingException("Unable to cast response interface to HTTPResponse type."); if (xmlObject->getParent()) throw BindingException("Cannot encode XML content with parent."); Response* response = dynamic_cast(xmlObject); @@ -141,8 +135,8 @@ long SAML1POSTEncoder::encode( params["TARGET"] = relayState; stringstream s; engine->run(infile, s, params); - httpResponse->setContentType("text/html"); - long ret = httpResponse->sendResponse(s, HTTPResponse::SAML_HTTP_STATUS_OK); + genericResponse.setContentType("text/html"); + long ret = genericResponse.sendResponse(s); // Cleanup by destroying XML. delete xmlObject; diff --git a/saml/saml1/binding/impl/SAML1SOAPEncoder.cpp b/saml/saml1/binding/impl/SAML1SOAPEncoder.cpp new file mode 100644 index 0000000..121acbe --- /dev/null +++ b/saml/saml1/binding/impl/SAML1SOAPEncoder.cpp @@ -0,0 +1,178 @@ +/* + * Copyright 2001-2006 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. + */ + +/** + * SAML1SOAPEncoder.cpp + * + * SAML 1.x SOAP binding message encoder + */ + +#include "internal.h" +#include "exceptions.h" +#include "binding/HTTPResponse.h" +#include "saml1/binding/SAML1SOAPEncoder.h" +#include "saml1/core/Protocols.h" + +#include +#include +#include +#include + +using namespace opensaml::saml1p; +using namespace opensaml; +using namespace xmlsignature; +using namespace soap11; +using namespace xmltooling; +using namespace log4cpp; +using namespace std; + +namespace opensaml { + namespace saml1p { + MessageEncoder* SAML_DLLLOCAL SAML1SOAPEncoderFactory(const DOMElement* const & e) + { + return new SAML1SOAPEncoder(e); + } + }; +}; + +SAML1SOAPEncoder::SAML1SOAPEncoder(const DOMElement* e) {} + +long SAML1SOAPEncoder::encode( + GenericResponse& genericResponse, + XMLObject* xmlObject, + const char* destination, + const char* recipientID, + const char* relayState, + const CredentialResolver* credResolver, + const XMLCh* sigAlgorithm + ) const +{ +#ifdef _DEBUG + xmltooling::NDC ndc("encode"); +#endif + Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML1SOAP"); + + log.debug("validating input"); + if (xmlObject->getParent()) + throw BindingException("Cannot encode XML content with parent."); + + genericResponse.setContentType("text/xml"); + + DOMElement* rootElement = NULL; + Response* response = dynamic_cast(xmlObject); + if (response) { + try { + Envelope* env = EnvelopeBuilder::buildEnvelope(); + Body* body = BodyBuilder::buildBody(); + env->setBody(body); + body->getXMLObjects().push_back(response); + if (credResolver ) { + if (response->getSignature()) { + log.debug("response already signed, skipping signature operation"); + rootElement = env->marshall(); + } + else { + log.debug("signing and marshalling the response"); + + // Build a Signature. + Signature* sig = buildSignature(credResolver, sigAlgorithm); + response->setSignature(sig); + + // Sign response while marshalling. + vector sigs(1,sig); + rootElement = env->marshall((DOMDocument*)NULL,&sigs); + } + } + else { + log.debug("marshalling the response"); + rootElement = env->marshall(); + } + + string xmlbuf; + XMLHelper::serialize(rootElement, xmlbuf); + istringstream s(xmlbuf); + log.debug("sending serialized response"); + long ret = genericResponse.sendResponse(s); + + // Cleanup by destroying XML. + delete env; + return ret; + } + catch (XMLToolingException&) { + // A bit weird...we have to "revert" things so that the response is isolated + // so the caller can free it. + if (response->getParent()) { + response->getParent()->detach(); + response->detach(); + } + throw; + } + } + + Fault* fault = dynamic_cast(xmlObject); + if (fault) { + try { + log.debug("building Envelope and marshalling Fault"); + Envelope* env = EnvelopeBuilder::buildEnvelope(); + Body* body = BodyBuilder::buildBody(); + env->setBody(body); + body->getXMLObjects().push_back(fault); + rootElement = env->marshall(); + + string xmlbuf; + XMLHelper::serialize(rootElement, xmlbuf); + istringstream s(xmlbuf); + log.debug("sending serialized fault"); + long ret = genericResponse.sendError(s); + + // Cleanup by destroying XML. + delete env; + return ret; + } + catch (XMLToolingException&) { + // A bit weird...we have to "revert" things so that the fault is isolated + // so the caller can free it. + if (fault->getParent()) { + fault->getParent()->detach(); + fault->detach(); + } + throw; + } + } + + Envelope* env = dynamic_cast(xmlObject); + if (env) { + log.debug("marshalling envelope"); + rootElement = env->marshall(); + + bool error = + (env->getBody() && + env->getBody()->hasChildren() && + dynamic_cast(env->getBody()->getXMLObjects().front())); + + string xmlbuf; + XMLHelper::serialize(rootElement, xmlbuf); + istringstream s(xmlbuf); + log.debug("sending serialized envelope"); + long ret = error ? genericResponse.sendError(s) : genericResponse.sendResponse(s); + + // Cleanup by destroying XML. + delete env; + return ret; + } + + throw BindingException("XML content for SAML 1.x SOAP Encoder must be a SAML 1.x or SOAP Fault/Envelope."); +} diff --git a/saml/saml2/binding/SAML2ArtifactDecoder.h b/saml/saml2/binding/SAML2ArtifactDecoder.h index bf297c0..ad35e45 100644 --- a/saml/saml2/binding/SAML2ArtifactDecoder.h +++ b/saml/saml2/binding/SAML2ArtifactDecoder.h @@ -37,7 +37,7 @@ namespace opensaml { { public: SAML2ArtifactDecoder(const DOMElement* e); - virtual ~SAML2ArtifactDecoder(); + virtual ~SAML2ArtifactDecoder() {} xmltooling::XMLObject* decode( std::string& relayState, diff --git a/saml/saml2/binding/SAML2ArtifactEncoder.h b/saml/saml2/binding/SAML2ArtifactEncoder.h index d3f5f3d..0977df3 100644 --- a/saml/saml2/binding/SAML2ArtifactEncoder.h +++ b/saml/saml2/binding/SAML2ArtifactEncoder.h @@ -33,7 +33,7 @@ namespace opensaml { { public: SAML2ArtifactEncoder(const DOMElement* e); - virtual ~SAML2ArtifactEncoder(); + virtual ~SAML2ArtifactEncoder() {} long encode( GenericResponse& genericResponse, diff --git a/saml/saml2/binding/SAML2POSTDecoder.h b/saml/saml2/binding/SAML2POSTDecoder.h index 00edb7a..e311366 100644 --- a/saml/saml2/binding/SAML2POSTDecoder.h +++ b/saml/saml2/binding/SAML2POSTDecoder.h @@ -34,7 +34,7 @@ namespace opensaml { { public: SAML2POSTDecoder(const DOMElement* e); - virtual ~SAML2POSTDecoder(); + virtual ~SAML2POSTDecoder() {} saml2::RootObject* decode( std::string& relayState, diff --git a/saml/saml2/binding/SAML2POSTEncoder.h b/saml/saml2/binding/SAML2POSTEncoder.h index 2c0c25d..521a4ae 100644 --- a/saml/saml2/binding/SAML2POSTEncoder.h +++ b/saml/saml2/binding/SAML2POSTEncoder.h @@ -33,7 +33,7 @@ namespace opensaml { { public: SAML2POSTEncoder(const DOMElement* e, bool simple=false); - virtual ~SAML2POSTEncoder(); + virtual ~SAML2POSTEncoder() {} long encode( GenericResponse& genericResponse, diff --git a/saml/saml2/binding/SAML2RedirectDecoder.h b/saml/saml2/binding/SAML2RedirectDecoder.h index f0ced2b..64743d1 100644 --- a/saml/saml2/binding/SAML2RedirectDecoder.h +++ b/saml/saml2/binding/SAML2RedirectDecoder.h @@ -32,7 +32,7 @@ namespace opensaml { { public: SAML2RedirectDecoder(const DOMElement* e); - virtual ~SAML2RedirectDecoder(); + virtual ~SAML2RedirectDecoder() {} xmltooling::XMLObject* decode( std::string& relayState, diff --git a/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp b/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp index 1cd434e..48fcceb 100644 --- a/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp +++ b/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp @@ -53,8 +53,6 @@ namespace opensaml { SAML2ArtifactDecoder::SAML2ArtifactDecoder(const DOMElement* e) {} -SAML2ArtifactDecoder::~SAML2ArtifactDecoder() {} - XMLObject* SAML2ArtifactDecoder::decode( string& relayState, const GenericRequest& genericRequest, diff --git a/saml/saml2/binding/impl/SAML2ArtifactEncoder.cpp b/saml/saml2/binding/impl/SAML2ArtifactEncoder.cpp index 2ce48a3..a6445bd 100644 --- a/saml/saml2/binding/impl/SAML2ArtifactEncoder.cpp +++ b/saml/saml2/binding/impl/SAML2ArtifactEncoder.cpp @@ -62,8 +62,6 @@ SAML2ArtifactEncoder::SAML2ArtifactEncoder(const DOMElement* e) } } -SAML2ArtifactEncoder::~SAML2ArtifactEncoder() {} - long SAML2ArtifactEncoder::encode( GenericResponse& genericResponse, xmltooling::XMLObject* xmlObject, @@ -158,6 +156,6 @@ long SAML2ArtifactEncoder::encode( stringstream s; engine->run(infile, s, params); httpResponse->setContentType("text/html"); - return httpResponse->sendResponse(s, HTTPResponse::SAML_HTTP_STATUS_OK); + return httpResponse->sendResponse(s); } } diff --git a/saml/saml2/binding/impl/SAML2POSTDecoder.cpp b/saml/saml2/binding/impl/SAML2POSTDecoder.cpp index f216a8d..32aedea 100644 --- a/saml/saml2/binding/impl/SAML2POSTDecoder.cpp +++ b/saml/saml2/binding/impl/SAML2POSTDecoder.cpp @@ -52,8 +52,6 @@ namespace opensaml { SAML2POSTDecoder::SAML2POSTDecoder(const DOMElement* e) {} -SAML2POSTDecoder::~SAML2POSTDecoder() {} - saml2::RootObject* SAML2POSTDecoder::decode( std::string& relayState, const GenericRequest& genericRequest, diff --git a/saml/saml2/binding/impl/SAML2POSTEncoder.cpp b/saml/saml2/binding/impl/SAML2POSTEncoder.cpp index 3a5fe25..3c73d86 100644 --- a/saml/saml2/binding/impl/SAML2POSTEncoder.cpp +++ b/saml/saml2/binding/impl/SAML2POSTEncoder.cpp @@ -22,7 +22,6 @@ #include "internal.h" #include "exceptions.h" -#include "binding/HTTPResponse.h" #include "saml2/binding/SAML2POSTEncoder.h" #include "saml2/core/Protocols.h" @@ -67,8 +66,6 @@ SAML2POSTEncoder::SAML2POSTEncoder(const DOMElement* e, bool simple) : m_simple( throw XMLToolingException("SAML2POSTEncoder requires template attribute."); } -SAML2POSTEncoder::~SAML2POSTEncoder() {} - long SAML2POSTEncoder::encode( GenericResponse& genericResponse, XMLObject* xmlObject, @@ -85,9 +82,6 @@ long SAML2POSTEncoder::encode( Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML2POST"); log.debug("validating input"); - HTTPResponse* httpResponse=dynamic_cast(&genericResponse); - if (!httpResponse) - throw BindingException("Unable to cast response interface to HTTPResponse type."); if (xmlObject->getParent()) throw BindingException("Cannot encode XML content with parent."); @@ -170,8 +164,8 @@ long SAML2POSTEncoder::encode( pmap["action"] = destination; stringstream s; engine->run(infile, s, pmap); - httpResponse->setContentType("text/html"); - long ret = httpResponse->sendResponse(s, HTTPResponse::SAML_HTTP_STATUS_OK); + genericResponse.setContentType("text/html"); + long ret = genericResponse.sendResponse(s); // Cleanup by destroying XML. delete xmlObject; diff --git a/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp b/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp index 4ea64ff..5c1dc39 100644 --- a/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp +++ b/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp @@ -54,8 +54,6 @@ namespace opensaml { SAML2RedirectDecoder::SAML2RedirectDecoder(const DOMElement* e) {} -SAML2RedirectDecoder::~SAML2RedirectDecoder() {} - XMLObject* SAML2RedirectDecoder::decode( string& relayState, const GenericRequest& genericRequest, diff --git a/samltest/binding.h b/samltest/binding.h index aa0bff9..13638f1 100644 --- a/samltest/binding.h +++ b/samltest/binding.h @@ -237,6 +237,14 @@ public: return decoded; } + long sendResponse(std::istream& inputStream) { + return sendResponse(inputStream, HTTPResponse::SAML_HTTP_STATUS_OK); + } + + long sendError(std::istream& inputStream) { + return sendResponse(inputStream, HTTPResponse::SAML_HTTP_STATUS_ERROR); + } + long sendResponse(std::istream& inputStream, long status) { m_method="POST"; string page,line;