-/*
- * 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.
*/
/**
#include "binding/ArtifactMap.h"
#include "binding/SAMLArtifact.h"
+#include <ctime>
+#include <boost/lambda/bind.hpp>
+#include <boost/lambda/lambda.hpp>
#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 boost::lambda;
+using namespace boost;
using namespace std;
namespace opensaml {
{
public:
ArtifactMappings() : m_lock(Mutex::create()) {}
- ~ArtifactMappings() {
- delete m_lock;
- for (map<string,Mapping>::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) {}
- XMLObject* m_xml;
+ Mapping() : m_expires(0) {}
+ auto_ptr<XMLObject> m_xml;
string m_relying;
time_t m_expires;
};
void removeMapping(const map<string,Mapping>::iterator& i);
- Mutex* m_lock;
+ auto_ptr<Mutex> m_lock;
map<string,Mapping> m_artMap;
multimap<time_t,string> m_expMap;
};
void ArtifactMappings::removeMapping(const map<string,Mapping>::iterator& i)
{
- // Update secondary map.
+ // All elements in the secondary map whose key matches the expiration of the removed mapping.
pair<multimap<time_t,string>::iterator,multimap<time_t,string>::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<time_t,string>::iterator el = find_if(
+ range.first, range.second,
+ (lambda::bind(&multimap<time_t,string>::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);
}
void ArtifactMappings::storeContent(XMLObject* content, const SAMLArtifact* artifact, const char* relyingParty, int TTL)
{
- Lock wrapper(m_lock);
+ Lock wrapper(m_lock.get());
// Garbage collect any expired artifacts.
- time_t now=time(NULL);
- 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;
+ 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++)) {
m_artMap.erase(i->second);
}
// Key is the hexed handle.
string hexed = SAMLArtifact::toHex(artifact->getMessageHandle());
Mapping& m = m_artMap[hexed];
- m.m_xml = content;
+ m.m_xml.reset(content);
if (relyingParty)
m.m_relying = relyingParty;
m.m_expires = now + TTL;
XMLObject* ArtifactMappings::retrieveContent(const SAMLArtifact* artifact, const char* relyingParty)
{
Category& log=Category::getInstance(SAML_LOGCAT".ArtifactMap");
- Lock wrapper(m_lock);
+ Lock wrapper(m_lock.get());
- map<string,Mapping>::iterator i=m_artMap.find(SAMLArtifact::toHex(artifact->getMessageHandle()));
- if (i==m_artMap.end())
+ map<string,Mapping>::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())) {
}
}
- 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
+ XMLObject* ret = i->second.m_xml.release();
removeMapping(i);
return ret;
}
string ArtifactMappings::getRelyingParty(const SAMLArtifact* artifact)
{
- map<string,Mapping>::iterator i=m_artMap.find(SAMLArtifact::toHex(artifact->getMessageHandle()));
- if (i==m_artMap.end())
+ map<string,Mapping>::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);
if (!m_artifactTTL)
}
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)
// 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.");
}
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());
// 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.");
{
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.
// 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();