X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-opensaml.git;a=blobdiff_plain;f=saml%2Fbinding%2Fimpl%2FArtifactMap.cpp;h=e4bae0e0c685116739b3956a59e8f3ec4c91c683;hp=c22c6ef7eda495ad6973fb86e5c8da541a4afc8f;hb=ec145bf31d59d23bbf63cdc39ffeb172ed29d67d;hpb=980a4a1e781a297075b50bb689c4eb2a4c226e17 diff --git a/saml/binding/impl/ArtifactMap.cpp b/saml/binding/impl/ArtifactMap.cpp index c22c6ef..e4bae0e 100644 --- a/saml/binding/impl/ArtifactMap.cpp +++ b/saml/binding/impl/ArtifactMap.cpp @@ -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. + * + * 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. */ /** @@ -25,15 +29,25 @@ #include "binding/ArtifactMap.h" #include "binding/SAMLArtifact.h" -#include +#include +#include +#include #include +#include #include +#include +#include #include +#include +#include #include +#include using namespace opensaml; +using namespace xmltooling::logging; using namespace xmltooling; -using namespace log4cpp; +using namespace boost::lambda; +using namespace boost; using namespace std; namespace opensaml { @@ -42,18 +56,18 @@ namespace opensaml { { public: ArtifactMappings() : m_lock(Mutex::create()) {} - ~ArtifactMappings() { - delete m_lock; - for (map::iterator i=m_artMap.begin(); i!=m_artMap.end(); ++i) - delete i->second.m_xml; - } + ~ArtifactMappings() {} + void storeContent(XMLObject* content, const SAMLArtifact* artifact, const char* relyingParty, int TTL); XMLObject* retrieveContent(const SAMLArtifact* artifact, const char* relyingParty); string getRelyingParty(const SAMLArtifact* artifact); private: struct SAML_DLLLOCAL Mapping { - Mapping() : m_xml(NULL), m_expires(0) {} + Mapping() : m_xml(nullptr), m_expires(0) {} + ~Mapping() { + delete m_xml; + } XMLObject* m_xml; string m_relying; time_t m_expires; @@ -61,7 +75,7 @@ namespace opensaml { void removeMapping(const map::iterator& i); - Mutex* m_lock; + auto_ptr m_lock; map m_artMap; multimap m_expMap; }; @@ -74,16 +88,19 @@ namespace opensaml { void ArtifactMappings::removeMapping(const map::iterator& i) { - // Update secondary map. + // All elements in the secondary map whose key matches the expiration of the removed mapping. pair::iterator,multimap::iterator> range = m_expMap.equal_range(i->second.m_expires); - for (; range.first != range.second; ++range.first) { - if (range.first->second == i->first) { - m_expMap.erase(range.first); - break; - } + + // Find an element in the matching range whose value matches the input key. + multimap::iterator el = find_if( + range.first, range.second, + (lambda::bind(&multimap::value_type::second, _1) == boost::ref(i->first)) + ); + if (el != range.second) { + m_expMap.erase(el); } - delete i->second.m_xml; + m_artMap.erase(i); } @@ -92,9 +109,9 @@ void ArtifactMappings::storeContent(XMLObject* content, const SAMLArtifact* arti Lock wrapper(m_lock); // Garbage collect any expired artifacts. - time_t now=time(NULL); - multimap::iterator stop=m_expMap.upper_bound(now); - for (multimap::iterator i=m_expMap.begin(); i!=stop; m_expMap.erase(i++)) { + time_t now = time(nullptr); + multimap::iterator stop = m_expMap.upper_bound(now); + for (multimap::iterator i = m_expMap.begin(); i != stop; m_expMap.erase(i++)) { delete m_artMap[i->second].m_xml; m_artMap.erase(i->second); } @@ -106,16 +123,16 @@ void ArtifactMappings::storeContent(XMLObject* content, const SAMLArtifact* arti if (relyingParty) m.m_relying = relyingParty; m.m_expires = now + TTL; - m_expMap.insert(pair(m.m_expires,hexed)); + m_expMap.insert(pair(m.m_expires, hexed)); } XMLObject* ArtifactMappings::retrieveContent(const SAMLArtifact* artifact, const char* relyingParty) { - Category& log=Category::getInstance(SAML_LOGCAT".ArtifactMap"); + Category& log=Category::getInstance(SAML_LOGCAT ".ArtifactMap"); Lock wrapper(m_lock); - map::iterator i=m_artMap.find(SAMLArtifact::toHex(artifact->getMessageHandle())); - if (i==m_artMap.end()) + map::iterator i = m_artMap.find(SAMLArtifact::toHex(artifact->getMessageHandle())); + if (i == m_artMap.end()) throw BindingException("Requested artifact not in map or may have expired."); if (!(i->second.m_relying.empty())) { @@ -129,58 +146,67 @@ 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; } string ArtifactMappings::getRelyingParty(const SAMLArtifact* artifact) { - map::iterator i=m_artMap.find(SAMLArtifact::toHex(artifact->getMessageHandle())); - if (i==m_artMap.end()) + map::iterator i = m_artMap.find(SAMLArtifact::toHex(artifact->getMessageHandle())); + if (i == m_artMap.end()) throw BindingException("Requested artifact not in map or may have expired."); return i->second.m_relying; } 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_artifactTTL(artifactTTL) { if (!m_storage) - m_mappings = new ArtifactMappings(); + m_mappings.reset(new ArtifactMappings()); } ArtifactMap::ArtifactMap(const DOMElement* e, xmltooling::StorageService* storage) - : m_storage(storage), m_mappings(NULL), m_artifactTTL(180) + : m_storage(storage), 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); + try { + m_artifactTTL = XMLString::parseInt(TTL); + } + catch (XMLException&) { + m_artifactTTL = 0; + } if (!m_artifactTTL) m_artifactTTL = 180; } } if (!m_storage) - m_mappings = new ArtifactMappings(); + m_mappings.reset(new ArtifactMappings()); } ArtifactMap::~ArtifactMap() { - delete m_mappings; } void ArtifactMap::storeContent(XMLObject* content, const SAMLArtifact* artifact, const char* relyingParty) @@ -196,17 +222,30 @@ 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); - m_storage->createText( - m_context.c_str(), SAMLArtifact::toHex(artifact->getMessageHandle()).c_str(), xmlbuf.c_str(), time(NULL) + m_artifactTTL - ); + + // 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(), + key.c_str(), + xmlbuf.c_str(), + time(nullptr) + m_artifactTTL + )) { + throw IOException("Attempt to insert duplicate artifact into map."); + } // Cleanup by destroying XML. delete content; @@ -217,14 +256,20 @@ XMLObject* ArtifactMap::retrieveContent(const SAMLArtifact* artifact, const char #ifdef _DEBUG xmltooling::NDC ndc("retrieveContent"); #endif - Category& log=Category::getInstance(SAML_LOGCAT".ArtifactMap"); + Category& log=Category::getInstance(SAML_LOGCAT ".ArtifactMap"); 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()); @@ -236,8 +281,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."); @@ -257,9 +302,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. @@ -269,8 +321,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();