SSPCPP-616 - clean up concatenated string literals
[shibboleth/cpp-opensaml.git] / saml / saml1 / binding / impl / SAML1SOAPEncoder.cpp
index c8e9e56..c5f41f5 100644 (file)
@@ -1,23 +1,27 @@
-/*
- *  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.
- * You may obtain a copy of the License at
+/**
+ * Licensed to the University Corporation for Advanced Internet
+ * Development, Inc. (UCAID) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * UCAID licenses this file to you 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
+ * 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.
+ * 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
+ * SAML 1.x SOAP binding message encoder.
  */
 
 #include "internal.h"
 #include "saml1/core/Protocols.h"
 
 #include <sstream>
-#include <log4cpp/Category.hh>
+#include <xmltooling/logging.h>
 #include <xmltooling/io/HTTPResponse.h>
+#include <xmltooling/signature/Signature.h>
 #include <xmltooling/util/NDC.h>
 #include <xmltooling/soap/SOAP.h>
 
 using namespace opensaml::saml1p;
+using namespace opensaml::saml2md;
 using namespace opensaml;
 using namespace xmlsignature;
 using namespace soap11;
+using namespace xmltooling::logging;
 using namespace xmltooling;
-using namespace log4cpp;
 using namespace std;
 
 namespace opensaml {
@@ -45,24 +51,33 @@ namespace opensaml {
         class SAML_DLLLOCAL SAML1SOAPEncoder : public MessageEncoder
         {
         public:
-            SAML1SOAPEncoder(const DOMElement* e) {}
+            SAML1SOAPEncoder() {}
             virtual ~SAML1SOAPEncoder() {}
-            
+
+            bool isUserAgentPresent() const {
+                return false;
+            }
+
+            const XMLCh* getProtocolFamily() const {
+                return samlconstants::SAML11_PROTOCOL_ENUM;
+            }
+
             long encode(
                 GenericResponse& genericResponse,
                 XMLObject* xmlObject,
                 const char* destination,
-                const char* recipientID=NULL,
-                const char* relayState=NULL,
-                const Credential* credential=NULL,
-                const XMLCh* signatureAlg=NULL,
-                const XMLCh* digestAlg=NULL
+                const EntityDescriptor* recipient=nullptr,
+                const char* relayState=nullptr,
+                const ArtifactGenerator* artifactGenerator=nullptr,
+                const Credential* credential=nullptr,
+                const XMLCh* signatureAlg=nullptr,
+                const XMLCh* digestAlg=nullptr
                 ) const;
         };
 
-        MessageEncoder* SAML_DLLLOCAL SAML1SOAPEncoderFactory(const DOMElement* const & e)
+        MessageEncoder* SAML_DLLLOCAL SAML1SOAPEncoderFactory(const pair<const DOMElement*,const XMLCh*>& p)
         {
-            return new SAML1SOAPEncoder(e);
+            return new SAML1SOAPEncoder();
         }
     };
 };
@@ -71,8 +86,9 @@ long SAML1SOAPEncoder::encode(
     GenericResponse& genericResponse,
     XMLObject* xmlObject,
     const char* destination,
-    const char* recipientID,
+    const EntityDescriptor* recipient,
     const char* relayState,
+    const ArtifactGenerator* artifactGenerator,
     const Credential* credential,
     const XMLCh* signatureAlg,
     const XMLCh* digestAlg
@@ -81,7 +97,7 @@ long SAML1SOAPEncoder::encode(
 #ifdef _DEBUG
     xmltooling::NDC ndc("encode");
 #endif
-    Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML1SOAP");
+    Category& log = Category::getInstance(SAML_LOGCAT ".MessageEncoder.SAML1SOAP");
 
     log.debug("validating input");
     if (xmlObject->getParent())
@@ -90,25 +106,42 @@ long SAML1SOAPEncoder::encode(
     genericResponse.setContentType("text/xml");
     HTTPResponse* httpResponse = dynamic_cast<HTTPResponse*>(&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");
     }
 
-    DOMElement* rootElement = NULL;
+    bool detachOnFailure = false;
+    DOMElement* rootElement = nullptr;
+    
+    // Check for a naked Response.
     Response* response = dynamic_cast<Response*>(xmlObject);
     if (response) {
+        // Wrap it in a SOAP envelope and point xmlObject at that.
+        detachOnFailure = true;
+        Envelope* env = EnvelopeBuilder::buildEnvelope();
+        Body* body = BodyBuilder::buildBody();
+        env->setBody(body);
+        body->getUnknownXMLObjects().push_back(response);
+        xmlObject = env;
+    }
+
+    // Now check for a full Envelope (which might have just been created).
+    Envelope* env = dynamic_cast<Envelope*>(xmlObject);
+    if (env) {
+        if (!response) {
+            response = (env->getBody() && env->getBody()->hasChildren()) ?
+                dynamic_cast<Response*>(env->getBody()->getUnknownXMLObjects().front()) : nullptr;
+        }
         try {
-            Envelope* env = EnvelopeBuilder::buildEnvelope();
-            Body* body = BodyBuilder::buildBody();
-            env->setBody(body);
-            body->getUnknownXMLObjects().push_back(response);
-            if (credential) {
+            // Now check for signing requirements.
+            if (response && credential) {
                 if (response->getSignature()) {
                     log.debug("response already signed, skipping signature operation");
                     rootElement = env->marshall();
                 }
                 else {
-                    log.debug("signing and marshalling the response");
+                    log.debug("signing the response and marshalling the envelope");
         
                     // Build a Signature.
                     Signature* sig = SignatureBuilder::buildSignature();
@@ -121,31 +154,39 @@ long SAML1SOAPEncoder::encode(
                             cr->setDigestAlgorithm(digestAlg);
                     }
             
-                    // Sign response while marshalling.
+                    // Sign message while marshalling.
                     vector<Signature*> sigs(1,sig);
-                    rootElement = env->marshall((DOMDocument*)NULL,&sigs,credential);
+                    rootElement = env->marshall((DOMDocument*)nullptr,&sigs,credential);
                 }
             }
             else {
-                log.debug("marshalling the response");
+                log.debug("marshalling the envelope");
                 rootElement = env->marshall();
             }
-            
+
             stringstream s;
             s << *rootElement;
-            log.debug("sending serialized response");
-            long ret = genericResponse.sendResponse(s);
+            
+            if (log.isDebugEnabled())
+                log.debug("marshalled envelope:\n%s", s.str().c_str());
+            
+            log.debug("sending serialized envelope");
+            bool error = (!response && env->getBody() && env->getBody()->hasChildren() &&
+                dynamic_cast<Fault*>(env->getBody()->getUnknownXMLObjects().front()));
+            long ret = error ? genericResponse.sendError(s) : 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();
+            if (response && detachOnFailure) {
+                // 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;
         }
@@ -154,17 +195,20 @@ long SAML1SOAPEncoder::encode(
     Fault* fault = dynamic_cast<Fault*>(xmlObject);
     if (fault) {
         try {
-            log.debug("building Envelope and marshalling Fault");
+            log.debug("building envelope and marshalling fault");
             Envelope* env = EnvelopeBuilder::buildEnvelope();
             Body* body = BodyBuilder::buildBody();
             env->setBody(body);
             body->getUnknownXMLObjects().push_back(fault);
             rootElement = env->marshall();
-    
-            string xmlbuf;
-            XMLHelper::serialize(rootElement, xmlbuf);
-            istringstream s(xmlbuf);
-            log.debug("sending serialized fault");
+
+            stringstream s;
+            s << *rootElement;
+            
+            if (log.isDebugEnabled())
+                log.debug("marshalled envelope:\n%s", s.str().c_str());
+            
+            log.debug("sending serialized envelope");
             long ret = genericResponse.sendError(s);
         
             // Cleanup by destroying XML.
@@ -181,27 +225,6 @@ long SAML1SOAPEncoder::encode(
             throw;
         }
     }
-
-    Envelope* env = dynamic_cast<Envelope*>(xmlObject);
-    if (env) {
-        log.debug("marshalling envelope");
-        rootElement = env->marshall();
-
-        bool error =
-            (env->getBody() &&
-                env->getBody()->hasChildren() &&
-                    dynamic_cast<Fault*>(env->getBody()->getUnknownXMLObjects().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 <Response> or SOAP Fault/Envelope.");
 }