ECP message decoder.
authorScott Cantor <cantor.2@osu.edu>
Tue, 6 Nov 2007 23:39:22 +0000 (23:39 +0000)
committerScott Cantor <cantor.2@osu.edu>
Tue, 6 Nov 2007 23:39:22 +0000 (23:39 +0000)
saml/Makefile.am
saml/binding/impl/MessageDecoder.cpp
saml/saml.vcproj
saml/saml2/binding/impl/SAML2ECPDecoder.cpp [new file with mode: 0644]

index 9c6cab4..b8171ff 100644 (file)
@@ -149,6 +149,8 @@ libsaml_la_SOURCES = \
        saml2/binding/impl/SAML2ArtifactType0004.cpp \
        saml2/binding/impl/SAML2ArtifactDecoder.cpp \
        saml2/binding/impl/SAML2ArtifactEncoder.cpp \
+    saml2/binding/impl/SAML2ECPDecoder.cpp \
+    saml2/binding/impl/SAML2ECPEncoder.cpp \
     saml2/binding/impl/SAML2MessageDecoder.cpp \
        saml2/binding/impl/SAML2POSTDecoder.cpp \
        saml2/binding/impl/SAML2POSTEncoder.cpp \
@@ -157,7 +159,6 @@ libsaml_la_SOURCES = \
        saml2/binding/impl/SAML2RedirectEncoder.cpp \
        saml2/binding/impl/SAML2SOAPDecoder.cpp \
        saml2/binding/impl/SAML2SOAPEncoder.cpp \
-       saml2/binding/impl/SAML2ECPEncoder.cpp \
        saml2/binding/impl/SAML2SOAPClient.cpp \
        saml2/profile/Assertion20Validator.cpp \
        saml2/profile/BrowserSSOProfile20Validator.cpp \
index 3017680..070d90d 100644 (file)
@@ -40,6 +40,7 @@ namespace opensaml {
         SAML_DLLLOCAL PluginManager< MessageDecoder,string,pair<const DOMElement*,const XMLCh*> >::Factory SAML2POSTDecoderFactory;
         SAML_DLLLOCAL PluginManager< MessageDecoder,string,pair<const DOMElement*,const XMLCh*> >::Factory SAML2RedirectDecoderFactory;
         SAML_DLLLOCAL PluginManager< MessageDecoder,string,pair<const DOMElement*,const XMLCh*> >::Factory SAML2SOAPDecoderFactory;
+        SAML_DLLLOCAL PluginManager< MessageDecoder,string,pair<const DOMElement*,const XMLCh*> >::Factory SAML2ECPDecoderFactory;
     };
 };
 
@@ -54,4 +55,5 @@ void SAML_API opensaml::registerMessageDecoders()
     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);
+    conf.MessageDecoderManager.registerFactory(samlconstants::SAML20_BINDING_PAOS, saml2p::SAML2ECPDecoderFactory);
 }
index 401ea47..efb495c 100644 (file)
                                                        </FileConfiguration>\r
                                                </File>\r
                                                <File\r
+                                                       RelativePath=".\saml2\binding\impl\SAML2ECPDecoder.cpp"\r
+                                                       >\r
+                                               </File>\r
+                                               <File\r
                                                        RelativePath=".\saml2\binding\impl\SAML2ECPEncoder.cpp"\r
                                                        >\r
                                                </File>\r
diff --git a/saml/saml2/binding/impl/SAML2ECPDecoder.cpp b/saml/saml2/binding/impl/SAML2ECPDecoder.cpp
new file mode 100644 (file)
index 0000000..9d4e2fd
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ *  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
+ *
+ *     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.
+ */
+
+/**
+ * SAML2ECPDecoder.cpp
+ * 
+ * SAML 2.0 ECP profile message decoder
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "saml2/binding/SAML2MessageDecoder.h"
+#include "saml2/core/Protocols.h"
+
+#include <xmltooling/logging.h>
+#include <xmltooling/soap/SOAP.h>
+#include <xmltooling/util/NDC.h>
+#include <xmltooling/validation/ValidatorSuite.h>
+
+using namespace opensaml::saml2p;
+using namespace opensaml;
+using namespace soap11;
+using namespace xmltooling::logging;
+using namespace xmltooling;
+using namespace std;
+
+namespace opensaml {
+    namespace saml2p {              
+        class SAML_DLLLOCAL SAML2ECPDecoder : public SAML2MessageDecoder
+        {
+        public:
+            SAML2ECPDecoder() {}
+            virtual ~SAML2ECPDecoder() {}
+
+            xmltooling::XMLObject* decode(
+                std::string& relayState,
+                const GenericRequest& genericRequest,
+                SecurityPolicy& policy
+                ) const;
+        };                
+
+        MessageDecoder* SAML_DLLLOCAL SAML2ECPDecoderFactory(const pair<const DOMElement*,const XMLCh*>& p)
+        {
+            return new SAML2ECPDecoder();
+        }
+    };
+};
+
+XMLObject* SAML2ECPDecoder::decode(
+    string& relayState,
+    const GenericRequest& genericRequest,
+    SecurityPolicy& policy
+    ) const
+{
+#ifdef _DEBUG
+    xmltooling::NDC ndc("decode");
+#endif
+    Category& log = Category::getInstance(SAML_LOGCAT".MessageDecoder.SAML2ECP");
+
+    log.debug("validating input");
+    string s = genericRequest.getContentType();
+    if (s.find("application/vnd.paos+xml") == string::npos) {
+        log.warn("ignoring incorrect content type (%s)", s.c_str() ? s.c_str() : "none");
+        throw BindingException("Invalid content type for PAOS message.");
+    }
+
+    const char* data = genericRequest.getRequestBody();
+    if (!data)
+        throw BindingException("PAOS message had an empty request body.");
+    istringstream is(data);
+    
+    // Parse and bind the document into an XMLObject.
+    DOMDocument* doc = (policy.getValidating() ? XMLToolingConfig::getConfig().getValidatingParser()
+        : XMLToolingConfig::getConfig().getParser()).parse(is); 
+    XercesJanitor<DOMDocument> janitor(doc);
+    auto_ptr<XMLObject> xmlObject(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true));
+    janitor.release();
+
+    Envelope* env = dynamic_cast<Envelope*>(xmlObject.get());
+    if (!env)
+        throw BindingException("Decoded message was not a SOAP 1.1 Envelope.");
+
+    if (!policy.getValidating())
+        SchemaValidators.validate(env);
+    
+    Body* body = env->getBody();
+    if (body && body->hasChildren()) {
+        Response* response = dynamic_cast<Response*>(body->getUnknownXMLObjects().front());
+        if (response) {
+            // Run through the policy at two layers.
+            extractMessageDetails(*env, genericRequest, samlconstants::SAML20P_NS, policy);
+            policy.evaluate(*env, &genericRequest);
+            policy.reset(true);
+            extractMessageDetails(*response, genericRequest, samlconstants::SAML20P_NS, policy);
+            policy.evaluate(*response, &genericRequest);
+            
+            // Check for RelayState header.
+            if (env->getHeader()) {
+                const vector<XMLObject*>& blocks = const_cast<const Header*>(env->getHeader())->getUnknownXMLObjects();
+                for (vector<XMLObject*>::const_iterator h = blocks.begin(); h != blocks.end(); ++h) {
+                    static const XMLCh RelayState[] = UNICODE_LITERAL_10(R,e,l,a,y,S,t,a,t,e);
+                    if (XMLString::equals((*h)->getElementQName().getLocalPart(), RelayState) &&
+                            XMLString::equals((*h)->getElementQName().getNamespaceURI(), samlconstants::SAML20ECP_NS)) {
+                        const ElementProxy* ep = dynamic_cast<const ElementProxy*>(*h);
+                        if (ep) {
+                            auto_ptr_char rs(ep->getTextContent());
+                            if (rs.get()) {
+                                relayState = rs.get();
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+            
+            xmlObject.release();
+            body->detach(); // frees Envelope
+            response->detach();   // frees Body
+            return response;
+        }
+    }
+    
+    throw BindingException("SOAP Envelope did not contain a SAML Response.");
+}