X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-sp.git;a=blobdiff_plain;f=shibsp%2Fattribute%2Fresolver%2Fimpl%2FXMLAttributeExtractor.cpp;h=beb726c5877e4ac20eeb0288ebcb8587683bfff5;hp=a8e599842ebb06e87fc68506019d0b046bf04426;hb=f0cab28136e0758f7bf7c60581d714f5f5dbbf08;hpb=9ccdbac09f806eb2fcd298c07110932d9b8c9004 diff --git a/shibsp/attribute/resolver/impl/XMLAttributeExtractor.cpp b/shibsp/attribute/resolver/impl/XMLAttributeExtractor.cpp index a8e5998..beb726c 100644 --- a/shibsp/attribute/resolver/impl/XMLAttributeExtractor.cpp +++ b/shibsp/attribute/resolver/impl/XMLAttributeExtractor.cpp @@ -1,17 +1,21 @@ -/* - * Copyright 2001-2009 Internet2 +/** + * 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. * - * 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 + * 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. */ /** @@ -33,6 +37,12 @@ #include "security/SecurityPolicy.h" #include "util/SPConstants.h" +#include +#include +#include +#include +#include +#include #include #include #include @@ -43,6 +53,7 @@ #include #include #include +#include #include #include @@ -50,6 +61,7 @@ using namespace shibsp; using namespace opensaml::saml2md; using namespace opensaml; using namespace xmltooling; +using namespace boost; using namespace std; using saml1::NameIdentifier; using saml2::NameID; @@ -72,12 +84,6 @@ namespace shibsp { for (decoded_t::iterator attrs = i->second.begin(); attrs!=i->second.end(); ++attrs) for_each(attrs->second.begin(), attrs->second.end(), mem_fun_ref(&DDF::destroy)); } - delete m_attrLock; - delete m_trust; - delete m_metadata; - delete m_filter; - for (attrmap_t::iterator j = m_attrMap.begin(); j!=m_attrMap.end(); ++j) - delete j->second.first; if (m_document) m_document->release(); } @@ -89,74 +95,46 @@ namespace shibsp { void onEvent(const ObservableMetadataProvider& metadata) const { // Destroy attributes we cached from this provider. m_attrLock->wrlock(); + SharedLock wrapper(m_attrLock, false); decoded_t& d = m_decodedMap[&metadata]; for (decoded_t::iterator a = d.begin(); a!=d.end(); ++a) for_each(a->second.begin(), a->second.end(), mem_fun_ref(&DDF::destroy)); d.clear(); - m_attrLock->unlock(); } + void extractAttributes(const Application&, const char*, const char*, const NameIdentifier&, ptr_vector&) const; + void extractAttributes(const Application&, const char*, const char*, const NameID&, ptr_vector&) const; + void extractAttributes(const Application&, const GenericRequest*, const char*, const char*, const saml1::Attribute&, ptr_vector&) const; + void extractAttributes(const Application&, const GenericRequest*, const char*, const char*, const saml2::Attribute&, ptr_vector&) const; + void extractAttributes(const Application&, const GenericRequest*, const char*, const char*, const saml1::AttributeStatement&, ptr_vector&) const; + void extractAttributes(const Application&, const GenericRequest*, const char*, const char*, const saml2::AttributeStatement&, ptr_vector&) const; void extractAttributes( - const Application& application, - const char* assertingParty, - const char* relyingParty, - const NameIdentifier& nameid, - vector& attributes - ) const; - void extractAttributes( - const Application& application, - const char* assertingParty, - const char* relyingParty, - const NameID& nameid, - vector& attributes - ) const; - void extractAttributes( - const Application& application, - const char* assertingParty, - const char* relyingParty, - const saml1::Attribute& attr, - vector& attributes - ) const; - void extractAttributes( - const Application& application, - const char* assertingParty, - const char* relyingParty, - const saml2::Attribute& attr, - vector& attributes - ) const; - void extractAttributes( - const Application& application, - const ObservableMetadataProvider* observable, - const XMLCh* entityID, - const char* relyingParty, - const Extensions& ext, - vector& attributes + const Application&, const GenericRequest*, const ObservableMetadataProvider*, const XMLCh*, const char*, const Extensions&, ptr_vector& ) const; void getAttributeIds(vector& attributes) const { attributes.insert(attributes.end(), m_attributeIds.begin(), m_attributeIds.end()); } + void generateMetadata(SPSSODescriptor& role) const; + private: Category& m_log; DOMDocument* m_document; -#ifdef HAVE_GOOD_STL - typedef map< pair,pair< AttributeDecoder*,vector > > attrmap_t; -#else - typedef map< pair,pair< AttributeDecoder*,vector > > attrmap_t; -#endif + typedef map< pair,pair< boost::shared_ptr,vector > > attrmap_t; attrmap_t m_attrMap; vector m_attributeIds; + vector< boost::tuple > m_requestedAttrs; // settings for embedded assertions in metadata - auto_ptr_char m_policyId; - MetadataProvider* m_metadata; - TrustEngine* m_trust; - AttributeFilter* m_filter; - bool m_entityAssertions; + string m_policyId; + scoped_ptr m_filter; + scoped_ptr m_metadata; + scoped_ptr m_trust; + bool m_entityAssertions,m_metaAttrCaching; // manages caching of decoded Attributes - mutable RWLock* m_attrLock; + scoped_ptr m_attrLock; typedef map< const EntityAttributes*,vector > decoded_t; mutable map m_decodedMap; }; @@ -164,27 +142,41 @@ namespace shibsp { class XMLExtractor : public AttributeExtractor, public ReloadableXMLFile { public: - XMLExtractor(const DOMElement* e) : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT".AttributeExtractor.XML")), m_impl(NULL) { - load(); + XMLExtractor(const DOMElement* e) : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT ".AttributeExtractor.XML")) { + if (m_local && m_lock) + m_log.warn("attribute mappings are reloadable; be sure to restart web server when adding new attribute IDs"); + background_load(); } ~XMLExtractor() { - delete m_impl; + shutdown(); } + // deprecated method void extractAttributes( const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector& attributes - ) const; + ) const { + extractAttributes(application, nullptr, issuer, xmlObject, attributes); + } + + void extractAttributes(const Application&, const GenericRequest*, const RoleDescriptor*, const XMLObject&, vector&) const; void getAttributeIds(std::vector& attributes) const { if (m_impl) m_impl->getAttributeIds(attributes); } + void generateMetadata(SPSSODescriptor& role) const { + if (m_impl) + m_impl->generateMetadata(role); + } + protected: - pair load(); + pair background_load(); private: - XMLExtractorImpl* m_impl; + scoped_ptr m_impl; + + void extractAttributes(const Application&, const GenericRequest*, const RoleDescriptor*, const XMLObject&, ptr_vector&) const; }; #if defined (_MSC_VER) @@ -196,28 +188,27 @@ namespace shibsp { return new XMLExtractor(e); } - static const XMLCh _aliases[] = UNICODE_LITERAL_7(a,l,i,a,s,e,s); - static const XMLCh _AttributeDecoder[] = UNICODE_LITERAL_16(A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r); - static const XMLCh _AttributeFilter[] = UNICODE_LITERAL_15(A,t,t,r,i,b,u,t,e,F,i,l,t,e,r); - static const XMLCh Attributes[] = UNICODE_LITERAL_10(A,t,t,r,i,b,u,t,e,s); - static const XMLCh _id[] = UNICODE_LITERAL_2(i,d); - static const XMLCh _MetadataProvider[] = UNICODE_LITERAL_16(M,e,t,a,d,a,t,a,P,r,o,v,i,d,e,r); - static const XMLCh _name[] = UNICODE_LITERAL_4(n,a,m,e); - static const XMLCh nameFormat[] = UNICODE_LITERAL_10(n,a,m,e,F,o,r,m,a,t); - static const XMLCh metadataPolicyId[] = UNICODE_LITERAL_16(m,e,t,a,d,a,t,a,P,o,l,i,c,y,I,d); - static const XMLCh _TrustEngine[] = UNICODE_LITERAL_11(T,r,u,s,t,E,n,g,i,n,e); - static const XMLCh _type[] = UNICODE_LITERAL_4(t,y,p,e); + static const XMLCh _aliases[] = UNICODE_LITERAL_7(a,l,i,a,s,e,s); + static const XMLCh _AttributeDecoder[] = UNICODE_LITERAL_16(A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r); + static const XMLCh _AttributeFilter[] = UNICODE_LITERAL_15(A,t,t,r,i,b,u,t,e,F,i,l,t,e,r); + static const XMLCh Attributes[] = UNICODE_LITERAL_10(A,t,t,r,i,b,u,t,e,s); + static const XMLCh _id[] = UNICODE_LITERAL_2(i,d); + static const XMLCh isRequested[] = UNICODE_LITERAL_11(i,s,R,e,q,u,e,s,t,e,d); + static const XMLCh _MetadataProvider[] = UNICODE_LITERAL_16(M,e,t,a,d,a,t,a,P,r,o,v,i,d,e,r); + static const XMLCh metadataAttributeCaching[] = UNICODE_LITERAL_24(m,e,t,a,d,a,t,a,A,t,t,r,i,b,u,t,e,C,a,c,h,i,n,g); + static const XMLCh metadataPolicyId[] = UNICODE_LITERAL_16(m,e,t,a,d,a,t,a,P,o,l,i,c,y,I,d); + static const XMLCh _name[] = UNICODE_LITERAL_4(n,a,m,e); + static const XMLCh nameFormat[] = UNICODE_LITERAL_10(n,a,m,e,F,o,r,m,a,t); + static const XMLCh _TrustEngine[] = UNICODE_LITERAL_11(T,r,u,s,t,E,n,g,i,n,e); + static const XMLCh _type[] = UNICODE_LITERAL_4(t,y,p,e); }; XMLExtractorImpl::XMLExtractorImpl(const DOMElement* e, Category& log) : m_log(log), - m_document(NULL), - m_policyId(e ? e->getAttributeNS(NULL, metadataPolicyId) : NULL), - m_metadata(NULL), - m_trust(NULL), - m_filter(NULL), + m_document(nullptr), + m_policyId(XMLHelper::getAttrString(e, nullptr, metadataPolicyId)), m_entityAssertions(true), - m_attrLock(NULL) + m_metaAttrCaching(XMLHelper::getAttrBool(e, true, metadataAttributeCaching)) { #ifdef _DEBUG xmltooling::NDC ndc("XMLExtractorImpl"); @@ -229,15 +220,15 @@ XMLExtractorImpl::XMLExtractorImpl(const DOMElement* e, Category& log) DOMElement* child = XMLHelper::getFirstChildElement(e, shibspconstants::SHIB2ATTRIBUTEMAP_NS, _MetadataProvider); if (child) { try { - auto_ptr_char type(child->getAttributeNS(NULL, _type)); - if (!type.get() || !*type.get()) + string t(XMLHelper::getAttrString(child, nullptr, _type)); + if (t.empty()) throw ConfigurationException("MetadataProvider element missing type attribute."); - m_log.info("building MetadataProvider of type %s...", type.get()); - auto_ptr mp(SAMLConfig::getConfig().MetadataProviderManager.newPlugin(type.get(), child)); - mp->init(); - m_metadata = mp.release(); + m_log.info("building MetadataProvider of type %s...", t.c_str()); + m_metadata.reset(SAMLConfig::getConfig().MetadataProviderManager.newPlugin(t.c_str(), child)); + m_metadata->init(); } - catch (exception& ex) { + catch (std::exception& ex) { + m_metadata.reset(); m_entityAssertions = false; m_log.crit("error building/initializing dedicated MetadataProvider: %s", ex.what()); m_log.crit("disabling support for Assertions in EntityAttributes extension"); @@ -248,13 +239,13 @@ XMLExtractorImpl::XMLExtractorImpl(const DOMElement* e, Category& log) child = XMLHelper::getFirstChildElement(e, shibspconstants::SHIB2ATTRIBUTEMAP_NS, _TrustEngine); if (child) { try { - auto_ptr_char type(child->getAttributeNS(NULL, _type)); - if (!type.get() || !*type.get()) + string t(XMLHelper::getAttrString(child, nullptr, _type)); + if (t.empty()) throw ConfigurationException("TrustEngine element missing type attribute."); - m_log.info("building TrustEngine of type %s...", type.get()); - m_trust = XMLToolingConfig::getConfig().TrustEngineManager.newPlugin(type.get(), child); + m_log.info("building TrustEngine of type %s...", t.c_str()); + m_trust.reset(XMLToolingConfig::getConfig().TrustEngineManager.newPlugin(t.c_str(), child)); } - catch (exception& ex) { + catch (std::exception& ex) { m_entityAssertions = false; m_log.crit("error building/initializing dedicated TrustEngine: %s", ex.what()); m_log.crit("disabling support for Assertions in EntityAttributes extension"); @@ -266,13 +257,13 @@ XMLExtractorImpl::XMLExtractorImpl(const DOMElement* e, Category& log) child = XMLHelper::getFirstChildElement(e, shibspconstants::SHIB2ATTRIBUTEMAP_NS, _AttributeFilter); if (child) { try { - auto_ptr_char type(child->getAttributeNS(NULL, _type)); - if (!type.get() || !*type.get()) + string t(XMLHelper::getAttrString(child, nullptr, _type)); + if (t.empty()) throw ConfigurationException("AttributeFilter element missing type attribute."); - m_log.info("building AttributeFilter of type %s...", type.get()); - m_filter = SPConfig::getConfig().AttributeFilterManager.newPlugin(type.get(), child); + m_log.info("building AttributeFilter of type %s...", t.c_str()); + m_filter.reset(SPConfig::getConfig().AttributeFilterManager.newPlugin(t.c_str(), child)); } - catch (exception& ex) { + catch (std::exception& ex) { m_entityAssertions = false; m_log.crit("error building/initializing dedicated AttributeFilter: %s", ex.what()); m_log.crit("disabling support for Assertions in EntityAttributes extension"); @@ -283,14 +274,14 @@ XMLExtractorImpl::XMLExtractorImpl(const DOMElement* e, Category& log) child = XMLHelper::getFirstChildElement(e, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME); while (child) { // Check for missing name or id. - const XMLCh* name = child->getAttributeNS(NULL, _name); + const XMLCh* name = child->getAttributeNS(nullptr, _name); if (!name || !*name) { m_log.warn("skipping Attribute with no name"); child = XMLHelper::getNextSiblingElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME); continue; } - auto_ptr_char id(child->getAttributeNS(NULL, _id)); + auto_ptr_char id(child->getAttributeNS(nullptr, _id)); if (!id.get() || !*id.get()) { m_log.warn("skipping Attribute with no id"); child = XMLHelper::getNextSiblingElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME); @@ -302,18 +293,18 @@ XMLExtractorImpl::XMLExtractorImpl(const DOMElement* e, Category& log) continue; } - AttributeDecoder* decoder=NULL; + boost::shared_ptr decoder; try { DOMElement* dchild = XMLHelper::getFirstChildElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, _AttributeDecoder); if (dchild) { auto_ptr q(XMLHelper::getXSIType(dchild)); if (q.get()) - decoder = SPConfig::getConfig().AttributeDecoderManager.newPlugin(*q.get(), dchild); + decoder.reset(SPConfig::getConfig().AttributeDecoderManager.newPlugin(*q.get(), dchild)); } if (!decoder) - decoder = SPConfig::getConfig().AttributeDecoderManager.newPlugin(StringAttributeDecoderType, NULL); + decoder.reset(SPConfig::getConfig().AttributeDecoderManager.newPlugin(StringAttributeDecoderType, nullptr)); } - catch (exception& ex) { + catch (std::exception& ex) { m_log.error("skipping Attribute (%s), error building AttributeDecoder: %s", id.get(), ex.what()); } @@ -323,31 +314,22 @@ XMLExtractorImpl::XMLExtractorImpl(const DOMElement* e, Category& log) } // Empty NameFormat implies the usual Shib URI naming defaults. - const XMLCh* format = child->getAttributeNS(NULL, nameFormat); + const XMLCh* format = child->getAttributeNS(nullptr, nameFormat); if (!format || XMLString::equals(format, shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI) || XMLString::equals(format, saml2::Attribute::URI_REFERENCE)) format = &chNull; // ignore default Format/Namespace values // Fetch/create the map entry and see if it's a duplicate rule. -#ifdef HAVE_GOOD_STL - pair< AttributeDecoder*,vector >& decl = m_attrMap[pair(name,format)]; -#else - auto_ptr_char n(name); - auto_ptr_char f(format); - pair< AttributeDecoder*,vector >& decl = m_attrMap[pair(n.get(),f.get())]; -#endif + pair< boost::shared_ptr,vector >& decl = m_attrMap[pair(name,format)]; if (decl.first) { m_log.warn("skipping duplicate Attribute mapping (same name and nameFormat)"); - delete decoder; child = XMLHelper::getNextSiblingElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME); continue; } if (m_log.isInfoEnabled()) { -#ifdef HAVE_GOOD_STL auto_ptr_char n(name); auto_ptr_char f(format); -#endif m_log.info("creating mapping for Attribute %s%s%s", n.get(), *f.get() ? ", Format/Namespace:" : "", f.get()); } @@ -355,34 +337,67 @@ XMLExtractorImpl::XMLExtractorImpl(const DOMElement* e, Category& log) decl.second.push_back(id.get()); m_attributeIds.push_back(id.get()); - name = child->getAttributeNS(NULL, _aliases); + // Check for isRequired/isRequested. + bool requested = XMLHelper::getAttrBool(child, false, isRequested); + bool required = XMLHelper::getAttrBool(child, false, RequestedAttribute::ISREQUIRED_ATTRIB_NAME); + if (required || requested) + m_requestedAttrs.push_back(boost::tuple(name,format,required)); + + name = child->getAttributeNS(nullptr, _aliases); if (name && *name) { + m_log.warn("attribute mapping rule (%s) uses deprecated aliases feature, consider revising", id.get()); auto_ptr_char aliases(name); - char* pos; - char* start = const_cast(aliases.get()); - while (start && *start) { - while (*start && isspace(*start)) - start++; - if (!*start) - break; - pos = strchr(start,' '); - if (pos) - *pos=0; - if (strcmp(start, "REMOTE_USER")) { - decl.second.push_back(start); - m_attributeIds.push_back(start); - } - else { - m_log.warn("skipping alias, REMOTE_USER is a reserved name"); - } - start = pos ? pos+1 : NULL; + string dup(aliases.get()); + trim(dup); + set new_aliases; + split(new_aliases, dup, is_space(), algorithm::token_compress_on); + set::iterator ru = new_aliases.find("REMOTE_USER"); + if (ru != new_aliases.end()) { + m_log.warn("skipping alias, REMOTE_USER is a reserved name"); + new_aliases.erase(ru); } + decl.second.insert(decl.second.end(), new_aliases.begin(), new_aliases.end()); + m_attributeIds.insert(m_attributeIds.end(), new_aliases.begin(), new_aliases.end()); } child = XMLHelper::getNextSiblingElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME); } - m_attrLock = RWLock::create(); + if (m_metaAttrCaching) + m_attrLock.reset(RWLock::create()); +} + +void XMLExtractorImpl::generateMetadata(SPSSODescriptor& role) const +{ + if (m_requestedAttrs.empty()) + return; + int index = 1; + const vector& svcs = const_cast(&role)->getAttributeConsumingServices(); + for (vector::const_iterator s =svcs.begin(); s != svcs.end(); ++s) { + pair i = (*s)->getIndex(); + if (i.first && index == i.second) + index = i.second + 1; + } + AttributeConsumingService* svc = AttributeConsumingServiceBuilder::buildAttributeConsumingService(); + role.getAttributeConsumingServices().push_back(svc); + svc->setIndex(index); + ServiceName* sn = ServiceNameBuilder::buildServiceName(); + svc->getServiceNames().push_back(sn); + sn->setName(dynamic_cast(role.getParent())->getEntityID()); + static const XMLCh english[] = UNICODE_LITERAL_2(e,n); + sn->setLang(english); + + for (vector< boost::tuple >::const_iterator i = m_requestedAttrs.begin(); i != m_requestedAttrs.end(); ++i) { + RequestedAttribute* req = RequestedAttributeBuilder::buildRequestedAttribute(); + svc->getRequestedAttributes().push_back(req); + req->setName(i->get<0>().c_str()); + if (i->get<1>().empty()) + req->setNameFormat(saml2::Attribute::URI_REFERENCE); + else + req->setNameFormat(i->get<1>().c_str()); + if (i->get<2>()) + req->isRequired(true); + } } void XMLExtractorImpl::extractAttributes( @@ -390,32 +405,22 @@ void XMLExtractorImpl::extractAttributes( const char* assertingParty, const char* relyingParty, const NameIdentifier& nameid, - vector& attributes + ptr_vector& attributes ) const { -#ifdef HAVE_GOOD_STL - map< pair,pair< AttributeDecoder*,vector > >::const_iterator rule; -#else - map< pair,pair< AttributeDecoder*,vector > >::const_iterator rule; -#endif - const XMLCh* format = nameid.getFormat(); if (!format || !*format) format = NameIdentifier::UNSPECIFIED; -#ifdef HAVE_GOOD_STL - if ((rule=m_attrMap.find(pair(format,xstring()))) != m_attrMap.end()) { -#else - auto_ptr_char temp(format); - if ((rule=m_attrMap.find(pair(temp.get(),string()))) != m_attrMap.end()) { -#endif - Attribute* a = rule->second.first->decode(rule->second.second, &nameid, assertingParty, relyingParty); - if (a) - attributes.push_back(a); + attrmap_t::const_iterator rule; + if ((rule = m_attrMap.find(pair(format,xstring()))) != m_attrMap.end()) { + auto_ptr a(rule->second.first->decode(nullptr, rule->second.second, &nameid, assertingParty, relyingParty)); + if (a.get()) { + attributes.push_back(a.get()); + a.release(); + } } else if (m_log.isDebugEnabled()) { -#ifdef HAVE_GOOD_STL auto_ptr_char temp(format); -#endif m_log.debug("skipping unmapped NameIdentifier with format (%s)", temp.get()); } } @@ -425,90 +430,65 @@ void XMLExtractorImpl::extractAttributes( const char* assertingParty, const char* relyingParty, const NameID& nameid, - vector& attributes + ptr_vector& attributes ) const { -#ifdef HAVE_GOOD_STL - map< pair,pair< AttributeDecoder*,vector > >::const_iterator rule; -#else - map< pair,pair< AttributeDecoder*,vector > >::const_iterator rule; -#endif - const XMLCh* format = nameid.getFormat(); if (!format || !*format) format = NameID::UNSPECIFIED; -#ifdef HAVE_GOOD_STL - if ((rule=m_attrMap.find(pair(format,xstring()))) != m_attrMap.end()) { -#else - auto_ptr_char temp(format); - if ((rule=m_attrMap.find(pair(temp.get(),string()))) != m_attrMap.end()) { -#endif - Attribute* a = rule->second.first->decode(rule->second.second, &nameid, assertingParty, relyingParty); - if (a) - attributes.push_back(a); + attrmap_t::const_iterator rule; + if ((rule = m_attrMap.find(pair(format,xstring()))) != m_attrMap.end()) { + auto_ptr a(rule->second.first->decode(nullptr, rule->second.second, &nameid, assertingParty, relyingParty)); + if (a.get()) { + attributes.push_back(a.get()); + a.release(); + } } else if (m_log.isDebugEnabled()) { -#ifdef HAVE_GOOD_STL auto_ptr_char temp(format); -#endif m_log.debug("skipping unmapped NameID with format (%s)", temp.get()); } } void XMLExtractorImpl::extractAttributes( const Application& application, + const GenericRequest* request, const char* assertingParty, const char* relyingParty, const saml1::Attribute& attr, - vector& attributes + ptr_vector& attributes ) const { -#ifdef HAVE_GOOD_STL - map< pair,pair< AttributeDecoder*,vector > >::const_iterator rule; -#else - map< pair,pair< AttributeDecoder*,vector > >::const_iterator rule; -#endif - const XMLCh* name = attr.getAttributeName(); const XMLCh* format = attr.getAttributeNamespace(); if (!name || !*name) return; if (!format || XMLString::equals(format, shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI)) format = &chNull; -#ifdef HAVE_GOOD_STL - if ((rule=m_attrMap.find(pair(name,format))) != m_attrMap.end()) { -#else - auto_ptr_char temp1(name); - auto_ptr_char temp2(format); - if ((rule=m_attrMap.find(pair(temp1.get(),temp2.get()))) != m_attrMap.end()) { -#endif - Attribute* a = rule->second.first->decode(rule->second.second, &attr, assertingParty, relyingParty); - if (a) - attributes.push_back(a); + attrmap_t::const_iterator rule; + if ((rule = m_attrMap.find(pair(name,format))) != m_attrMap.end()) { + auto_ptr a(rule->second.first->decode(request, rule->second.second, &attr, assertingParty, relyingParty)); + if (a.get()) { + attributes.push_back(a.get()); + a.release(); + } } else if (m_log.isInfoEnabled()) { -#ifdef HAVE_GOOD_STL auto_ptr_char temp1(name); auto_ptr_char temp2(format); -#endif m_log.info("skipping unmapped SAML 1.x Attribute with Name: %s%s%s", temp1.get(), *temp2.get() ? ", Namespace:" : "", temp2.get()); } } void XMLExtractorImpl::extractAttributes( const Application& application, + const GenericRequest* request, const char* assertingParty, const char* relyingParty, const saml2::Attribute& attr, - vector& attributes + ptr_vector& attributes ) const { -#ifdef HAVE_GOOD_STL - map< pair,pair< AttributeDecoder*,vector > >::const_iterator rule; -#else - map< pair,pair< AttributeDecoder*,vector > >::const_iterator rule; -#endif - const XMLCh* name = attr.getName(); const XMLCh* format = attr.getNameFormat(); if (!name || !*name) @@ -517,37 +497,82 @@ void XMLExtractorImpl::extractAttributes( format = saml2::Attribute::UNSPECIFIED; else if (XMLString::equals(format, saml2::Attribute::URI_REFERENCE)) format = &chNull; -#ifdef HAVE_GOOD_STL - if ((rule=m_attrMap.find(pair(name,format))) != m_attrMap.end()) { -#else - auto_ptr_char temp1(name); - auto_ptr_char temp2(format); - if ((rule=m_attrMap.find(pair(temp1.get(),temp2.get()))) != m_attrMap.end()) { -#endif - Attribute* a = rule->second.first->decode(rule->second.second, &attr, assertingParty, relyingParty); - if (a) - attributes.push_back(a); + attrmap_t::const_iterator rule; + if ((rule = m_attrMap.find(pair(name,format))) != m_attrMap.end()) { + auto_ptr a(rule->second.first->decode(request, rule->second.second, &attr, assertingParty, relyingParty)); + if (a.get()) { + attributes.push_back(a.get()); + a.release(); + return; + } } - else if (m_log.isInfoEnabled()) { -#ifdef HAVE_GOOD_STL + else if (XMLString::equals(format, saml2::Attribute::UNSPECIFIED)) { + // As a fallback, if the format is "unspecified", null out the value and re-map. + if ((rule = m_attrMap.find(pair(name,xstring()))) != m_attrMap.end()) { + auto_ptr a(rule->second.first->decode(request, rule->second.second, &attr, assertingParty, relyingParty)); + if (a.get()) { + attributes.push_back(a.get()); + a.release(); + return; + } + } + } + + if (m_log.isInfoEnabled()) { auto_ptr_char temp1(name); auto_ptr_char temp2(format); -#endif m_log.info("skipping unmapped SAML 2.0 Attribute with Name: %s%s%s", temp1.get(), *temp2.get() ? ", Format:" : "", temp2.get()); } } void XMLExtractorImpl::extractAttributes( const Application& application, + const GenericRequest* request, + const char* assertingParty, + const char* relyingParty, + const saml1::AttributeStatement& statement, + ptr_vector& attributes + ) const +{ + static void (XMLExtractorImpl::* extract)( + const Application&, const GenericRequest*, const char*, const char*, const saml1::Attribute&, ptr_vector& + ) const = &XMLExtractorImpl::extractAttributes; + for_each( + make_indirect_iterator(statement.getAttributes().begin()), make_indirect_iterator(statement.getAttributes().end()), + boost::bind(extract, this, boost::cref(application), request, assertingParty, relyingParty, _1, boost::ref(attributes)) + ); +} + +void XMLExtractorImpl::extractAttributes( + const Application& application, + const GenericRequest* request, + const char* assertingParty, + const char* relyingParty, + const saml2::AttributeStatement& statement, + ptr_vector& attributes + ) const +{ + static void (XMLExtractorImpl::* extract)( + const Application&, const GenericRequest*, const char*, const char*, const saml2::Attribute&, ptr_vector& + ) const = &XMLExtractorImpl::extractAttributes; + for_each( + make_indirect_iterator(statement.getAttributes().begin()), make_indirect_iterator(statement.getAttributes().end()), + boost::bind(extract, this, boost::cref(application), request, assertingParty, relyingParty, _1, boost::ref(attributes)) + ); +} + +void XMLExtractorImpl::extractAttributes( + const Application& application, + const GenericRequest* request, const ObservableMetadataProvider* observable, const XMLCh* entityID, const char* relyingParty, const Extensions& ext, - vector& attributes + ptr_vector& attributes ) const { const vector& exts = ext.getUnknownXMLObjects(); - for (vector::const_iterator i = exts.begin(); i!=exts.end(); ++i) { + for (vector::const_iterator i = exts.begin(); i != exts.end(); ++i) { const EntityAttributes* container = dynamic_cast(*i); if (!container) continue; @@ -556,7 +581,7 @@ void XMLExtractorImpl::extractAttributes( map::iterator cacheEntry; // Check for cached result. - if (observable) { + if (observable && m_metaAttrCaching) { m_attrLock->rdlock(); cacheEntry = m_decodedMap.find(observable); if (cacheEntry == m_decodedMap.end()) { @@ -564,7 +589,8 @@ void XMLExtractorImpl::extractAttributes( m_attrLock->unlock(); m_attrLock->wrlock(); cacheEntry = m_decodedMap.find(observable); - if (cacheEntry==m_decodedMap.end()) { + if (cacheEntry == m_decodedMap.end()) { + SharedLock locker(m_attrLock, false); // guard in case these throw // It's still brand new, so hook it for cache activation. observable->addObserver(this); @@ -574,6 +600,7 @@ void XMLExtractorImpl::extractAttributes( // Downgrade the lock. // We don't have to recheck because we never erase the master map entry entirely, even on changes. + locker.release(); // unguard for lock downgrade m_attrLock->unlock(); m_attrLock->rdlock(); } @@ -582,46 +609,47 @@ void XMLExtractorImpl::extractAttributes( } if (useCache) { - // We're holding a read lock, so check the cache. + // We're holding the lock, so check the cache. decoded_t::iterator d = cacheEntry->second.find(container); if (d != cacheEntry->second.end()) { SharedLock locker(m_attrLock, false); // pop the lock when we're done for (vector::iterator obj = d->second.begin(); obj != d->second.end(); ++obj) { auto_ptr wrapper(Attribute::unmarshall(*obj)); m_log.debug("recovered cached metadata attribute (%s)", wrapper->getId()); - attributes.push_back(wrapper.release()); + attributes.push_back(wrapper.get()); + wrapper.release(); } break; } } + // Add a guard for the lock if we're caching. + SharedLock locker(useCache ? m_attrLock.get() : nullptr, false); + // Use a holding area to support caching. - vector holding; + ptr_vector holding; - const vector& attrs = container->getAttributes(); - for (vector::const_iterator attr = attrs.begin(); attr != attrs.end(); ++attr) { - try { - extractAttributes(application, NULL, relyingParty, *(*attr), holding); - } - catch (...) { - if (useCache) - m_attrLock->unlock(); - for_each(holding.begin(), holding.end(), xmltooling::cleanup()); - throw; - } - } + // Extract attributes into holding area with no asserting party set. + static void (XMLExtractorImpl::* extractV2Attr)( + const Application&, const GenericRequest*, const char*, const char*, const saml2::Attribute&, ptr_vector& + ) const = &XMLExtractorImpl::extractAttributes; + for_each( + make_indirect_iterator(container->getAttributes().begin()), make_indirect_iterator(container->getAttributes().end()), + boost::bind(extractV2Attr, this, boost::ref(application), request, (const char*)nullptr, relyingParty, _1, boost::ref(holding)) + ); if (entityID && m_entityAssertions) { const vector& asserts = container->getAssertions(); - for (vector::const_iterator assert = asserts.begin(); assert != asserts.end(); ++assert) { - if (!(*assert)->getSignature()) { + for (indirect_iterator::const_iterator> assert = make_indirect_iterator(asserts.begin()); + assert != make_indirect_iterator(asserts.end()); ++assert) { + if (!(assert->getSignature())) { if (m_log.isDebugEnabled()) { auto_ptr_char eid(entityID); m_log.debug("skipping unsigned assertion in metadata extension for entity (%s)", eid.get()); } continue; } - else if ((*assert)->getAttributeStatements().empty()) { + else if (assert->getAttributeStatements().empty()) { if (m_log.isDebugEnabled()) { auto_ptr_char eid(entityID); m_log.debug("skipping assertion with no AttributeStatement in metadata extension for entity (%s)", eid.get()); @@ -630,7 +658,7 @@ void XMLExtractorImpl::extractAttributes( } else { // Check subject. - const NameID* subject = (*assert)->getSubject() ? (*assert)->getSubject()->getNameID() : NULL; + const NameID* subject = assert->getSubject() ? assert->getSubject()->getNameID() : nullptr; if (!subject || !XMLString::equals(subject->getFormat(), NameID::ENTITY) || !XMLString::equals(subject->getName(), entityID)) { @@ -642,25 +670,22 @@ void XMLExtractorImpl::extractAttributes( } } - // Use a private holding area for filtering purposes. - vector holding2; - try { // Set up and evaluate a policy for an AA asserting attributes to us. - shibsp::SecurityPolicy policy(application, &AttributeAuthorityDescriptor::ELEMENT_QNAME, false, m_policyId.get()); - Locker locker(m_metadata); + shibsp::SecurityPolicy policy(application, &AttributeAuthorityDescriptor::ELEMENT_QNAME, false, m_policyId.c_str()); + Locker locker(m_metadata.get()); if (m_metadata) - policy.setMetadataProvider(m_metadata); + policy.setMetadataProvider(m_metadata.get()); if (m_trust) - policy.setTrustEngine(m_trust); + policy.setTrustEngine(m_trust.get()); // Populate recipient as audience. - const XMLCh* issuer = (*assert)->getIssuer() ? (*assert)->getIssuer()->getName() : NULL; + const XMLCh* issuer = assert->getIssuer() ? assert->getIssuer()->getName() : nullptr; policy.getAudiences().push_back(application.getRelyingParty(issuer)->getXMLString("entityID").second); // Extract assertion information for policy. - policy.setMessageID((*assert)->getID()); - policy.setIssueInstant((*assert)->getIssueInstantEpoch()); - policy.setIssuer((*assert)->getIssuer()); + policy.setMessageID(assert->getID()); + policy.setIssueInstant(assert->getIssueInstantEpoch()); + policy.setIssuer(assert->getIssuer()); // Look up metadata for issuer. if (policy.getIssuer() && policy.getMetadataProvider()) { @@ -689,7 +714,7 @@ void XMLExtractorImpl::extractAttributes( } // Authenticate the assertion. We have to clone and marshall it to establish the signature for verification. - auto_ptr tokencopy((*assert)->cloneAssertion()); + scoped_ptr tokencopy(assert->cloneAssertion()); tokencopy->marshall(); policy.evaluate(*tokencopy); if (!policy.isAuthenticated()) { @@ -705,40 +730,63 @@ void XMLExtractorImpl::extractAttributes( // Override the asserting/relying party names based on this new issuer. const EntityDescriptor* inlineEntity = - policy.getIssuerMetadata() ? dynamic_cast(policy.getIssuerMetadata()->getParent()) : NULL; - auto_ptr_char inlineAssertingParty(inlineEntity ? inlineEntity->getEntityID() : NULL); + policy.getIssuerMetadata() ? dynamic_cast(policy.getIssuerMetadata()->getParent()) : nullptr; + auto_ptr_char inlineAssertingParty(inlineEntity ? inlineEntity->getEntityID() : nullptr); relyingParty = application.getRelyingParty(inlineEntity)->getString("entityID").second; + + // Use a private holding area for filtering purposes. + ptr_vector holding2; const vector& attrs2 = const_cast(tokencopy->getAttributeStatements().front())->getAttributes(); - for (vector::const_iterator a = attrs2.begin(); a!=attrs2.end(); ++a) - extractAttributes(application, inlineAssertingParty.get(), relyingParty, *(*a), holding2); + for_each( + make_indirect_iterator(attrs2.begin()), make_indirect_iterator(attrs2.end()), + boost::bind(extractV2Attr, this, boost::ref(application), request, inlineAssertingParty.get(), relyingParty, _1, boost::ref(holding2)) + ); // Now we locally filter the attributes so that the actual issuer can be properly set. // If we relied on outside filtering, the attributes couldn't be distinguished from the // ones that come from the user's IdP. if (m_filter && !holding2.empty()) { - BasicFilteringContext fc(application, holding2, policy.getIssuerMetadata()); - Locker filtlocker(m_filter); + + // The filter API uses an unsafe container, so we have to transfer everything into one and back. + vector unsafe_holding2; + + // Use a local exception context since the container is unsafe. try { - m_filter->filterAttributes(fc, holding2); + while (!holding2.empty()) { + ptr_vector::auto_type ptr = holding2.pop_back(); + unsafe_holding2.push_back(ptr.get()); + ptr.release(); + } + BasicFilteringContext fc(application, unsafe_holding2, policy.getIssuerMetadata()); + Locker filtlocker(m_filter.get()); + m_filter->filterAttributes(fc, unsafe_holding2); + + // Transfer back to safe container + while (!unsafe_holding2.empty()) { + auto_ptr ptr(unsafe_holding2.back()); + unsafe_holding2.pop_back(); + holding2.push_back(ptr.get()); + ptr.release(); + } } - catch (exception& ex) { + catch (std::exception& ex) { m_log.error("caught exception filtering attributes: %s", ex.what()); m_log.error("dumping extracted attributes due to filtering exception"); - for_each(holding2.begin(), holding2.end(), xmltooling::cleanup()); - holding2.clear(); + for_each(unsafe_holding2.begin(), unsafe_holding2.end(), xmltooling::cleanup()); + holding2.clear(); // in case the exception was during transfer between containers } } if (!holding2.empty()) { - // Copy them over to the main holding tank. - holding.insert(holding.end(), holding2.begin(), holding2.end()); + // Copy them over to the main holding tank, which transfers ownership. + holding.transfer(holding.end(), holding2); } } - catch (exception& ex) { + catch (std::exception& ex) { // Known exceptions are handled gracefully by skipping the assertion. if (m_log.isDebugEnabled()) { - auto_ptr_char tempid((*assert)->getID()); + auto_ptr_char tempid(assert->getID()); auto_ptr_char eid(entityID); m_log.debug( "exception authenticating assertion (%s) in metadata extension for entity (%s): %s", @@ -747,77 +795,122 @@ void XMLExtractorImpl::extractAttributes( ex.what() ); } - for_each(holding2.begin(), holding2.end(), xmltooling::cleanup()); continue; } - catch (...) { - // Unknown exceptions are fatal. - if (useCache) - m_attrLock->unlock(); - for_each(holding.begin(), holding.end(), xmltooling::cleanup()); - for_each(holding2.begin(), holding2.end(), xmltooling::cleanup()); - throw; - } } } if (!holding.empty()) { if (useCache) { + locker.release(); // unguard to upgrade lock m_attrLock->unlock(); m_attrLock->wrlock(); - SharedLock locker(m_attrLock, false); // pop the lock when we're done + SharedLock locker2(m_attrLock, false); // pop the lock when we're done if (cacheEntry->second.count(container) == 0) { - for (vector::const_iterator held = holding.begin(); held != holding.end(); ++held) - cacheEntry->second[container].push_back((*held)->marshall()); + static void (vector::* push_back)(DDF const &) = &vector::push_back; + vector& marshalled = cacheEntry->second[container]; + for_each( + holding.begin(), holding.end(), + boost::bind(push_back, boost::ref(marshalled), boost::bind(&Attribute::marshall, _1)) + ); } } - attributes.insert(attributes.end(), holding.begin(), holding.end()); - } - else if (useCache) { - m_attrLock->unlock(); + + // Copy them to the output parameter, which transfers ownership. + attributes.transfer(attributes.end(), holding); } + // If the lock is held, it's guarded. + break; // only process a single extension element } } void XMLExtractor::extractAttributes( - const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector& attributes + const Application& application, const GenericRequest* request, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector& attributes ) const { if (!m_impl) return; - const EntityDescriptor* entity = issuer ? dynamic_cast(issuer->getParent()) : NULL; + ptr_vector holding; + extractAttributes(application, request, issuer, xmlObject, holding); + + // Transfer ownership from the ptr_vector to the unsafe vector for API compatibility. + // Any throws should leave each container in a consistent state. The holding container + // is freed by us, and the result container by the caller. + while (!holding.empty()) { + ptr_vector::auto_type ptr = holding.pop_back(); + attributes.push_back(ptr.get()); + ptr.release(); + } +} + +void XMLExtractor::extractAttributes( + const Application& application, const GenericRequest* request, const RoleDescriptor* issuer, const XMLObject& xmlObject, ptr_vector& attributes + ) const +{ + static void (XMLExtractor::* extractEncrypted)( + const Application&, const GenericRequest*, const RoleDescriptor*, const XMLObject&, ptr_vector& + ) const = &XMLExtractor::extractAttributes; + static void (XMLExtractorImpl::* extractV1Statement)( + const Application&, const GenericRequest*, const char*, const char*, const saml1::AttributeStatement&, ptr_vector& + ) const = &XMLExtractorImpl::extractAttributes; + + const EntityDescriptor* entity = issuer ? dynamic_cast(issuer->getParent()) : nullptr; const char* relyingParty = application.getRelyingParty(entity)->getString("entityID").second; + // Check for statements. + if (XMLString::equals(xmlObject.getElementQName().getLocalPart(), saml1::AttributeStatement::LOCAL_NAME)) { + const saml2::AttributeStatement* statement2 = dynamic_cast(&xmlObject); + if (statement2) { + auto_ptr_char assertingParty(entity ? entity->getEntityID() : nullptr); + m_impl->extractAttributes(application, request, assertingParty.get(), relyingParty, *statement2, attributes); + // Handle EncryptedAttributes inline so we have access to the role descriptor. + const vector& encattrs = statement2->getEncryptedAttributes(); + for_each( + make_indirect_iterator(encattrs.begin()), make_indirect_iterator(encattrs.end()), + boost::bind(extractEncrypted, this, boost::ref(application), request, issuer, _1, boost::ref(attributes)) + ); + return; + } + + const saml1::AttributeStatement* statement1 = dynamic_cast(&xmlObject); + if (statement1) { + auto_ptr_char assertingParty(entity ? entity->getEntityID() : nullptr); + m_impl->extractAttributes(application, request, assertingParty.get(), relyingParty, *statement1, attributes); + return; + } + + throw AttributeExtractionException("Unable to extract attributes, unknown object type."); + } + // Check for assertions. if (XMLString::equals(xmlObject.getElementQName().getLocalPart(), saml1::Assertion::LOCAL_NAME)) { const saml2::Assertion* token2 = dynamic_cast(&xmlObject); if (token2) { - auto_ptr_char assertingParty(entity ? entity->getEntityID() : NULL); + auto_ptr_char assertingParty(entity ? entity->getEntityID() : nullptr); const vector& statements = token2->getAttributeStatements(); - for (vector::const_iterator s = statements.begin(); s!=statements.end(); ++s) { - const vector& attrs = const_cast(*s)->getAttributes(); - for (vector::const_iterator a = attrs.begin(); a!=attrs.end(); ++a) - m_impl->extractAttributes(application, assertingParty.get(), relyingParty, *(*a), attributes); - - const vector& encattrs = const_cast(*s)->getEncryptedAttributes(); - for (vector::const_iterator ea = encattrs.begin(); ea!=encattrs.end(); ++ea) - extractAttributes(application, issuer, *(*ea), attributes); + for (indirect_iterator::const_iterator> s = make_indirect_iterator(statements.begin()); + s != make_indirect_iterator(statements.end()); ++s) { + m_impl->extractAttributes(application, request, assertingParty.get(), relyingParty, *s, attributes); + // Handle EncryptedAttributes inline so we have access to the role descriptor. + const vector& encattrs = const_cast(*s).getEncryptedAttributes(); + for_each( + make_indirect_iterator(encattrs.begin()), make_indirect_iterator(encattrs.end()), + boost::bind(extractEncrypted, this, boost::ref(application), request, issuer, _1, boost::ref(attributes)) + ); } return; } const saml1::Assertion* token1 = dynamic_cast(&xmlObject); if (token1) { - auto_ptr_char assertingParty(entity ? entity->getEntityID() : NULL); + auto_ptr_char assertingParty(entity ? entity->getEntityID() : nullptr); const vector& statements = token1->getAttributeStatements(); - for (vector::const_iterator s = statements.begin(); s!=statements.end(); ++s) { - const vector& attrs = const_cast(*s)->getAttributes(); - for (vector::const_iterator a = attrs.begin(); a!=attrs.end(); ++a) - m_impl->extractAttributes(application, assertingParty.get(), relyingParty, *(*a), attributes); - } + for_each(make_indirect_iterator(statements.begin()), make_indirect_iterator(statements.end()), + boost::bind(extractV1Statement, m_impl.get(), boost::ref(application), request, assertingParty.get(), relyingParty, _1, boost::ref(attributes)) + ); return; } @@ -827,13 +920,14 @@ void XMLExtractor::extractAttributes( // Check for metadata. if (XMLString::equals(xmlObject.getElementQName().getNamespaceURI(), samlconstants::SAML20MD_NS)) { const RoleDescriptor* roleToExtract = dynamic_cast(&xmlObject); - const EntityDescriptor* entityToExtract = roleToExtract ? dynamic_cast(roleToExtract->getParent()) : NULL; + const EntityDescriptor* entityToExtract = roleToExtract ? dynamic_cast(roleToExtract->getParent()) : nullptr; if (!entityToExtract) throw AttributeExtractionException("Unable to extract attributes, unknown metadata object type."); const Extensions* ext = entityToExtract->getExtensions(); if (ext) { m_impl->extractAttributes( application, + request, dynamic_cast(application.getMetadataProvider(false)), entityToExtract->getEntityID(), relyingParty, @@ -847,8 +941,9 @@ void XMLExtractor::extractAttributes( if (ext) { m_impl->extractAttributes( application, + request, dynamic_cast(application.getMetadataProvider(false)), - NULL, // not an entity, so inline assertions won't be processed + nullptr, // not an entity, so inline assertions won't be processed relyingParty, *ext, attributes @@ -861,14 +956,14 @@ void XMLExtractor::extractAttributes( // Check for attributes. if (XMLString::equals(xmlObject.getElementQName().getLocalPart(), saml1::Attribute::LOCAL_NAME)) { - auto_ptr_char assertingParty(entity ? entity->getEntityID() : NULL); + auto_ptr_char assertingParty(entity ? entity->getEntityID() : nullptr); const saml2::Attribute* attr2 = dynamic_cast(&xmlObject); if (attr2) - return m_impl->extractAttributes(application, assertingParty.get(), relyingParty, *attr2, attributes); + return m_impl->extractAttributes(application, request, assertingParty.get(), relyingParty, *attr2, attributes); const saml1::Attribute* attr1 = dynamic_cast(&xmlObject); if (attr1) - return m_impl->extractAttributes(application, assertingParty.get(), relyingParty, *attr1, attributes); + return m_impl->extractAttributes(application, request, assertingParty.get(), relyingParty, *attr1, attributes); throw AttributeExtractionException("Unable to extract attributes, unknown object type."); } @@ -887,20 +982,20 @@ void XMLExtractor::extractAttributes( Locker credlocker(cr); if (issuer) { MetadataCredentialCriteria mcc(*issuer); - auto_ptr decrypted(encattr->decrypt(*cr, recipient, &mcc)); + scoped_ptr decrypted(encattr->decrypt(*cr, recipient, &mcc)); if (m_log.isDebugEnabled()) - m_log.debugStream() << "decrypted Attribute: " << *(decrypted.get()) << logging::eol; - return extractAttributes(application, issuer, *(decrypted.get()), attributes); + m_log.debugStream() << "decrypted Attribute: " << *decrypted << logging::eol; + return extractAttributes(application, request, issuer, *decrypted, attributes); } else { - auto_ptr decrypted(encattr->decrypt(*cr, recipient)); + scoped_ptr decrypted(encattr->decrypt(*cr, recipient)); if (m_log.isDebugEnabled()) - m_log.debugStream() << "decrypted Attribute: " << *(decrypted.get()) << logging::eol; - return extractAttributes(application, issuer, *(decrypted.get()), attributes); + m_log.debugStream() << "decrypted Attribute: " << *decrypted << logging::eol; + return extractAttributes(application, request, issuer, *decrypted, attributes); } } - catch (exception& ex) { - m_log.error("caught exception decrypting Attribute: %s", ex.what()); + catch (std::exception& ex) { + m_log.error("failed to decrypt Attribute: %s", ex.what()); return; } } @@ -909,34 +1004,37 @@ void XMLExtractor::extractAttributes( // Check for NameIDs. const NameID* name2 = dynamic_cast(&xmlObject); if (name2) { - auto_ptr_char assertingParty(entity ? entity->getEntityID() : NULL); + auto_ptr_char assertingParty(entity ? entity->getEntityID() : nullptr); return m_impl->extractAttributes(application, assertingParty.get(), relyingParty, *name2, attributes); } const NameIdentifier* name1 = dynamic_cast(&xmlObject); if (name1) { - auto_ptr_char assertingParty(entity ? entity->getEntityID() : NULL); + auto_ptr_char assertingParty(entity ? entity->getEntityID() : nullptr); return m_impl->extractAttributes(application, assertingParty.get(), relyingParty, *name1, attributes); } - throw AttributeExtractionException("Unable to extract attributes, unknown object type."); + m_log.debug("unable to extract attributes, unknown XML object type: %s", xmlObject.getElementQName().toString().c_str()); } -pair XMLExtractor::load() +pair XMLExtractor::background_load() { // Load from source using base class. pair raw = ReloadableXMLFile::load(); // If we own it, wrap it. - XercesJanitor docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL); + XercesJanitor docjanitor(raw.first ? raw.second->getOwnerDocument() : nullptr); - XMLExtractorImpl* impl = new XMLExtractorImpl(raw.second, m_log); + scoped_ptr impl(new XMLExtractorImpl(raw.second, m_log)); // If we held the document, transfer it to the impl. If we didn't, it's a no-op. impl->setDocument(docjanitor.release()); - delete m_impl; - m_impl = impl; + // Perform the swap inside a lock. + if (m_lock) + m_lock->wrlock(); + SharedLock locker(m_lock, false); + m_impl.swap(impl); - return make_pair(false,(DOMElement*)NULL); + return make_pair(false,(DOMElement*)nullptr); }