X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=saml%2Fsaml2%2Fbinding%2Fimpl%2FSAML2POSTEncoder.cpp;h=0ae74080deff879eb80b4e504300df7f337afb53;hb=54b7006826fd06e8e2bc251aaba38cccc85b3936;hp=3a5fe2592160befb8e62cb1f9cfbb96938962797;hpb=0cd2ac24566bb0881143d8a9a3428292e6ad19a8;p=shibboleth%2Fcpp-opensaml.git diff --git a/saml/saml2/binding/impl/SAML2POSTEncoder.cpp b/saml/saml2/binding/impl/SAML2POSTEncoder.cpp index 3a5fe25..0ae7408 100644 --- a/saml/saml2/binding/impl/SAML2POSTEncoder.cpp +++ b/saml/saml2/binding/impl/SAML2POSTEncoder.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2006 Internet2 + * Copyright 2001-2009 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,77 +17,110 @@ /** * SAML2POSTEncoder.cpp * - * SAML 2.0 HTTP-POST binding message encoder + * SAML 2.0 HTTP-POST binding message encoder. */ #include "internal.h" #include "exceptions.h" -#include "binding/HTTPResponse.h" -#include "saml2/binding/SAML2POSTEncoder.h" +#include "binding/MessageEncoder.h" +#include "signature/ContentReference.h" #include "saml2/core/Protocols.h" #include #include -#include #include +#include +#include +#include +#include +#include +#include +#include #include +#include #include using namespace opensaml::saml2p; +using namespace opensaml::saml2md; using namespace opensaml; using namespace xmlsignature; +using namespace xmltooling::logging; using namespace xmltooling; -using namespace log4cpp; using namespace std; namespace opensaml { namespace saml2p { - MessageEncoder* SAML_DLLLOCAL SAML2POSTEncoderFactory(const DOMElement* const & e) + class SAML_DLLLOCAL SAML2POSTEncoder : public MessageEncoder { - return new SAML2POSTEncoder(e, false); + public: + SAML2POSTEncoder(const DOMElement* e, const XMLCh* ns, bool simple=false); + virtual ~SAML2POSTEncoder() {} + + long encode( + GenericResponse& genericResponse, + XMLObject* xmlObject, + const char* destination, + const EntityDescriptor* recipient=NULL, + const char* relayState=NULL, + const ArtifactGenerator* artifactGenerator=NULL, + const Credential* credential=NULL, + const XMLCh* signatureAlg=NULL, + const XMLCh* digestAlg=NULL + ) const; + + private: + string m_template; + bool m_simple; + }; + + MessageEncoder* SAML_DLLLOCAL SAML2POSTEncoderFactory(const pair& p) + { + return new SAML2POSTEncoder(p.first, p.second, false); } - MessageEncoder* SAML_DLLLOCAL SAML2POSTSimpleSignEncoderFactory(const DOMElement* const & e) + MessageEncoder* SAML_DLLLOCAL SAML2POSTSimpleSignEncoderFactory(const pair& p) { - return new SAML2POSTEncoder(e, true); + return new SAML2POSTEncoder(p.first, p.second, true); } }; }; -static const XMLCh templat[] = UNICODE_LITERAL_8(t,e,m,p,l,a,t,e); +static const XMLCh _template[] = UNICODE_LITERAL_8(t,e,m,p,l,a,t,e); -SAML2POSTEncoder::SAML2POSTEncoder(const DOMElement* e, bool simple) : m_simple(simple) +SAML2POSTEncoder::SAML2POSTEncoder(const DOMElement* e, const XMLCh* ns, bool simple) : m_simple(simple) { if (e) { - auto_ptr_char t(e->getAttributeNS(NULL, templat)); - if (t.get()) + auto_ptr_char t(e->getAttributeNS(ns, _template)); + if (t.get() && *t.get()) m_template = t.get(); } if (m_template.empty()) - throw XMLToolingException("SAML2POSTEncoder requires template attribute."); + throw XMLToolingException("SAML2POSTEncoder requires template XML attribute."); + XMLToolingConfig::getConfig().getPathResolver()->resolve(m_template, PathResolver::XMLTOOLING_CFG_FILE); } -SAML2POSTEncoder::~SAML2POSTEncoder() {} - long SAML2POSTEncoder::encode( GenericResponse& genericResponse, XMLObject* xmlObject, const char* destination, - const char* recipientID, + const EntityDescriptor* recipient, const char* relayState, - const CredentialResolver* credResolver, - const XMLCh* sigAlgorithm + const ArtifactGenerator* artifactGenerator, + const Credential* credential, + const XMLCh* signatureAlg, + const XMLCh* digestAlg ) const { #ifdef _DEBUG xmltooling::NDC ndc("encode"); #endif 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."); + + TemplateEngine* engine = XMLToolingConfig::getConfig().getTemplateEngine(); + if (!engine || !destination) + throw BindingException("Encoding message using POST requires a TemplateEngine instance and a destination."); + HTTPResponse::sanitizeURL(destination); if (xmlObject->getParent()) throw BindingException("Cannot encode XML content with parent."); @@ -100,8 +133,7 @@ long SAML2POSTEncoder::encode( } DOMElement* rootElement = NULL; - vector sigs; - if (credResolver && !m_simple) { + if (credential && !m_simple) { // Signature based on native XML signing. if (request ? request->getSignature() : response->getSignature()) { log.debug("message already signed, skipping signature operation"); @@ -110,68 +142,98 @@ long SAML2POSTEncoder::encode( log.debug("signing and marshalling the message"); // Build a Signature. - Signature* sig = buildSignature(credResolver, sigAlgorithm); - - // Append Signature. + Signature* sig = SignatureBuilder::buildSignature(); request ? request->setSignature(sig) : response->setSignature(sig); - + if (signatureAlg) + sig->setSignatureAlgorithm(signatureAlg); + if (digestAlg) { + opensaml::ContentReference* cr = dynamic_cast(sig->getContentReference()); + if (cr) + cr->setDigestAlgorithm(digestAlg); + } + // Sign response while marshalling. - sigs.push_back(sig); + vector sigs(1,sig); + rootElement = xmlObject->marshall((DOMDocument*)NULL,&sigs,credential); } } else { log.debug("marshalling the message"); + rootElement = xmlObject->marshall((DOMDocument*)NULL); } - rootElement = xmlObject->marshall((DOMDocument*)NULL,&sigs); - - // Start tracking data. - map pmap; - if (relayState) - pmap["RelayState"] = relayState; - - // Base64 the message. - string& msg = pmap[(request ? "SAMLRequest" : "SAMLResponse")]; + // Serialize the message. + TemplateEngine::TemplateParameters pmap; + string& msg = pmap.m_map[(request ? "SAMLRequest" : "SAMLResponse")]; XMLHelper::serialize(rootElement, msg); - unsigned int len=0; - XMLByte* out=Base64::encode(reinterpret_cast(msg.data()),msg.size(),&len); - if (!out) - throw BindingException("Base64 encoding of XML failed."); - msg.erase(); - msg.append(reinterpret_cast(out),len); - XMLString::release(&out); + log.debug("marshalled message:\n%s", msg.c_str()); - if (credResolver && m_simple) { + // SimpleSign. + if (credential && m_simple) { log.debug("applying simple signature to message data"); string input = (request ? "SAMLRequest=" : "SAMLResponse=") + msg; - if (relayState) + if (relayState && *relayState) input = input + "&RelayState=" + relayState; - if (!sigAlgorithm) - sigAlgorithm = DSIGConstants::s_unicodeStrURIRSA_SHA1; - auto_ptr_char alg(sigAlgorithm); - pmap["SigAlg"] = alg.get(); + if (!signatureAlg) + signatureAlg = DSIGConstants::s_unicodeStrURIRSA_SHA1; + auto_ptr_char alg(signatureAlg); + pmap.m_map["SigAlg"] = alg.get(); input = input + "&SigAlg=" + alg.get(); char sigbuf[1024]; memset(sigbuf,0,sizeof(sigbuf)); - auto_ptr key(credResolver->getKey()); - Signature::createRawSignature(key.get(), sigAlgorithm, input.c_str(), input.length(), sigbuf, sizeof(sigbuf)-1); - pmap["Signature"] = sigbuf; + Signature::createRawSignature(credential->getPrivateKey(), signatureAlg, input.c_str(), input.length(), sigbuf, sizeof(sigbuf)-1); + pmap.m_map["Signature"] = sigbuf; + + auto_ptr keyInfo(credential->getKeyInfo()); + if (keyInfo.get()) { + string& kstring = pmap.m_map["KeyInfo"]; + XMLHelper::serialize(keyInfo->marshall((DOMDocument*)NULL), kstring); + xsecsize_t len=0; + XMLByte* out=Base64::encode(reinterpret_cast(kstring.data()),kstring.size(),&len); + if (!out) + throw BindingException("Base64 encoding of XML failed."); + kstring.erase(); + kstring.append(reinterpret_cast(out),len); +#ifdef OPENSAML_XERCESC_HAS_XMLBYTE_RELEASE + XMLString::release(&out); +#else + XMLString::release((char**)&out); +#endif + } } - // Push message into template and send result to client. + // Base64 the message. + xsecsize_t len=0; + XMLByte* out=Base64::encode(reinterpret_cast(msg.data()),msg.size(),&len); + if (!out) + throw BindingException("Base64 encoding of XML failed."); + msg.erase(); + msg.append(reinterpret_cast(out),len); +#ifdef OPENSAML_XERCESC_HAS_XMLBYTE_RELEASE + XMLString::release(&out); +#else + XMLString::release((char**)&out); +#endif + + // Push the rest of it 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())); - pmap["action"] = destination; + pmap.m_map["action"] = destination; + if (relayState && *relayState) + pmap.m_map["RelayState"] = relayState; 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"); + HTTPResponse* httpResponse = dynamic_cast(&genericResponse); + if (httpResponse) { + httpResponse->setResponseHeader("Expires", "01-Jan-1997 12:00:00 GMT"); + httpResponse->setResponseHeader("Cache-Control", "no-cache, no-store, must-revalidate, private"); + httpResponse->setResponseHeader("Pragma", "no-cache"); + } + long ret = genericResponse.sendResponse(s); // Cleanup by destroying XML. delete xmlObject;