Add simple signing support for POST binding.
[shibboleth/cpp-opensaml.git] / saml / binding / impl / SimpleSigningRule.cpp
index 9641ab5..481223d 100644 (file)
@@ -43,6 +43,8 @@ using namespace xmltooling;
 using namespace log4cpp;
 using namespace std;
 
+using xmlsignature::KeyInfo;
+
 namespace opensaml {
     SecurityPolicyRule* SAML_DLLLOCAL SimpleSigningRuleFactory(const DOMElement* const & e)
     {
@@ -123,20 +125,57 @@ pair<saml2::Issuer*,const saml2md::RoleDescriptor*> SimpleSigningRule::evaluate(
             return ret;
         }
 
-        // We have to construct a string containing the signature input by accessing the
-        // request directly. We can't use the decoded parameters because we need the raw
-        // data and URL-encoding isn't canonical.
         string input;
+        const char* pch;
         const HTTPRequest& httpRequest = dynamic_cast<const HTTPRequest&>(request);
-        const char* raw =
-            (!strcmp(httpRequest.getMethod(), "GET")) ? httpRequest.getQueryString() : httpRequest.getRequestBody();
-        if (!appendParameter(input, raw, "SAMLRequest="))
-            appendParameter(input, raw, "SAMLResponse=");
-        appendParameter(input, raw, "RelayState=");
-        appendParameter(input, raw, "SigAlg=");
+        if (!strcmp(httpRequest.getMethod(), "GET")) {
+            // We have to construct a string containing the signature input by accessing the
+            // request directly. We can't use the decoded parameters because we need the raw
+            // data and URL-encoding isn't canonical.
+            pch = httpRequest.getQueryString();
+            if (!appendParameter(input, pch, "SAMLRequest="))
+                appendParameter(input, pch, "SAMLResponse=");
+            appendParameter(input, pch, "RelayState=");
+            appendParameter(input, pch, "SigAlg=");
+        }
+        else {
+            // With POST, the input string is concatenated from the decoded form controls.
+            // GET should be this way too, but I messed up the spec, sorry.
+            pch = httpRequest.getParameter("SAMLRequest");
+            if (pch)
+                input = string("SAMLRequest=") + pch;
+            else {
+                pch = httpRequest.getParameter("SAMLResponse");
+                input = string("SAMLResponse=") + pch;
+            }
+            pch = httpRequest.getParameter("RelayState");
+            if (pch)
+                input = input + "&RelayState=" + pch;
+            input = input + "&SigAlg=" + sigAlgorithm;
+        }
 
+        // Check for KeyInfo, but defensively (we might be able to run without it).
+        KeyInfo* keyInfo=NULL;
+        pch = request.getParameter("KeyInfo");
+        if (pch) {
+            try {
+                istringstream kstrm(pch);
+                DOMDocument* doc = XMLToolingConfig::getConfig().getParser().parse(kstrm);
+                XercesJanitor<DOMDocument> janitor(doc);
+                XMLObject* kxml = XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true);
+                janitor.release();
+                if (!(keyInfo=dynamic_cast<KeyInfo*>(kxml)))
+                    delete kxml;
+            }
+            catch (XMLToolingException& ex) {
+                log.warn("Failed to load KeyInfo from message: %s", ex.what());
+            }
+        }
+        
+        auto_ptr<KeyInfo> kjanitor(keyInfo);
         auto_ptr_XMLCh alg(sigAlgorithm);
-        if (!trustEngine->validate(alg.get(), signature, NULL, input.c_str(), input.length(), *roledesc, metadataProvider->getKeyResolver())) {
+        
+        if (!trustEngine->validate(alg.get(), signature, keyInfo, input.c_str(), input.length(), *roledesc, metadataProvider->getKeyResolver())) {
             log.error("unable to verify signature on message with supplied trust engine");
             return ret;
         }