From c3c89629114e8a29b8c9a769956b6b4e7e2c4c24 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Sun, 12 Nov 2006 22:40:36 +0000 Subject: [PATCH] 2.0 SOAP Encoder --- saml/Makefile.am | 4 +- saml/binding/impl/MessageDecoder.cpp | 2 + saml/binding/impl/MessageEncoder.cpp | 4 + saml/saml.vcproj | 8 ++ saml/saml1/binding/SAML1SOAPEncoder.h | 2 +- saml/saml1/binding/impl/SAML1SOAPEncoder.cpp | 5 + saml/saml2/binding/SAML2SOAPEncoder.h | 50 ++++++++ saml/saml2/binding/impl/SAML2SOAPEncoder.cpp | 183 +++++++++++++++++++++++++++ 8 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 saml/saml2/binding/SAML2SOAPEncoder.h create mode 100644 saml/saml2/binding/impl/SAML2SOAPEncoder.cpp diff --git a/saml/Makefile.am b/saml/Makefile.am index 78ae9b2..c5f69ec 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -94,7 +94,8 @@ saml2bindinclude_HEADERS = \ saml2/binding/SAML2Redirect.h \ saml2/binding/SAML2RedirectDecoder.h \ saml2/binding/SAML2RedirectEncoder.h \ - saml2/binding/SAML2SOAPDecoder.h + saml2/binding/SAML2SOAPDecoder.h \ + saml2/binding/SAML2SOAPEncoder.h saml2mdinclude_HEADERS = \ saml2/metadata/AbstractMetadataProvider.h \ @@ -155,6 +156,7 @@ libsaml_la_SOURCES = \ saml2/binding/impl/SAML2RedirectDecoder.cpp \ saml2/binding/impl/SAML2RedirectEncoder.cpp \ saml2/binding/impl/SAML2SOAPDecoder.cpp \ + saml2/binding/impl/SAML2SOAPEncoder.cpp \ encryption/EncryptedKeyResolver.cpp \ security/impl/TrustEngine.cpp \ security/impl/AbstractPKIXTrustEngine.cpp \ diff --git a/saml/binding/impl/MessageDecoder.cpp b/saml/binding/impl/MessageDecoder.cpp index 83bd7b1..cf785f6 100644 --- a/saml/binding/impl/MessageDecoder.cpp +++ b/saml/binding/impl/MessageDecoder.cpp @@ -38,6 +38,7 @@ namespace opensaml { SAML_DLLLOCAL PluginManager::Factory SAML2ArtifactDecoderFactory; SAML_DLLLOCAL PluginManager::Factory SAML2POSTDecoderFactory; SAML_DLLLOCAL PluginManager::Factory SAML2RedirectDecoderFactory; + SAML_DLLLOCAL PluginManager::Factory SAML2SOAPDecoderFactory; }; }; @@ -51,4 +52,5 @@ void SAML_API opensaml::registerMessageDecoders() conf.MessageDecoderManager.registerFactory(samlconstants::SAML20_BINDING_HTTP_POST, saml2p::SAML2POSTDecoderFactory); conf.MessageDecoderManager.registerFactory(samlconstants::SAML20_BINDING_HTTP_POST_SIMPLESIGN, saml2p::SAML2POSTDecoderFactory); conf.MessageDecoderManager.registerFactory(samlconstants::SAML20_BINDING_HTTP_REDIRECT, saml2p::SAML2RedirectDecoderFactory); + conf.MessageDecoderManager.registerFactory(samlconstants::SAML20_BINDING_SOAP, saml2p::SAML2SOAPDecoderFactory); } diff --git a/saml/binding/impl/MessageEncoder.cpp b/saml/binding/impl/MessageEncoder.cpp index 74e9a8a..5b6f761 100644 --- a/saml/binding/impl/MessageEncoder.cpp +++ b/saml/binding/impl/MessageEncoder.cpp @@ -36,6 +36,7 @@ namespace opensaml { namespace saml1p { SAML_DLLLOCAL PluginManager::Factory SAML1ArtifactEncoderFactory; SAML_DLLLOCAL PluginManager::Factory SAML1POSTEncoderFactory; + SAML_DLLLOCAL PluginManager::Factory SAML1SOAPEncoderFactory; }; namespace saml2p { @@ -43,6 +44,7 @@ namespace opensaml { SAML_DLLLOCAL PluginManager::Factory SAML2POSTEncoderFactory; SAML_DLLLOCAL PluginManager::Factory SAML2POSTSimpleSignEncoderFactory; SAML_DLLLOCAL PluginManager::Factory SAML2RedirectEncoderFactory; + SAML_DLLLOCAL PluginManager::Factory SAML2SOAPEncoderFactory; }; }; @@ -51,10 +53,12 @@ void SAML_API opensaml::registerMessageEncoders() SAMLConfig& conf=SAMLConfig::getConfig(); conf.MessageEncoderManager.registerFactory(samlconstants::SAML1_PROFILE_BROWSER_ARTIFACT, saml1p::SAML1ArtifactEncoderFactory); conf.MessageEncoderManager.registerFactory(samlconstants::SAML1_PROFILE_BROWSER_POST, saml1p::SAML1POSTEncoderFactory); + conf.MessageEncoderManager.registerFactory(samlconstants::SAML1_BINDING_SOAP, saml1p::SAML1SOAPEncoderFactory); conf.MessageEncoderManager.registerFactory(samlconstants::SAML20_BINDING_HTTP_ARTIFACT, saml2p::SAML2ArtifactEncoderFactory); conf.MessageEncoderManager.registerFactory(samlconstants::SAML20_BINDING_HTTP_POST, saml2p::SAML2POSTEncoderFactory); conf.MessageEncoderManager.registerFactory(samlconstants::SAML20_BINDING_HTTP_POST_SIMPLESIGN, saml2p::SAML2POSTSimpleSignEncoderFactory); conf.MessageEncoderManager.registerFactory(samlconstants::SAML20_BINDING_HTTP_REDIRECT, saml2p::SAML2RedirectEncoderFactory); + conf.MessageEncoderManager.registerFactory(samlconstants::SAML20_BINDING_SOAP, saml2p::SAML2SOAPEncoderFactory); } namespace { diff --git a/saml/saml.vcproj b/saml/saml.vcproj index 80d71c6..3183249 100644 --- a/saml/saml.vcproj +++ b/saml/saml.vcproj @@ -440,6 +440,10 @@ RelativePath=".\saml2\binding\impl\SAML2SOAPDecoder.cpp" > + + @@ -759,6 +763,10 @@ RelativePath=".\saml2\binding\SAML2SOAPDecoder.h" > + + (&genericResponse); + if (httpResponse) { + httpResponse->setHeader("Cache-Control", "no-cache, no-store, must-revalidate, private"); + httpResponse->setHeader("Pragma", "no-cache"); + } DOMElement* rootElement = NULL; Response* response = dynamic_cast(xmlObject); diff --git a/saml/saml2/binding/SAML2SOAPEncoder.h b/saml/saml2/binding/SAML2SOAPEncoder.h new file mode 100644 index 0000000..6df8d7e --- /dev/null +++ b/saml/saml2/binding/SAML2SOAPEncoder.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/saml2/binding/SAML2SOAPEncoder.h + * + * SAML 2.0 SOAP binding message encoder + */ + +#include + + +namespace opensaml { + namespace saml2p { + + /** + * SAML 2.0 POST binding message encoder + */ + class SAML_API SAML2SOAPEncoder : public MessageEncoder + { + public: + SAML2SOAPEncoder(const DOMElement* e); + virtual ~SAML2SOAPEncoder() {} + + 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/saml2/binding/impl/SAML2SOAPEncoder.cpp b/saml/saml2/binding/impl/SAML2SOAPEncoder.cpp new file mode 100644 index 0000000..7b56dee --- /dev/null +++ b/saml/saml2/binding/impl/SAML2SOAPEncoder.cpp @@ -0,0 +1,183 @@ +/* + * 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. + */ + +/** + * SAML2SOAPEncoder.cpp + * + * SAML 2.0 SOAP binding message encoder + */ + +#include "internal.h" +#include "exceptions.h" +#include "binding/HTTPResponse.h" +#include "saml2/binding/SAML2SOAPEncoder.h" +#include "saml2/core/Protocols.h" + +#include +#include +#include +#include + +using namespace opensaml::saml2p; +using namespace opensaml; +using namespace xmlsignature; +using namespace soap11; +using namespace xmltooling; +using namespace log4cpp; +using namespace std; + +namespace opensaml { + namespace saml2p { + MessageEncoder* SAML_DLLLOCAL SAML2SOAPEncoderFactory(const DOMElement* const & e) + { + return new SAML2SOAPEncoder(e); + } + }; +}; + +SAML2SOAPEncoder::SAML2SOAPEncoder(const DOMElement* e) {} + +long SAML2SOAPEncoder::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"); + HTTPResponse* httpResponse = dynamic_cast(&genericResponse); + if (httpResponse) { + httpResponse->setHeader("Cache-Control", "no-cache, no-store, must-revalidate, private"); + httpResponse->setHeader("Pragma", "no-cache"); + } + + DOMElement* rootElement = NULL; + StatusResponseType* 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 2.0 SOAP Encoder must be a SAML 2.0 response or SOAP Fault/Envelope."); +} -- 2.1.4