Handle overflow in storage keys.
[shibboleth/cpp-opensaml.git] / saml / binding / impl / ArtifactMap.cpp
index 2028ac0..8403084 100644 (file)
@@ -1,17 +1,21 @@
-/*
- *  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.
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ * 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
  *
- * 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.
+ * 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.
  */
 
 /**
 #include "binding/ArtifactMap.h"
 #include "binding/SAMLArtifact.h"
 
-#include <log4cpp/Category.hh>
+#include <ctime>
 #include <xercesc/util/XMLUniDefs.hpp>
+#include <xmltooling/logging.h>
 #include <xmltooling/XMLObjectBuilder.h>
+#include <xmltooling/XMLToolingConfig.h>
+#include <xmltooling/security/SecurityHelper.h>
 #include <xmltooling/util/NDC.h>
+#include <xmltooling/util/ParserPool.h>
+#include <xmltooling/util/StorageService.h>
 #include <xmltooling/util/XMLHelper.h>
+#include <xmltooling/util/Threads.h>
 
 using namespace opensaml;
+using namespace xmltooling::logging;
 using namespace xmltooling;
-using namespace log4cpp;
 using namespace std;
 
 namespace opensaml {
@@ -53,7 +63,7 @@ namespace opensaml {
     
     private:
         struct SAML_DLLLOCAL Mapping {
-            Mapping() : m_xml(NULL), m_expires(0) {}
+            Mapping() : m_xml(nullptr), m_expires(0) {}
             XMLObject* m_xml;
             string m_relying;
             time_t m_expires;
@@ -92,7 +102,7 @@ void ArtifactMappings::storeContent(XMLObject* content, const SAMLArtifact* arti
     Lock wrapper(m_lock);
 
     // Garbage collect any expired artifacts.
-    time_t now=time(NULL);
+    time_t now=time(nullptr);
     multimap<time_t,string>::iterator stop=m_expMap.upper_bound(now);
     for (multimap<time_t,string>::iterator i=m_expMap.begin(); i!=stop; m_expMap.erase(i++)) {
         delete m_artMap[i->second].m_xml;
@@ -129,14 +139,14 @@ XMLObject* ArtifactMappings::retrieveContent(const SAMLArtifact* artifact, const
         }
     }
     
-    if (time(NULL) >= i->second.m_expires) {
+    if (time(nullptr) >= i->second.m_expires) {
         removeMapping(i);
         throw BindingException("Requested artifact has expired.");
     }
     
     log.debug("resolved artifact for (%s)", relyingParty ? relyingParty : "unknown");
     XMLObject* ret = i->second.m_xml;
-    i->second.m_xml = NULL; // clear member so it doesn't get deleted
+    i->second.m_xml = nullptr; // clear member so it doesn't get deleted
     removeMapping(i);
     return ret;
 }
@@ -150,23 +160,28 @@ string ArtifactMappings::getRelyingParty(const SAMLArtifact* artifact)
 }
 
 ArtifactMap::ArtifactMap(xmltooling::StorageService* storage, const char* context, unsigned int artifactTTL)
-    : m_storage(storage), m_context((context && *context) ? context : "opensaml::ArtifactMap"), m_mappings(NULL), m_artifactTTL(artifactTTL)
+    : m_storage(storage), m_context((context && *context) ? context : "opensaml::ArtifactMap"), m_mappings(nullptr), m_artifactTTL(artifactTTL)
 {
     if (!m_storage)
         m_mappings = new ArtifactMappings();
 }
 
 ArtifactMap::ArtifactMap(const DOMElement* e, xmltooling::StorageService* storage)
-    : m_storage(storage), m_mappings(NULL), m_artifactTTL(180)
+    : m_storage(storage), m_mappings(nullptr), m_artifactTTL(180)
 {
     if (e) {
-        auto_ptr_char c(e->getAttributeNS(NULL, context));
-        if (c.get() && *c.get())
+        auto_ptr_char c(e->getAttributeNS(nullptr, context));
+        if (c.get() && *c.get()) {
             m_context = c.get();
-        else
+            if (storage && m_context.length() > m_storage->getCapabilities().getContextSize()) {
+                throw IOException("ArtifactMap context length exceeds capacity of storage service.");
+            }
+        }
+        else {
             m_context = "opensaml::ArtifactMap";
-        
-        const XMLCh* TTL = e->getAttributeNS(NULL, artifactTTL);
+        }
+
+        const XMLCh* TTL = e->getAttributeNS(nullptr, artifactTTL);
         if (TTL) {
             m_artifactTTL = XMLString::parseInt(TTL);
             if (!m_artifactTTL)
@@ -196,19 +211,27 @@ void ArtifactMap::storeContent(XMLObject* content, const SAMLArtifact* artifact,
     // Build a DOM with the same document to store the relyingParty mapping.
     if (relyingParty) {
         auto_ptr_XMLCh temp(relyingParty);
-        root = root->getOwnerDocument()->createElementNS(NULL,Mapping);
-        root->setAttributeNS(NULL,_relyingParty,temp.get());
+        root = root->getOwnerDocument()->createElementNS(nullptr,Mapping);
+        root->setAttributeNS(nullptr,_relyingParty,temp.get());
         root->appendChild(content->getDOM());
     }
     
     // Serialize the root element, whatever it is, for storage.
     string xmlbuf;
     XMLHelper::serialize(root, xmlbuf);
+
+    // Use hex form of message handler as storage key unless it's too big.
+    string key = artifact->getMessageHandle();
+    if (key.length() > m_storage->getCapabilities().getKeySize())
+        key = SecurityHelper::doHash("SHA1", key.data(), key.length());
+    else
+        key = SAMLArtifact::toHex(key);
+
     if (!m_storage->createText(
         m_context.c_str(),
-        SAMLArtifact::toHex(artifact->getMessageHandle()).c_str(),
+        key.c_str(),
         xmlbuf.c_str(),
-        time(NULL) + m_artifactTTL
+        time(nullptr) + m_artifactTTL
         )) {
         throw IOException("Attempt to insert duplicate artifact into map.");
     }
@@ -226,10 +249,16 @@ XMLObject* ArtifactMap::retrieveContent(const SAMLArtifact* artifact, const char
 
     if (!m_storage)
         return m_mappings->retrieveContent(artifact, relyingParty);
-    
+
+    // Use hex form of message handler as storage key unless it's too big.
+    string key = artifact->getMessageHandle();
+    if (key.length() > m_storage->getCapabilities().getKeySize())
+        key = SecurityHelper::doHash("SHA1", key.data(), key.length());
+    else
+        key = SAMLArtifact::toHex(key);
+
     // Read the mapping and then delete it.
     string xmlbuf;
-    string key = SAMLArtifact::toHex(artifact->getMessageHandle());
     if (!m_storage->readText(m_context.c_str(), key.c_str(), &xmlbuf))
         throw BindingException("Artifact not found in mapping database.");
     m_storage->deleteText(m_context.c_str(), key.c_str());
@@ -241,8 +270,8 @@ XMLObject* ArtifactMap::retrieveContent(const SAMLArtifact* artifact, const char
     
     // Check the root element.
     DOMElement* messageRoot = doc->getDocumentElement();
-    if (XMLHelper::isNodeNamed(messageRoot, NULL, Mapping)) {
-        auto_ptr_char temp(messageRoot->getAttributeNS(NULL,_relyingParty));
+    if (XMLHelper::isNodeNamed(messageRoot, nullptr, Mapping)) {
+        auto_ptr_char temp(messageRoot->getAttributeNS(nullptr,_relyingParty));
         if (!relyingParty || strcmp(temp.get(),relyingParty)) {
             log.warn("request from (%s) for artifact issued to (%s)", relyingParty ? relyingParty : "unknown", temp.get());
             throw BindingException("Unauthorized artifact mapping request.");
@@ -262,9 +291,16 @@ string ArtifactMap::getRelyingParty(const SAMLArtifact* artifact)
 {
     if (!m_storage)
         return m_mappings->getRelyingParty(artifact);
-    
+
+    // Use hex form of message handler as storage key unless it's too big.
+    string key = artifact->getMessageHandle();
+    if (key.length() > m_storage->getCapabilities().getKeySize())
+        key = SecurityHelper::doHash("SHA1", key.data(), key.length());
+    else
+        key = SAMLArtifact::toHex(key);
+
     string xmlbuf;
-    if (!m_storage->readText(m_context.c_str(), SAMLArtifact::toHex(artifact->getMessageHandle()).c_str(), &xmlbuf))
+    if (!m_storage->readText(m_context.c_str(), key.c_str(), &xmlbuf))
         throw BindingException("Artifact not found in mapping database.");
     
     // Parse the data back into XML.
@@ -274,8 +310,8 @@ string ArtifactMap::getRelyingParty(const SAMLArtifact* artifact)
     
     // Check the root element.
     DOMElement* messageRoot = doc->getDocumentElement();
-    if (XMLHelper::isNodeNamed(messageRoot, NULL, Mapping)) {
-        auto_ptr_char temp(messageRoot->getAttributeNS(NULL,_relyingParty));
+    if (XMLHelper::isNodeNamed(messageRoot, nullptr, Mapping)) {
+        auto_ptr_char temp(messageRoot->getAttributeNS(nullptr,_relyingParty));
         return temp.get();
     }
     return string();