X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-opensaml.git;a=blobdiff_plain;f=saml%2Fsaml1%2Fbinding%2Fimpl%2FSAML1POSTEncoder.cpp;h=d362a3da71a0abd8665e4bd48fbb64f86725252c;hp=5b0704fde7483ff10c25280eb98e43ef90d6fb87;hb=07dbbcf3a8fc0aba6fefe741f1760442a0a6ea65;hpb=6dc8738c279c46c5951e87d5e8424683e657f513 diff --git a/saml/saml1/binding/impl/SAML1POSTEncoder.cpp b/saml/saml1/binding/impl/SAML1POSTEncoder.cpp index 5b0704f..d362a3d 100644 --- a/saml/saml1/binding/impl/SAML1POSTEncoder.cpp +++ b/saml/saml1/binding/impl/SAML1POSTEncoder.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2006 Internet2 + * Copyright 2001-2007 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,49 +22,95 @@ #include "internal.h" #include "exceptions.h" -#include "saml1/binding/SAML1POSTEncoder.h" +#include "binding/MessageEncoder.h" +#include "signature/ContentReference.h" #include "saml1/core/Protocols.h" -#include +#include +#include #include +#include +#include #include +#include +#include using namespace opensaml::saml1p; +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 saml1p { - MessageEncoder* SAML_DLLLOCAL SAML1POSTEncoderFactory(const DOMElement* const & e) + class SAML_DLLLOCAL SAML1POSTEncoder : public MessageEncoder { - return new SAML1POSTEncoder(e); + public: + SAML1POSTEncoder(const DOMElement* e, const XMLCh* ns); + virtual ~SAML1POSTEncoder() {} + + 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; + + protected: + /** Pathname of HTML template for transmission of message via POST. */ + string m_template; + }; + + MessageEncoder* SAML_DLLLOCAL SAML1POSTEncoderFactory(const pair& p) + { + return new SAML1POSTEncoder(p.first, p.second); } }; }; -SAML1POSTEncoder::SAML1POSTEncoder(const DOMElement* e) {} +static const XMLCh _template[] = UNICODE_LITERAL_8(t,e,m,p,l,a,t,e); -SAML1POSTEncoder::~SAML1POSTEncoder() {} +SAML1POSTEncoder::SAML1POSTEncoder(const DOMElement* e, const XMLCh* ns) +{ + if (e) { + auto_ptr_char t(e->getAttributeNS(ns, _template)); + if (t.get() && *t.get()) + m_template = t.get(); + } + if (m_template.empty()) + throw XMLToolingException("SAML1POSTEncoder requires template XML attribute."); + XMLToolingConfig::getConfig().getPathResolver()->resolve(m_template, PathResolver::XMLTOOLING_CFG_FILE); +} -void SAML1POSTEncoder::encode( - map& outputFields, +long SAML1POSTEncoder::encode( + GenericResponse& genericResponse, XMLObject* xmlObject, - const char* recipientID, + const char* destination, + 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.SAML1POST"); - log.debug("validating input"); + + TemplateEngine* engine = XMLToolingConfig::getConfig().getTemplateEngine(); + if (!engine) + throw BindingException("Encoding response using POST requires a TemplateEngine instance."); - outputFields.clear(); + log.debug("validating input"); if (xmlObject->getParent()) throw BindingException("Cannot encode XML content with parent."); Response* response = dynamic_cast(xmlObject); @@ -74,7 +120,7 @@ void SAML1POSTEncoder::encode( throw BindingException("SAML 1.x POST Encoder requires relay state (TARGET) value."); DOMElement* rootElement = NULL; - if (credResolver) { + if (credential) { // Signature based on native XML signing. if (response->getSignature()) { log.debug("response already signed, skipping signature operation"); @@ -83,38 +129,67 @@ void SAML1POSTEncoder::encode( log.debug("signing and marshalling the response"); // Build a Signature. - Signature* sig = buildSignature(credResolver, sigAlgorithm); + Signature* sig = SignatureBuilder::buildSignature(); 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. vector sigs(1,sig); - rootElement = response->marshall((DOMDocument*)NULL,&sigs); + rootElement = response->marshall((DOMDocument*)NULL,&sigs,credential); } } else { log.debug("marshalling the response"); rootElement = response->marshall(); } - - string xmlbuf; + + // Push message into template. + TemplateEngine::TemplateParameters pmap; + string& xmlbuf = pmap.m_map["SAMLResponse"]; XMLHelper::serialize(rootElement, xmlbuf); - unsigned int len=0; + log.debug("marshalled response:\n%s", xmlbuf.c_str()); + + // Replace with base-64 encoded version. + xsecsize_t len=0; XMLByte* out=Base64::encode(reinterpret_cast(xmlbuf.data()),xmlbuf.size(),&len); if (out) { xmlbuf.erase(); xmlbuf.append(reinterpret_cast(out),len); +#ifdef OPENSAML_XERCESC_HAS_XMLBYTE_RELEASE XMLString::release(&out); +#else + XMLString::release((char**)&out); +#endif } else { throw BindingException("Base64 encoding of XML failed."); } - - // Pass back output fields. - outputFields["SAMLResponse"] = xmlbuf; - outputFields["TARGET"] = relayState; + + // Fill in the rest of the data and send to the client. + log.debug("message encoded, sending HTML form template to client"); + 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())); + pmap.m_map["action"] = destination; + pmap.m_map["TARGET"] = relayState; + stringstream s; + engine->run(infile, s, pmap); + 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; - - log.debug("message encoded"); + return ret; }