[cpp-sp] branch main updated: Remove AttrbuteResolver and extractor code.

Scott Cantor cantor.2 at osu.edu
Wed Oct 30 21:24:45 UTC 2024


This is an automated email from the git hooks/post-receive script.

scantor pushed a commit to branch main
in repository cpp-sp.

View the commit online:
http://git.shibboleth.net/view/?p=cpp-sp.git;a=commit;h=6cdf44b27d81c7e40b99e86cf35b6786f62199af

The following commit(s) were added to refs/heads/main by this push:
     new 6cdf44b2 Remove AttrbuteResolver and extractor code.
6cdf44b2 is described below

commit 6cdf44b27d81c7e40b99e86cf35b6786f62199af
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Oct 30 17:24:40 2024 -0400

    Remove AttrbuteResolver and extractor code.
---
 shibsp/Makefile.am                                 |    9 -
 shibsp/attribute/resolver/AttributeExtractor.h     |  124 ---
 shibsp/attribute/resolver/AttributeResolver.h      |  150 ---
 shibsp/attribute/resolver/ResolutionContext.h      |   77 --
 .../resolver/impl/AssertionAttributeExtractor.cpp  |  399 --------
 .../resolver/impl/ChainingAttributeExtractor.cpp   |  150 ---
 .../resolver/impl/ChainingAttributeResolver.cpp    |  242 -----
 .../resolver/impl/DelegationAttributeExtractor.cpp |  202 ----
 .../impl/KeyDescriptorAttributeExtractor.cpp       |  192 ----
 .../resolver/impl/MetadataAttributeExtractor.cpp   |  406 --------
 .../resolver/impl/QueryAttributeResolver.cpp       |  764 --------------
 .../impl/SimpleAggregationAttributeResolver.cpp    |  765 --------------
 .../resolver/impl/XMLAttributeExtractor.cpp        | 1068 --------------------
 13 files changed, 4548 deletions(-)

diff --git a/shibsp/Makefile.am b/shibsp/Makefile.am
index e4cd946b..ec2ae137 100644
--- a/shibsp/Makefile.am
+++ b/shibsp/Makefile.am
@@ -6,10 +6,6 @@ libshibspincludedir = $(includedir)/shibsp
 
 attrincludedir = $(includedir)/shibsp/attribute
 
-attrresincludedir = $(includedir)/shibsp/attribute/resolver
-
-attrfiltincludedir = $(includedir)/shibsp/attribute/filtering
-
 bindincludedir = $(includedir)/shibsp/binding
 
 handincludedir = $(includedir)/shibsp/handler
@@ -51,11 +47,6 @@ attrinclude_HEADERS = \
 	attribute/SimpleAttribute.h \
 	attribute/XMLAttribute.h
 
-attrresinclude_HEADERS = \
-	attribute/resolver/AttributeExtractor.h \
-	attribute/resolver/AttributeResolver.h \
-	attribute/resolver/ResolutionContext.h
-
 bindinclude_HEADERS = \
 	binding/ArtifactResolver.h \
 	binding/ProtocolProvider.h \
diff --git a/shibsp/attribute/resolver/AttributeExtractor.h b/shibsp/attribute/resolver/AttributeExtractor.h
deleted file mode 100644
index fd0d30dc..00000000
--- a/shibsp/attribute/resolver/AttributeExtractor.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/**
- * 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
- *
- * 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.
- */
-
-/**
- * @file shibsp/attribute/resolver/AttributeExtractor.h
- *
- * A service that extracts and decodes attributes from XML objects.
- */
-
-#ifndef __shibsp_extractor_h__
-#define __shibsp_extractor_h__
-
-#include <shibsp/base.h>
-
-#include <string>
-#include <vector>
-#include <xmltooling/Lockable.h>
-
-namespace xmltooling {
-    class XMLTOOL_API XMLObject;
-};
-
-namespace opensaml {
-    namespace saml2md {
-        class SAML_API RoleDescriptor;
-        class SAML_API SPSSODescriptor;
-    };
-};
-
-namespace shibsp {
-
-    class SHIBSP_API Application;
-    class SHIBSP_API Attribute;
-
-    /**
-     * A service that extracts and decodes attributes from XML objects.
-     */
-    class SHIBSP_API AttributeExtractor : public virtual xmltooling::Lockable
-    {
-        MAKE_NONCOPYABLE(AttributeExtractor);
-    protected:
-        AttributeExtractor();
-    public:
-        virtual ~AttributeExtractor();
-
-        /**
-         * Extracts the attributes found in an XMLObject.
-         *
-         * @param application   Application performing the extraction
-         * @param request       request triggering the extraction, if any
-         * @param issuer        source of object, if known
-         * @param xmlObject     object to extract
-         * @param attributes    an array to populate with the extracted attributes
-         *
-         * @throws AttributeExtractionException thrown if there is a problem extracting attributes
-         */
-        virtual void extractAttributes(
-            const Application& application,
-            const xmltooling::GenericRequest* request,
-            const opensaml::saml2md::RoleDescriptor* issuer,
-            const xmltooling::XMLObject& xmlObject,
-            std::vector<Attribute*>& attributes
-            ) const=0;
-
-        /**
-         * Populates an array with the set of Attribute IDs that might be generated.
-         *
-         * @param attributes    array to populate
-         */
-        virtual void getAttributeIds(std::vector<std::string>& attributes) const=0;
-
-        /**
-         * Generates and/or modifies metadata reflecting the extractor,
-         * typically attribute-related requirements.
-         *
-         * <p>The default implementation does nothing.
-         *
-         * @param role          metadata role to decorate
-         */
-        virtual void generateMetadata(opensaml::saml2md::SPSSODescriptor& role) const;
-    };
-
-    /**
-     * Registers AttributeExtractor classes into the runtime.
-     */
-    void SHIBSP_API registerAttributeExtractors();
-
-    /** AttributeExtractor based on an XML mapping schema. */
-    #define XML_ATTRIBUTE_EXTRACTOR "XML"
-
-    /** AttributeExtractor for SAML assertion information. */
-    #define ASSERTION_ATTRIBUTE_EXTRACTOR "Assertion"
-
-    /** AttributeExtractor for SAML metadata information. */
-    #define METADATA_ATTRIBUTE_EXTRACTOR "Metadata"
-
-    /** AttributeExtractor for DelegationRestriction information. */
-    #define DELEGATION_ATTRIBUTE_EXTRACTOR "Delegation"
-
-    /** AttributeExtractor for KeyInfo information. */
-    #define KEYDESCRIPTOR_ATTRIBUTE_EXTRACTOR "KeyDescriptor"
-
-    /** AttributeExtractor based on chaining together other extractors. */
-    #define CHAINING_ATTRIBUTE_EXTRACTOR "Chaining"
-};
-
-#endif /* __shibsp_extractor_h__ */
diff --git a/shibsp/attribute/resolver/AttributeResolver.h b/shibsp/attribute/resolver/AttributeResolver.h
deleted file mode 100644
index 5c34b6ef..00000000
--- a/shibsp/attribute/resolver/AttributeResolver.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/**
- * 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
- *
- * 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.
- */
-
-/**
- * @file shibsp/attribute/resolver/AttributeResolver.h
- *
- * A service that transforms or resolves additional attributes for a
- * particular subject.
- */
-
-#ifndef __shibsp_resolver_h__
-#define __shibsp_resolver_h__
-
-#include <shibsp/base.h>
-
-#include <string>
-#include <vector>
-#include <xercesc/util/XercesDefs.hpp>
-#include <xmltooling/Lockable.h>
-
-namespace xmltooling {
-    class XMLTOOL_API GenericRequest;
-};
-
-namespace opensaml {
-    class SAML_API Assertion;
-    namespace saml2 {
-        class SAML_API NameID;
-    };
-    namespace saml2md {
-        class SAML_API EntityDescriptor;
-    };
-};
-
-namespace shibsp {
-
-    class SHIBSP_API Application;
-    class SHIBSP_API Attribute;
-    class SHIBSP_API Session;
-    class SHIBSP_API ResolutionContext;
-
-#if defined (_MSC_VER)
-    #pragma warning( push )
-    #pragma warning( disable : 4250 4251 )
-#endif
-
-    /**
-     * The service that resolves the attributes for a particular subject.
-     */
-    class SHIBSP_API AttributeResolver : public virtual xmltooling::Lockable
-    {
-        MAKE_NONCOPYABLE(AttributeResolver);
-    protected:
-        AttributeResolver();
-    public:
-        virtual ~AttributeResolver();
-
-        /**
-         * Creates a ResolutionContext based on session bootstrap material.
-         *
-         * <p>This enables resolution to occur ahead of session creation so that
-         * Attributes can be supplied while creating the session.
-         *
-         * @param application       reference to Application that owns the eventual Session
-         * @param request           request triggering the resolution, if any
-         * @param issuer            issuing metadata of assertion issuer, if known
-         * @param protocol          protocol used to establish Session
-         * @param nameid            principal identifier, normalized to SAML 2, if any
-         * @param authncontext_class    method/category of authentication event, if known
-         * @param authncontext_decl specifics of authentication event, if known
-         * @param tokens            assertions initiating the Session, if any
-         * @param attributes        array of previously resolved attributes, if any
-         * @return  newly created ResolutionContext, owned by caller
-         */
-        virtual ResolutionContext* createResolutionContext(
-            const Application& application,
-            const xmltooling::GenericRequest* request,
-            const opensaml::saml2md::EntityDescriptor* issuer,
-            const XMLCh* protocol,
-            const opensaml::saml2::NameID* nameid=nullptr,
-            const XMLCh* authncontext_class=nullptr,
-            const XMLCh* authncontext_decl=nullptr,
-            const std::vector<const opensaml::Assertion*>* tokens=nullptr,
-            const std::vector<Attribute*>* attributes=nullptr
-            ) const=0;
-
-        /**
-         * Creates a ResolutionContext for an existing Session.
-         *
-         * @param application   reference to Application that owns the Session
-         * @param session       reference to Session
-         * @return  newly created ResolutionContext, owned by caller
-         */
-        virtual ResolutionContext* createResolutionContext(const Application& application, const Session& session) const=0;
-
-
-        /**
-         * Resolves attributes for a given subject and returns them in the supplied context.
-         *
-         * @param ctx           resolution context to use to resolve attributes
-         *
-         * @throws AttributeResolutionException thrown if there is a problem resolving the attributes for the subject
-         */
-        virtual void resolveAttributes(ResolutionContext& ctx) const=0;
-
-        /**
-         * Populates an array with the set of Attribute IDs that might be generated.
-         *
-         * @param attributes    array to populate
-         */
-        virtual void getAttributeIds(std::vector<std::string>& attributes) const=0;
-    };
-
-#if defined (_MSC_VER)
-    #pragma warning( pop )
-#endif
-
-    /**
-     * Registers AttributeResolver classes into the runtime.
-     */
-    void SHIBSP_API registerAttributeResolvers();
-
-    /** AttributeResolver based on SAML queries to an IdP during SSO. */
-    #define QUERY_ATTRIBUTE_RESOLVER "Query"
-
-    /** AttributeResolver based on free-standing SAML queries to additional AAs. */
-    #define SIMPLEAGGREGATION_ATTRIBUTE_RESOLVER "SimpleAggregation"
-
-    /** AttributeResolver based on chaining together other resolvers. */
-    #define CHAINING_ATTRIBUTE_RESOLVER "Chaining"
-};
-
-#endif /* __shibsp_resolver_h__ */
diff --git a/shibsp/attribute/resolver/ResolutionContext.h b/shibsp/attribute/resolver/ResolutionContext.h
deleted file mode 100644
index aedb5da4..00000000
--- a/shibsp/attribute/resolver/ResolutionContext.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * 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
- *
- * 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.
- */
-
-/**
- * @file shibsp/attribute/resolver/ResolutionContext.h
- * 
- * A context for a resolution request.
- */
-
-#ifndef __shibsp_resctx_h__
-#define __shibsp_resctx_h__
-
-#include <shibsp/base.h>
-
-#include <vector>
-
-namespace opensaml {
-    class SAML_API Assertion;
-};
-
-namespace shibsp {
-
-    class SHIBSP_API Attribute;
-
-    /**
-     * A context for a resolution request.
-     */
-    class SHIBSP_API ResolutionContext
-    {
-        MAKE_NONCOPYABLE(ResolutionContext);
-    protected:
-        ResolutionContext();
-    public:
-        virtual ~ResolutionContext();
-        
-        /**
-         * Returns the set of Attributes resolved and added to the context.
-         * 
-         * <p>Any Attributes left in the returned container will be freed by the
-         * context, so the caller should modify/clear the container after copying
-         * objects for its own use.
-         * 
-         * @return  a mutable array of Attributes.
-         */
-        virtual std::vector<Attribute*>& getResolvedAttributes()=0;
-
-        /**
-         * Returns the set of assertions resolved and added to the context.
-         * 
-         * <p>Any assertions left in the returned container will be freed by the
-         * context, so the caller should modify/clear the container after copying
-         * objects for its own use.
-         * 
-         * @return  a mutable array of Assertions
-         */
-        virtual std::vector<opensaml::Assertion*>& getResolvedAssertions()=0;
-    };
-};
-
-#endif /* __shibsp_resctx_h__ */
diff --git a/shibsp/attribute/resolver/impl/AssertionAttributeExtractor.cpp b/shibsp/attribute/resolver/impl/AssertionAttributeExtractor.cpp
deleted file mode 100644
index 64d8136b..00000000
--- a/shibsp/attribute/resolver/impl/AssertionAttributeExtractor.cpp
+++ /dev/null
@@ -1,399 +0,0 @@
-/**
- * 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
- *
- * 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.
- */
-
-/**
- * AssertionAttributeExtractor.cpp
- *
- * AttributeExtractor for SAML assertion content.
- */
-
-#include "internal.h"
-#include "Application.h"
-#include "ServiceProvider.h"
-#include "attribute/SimpleAttribute.h"
-#include "attribute/resolver/AttributeExtractor.h"
-
-#include <saml/saml1/core/Assertions.h>
-#include <saml/saml2/core/Protocols.h>
-#include <saml/saml2/metadata/Metadata.h>
-#include <xmltooling/util/XMLHelper.h>
-#include <xercesc/util/XMLUniDefs.hpp>
-
-using namespace shibsp;
-using namespace opensaml::saml2;
-using namespace opensaml::saml2md;
-using namespace opensaml::saml1;
-using namespace opensaml;
-using namespace xmltooling;
-using namespace std;
-
-namespace shibsp {
-
-#if defined (_MSC_VER)
-    #pragma warning( push )
-    #pragma warning( disable : 4250 )
-#endif
-
-    class AssertionExtractor : public AttributeExtractor
-    {
-    public:
-        AssertionExtractor(const DOMElement* e);
-        ~AssertionExtractor() {}
-
-        Lockable* lock() {
-            return this;
-        }
-
-        void unlock() {
-        }
-
-        void extractAttributes(
-            const Application& application,
-            const GenericRequest* request,
-            const RoleDescriptor* issuer,
-            const XMLObject& xmlObject,
-            vector<shibsp::Attribute*>& attributes
-            ) const;
-        void getAttributeIds(vector<string>& attributes) const;
-
-    private:
-        string m_authnAuthority,
-            m_authnClass,
-            m_authnDecl,
-            m_authnInstant,
-            m_issuer,
-            m_issuerFormat,
-            m_notBefore,
-            m_notOnOrAfter,
-            m_sessionIndex,
-            m_sessionNotOnOrAfter,
-            m_subjectAddress,
-            m_subjectDNS,
-            m_consent;
-    };
-
-#if defined (_MSC_VER)
-    #pragma warning( pop )
-#endif
-
-    AttributeExtractor* SHIBSP_DLLLOCAL AssertionAttributeExtractorFactory(const DOMElement* const & e, bool)
-    {
-        return new AssertionExtractor(e);
-    }
-
-    static const XMLCh IssuerFormat[] = UNICODE_LITERAL_12(I,s,s,u,e,r,F,o,r,m,a,t);
-};
-
-AssertionExtractor::AssertionExtractor(const DOMElement* e)
-    : m_authnAuthority(XMLHelper::getAttrString(e, nullptr, AuthenticatingAuthority::LOCAL_NAME)),
-        m_authnClass(XMLHelper::getAttrString(e, nullptr, AuthnContextClassRef::LOCAL_NAME)),
-        m_authnDecl(XMLHelper::getAttrString(e, nullptr, AuthnContextDeclRef::LOCAL_NAME)),
-        m_authnInstant(XMLHelper::getAttrString(e, nullptr, AuthnStatement::AUTHNINSTANT_ATTRIB_NAME)),
-        m_issuer(XMLHelper::getAttrString(e, nullptr, Issuer::LOCAL_NAME)),
-        m_issuerFormat(XMLHelper::getAttrString(e, nullptr, IssuerFormat)),
-        m_notBefore(XMLHelper::getAttrString(e, nullptr, saml2::Conditions::NOTBEFORE_ATTRIB_NAME)),
-        m_notOnOrAfter(XMLHelper::getAttrString(e, nullptr, saml2::Conditions::NOTONORAFTER_ATTRIB_NAME)),
-        m_sessionIndex(XMLHelper::getAttrString(e, nullptr, AuthnStatement::SESSIONINDEX_ATTRIB_NAME)),
-        m_sessionNotOnOrAfter(XMLHelper::getAttrString(e, nullptr, AuthnStatement::SESSIONNOTONORAFTER_ATTRIB_NAME)),
-        m_subjectAddress(XMLHelper::getAttrString(e, nullptr, saml2::SubjectLocality::ADDRESS_ATTRIB_NAME)),
-        m_subjectDNS(XMLHelper::getAttrString(e, nullptr, saml2::SubjectLocality::DNSNAME_ATTRIB_NAME)),
-        m_consent(XMLHelper::getAttrString(e, nullptr, saml2p::StatusResponseType::CONSENT_ATTRIB_NAME))
-{
-}
-
-void AssertionExtractor::extractAttributes(
-    const Application& application, const GenericRequest* request, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<shibsp::Attribute*>& attributes
-    ) const
-{
-    const saml2p::StatusResponseType* srt = dynamic_cast<const saml2p::StatusResponseType*>(&xmlObject);
-    if (srt) {
-        // Consent
-        if (!m_consent.empty() && srt->getConsent()) {
-            auto_ptr_char temp(srt->getConsent());
-            if (temp.get() && *temp.get()) {
-                auto_ptr<SimpleAttribute> consent(new SimpleAttribute(vector<string>(1, m_consent)));
-                consent->getValues().push_back(temp.get());
-                attributes.push_back(consent.get());
-                consent.release();
-            }
-        }
-        return;
-    }
-
-    const saml2::Assertion* saml2assertion = dynamic_cast<const saml2::Assertion*>(&xmlObject);
-    if (saml2assertion) {
-
-        if (saml2assertion->getIssuer()) {
-            // Issuer
-            if (!m_issuer.empty()) {
-                auto_ptr_char temp(saml2assertion->getIssuer()->getName());
-                if (temp.get() && *temp.get()) {
-                    auto_ptr<SimpleAttribute> issuer(new SimpleAttribute(vector<string>(1, m_issuer)));
-                    issuer->getValues().push_back(temp.get());
-                    attributes.push_back(issuer.get());
-                    issuer.release();
-                }
-            }
-
-            // Format
-            if (!m_issuerFormat.empty()) {
-                auto_ptr_char temp(saml2assertion->getIssuer()->getFormat());
-                if (temp.get()) {
-                    auto_ptr<SimpleAttribute> format(new SimpleAttribute(vector<string>(1, m_issuerFormat)));
-                    format->getValues().push_back(temp.get());
-                    attributes.push_back(format.get());
-                    format.release();
-                }
-            }
-        }
-
-        // NotBefore / NotOnOrAfter
-        if (saml2assertion->getConditions()) {
-            if (!m_notBefore.empty() && saml2assertion->getConditions()->getNotBefore()) {
-                auto_ptr_char temp(saml2assertion->getConditions()->getNotBefore()->getRawData());
-                if (temp.get()) {
-                    auto_ptr<SimpleAttribute> notbefore(new SimpleAttribute(vector<string>(1, m_notBefore)));
-                    notbefore->getValues().push_back(temp.get());
-                    attributes.push_back(notbefore.get());
-                    notbefore.release();
-                }
-            }
-            if (!m_notOnOrAfter.empty() && saml2assertion->getConditions()->getNotOnOrAfter()) {
-                auto_ptr_char temp(saml2assertion->getConditions()->getNotOnOrAfter()->getRawData());
-                if (temp.get()) {
-                    auto_ptr<SimpleAttribute> notonorafter(new SimpleAttribute(vector<string>(1, m_notOnOrAfter)));
-                    notonorafter->getValues().push_back(temp.get());
-                    attributes.push_back(notonorafter.get());
-                    notonorafter.release();
-                }
-            }
-        }
-
-        return;
-    }
-
-    const AuthnStatement* saml2statement = dynamic_cast<const AuthnStatement*>(&xmlObject);
-    if (saml2statement) {
-        // AuthnInstant
-        if (!m_authnInstant.empty() && saml2statement->getAuthnInstant()) {
-            auto_ptr_char temp(saml2statement->getAuthnInstant()->getRawData());
-            if (temp.get()) {
-                auto_ptr<SimpleAttribute> authninstant(new SimpleAttribute(vector<string>(1, m_authnInstant)));
-                authninstant->getValues().push_back(temp.get());
-                attributes.push_back(authninstant.get());
-                authninstant.release();
-            }
-        }
-
-        // SessionIndex
-        if (!m_sessionIndex.empty() && saml2statement->getSessionIndex() && *(saml2statement->getSessionIndex())) {
-            auto_ptr_char temp(saml2statement->getSessionIndex());
-            if (temp.get()) {
-                auto_ptr<SimpleAttribute> sessionindex(new SimpleAttribute(vector<string>(1, m_sessionIndex)));
-                sessionindex->getValues().push_back(temp.get());
-                attributes.push_back(sessionindex.get());
-                sessionindex.release();
-            }
-        }
-
-        // SessionNotOnOrAfter
-        if (!m_sessionNotOnOrAfter.empty() && saml2statement->getSessionNotOnOrAfter()) {
-            auto_ptr_char temp(saml2statement->getSessionNotOnOrAfter()->getRawData());
-            if (temp.get()) {
-                auto_ptr<SimpleAttribute> sessionnotonorafter(new SimpleAttribute(vector<string>(1, m_sessionNotOnOrAfter)));
-                sessionnotonorafter->getValues().push_back(temp.get());
-                attributes.push_back(sessionnotonorafter.get());
-                sessionnotonorafter.release();
-            }
-        }
-
-        if (saml2statement->getSubjectLocality()) {
-            const saml2::SubjectLocality* locality = saml2statement->getSubjectLocality();
-            // Address
-            if (!m_subjectAddress.empty() && locality->getAddress() && *(locality->getAddress())) {
-                auto_ptr_char temp(locality->getAddress());
-                if (temp.get()) {
-                    auto_ptr<SimpleAttribute> address(new SimpleAttribute(vector<string>(1, m_subjectAddress)));
-                    address->getValues().push_back(temp.get());
-                    attributes.push_back(address.get());
-                    address.release();
-                }
-            }
-
-            // DNSName
-            if (!m_subjectDNS.empty() && locality->getDNSName() && *(locality->getDNSName())) {
-                auto_ptr_char temp(locality->getDNSName());
-                if (temp.get()) {
-                    auto_ptr<SimpleAttribute> dns(new SimpleAttribute(vector<string>(1, m_subjectDNS)));
-                    dns->getValues().push_back(temp.get());
-                    attributes.push_back(dns.get());
-                    dns.release();
-                }
-            }
-        }
-
-        if (saml2statement->getAuthnContext()) {
-            const AuthnContext* ac = saml2statement->getAuthnContext();
-            // AuthnContextClassRef
-            if (!m_authnClass.empty() && ac->getAuthnContextClassRef() && ac->getAuthnContextClassRef()->getReference()) {
-                auto_ptr_char temp(ac->getAuthnContextClassRef()->getReference());
-                if (temp.get()) {
-                    auto_ptr<SimpleAttribute> classref(new SimpleAttribute(vector<string>(1, m_authnClass)));
-                    classref->getValues().push_back(temp.get());
-                    attributes.push_back(classref.get());
-                    classref.release();
-                }
-            }
-
-            // AuthnContextDeclRef
-            if (!m_authnDecl.empty() && ac->getAuthnContextDeclRef() && ac->getAuthnContextDeclRef()->getReference()) {
-                auto_ptr_char temp(ac->getAuthnContextDeclRef()->getReference());
-                if (temp.get()) {
-                    auto_ptr<SimpleAttribute> declref(new SimpleAttribute(vector<string>(1, m_authnDecl)));
-                    declref->getValues().push_back(temp.get());
-                    attributes.push_back(declref.get());
-                    declref.release();
-                }
-            }
-
-            // AuthenticatingAuthority
-            if (!m_authnAuthority.empty() && !ac->getAuthenticatingAuthoritys().empty()) {
-                auto_ptr<SimpleAttribute> attr(new SimpleAttribute(vector<string>(1, m_authnAuthority)));
-                const vector<AuthenticatingAuthority*>& authorities = ac->getAuthenticatingAuthoritys();
-                for (vector<AuthenticatingAuthority*>::const_iterator a = authorities.begin(); a != authorities.end(); ++a) {
-                    auto_ptr_char temp((*a)->getID());
-                    if (temp.get())
-                        attr->getValues().push_back(temp.get());
-                }
-                if (attr->valueCount() > 0) {
-                    attributes.push_back(attr.get());
-                    attr.release();
-                }
-            }
-        }
-
-        return;
-    }
-
-    const saml1::Assertion* saml1assertion = dynamic_cast<const saml1::Assertion*>(&xmlObject);
-    if (saml1assertion) {
-        // Issuer
-        if (!m_issuer.empty()) {
-            if (saml1assertion->getIssuer() && *(saml1assertion->getIssuer())) {
-                auto_ptr_char temp(saml1assertion->getIssuer());
-                if (temp.get()) {
-                    auto_ptr<SimpleAttribute> issuer(new SimpleAttribute(vector<string>(1, m_issuer)));
-                    issuer->getValues().push_back(temp.get());
-                    attributes.push_back(issuer.get());
-                    issuer.release();
-                }
-            }
-        }
-
-        // NotOnOrAfter
-        if (!m_notOnOrAfter.empty() && saml1assertion->getConditions() && saml1assertion->getConditions()->getNotOnOrAfter()) {
-            auto_ptr_char temp(saml1assertion->getConditions()->getNotOnOrAfter()->getRawData());
-            if (temp.get()) {
-                auto_ptr<SimpleAttribute> notonorafter(new SimpleAttribute(vector<string>(1, m_notOnOrAfter)));
-                notonorafter->getValues().push_back(temp.get());
-                attributes.push_back(notonorafter.get());
-                notonorafter.release();
-            }
-        }
-
-        return;
-    }
-
-    const AuthenticationStatement* saml1statement = dynamic_cast<const AuthenticationStatement*>(&xmlObject);
-    if (saml1statement) {
-        // AuthnInstant
-        if (!m_authnInstant.empty() && saml1statement->getAuthenticationInstant()) {
-            auto_ptr_char temp(saml1statement->getAuthenticationInstant()->getRawData());
-            if (temp.get()) {
-                auto_ptr<SimpleAttribute> authninstant(new SimpleAttribute(vector<string>(1, m_authnInstant)));
-                authninstant->getValues().push_back(temp.get());
-                attributes.push_back(authninstant.get());
-                authninstant.release();
-            }
-        }
-
-        // AuthenticationMethod
-        if (!m_authnClass.empty() && saml1statement->getAuthenticationMethod() && *(saml1statement->getAuthenticationMethod())) {
-            auto_ptr_char temp(saml1statement->getAuthenticationMethod());
-            if (temp.get()) {
-                auto_ptr<SimpleAttribute> authnmethod(new SimpleAttribute(vector<string>(1, m_authnClass)));
-                authnmethod->getValues().push_back(temp.get());
-                attributes.push_back(authnmethod.get());
-                authnmethod.release();
-            }
-        }
-
-        if (saml1statement->getSubjectLocality()) {
-            const saml1::SubjectLocality* locality = saml1statement->getSubjectLocality();
-            // IPAddress
-            if (!m_subjectAddress.empty() && locality->getIPAddress() && *(locality->getIPAddress())) {
-                auto_ptr_char temp(locality->getIPAddress());
-                if (temp.get()) {
-                    auto_ptr<SimpleAttribute> address(new SimpleAttribute(vector<string>(1, m_subjectAddress)));
-                    address->getValues().push_back(temp.get());
-                    attributes.push_back(address.get());
-                    address.release();
-                }
-            }
-
-            // DNSAddress
-            if (!m_subjectDNS.empty() && locality->getDNSAddress() && *(locality->getDNSAddress())) {
-                auto_ptr_char temp(locality->getDNSAddress());
-                if (temp.get()) {
-                    auto_ptr<SimpleAttribute> dns(new SimpleAttribute(vector<string>(1, m_subjectDNS)));
-                    dns->getValues().push_back(temp.get());
-                    attributes.push_back(dns.get());
-                    dns.release();
-                }
-            }
-        }
-    }
-}
-
-void AssertionExtractor::getAttributeIds(vector<string>& attributes) const
-{
-    if (!m_authnAuthority.empty())
-        attributes.push_back(m_authnAuthority);
-    if (!m_authnClass.empty())
-        attributes.push_back(m_authnClass);
-    if (!m_authnDecl.empty())
-        attributes.push_back(m_authnDecl);
-    if (!m_authnInstant.empty())
-        attributes.push_back(m_authnInstant);
-    if (!m_issuer.empty())
-        attributes.push_back(m_issuer);
-    if (!m_notOnOrAfter.empty())
-        attributes.push_back(m_notOnOrAfter);
-    if (!m_sessionIndex.empty())
-        attributes.push_back(m_sessionIndex);
-    if (!m_sessionNotOnOrAfter.empty())
-        attributes.push_back(m_sessionNotOnOrAfter);
-    if (!m_subjectAddress.empty())
-        attributes.push_back(m_subjectAddress);
-    if (!m_subjectDNS.empty())
-        attributes.push_back(m_subjectDNS);
-    if (!m_consent.empty())
-        attributes.push_back(m_consent);
-}
diff --git a/shibsp/attribute/resolver/impl/ChainingAttributeExtractor.cpp b/shibsp/attribute/resolver/impl/ChainingAttributeExtractor.cpp
deleted file mode 100644
index 07a7d4ff..00000000
--- a/shibsp/attribute/resolver/impl/ChainingAttributeExtractor.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/**
- * 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
- *
- * 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.
- */
-
-/**
- * ChainingAttributeExtractor.cpp
- *
- * Chains together multiple AttributeExtractor plugins.
- */
-
-#include "internal.h"
-#include "Application.h"
-#include "ServiceProvider.h"
-#include "attribute/Attribute.h"
-#include "attribute/resolver/AttributeExtractor.h"
-
-#include <boost/ptr_container/ptr_vector.hpp>
-#include <xercesc/util/XMLUniDefs.hpp>
-#include <xmltooling/util/XMLHelper.h>
-
-using namespace shibsp;
-using namespace opensaml::saml2md;
-using namespace xmltooling;
-using namespace boost;
-using namespace std;
-
-namespace shibsp {
-
-    class SHIBSP_DLLLOCAL ChainingAttributeExtractor : public AttributeExtractor
-    {
-    public:
-        ChainingAttributeExtractor(const DOMElement* e, bool deprecationSupport=true);
-        virtual ~ChainingAttributeExtractor() {}
-
-        Lockable* lock() {
-            return this;
-        }
-        void unlock() {
-        }
-
-        void extractAttributes(
-            const Application& application,
-            const GenericRequest* request,
-            const RoleDescriptor* issuer,
-            const XMLObject& xmlObject,
-            vector<Attribute*>& attributes
-            ) const {
-            for (ptr_vector<AttributeExtractor>::iterator i = m_extractors.begin(); i != m_extractors.end(); ++i) {
-                Locker locker(&(*i));
-                i->extractAttributes(application, request, issuer, xmlObject, attributes);
-            }
-        }
-
-        void getAttributeIds(vector<string>& attributes) const {
-            for (ptr_vector<AttributeExtractor>::iterator i = m_extractors.begin(); i != m_extractors.end(); ++i) {
-                Locker locker(&(*i));
-                i->getAttributeIds(attributes);
-            }
-        }
-
-        void generateMetadata(SPSSODescriptor& role) const {
-            for (ptr_vector<AttributeExtractor>::iterator i = m_extractors.begin(); i != m_extractors.end(); ++i) {
-                Locker locker(&(*i));
-                i->generateMetadata(role);
-            }
-        }
-
-    private:
-        mutable ptr_vector<AttributeExtractor> m_extractors;
-    };
-
-    static const XMLCh _AttributeExtractor[] =  UNICODE_LITERAL_18(A,t,t,r,i,b,u,t,e,E,x,t,r,a,c,t,o,r);
-    static const XMLCh _type[] =                UNICODE_LITERAL_4(t,y,p,e);
-
-    SHIBSP_DLLLOCAL PluginManager<AttributeExtractor,string,const DOMElement*>::Factory AssertionAttributeExtractorFactory;
-    SHIBSP_DLLLOCAL PluginManager<AttributeExtractor,string,const DOMElement*>::Factory MetadataAttributeExtractorFactory;
-    SHIBSP_DLLLOCAL PluginManager<AttributeExtractor,string,const DOMElement*>::Factory DelegationAttributeExtractorFactory;
-    SHIBSP_DLLLOCAL PluginManager<AttributeExtractor,string,const DOMElement*>::Factory KeyDescriptorAttributeExtractorFactory;
-    SHIBSP_DLLLOCAL PluginManager<AttributeExtractor,string,const DOMElement*>::Factory XMLAttributeExtractorFactory;
-
-    AttributeExtractor* SHIBSP_DLLLOCAL ChainingExtractorFactory(const DOMElement* const & e, bool deprecationSupport)
-    {
-        return new ChainingAttributeExtractor(e, deprecationSupport);
-    }
-};
-
-void SHIBSP_API shibsp::registerAttributeExtractors()
-{
-    SPConfig::getConfig().AttributeExtractorManager.registerFactory(ASSERTION_ATTRIBUTE_EXTRACTOR, AssertionAttributeExtractorFactory);
-    SPConfig::getConfig().AttributeExtractorManager.registerFactory(METADATA_ATTRIBUTE_EXTRACTOR, MetadataAttributeExtractorFactory);
-    SPConfig::getConfig().AttributeExtractorManager.registerFactory(DELEGATION_ATTRIBUTE_EXTRACTOR, DelegationAttributeExtractorFactory);
-    SPConfig::getConfig().AttributeExtractorManager.registerFactory(KEYDESCRIPTOR_ATTRIBUTE_EXTRACTOR, KeyDescriptorAttributeExtractorFactory);
-    SPConfig::getConfig().AttributeExtractorManager.registerFactory(XML_ATTRIBUTE_EXTRACTOR, XMLAttributeExtractorFactory);
-    SPConfig::getConfig().AttributeExtractorManager.registerFactory(CHAINING_ATTRIBUTE_EXTRACTOR, ChainingExtractorFactory);
-}
-
-AttributeExtractor::AttributeExtractor()
-{
-}
-
-AttributeExtractor::~AttributeExtractor()
-{
-}
-
-void AttributeExtractor::generateMetadata(SPSSODescriptor& role) const
-{
-}
-
-ChainingAttributeExtractor::ChainingAttributeExtractor(const DOMElement* e, bool deprecationSupport)
-{
-    SPConfig& conf = SPConfig::getConfig();
-
-    // Load up the chain of handlers.
-    e = XMLHelper::getFirstChildElement(e, _AttributeExtractor);
-    while (e) {
-        string t(XMLHelper::getAttrString(e, nullptr, _type));
-        if (!t.empty()) {
-            try {
-                Category::getInstance(SHIBSP_LOGCAT ".AttributeExtractor.Chaining").info(
-                    "building AttributeExtractor of type (%s)...", t.c_str()
-                    );
-                auto_ptr<AttributeExtractor> np(conf.AttributeExtractorManager.newPlugin(t.c_str(), e, deprecationSupport));
-                m_extractors.push_back(np.get());
-                np.release();
-            }
-            catch (const exception& ex) {
-                Category::getInstance(SHIBSP_LOGCAT ".AttributeExtractor.Chaining").error(
-                    "caught exception processing embedded AttributeExtractor element: %s", ex.what()
-                    );
-            }
-        }
-        e = XMLHelper::getNextSiblingElement(e, _AttributeExtractor);
-    }
-}
diff --git a/shibsp/attribute/resolver/impl/ChainingAttributeResolver.cpp b/shibsp/attribute/resolver/impl/ChainingAttributeResolver.cpp
deleted file mode 100644
index c9b5b78a..00000000
--- a/shibsp/attribute/resolver/impl/ChainingAttributeResolver.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/**
- * 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
- *
- * 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.
- */
-
-/**
- * ChainingAttributeResolver.cpp
- *
- * Chains together multiple AttributeResolver plugins.
- */
-
-#include "internal.h"
-#include "exceptions.h"
-#include "Application.h"
-#include "ServiceProvider.h"
-#include "attribute/Attribute.h"
-#include "attribute/resolver/AttributeResolver.h"
-#include "attribute/resolver/ResolutionContext.h"
-
-#include <boost/ptr_container/ptr_vector.hpp>
-#include <xercesc/util/XMLUniDefs.hpp>
-#include <saml/Assertion.h>
-#include <xmltooling/util/XMLHelper.h>
-
-using namespace shibsp;
-using namespace opensaml::saml2;
-using namespace opensaml::saml2md;
-using namespace xmltooling;
-using namespace boost;
-using namespace std;
-
-namespace shibsp {
-
-    struct SHIBSP_DLLLOCAL ChainingContext : public ResolutionContext
-    {
-        ChainingContext(
-            const Application& application,
-            const GenericRequest* request,
-            const EntityDescriptor* issuer,
-            const XMLCh* protocol,
-            const NameID* nameid,
-            const XMLCh* authncontext_class,
-            const XMLCh* authncontext_decl,
-            const vector<const opensaml::Assertion*>* tokens,
-            const vector<shibsp::Attribute*>* attributes
-            ) : m_app(application), m_request(request), m_issuer(issuer), m_protocol(protocol), m_nameid(nameid),
-                m_authclass(authncontext_class), m_authdecl(authncontext_decl), m_session(nullptr) {
-            if (tokens)
-                m_tokens.assign(tokens->begin(), tokens->end());
-            if (attributes)
-                m_attributes.assign(attributes->begin(), attributes->end());
-        }
-
-        ChainingContext(const Application& application, const Session& session)
-            : m_app(application), m_request(nullptr), m_issuer(nullptr), m_protocol(nullptr), m_nameid(nullptr),
-                m_authclass(nullptr), m_authdecl(nullptr), m_session(&session) {
-        }
-
-        ~ChainingContext() {
-            for_each(m_ownedAttributes.begin(), m_ownedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
-            for_each(m_ownedAssertions.begin(), m_ownedAssertions.end(), xmltooling::cleanup<opensaml::Assertion>());
-        }
-
-        vector<shibsp::Attribute*>& getResolvedAttributes() {
-            return m_ownedAttributes;
-        }
-        vector<opensaml::Assertion*>& getResolvedAssertions() {
-            return m_ownedAssertions;
-        }
-
-        vector<shibsp::Attribute*> m_ownedAttributes;
-        vector<opensaml::Assertion*> m_ownedAssertions;
-
-        const Application& m_app;
-        const GenericRequest* m_request;
-        const EntityDescriptor* m_issuer;
-        const XMLCh* m_protocol;
-        const NameID* m_nameid;
-        const XMLCh* m_authclass;
-        const XMLCh* m_authdecl;
-        vector<const opensaml::Assertion*> m_tokens;
-        vector<shibsp::Attribute*> m_attributes;
-
-        const Session* m_session;
-    };
-
-    class SHIBSP_DLLLOCAL ChainingAttributeResolver : public AttributeResolver
-    {
-    public:
-        ChainingAttributeResolver(const DOMElement* e, bool deprecationSupport=true);
-        virtual ~ChainingAttributeResolver() {}
-
-        Lockable* lock() {
-            return this;
-        }
-        void unlock() {
-        }
-
-        ResolutionContext* createResolutionContext(
-            const Application& application,
-            const GenericRequest* request,
-            const EntityDescriptor* issuer,
-            const XMLCh* protocol,
-            const NameID* nameid=nullptr,
-            const XMLCh* authncontext_class=nullptr,
-            const XMLCh* authncontext_decl=nullptr,
-            const vector<const opensaml::Assertion*>* tokens=nullptr,
-            const vector<shibsp::Attribute*>* attributes=nullptr
-            ) const {
-            return new ChainingContext(application, request, issuer, protocol, nameid, authncontext_class, authncontext_decl, tokens, attributes);
-        }
-
-        ResolutionContext* createResolutionContext(const Application& application, const Session& session) const {
-            return new ChainingContext(application, session);
-        }
-
-        void resolveAttributes(ResolutionContext& ctx) const;
-
-        void getAttributeIds(vector<string>& attributes) const {
-            for (ptr_vector<AttributeResolver>::iterator i = m_resolvers.begin(); i != m_resolvers.end(); ++i) {
-                Locker locker(&(*i));
-                i->getAttributeIds(attributes);
-            }
-        }
-
-    private:
-        mutable ptr_vector<AttributeResolver> m_resolvers;
-        bool m_failFast;
-    };
-
-    static const XMLCh _AttributeResolver[] =   UNICODE_LITERAL_17(A,t,t,r,i,b,u,t,e,R,e,s,o,l,v,e,r);
-    static const XMLCh failFast[] =             UNICODE_LITERAL_8(f,a,i,l,F,a,s,t);
-    static const XMLCh _type[] =                UNICODE_LITERAL_4(t,y,p,e);
-
-    SHIBSP_DLLLOCAL PluginManager<AttributeResolver,string,const DOMElement*>::Factory QueryResolverFactory;
-    SHIBSP_DLLLOCAL PluginManager<AttributeResolver,string,const DOMElement*>::Factory SimpleAggregationResolverFactory;
-
-    AttributeResolver* SHIBSP_DLLLOCAL ChainingResolverFactory(const DOMElement* const & e, bool deprecationSupport)
-    {
-        return new ChainingAttributeResolver(e, deprecationSupport);
-    }
-};
-
-void SHIBSP_API shibsp::registerAttributeResolvers()
-{
-    SPConfig::getConfig().AttributeResolverManager.registerFactory(QUERY_ATTRIBUTE_RESOLVER, QueryResolverFactory);
-    SPConfig::getConfig().AttributeResolverManager.registerFactory(SIMPLEAGGREGATION_ATTRIBUTE_RESOLVER, SimpleAggregationResolverFactory);
-    SPConfig::getConfig().AttributeResolverManager.registerFactory(CHAINING_ATTRIBUTE_RESOLVER, ChainingResolverFactory);
-}
-
-ResolutionContext::ResolutionContext()
-{
-}
-
-ResolutionContext::~ResolutionContext()
-{
-}
-
-AttributeResolver::AttributeResolver()
-{
-}
-
-AttributeResolver::~AttributeResolver()
-{
-}
-
-ChainingAttributeResolver::ChainingAttributeResolver(const DOMElement* e, bool deprecationSupport)
-    : m_failFast(XMLHelper::getAttrBool(e, false, failFast))
-{
-    SPConfig& conf = SPConfig::getConfig();
-
-    // Load up the chain of handlers.
-    e = XMLHelper::getFirstChildElement(e, _AttributeResolver);
-    while (e) {
-        string t(XMLHelper::getAttrString(e, nullptr, _type));
-        if (!t.empty()) {
-            try {
-                Category::getInstance(SHIBSP_LOGCAT ".AttributeResolver." CHAINING_ATTRIBUTE_RESOLVER).info(
-                    "building AttributeResolver of type (%s)...", t.c_str()
-                    );
-                auto_ptr<AttributeResolver> np(conf.AttributeResolverManager.newPlugin(t.c_str(), e, deprecationSupport));
-                m_resolvers.push_back(np.get());
-                np.release();
-            }
-            catch (const exception& ex) {
-                Category::getInstance(SHIBSP_LOGCAT ".AttributeResolver." CHAINING_ATTRIBUTE_RESOLVER).error(
-                    "caught exception processing embedded AttributeResolver element: %s", ex.what()
-                    );
-            }
-        }
-        e = XMLHelper::getNextSiblingElement(e, _AttributeResolver);
-    }
-}
-
-void ChainingAttributeResolver::resolveAttributes(ResolutionContext& ctx) const
-{
-    ChainingContext& chain = dynamic_cast<ChainingContext&>(ctx);
-    for (ptr_vector<AttributeResolver>::iterator i = m_resolvers.begin(); i != m_resolvers.end(); ++i) {
-        try {
-            Locker locker(&(*i));
-            scoped_ptr<ResolutionContext> context(
-                chain.m_session ?
-                    i->createResolutionContext(chain.m_app, *chain.m_session) :
-                    i->createResolutionContext(
-                        chain.m_app, chain.m_request, chain.m_issuer, chain.m_protocol, chain.m_nameid, chain.m_authclass, chain.m_authdecl, &chain.m_tokens, &chain.m_attributes
-                        )
-                );
-
-            i->resolveAttributes(*context);
-
-            chain.m_attributes.insert(chain.m_attributes.end(), context->getResolvedAttributes().begin(), context->getResolvedAttributes().end());
-            chain.m_ownedAttributes.insert(chain.m_ownedAttributes.end(), context->getResolvedAttributes().begin(), context->getResolvedAttributes().end());
-            context->getResolvedAttributes().clear();
-
-            chain.m_tokens.insert(chain.m_tokens.end(), context->getResolvedAssertions().begin(), context->getResolvedAssertions().end());
-            chain.m_ownedAssertions.insert(chain.m_ownedAssertions.end(), context->getResolvedAssertions().begin(), context->getResolvedAssertions().end());
-            context->getResolvedAssertions().clear();
-        }
-        catch (const exception& ex) {
-            Category::getInstance(SHIBSP_LOGCAT ".AttributeResolver." CHAINING_ATTRIBUTE_RESOLVER).error(
-                "caught exception applying AttributeResolver in chain: %s", ex.what()
-                );
-            if (failFast)
-                throw;
-        }
-    }
-}
diff --git a/shibsp/attribute/resolver/impl/DelegationAttributeExtractor.cpp b/shibsp/attribute/resolver/impl/DelegationAttributeExtractor.cpp
deleted file mode 100644
index 2b9d8413..00000000
--- a/shibsp/attribute/resolver/impl/DelegationAttributeExtractor.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/**
- * 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
- *
- * 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.
- */
-
-/**
- * DelegationAttributeExtractor.cpp
- *
- * AttributeExtractor for DelegationRestriction information.
- */
-
-#include "internal.h"
-#include "Application.h"
-#include "ServiceProvider.h"
-#include "attribute/ExtensibleAttribute.h"
-#include "attribute/resolver/AttributeExtractor.h"
-#include "util/SPConstants.h"
-
-#include <boost/shared_ptr.hpp>
-#include <boost/iterator/indirect_iterator.hpp>
-#include <saml/saml2/core/Assertions.h>
-#include <saml/saml2/metadata/Metadata.h>
-#include <saml/saml2/metadata/MetadataCredentialCriteria.h>
-#include <xmltooling/security/CredentialResolver.h>
-#include <xmltooling/util/XMLHelper.h>
-#include <xercesc/util/XMLUniDefs.hpp>
-
-using namespace shibsp;
-using namespace opensaml::saml2md;
-using namespace opensaml;
-using namespace xmltooling;
-using namespace boost;
-using namespace std;
-
-namespace shibsp {
-
-#if defined (_MSC_VER)
-    #pragma warning( push )
-    #pragma warning( disable : 4250 )
-#endif
-
-    class DelegationExtractor : public AttributeExtractor
-    {
-    public:
-        DelegationExtractor(const DOMElement* e);
-        ~DelegationExtractor() {}
-
-        Lockable* lock() {
-            return this;
-        }
-
-        void unlock() {
-        }
-
-        void extractAttributes(
-            const Application& application, const GenericRequest* request, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<Attribute*>& attributes
-            ) const;
-
-        void getAttributeIds(std::vector<std::string>& attributes) const {
-            attributes.push_back(m_attributeId);
-        }
-
-    private:
-        string m_attributeId,m_formatter;
-    };
-
-#if defined (_MSC_VER)
-    #pragma warning( pop )
-#endif
-
-    AttributeExtractor* SHIBSP_DLLLOCAL DelegationAttributeExtractorFactory(const DOMElement* const & e, bool)
-    {
-        return new DelegationExtractor(e);
-    }
-
-    static const XMLCh attributeId[] =  UNICODE_LITERAL_11(a,t,t,r,i,b,u,t,e,I,d);
-    static const XMLCh formatter[] =    UNICODE_LITERAL_9(f,o,r,m,a,t,t,e,r);
-};
-
-DelegationExtractor::DelegationExtractor(const DOMElement* e)
-    : m_attributeId(XMLHelper::getAttrString(e, "delegate", attributeId)),
-        m_formatter(XMLHelper::getAttrString(e, "$Name", formatter))
-{
-}
-
-void DelegationExtractor::extractAttributes(
-    const Application& application, const GenericRequest* request, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<Attribute*>& attributes
-    ) const
-{
-    const saml2::Assertion* assertion = dynamic_cast<const saml2::Assertion*>(&xmlObject);
-    if (!assertion || !assertion->getConditions())
-        return;
-
-    Category& log = Category::getInstance(SHIBSP_LOGCAT ".AttributeExtractor.Delegation");
-
-    const vector<saml2::Condition*>& conditions = const_cast<const saml2::Conditions*>(assertion->getConditions())->getConditions();
-    for (vector<saml2::Condition*>::const_iterator c = conditions.begin(); c != conditions.end(); ++c) {
-        const saml2::DelegationRestrictionType* drt = dynamic_cast<const saml2::DelegationRestrictionType*>(*c);
-        if (drt) {
-            auto_ptr<ExtensibleAttribute> attr(new ExtensibleAttribute(vector<string>(1,m_attributeId), m_formatter.c_str()));
-
-            const vector<saml2::Delegate*>& dels = drt->getDelegates();
-            for (indirect_iterator<vector<saml2::Delegate*>::const_iterator> d = make_indirect_iterator(dels.begin());
-                    d != make_indirect_iterator(dels.end()); ++d) {
-                if (d->getBaseID()) {
-                    log.error("delegate identified by saml:BaseID cannot be processed into an attribute value");
-                    continue;
-                }
-
-                saml2::NameID* n = nullptr;
-                boost::shared_ptr<saml2::NameID> namewrapper;
-                if (d->getEncryptedID()) {
-                    CredentialResolver* cr = application.getCredentialResolver();
-                    if (!cr) {
-                        log.warn("found encrypted Delegate, but no CredentialResolver was available");
-                    }
-
-                    try {
-                        const XMLCh* recipient = application.getRelyingParty(
-                            issuer ? dynamic_cast<EntityDescriptor*>(issuer->getParent()) : nullptr
-                            )->getXMLString("entityID").second;
-                        Locker credlocker(cr);
-                        if (issuer) {
-                            MetadataCredentialCriteria mcc(*issuer);
-                            boost::shared_ptr<XMLObject> decrypted(d->getEncryptedID()->decrypt(*cr, recipient, &mcc));
-                            namewrapper = dynamic_pointer_cast<saml2::NameID>(decrypted);
-                            n = namewrapper.get();
-                        }
-                        else {
-                            boost::shared_ptr<XMLObject> decrypted(d->getEncryptedID()->decrypt(*cr, recipient));
-                            namewrapper = dynamic_pointer_cast<saml2::NameID>(decrypted);
-                            n = namewrapper.get();
-                        }
-                        if (n && log.isDebugEnabled())
-                            log.debugStream() << "decrypted Delegate: " << *n << logging::eol;
-                    }
-                    catch (std::exception& ex) {
-                        log.error("caught exception decrypting Delegate: %s", ex.what());
-                    }
-                }
-                else {
-                    n = d->getNameID();
-                }
-
-                if (n) {
-                    DDF val = DDF(nullptr).structure();
-                    if (d->getConfirmationMethod()) {
-                        auto_ptr_char temp(d->getConfirmationMethod());
-                        val.addmember("ConfirmationMethod").string(temp.get());
-                    }
-                    if (d->getDelegationInstant()) {
-                        auto_ptr_char temp(d->getDelegationInstant()->getRawData());
-                        val.addmember("DelegationInstant").string(temp.get());
-                    }
-
-                    auto_arrayptr<char> name(toUTF8(n->getName()));
-                    if (name.get() && *name.get()) {
-                        val.addmember("Name").string(name.get());
-                        auto_arrayptr<char> format(toUTF8(n->getFormat()));
-                        if (format.get())
-                            val.addmember("Format").string(format.get());
-
-                        auto_arrayptr<char> nq(toUTF8(n->getNameQualifier()));
-                        if (nq.get())
-                            val.addmember("NameQualifier").string(nq.get());
-
-                        auto_arrayptr<char> spnq(toUTF8(n->getSPNameQualifier()));
-                        if (spnq.get())
-                            val.addmember("SPNameQualifier").string(spnq.get());
-
-                        auto_arrayptr<char> sppid(toUTF8(n->getSPProvidedID()));
-                        if (sppid.get())
-                            val.addmember("SPProvidedID").string(sppid.get());
-                    }
-
-                    if (val.integer())
-                        attr->getValues().add(val);
-                    else
-                        val.destroy();
-                }
-            }
-
-            attributes.push_back(attr.get());
-            attr.release();
-        }
-    }
-}
diff --git a/shibsp/attribute/resolver/impl/KeyDescriptorAttributeExtractor.cpp b/shibsp/attribute/resolver/impl/KeyDescriptorAttributeExtractor.cpp
deleted file mode 100644
index 370321d2..00000000
--- a/shibsp/attribute/resolver/impl/KeyDescriptorAttributeExtractor.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-/**
- * 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
- *
- * 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.
- */
-
-/**
- * KeyDescriptorAttributeExtractor.cpp
- *
- * AttributeExtractor for KeyDescriptor information.
- */
-
-#include "internal.h"
-#include "exceptions.h"
-#include "Application.h"
-#include "attribute/AttributeDecoder.h"
-#include "attribute/SimpleAttribute.h"
-#include "attribute/resolver/AttributeExtractor.h"
-
-#include <boost/iterator/indirect_iterator.hpp>
-#include <saml/saml2/metadata/Metadata.h>
-#include <saml/saml2/metadata/MetadataCredentialCriteria.h>
-#include <saml/saml2/metadata/MetadataProvider.h>
-#include <xmltooling/security/Credential.h>
-#include <xmltooling/security/SecurityHelper.h>
-#include <xmltooling/util/XMLHelper.h>
-#include <xercesc/util/XMLUniDefs.hpp>
-
-using namespace shibsp;
-using namespace opensaml::saml2md;
-using namespace opensaml;
-using namespace xmltooling;
-using namespace boost;
-using namespace std;
-
-namespace shibsp {
-
-#if defined (_MSC_VER)
-    #pragma warning( push )
-    #pragma warning( disable : 4250 )
-#endif
-
-    class KeyDescriptorExtractor : public AttributeExtractor
-    {
-    public:
-        KeyDescriptorExtractor(const DOMElement* e);
-        ~KeyDescriptorExtractor() {}
-
-        Lockable* lock() {
-            return this;
-        }
-
-        void unlock() {
-        }
-
-        void extractAttributes(
-            const Application& application, const GenericRequest* request, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<Attribute*>& attributes
-            ) const;
-
-        void getAttributeIds(std::vector<std::string>& attributes) const {
-            if (!m_hashId.empty())
-                attributes.push_back(m_hashId.front());
-            if (!m_signingId.empty())
-                attributes.push_back(m_signingId.front());
-            if (!m_encryptionId.empty())
-                attributes.push_back(m_encryptionId.front());
-        }
-
-    private:
-        string m_hashAlg;
-        vector<string> m_hashId;
-        vector<string> m_signingId;
-        vector<string> m_encryptionId;
-    };
-
-#if defined (_MSC_VER)
-    #pragma warning( pop )
-#endif
-
-    AttributeExtractor* SHIBSP_DLLLOCAL KeyDescriptorAttributeExtractorFactory(const DOMElement* const & e, bool)
-    {
-        return new KeyDescriptorExtractor(e);
-    }
-
-    static const XMLCh encryptionId[] = UNICODE_LITERAL_12(e,n,c,r,y,p,t,i,o,n,I,d);
-    static const XMLCh hashId[] =       UNICODE_LITERAL_6(h,a,s,h,I,d);
-    static const XMLCh hashAlg[] =      UNICODE_LITERAL_7(h,a,s,h,A,l,g);
-    static const XMLCh signingId[] =    UNICODE_LITERAL_9(s,i,g,n,i,n,g,I,d);
-};
-
-KeyDescriptorExtractor::KeyDescriptorExtractor(const DOMElement* e) : m_hashAlg(XMLHelper::getAttrString(e, "SHA1", hashAlg))
-{
-    SPConfig::getConfig().deprecation().warn(KEYDESCRIPTOR_ATTRIBUTE_EXTRACTOR" AttributeExtractor");
-    if (e) {
-        string a(XMLHelper::getAttrString(e, nullptr, hashId));
-        if (!a.empty())
-            m_hashId.push_back(a);
-        a = XMLHelper::getAttrString(e, nullptr, signingId);
-        if (!a.empty())
-            m_signingId.push_back(a);
-        a = XMLHelper::getAttrString(e, nullptr, encryptionId);
-        if (!a.empty())
-            m_encryptionId.push_back(a);
-    }
-    if (m_hashId.empty() && m_signingId.empty() && m_encryptionId.empty())
-        throw ConfigurationException("KeyDescriptor AttributeExtractor requires hashId, signingId, or encryptionId property.");
-}
-
-void KeyDescriptorExtractor::extractAttributes(
-    const Application& application, const GenericRequest* request, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<Attribute*>& attributes
-    ) const
-{
-    const RoleDescriptor* role = dynamic_cast<const RoleDescriptor*>(&xmlObject);
-    if (!role)
-        return;
-
-    vector<const Credential*> creds;
-    MetadataCredentialCriteria mcc(*role);
-
-    if (!m_signingId.empty() || !m_hashId.empty()) {
-        mcc.setUsage(Credential::SIGNING_CREDENTIAL);
-        if (application.getMetadataProvider()->resolve(creds, &mcc)) {
-            if (!m_hashId.empty()) {
-                auto_ptr<SimpleAttribute> attr(new SimpleAttribute(m_hashId));
-                vector<string>& vals = attr->getValues();
-                for (indirect_iterator<vector<const Credential*>::const_iterator> c = make_indirect_iterator(creds.begin());
-                        c != make_indirect_iterator(creds.end()); ++c) {
-                    if (vals.empty() || !vals.back().empty())
-                        vals.push_back(string());
-                    vals.back() = SecurityHelper::getDEREncoding(*c, m_hashAlg.c_str());
-                }
-                if (vals.back().empty())
-                    vals.pop_back();
-                if (!vals.empty()) {
-                    attributes.push_back(attr.get());
-                    attr.release();
-                }
-            }
-            if (!m_signingId.empty()) {
-                auto_ptr<SimpleAttribute> attr(new SimpleAttribute(m_signingId));
-                vector<string>& vals = attr->getValues();
-                for (indirect_iterator<vector<const Credential*>::const_iterator> c = make_indirect_iterator(creds.begin());
-                        c != make_indirect_iterator(creds.end()); ++c) {
-                    if (vals.empty() || !vals.back().empty())
-                        vals.push_back(string());
-                    vals.back() = SecurityHelper::getDEREncoding(*c);
-                }
-                if (vals.back().empty())
-                    vals.pop_back();
-                if (!vals.empty()) {
-                    attributes.push_back(attr.get());
-                    attr.release();
-                }
-            }
-            creds.clear();
-        }
-    }
-
-    if (!m_encryptionId.empty()) {
-        mcc.setUsage(Credential::ENCRYPTION_CREDENTIAL);
-        if (application.getMetadataProvider()->resolve(creds, &mcc)) {
-            auto_ptr<SimpleAttribute> attr(new SimpleAttribute(m_encryptionId));
-            vector<string>& vals = attr->getValues();
-            for (indirect_iterator<vector<const Credential*>::const_iterator> c = make_indirect_iterator(creds.begin());
-                    c != make_indirect_iterator(creds.end()); ++c) {
-                if (vals.empty() || !vals.back().empty())
-                    vals.push_back(string());
-                vals.back() = SecurityHelper::getDEREncoding(*c);
-            }
-            if (vals.back().empty())
-                vals.pop_back();
-            if (!vals.empty()) {
-                attributes.push_back(attr.get());
-                attr.release();
-            }
-        }
-    }
-}
diff --git a/shibsp/attribute/resolver/impl/MetadataAttributeExtractor.cpp b/shibsp/attribute/resolver/impl/MetadataAttributeExtractor.cpp
deleted file mode 100644
index 600de29a..00000000
--- a/shibsp/attribute/resolver/impl/MetadataAttributeExtractor.cpp
+++ /dev/null
@@ -1,406 +0,0 @@
-/**
- * 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
- *
- * 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.
- */
-
-/**
- * MetadataAttributeExtractor.cpp
- *
- * AttributeExtractor for SAML metadata content.
- */
-
-#include "internal.h"
-#include "Application.h"
-#include "ServiceProvider.h"
-#include "attribute/SimpleAttribute.h"
-#include "attribute/AttributeDecoder.h"
-#include "attribute/resolver/AttributeExtractor.h"
-
-#define BOOST_BIND_GLOBAL_PLACEHOLDERS
-#include <boost/bind.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/iterator/indirect_iterator.hpp>
-#include <boost/tuple/tuple.hpp>
-#include <saml/saml2/metadata/Metadata.h>
-#include <xmltooling/util/XMLHelper.h>
-#include <xercesc/util/XMLStringTokenizer.hpp>
-#include <xercesc/util/XMLUniDefs.hpp>
-
-using namespace shibsp;
-using namespace opensaml::saml2md;
-using namespace opensaml;
-using namespace xmltooling;
-using namespace boost;
-using namespace std;
-
-namespace shibsp {
-
-#if defined (_MSC_VER)
-    #pragma warning( push )
-    #pragma warning( disable : 4250 )
-#endif
-
-    class MetadataExtractor : public AttributeExtractor
-    {
-    public:
-        MetadataExtractor(const DOMElement* e, bool deprecationSupport=true);
-        ~MetadataExtractor() {}
-
-        Lockable* lock() {
-            return this;
-        }
-
-        void unlock() {
-        }
-
-        void extractAttributes(
-            const Application& application,
-            const GenericRequest* request,
-            const RoleDescriptor* issuer,
-            const XMLObject& xmlObject,
-            vector<shibsp::Attribute*>& attributes
-            ) const;
-        void getAttributeIds(vector<string>& attributes) const;
-
-    private:
-        string m_attributeProfiles,
-            m_errorURL,
-            m_displayName,
-            m_description,
-            m_informationURL,
-            m_privacyURL,
-            m_orgName,
-            m_orgDisplayName,
-            m_orgURL,
-            m_registrationAuthority;
-        typedef boost::tuple< string,xstring,boost::shared_ptr<AttributeDecoder> > contact_tuple_t;
-        typedef boost::tuple< string,int,int,boost::shared_ptr<AttributeDecoder> > logo_tuple_t;
-        vector<contact_tuple_t> m_contacts; // tuple is attributeID, contact type, decoder
-        vector<logo_tuple_t> m_logos;       // tuple is attributeID, height, width, decoder
-
-        template <class T> void doLangSensitive(const GenericRequest*, const vector<T*>&, const string&, vector<shibsp::Attribute*>&) const;
-        void doContactPerson(const GenericRequest* request, const RoleDescriptor*, const contact_tuple_t&, vector<shibsp::Attribute*>&) const;
-        void doLogo(const GenericRequest*, const vector<Logo*>&,const logo_tuple_t&, vector<shibsp::Attribute*>&) const;
-    };
-
-#if defined (_MSC_VER)
-    #pragma warning( pop )
-#endif
-
-    AttributeExtractor* SHIBSP_DLLLOCAL MetadataAttributeExtractorFactory(const DOMElement* const & e, bool deprecationSupport)
-    {
-        return new MetadataExtractor(e, deprecationSupport);
-    }
-
-    static const XMLCh _id[] = UNICODE_LITERAL_2(i,d);
-    static const XMLCh _formatter[] = UNICODE_LITERAL_9(f,o,r,m,a,t,t,e,r);
-};
-
-MetadataExtractor::MetadataExtractor(const DOMElement* e, bool deprecationSupport)
-    : m_attributeProfiles(XMLHelper::getAttrString(e, nullptr, AttributeProfile::LOCAL_NAME)),
-        m_errorURL(XMLHelper::getAttrString(e, nullptr, RoleDescriptor::ERRORURL_ATTRIB_NAME)),
-        m_displayName(XMLHelper::getAttrString(e, nullptr, DisplayName::LOCAL_NAME)),
-        m_description(XMLHelper::getAttrString(e, nullptr, Description::LOCAL_NAME)),
-        m_informationURL(XMLHelper::getAttrString(e, nullptr, InformationURL::LOCAL_NAME)),
-        m_privacyURL(XMLHelper::getAttrString(e, nullptr, PrivacyStatementURL::LOCAL_NAME)),
-        m_orgName(XMLHelper::getAttrString(e, nullptr, OrganizationName::LOCAL_NAME)),
-        m_orgDisplayName(XMLHelper::getAttrString(e, nullptr, OrganizationDisplayName::LOCAL_NAME)),
-        m_orgURL(XMLHelper::getAttrString(e, nullptr, OrganizationURL::LOCAL_NAME)),
-        m_registrationAuthority(XMLHelper::getAttrString(e, nullptr, RegistrationInfo::REGAUTHORITY_ATTRIB_NAME))
-{
-    const DOMElement* child = e ? XMLHelper::getFirstChildElement(e) : nullptr;
-    while (child) {
-        if (XMLHelper::isNodeNamed(child, e->getNamespaceURI(), ContactPerson::LOCAL_NAME)) {
-            string id(XMLHelper::getAttrString(child, nullptr, _id));
-            const XMLCh* type = child->getAttributeNS(nullptr, ContactPerson::CONTACTTYPE_ATTRIB_NAME);
-            if (!id.empty() && type && *type) {
-                boost::shared_ptr<AttributeDecoder> decoder(SPConfig::getConfig().AttributeDecoderManager.newPlugin(DOMAttributeDecoderType, child, deprecationSupport));
-                m_contacts.push_back(contact_tuple_t(id, type, decoder));
-            }
-        }
-        else if (XMLHelper::isNodeNamed(child, e->getNamespaceURI(), Logo::LOCAL_NAME)) {
-            string id(XMLHelper::getAttrString(child, nullptr, _id));
-            int h(XMLHelper::getAttrInt(child, 0, Logo::HEIGHT_ATTRIB_NAME));
-            int w(XMLHelper::getAttrInt(child, 0, Logo::WIDTH_ATTRIB_NAME));
-            if (!id.empty()) {
-                boost::shared_ptr<AttributeDecoder> decoder(SPConfig::getConfig().AttributeDecoderManager.newPlugin(DOMAttributeDecoderType, child, deprecationSupport));
-                m_logos.push_back(logo_tuple_t(id, h, w, decoder));
-            }
-        }
-        child = XMLHelper::getNextSiblingElement(child);
-    }
-}
-
-void MetadataExtractor::getAttributeIds(vector<string>& attributes) const
-{
-    if (!m_attributeProfiles.empty())
-        attributes.push_back(m_attributeProfiles);
-    if (!m_errorURL.empty())
-        attributes.push_back(m_errorURL);
-    if (!m_displayName.empty())
-        attributes.push_back(m_displayName);
-    if (!m_description.empty())
-        attributes.push_back(m_description);
-    if (!m_informationURL.empty())
-        attributes.push_back(m_informationURL);
-    if (!m_privacyURL.empty())
-        attributes.push_back(m_privacyURL);
-    if (!m_orgName.empty())
-        attributes.push_back(m_orgName);
-    if (!m_orgDisplayName.empty())
-        attributes.push_back(m_orgDisplayName);
-    if (!m_orgURL.empty())
-        attributes.push_back(m_orgURL);
-    if (!m_registrationAuthority.empty())
-        attributes.push_back(m_registrationAuthority);
-    for (vector<contact_tuple_t>::const_iterator c = m_contacts.begin(); c != m_contacts.end(); ++c)
-        attributes.push_back(c->get<0>());
-    for (vector<logo_tuple_t>::const_iterator l = m_logos.begin(); l != m_logos.end(); ++l)
-        attributes.push_back(l->get<0>());
-}
-
-void MetadataExtractor::extractAttributes(
-    const Application& application,
-    const GenericRequest* request,
-    const RoleDescriptor* issuer,
-    const XMLObject& xmlObject,
-    vector<shibsp::Attribute*>& attributes
-    ) const
-{
-    const RoleDescriptor* roleToExtract = dynamic_cast<const RoleDescriptor*>(&xmlObject);
-    if (!roleToExtract)
-        return;
-
-    if (!m_attributeProfiles.empty()) {
-        const vector<AttributeProfile*>* profiles = nullptr;
-        const IDPSSODescriptor* idpRole = dynamic_cast<const IDPSSODescriptor*>(roleToExtract);
-        if (idpRole) {
-            profiles = &(idpRole->getAttributeProfiles());
-        }
-        else {
-            const AttributeAuthorityDescriptor* aaRole = dynamic_cast<const AttributeAuthorityDescriptor*>(roleToExtract);
-            if (aaRole) {
-                profiles = &(aaRole->getAttributeProfiles());
-            }
-        }
-        if (profiles && !profiles->empty()) {
-            auto_ptr<SimpleAttribute> attr(new SimpleAttribute(vector<string>(1, m_attributeProfiles)));
-            for (indirect_iterator<vector<AttributeProfile*>::const_iterator> i = make_indirect_iterator(profiles->begin());
-                    i != make_indirect_iterator(profiles->end()); ++i) {
-                auto_ptr_char temp(i->getProfileURI());
-                if (temp.get())
-                    attr->getValues().push_back(temp.get());
-            }
-            if (attr->valueCount() > 0) {
-                attributes.push_back(attr.get());
-                attr.release();
-            }
-        }
-    }
-
-    if (!m_errorURL.empty() && roleToExtract->getErrorURL()) {
-        auto_ptr_char temp(roleToExtract->getErrorURL());
-        if (temp.get() && *temp.get()) {
-            auto_ptr<SimpleAttribute> attr(new SimpleAttribute(vector<string>(1, m_errorURL)));
-            attr->getValues().push_back(temp.get());
-            attributes.push_back(attr.get());
-            attr.release();
-        }
-    }
-
-    if (!m_displayName.empty() || !m_description.empty() || !m_informationURL.empty() || !m_privacyURL.empty()) {
-        const Extensions* exts = roleToExtract->getExtensions();
-        if (exts) {
-            const UIInfo* ui;
-            for (vector<XMLObject*>::const_iterator ext = exts->getUnknownXMLObjects().begin(); ext != exts->getUnknownXMLObjects().end(); ++ext) {
-                ui = dynamic_cast<const UIInfo*>(*ext);
-                if (ui) {
-                    doLangSensitive(request, ui->getDisplayNames(), m_displayName, attributes);
-                    doLangSensitive(request, ui->getDescriptions(), m_description, attributes);
-                    doLangSensitive(request, ui->getInformationURLs(), m_informationURL, attributes);
-                    doLangSensitive(request, ui->getPrivacyStatementURLs(), m_privacyURL, attributes);
-                    const vector<Logo*>& logos = ui->getLogos();
-                    if (!logos.empty()) {
-                        for_each(
-                            m_logos.begin(), m_logos.end(),
-                            boost::bind(&MetadataExtractor::doLogo, this, request, boost::ref(logos), _1, boost::ref(attributes))
-                            );
-                    }
-                    break;
-                }
-            }
-        }
-    }
-
-    if (!m_orgName.empty() || !m_orgDisplayName.empty() || !m_orgURL.empty()) {
-        const Organization* org = roleToExtract->getOrganization();
-        if (!org)
-            org = dynamic_cast<EntityDescriptor*>(roleToExtract->getParent())->getOrganization();
-        if (org) {
-            doLangSensitive(request, org->getOrganizationNames(), m_orgName, attributes);
-            doLangSensitive(request, org->getOrganizationDisplayNames(), m_orgDisplayName, attributes);
-            doLangSensitive(request, org->getOrganizationURLs(), m_orgURL, attributes);
-        }
-    }
-
-    for_each(
-        m_contacts.begin(), m_contacts.end(),
-        boost::bind(&MetadataExtractor::doContactPerson, this, request, roleToExtract, _1, boost::ref(attributes))
-        );
-
-    if (!m_registrationAuthority.empty()) {
-        const Extensions* exts = dynamic_cast<EntityDescriptor*>(roleToExtract->getParent())->getExtensions();
-        if (exts) {
-            const RegistrationInfo* reginfo;
-            for (vector<XMLObject*>::const_iterator ext = exts->getUnknownXMLObjects().begin(); ext != exts->getUnknownXMLObjects().end(); ++ext) {
-                reginfo = dynamic_cast<const RegistrationInfo*>(*ext);
-                if (reginfo) {
-                    auto_ptr_char temp(reginfo->getRegistrationAuthority());
-                    if (temp.get()) {
-                        auto_ptr<SimpleAttribute> attr(new SimpleAttribute(vector<string>(1, m_registrationAuthority)));
-                        attr->getValues().push_back(temp.get());
-                        attributes.push_back(attr.get());
-                        attr.release();
-                    }
-                }
-            }
-        }
-    }
-}
-
-template <class T> void MetadataExtractor::doLangSensitive(
-    const GenericRequest* request, const vector<T*>& objects, const string& id, vector<shibsp::Attribute*>& attributes
-    ) const
-{
-    if (objects.empty() || id.empty())
-        return;
-
-    T* match = nullptr;
-    if (request && request->startLangMatching()) {
-        do {
-            for (typename vector<T*>::const_iterator i = objects.begin(); !match && i != objects.end(); ++i) {
-                if (request->matchLang((*i)->getLang()))
-                    match = *i;
-            }
-        } while (!match && request->continueLangMatching());
-    }
-    if (!match)
-        match = objects.front();
-
-    auto_arrayptr<char> temp(toUTF8(match->getTextContent()));
-    if (temp.get() && *temp.get()) {
-        auto_ptr<SimpleAttribute> attr(new SimpleAttribute(vector<string>(1, id)));
-        attr->getValues().push_back(temp.get());
-        attributes.push_back(attr.get());
-        attr.release();
-    }
-}
-
-void MetadataExtractor::doLogo(
-    const GenericRequest* request, const vector<Logo*>& logos, const logo_tuple_t& params, vector<shibsp::Attribute*>& attributes
-    ) const
-{
-    if (logos.empty())
-        return;
-
-    pair<bool,int> dim;
-    Logo* match = nullptr;
-    int h = params.get<1>(), w = params.get<2>(), sizediff, bestdiff = INT_MAX;
-    if (request && request->startLangMatching()) {
-        do {
-            for (vector<Logo*>::const_iterator i = logos.begin(); i != logos.end(); ++i) {
-                if (!(*i)->getLang() || request->matchLang((*i)->getLang())) {
-                    sizediff = 0;
-                    if (h > 0) {
-                        dim = (*i)->getHeight();
-                        sizediff += abs(h - dim.second);
-                    }
-                    if (w > 0) {
-                        dim = (*i)->getWidth();
-                        sizediff += abs(w - dim.second);
-                    }
-                    if (sizediff < bestdiff) {
-                        match = *i;
-                        bestdiff = sizediff;
-                    }
-                }
-                if (match && bestdiff == 0)
-                    break;
-            }
-            if (match && bestdiff == 0)
-                break;
-        } while (request->continueLangMatching());
-    }
-    else if (h > 0 || w > 0) {
-        for (vector<Logo*>::const_iterator i = logos.begin(); i != logos.end(); ++i) {
-            sizediff = 0;
-            if (h > 0) {
-                dim = (*i)->getHeight();
-                sizediff += abs(h - dim.second);
-            }
-            if (w > 0) {
-                dim = (*i)->getWidth();
-                sizediff += abs(w - dim.second);
-            }
-            if (sizediff < bestdiff) {
-                match = *i;
-                bestdiff = sizediff;
-            }
-            if (match && bestdiff == 0)
-                break;
-        }
-    }
-
-    if (!match)
-        match = logos.front();
-
-    if (!match->getDOM()) {
-        match->marshall();
-    }
-    vector<string> ids(1, params.get<0>());
-    auto_ptr<Attribute> attr(params.get<3>()->decode(request, ids, match));
-    if (attr.get()) {
-        attributes.push_back(attr.get());
-        attr.release();
-    }
-}
-
-void MetadataExtractor::doContactPerson(
-    const GenericRequest* request, const RoleDescriptor* role, const contact_tuple_t& params, vector<shibsp::Attribute*>& attributes
-    ) const
-{
-    const XMLCh* ctype = params.get<1>().c_str();
-    static bool (*eq)(const XMLCh*, const XMLCh*) = &XMLString::equals;
-    const ContactPerson* cp = find_if(role->getContactPersons(),boost::bind(eq, ctype, boost::bind(&ContactPerson::getContactType, _1)));
-    if (!cp) {
-        cp = find_if(dynamic_cast<EntityDescriptor*>(role->getParent())->getContactPersons(),
-                boost::bind(eq, ctype, boost::bind(&ContactPerson::getContactType, _1)));
-    }
-
-    if (cp) {
-        if (!cp->getDOM()) {
-            cp->marshall();
-        }
-        vector<string> ids(1, params.get<0>());
-        auto_ptr<Attribute> attr(params.get<2>()->decode(request, ids, cp));
-        if (attr.get()) {
-            attributes.push_back(attr.get());
-            attr.release();
-        }
-    }
-}
diff --git a/shibsp/attribute/resolver/impl/QueryAttributeResolver.cpp b/shibsp/attribute/resolver/impl/QueryAttributeResolver.cpp
deleted file mode 100644
index 9b6b7a94..00000000
--- a/shibsp/attribute/resolver/impl/QueryAttributeResolver.cpp
+++ /dev/null
@@ -1,764 +0,0 @@
-/**
- * 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
- *
- * 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.
- */
-
-/**
- * QueryAttributeResolver.cpp
- *
- * AttributeResolver based on SAML queries.
- */
-
-#include "internal.h"
-#include "Application.h"
-#include "ServiceProvider.h"
-#include "SessionCache.h"
-#include "attribute/SimpleAttribute.h"
-#include "attribute/filtering/AttributeFilter.h"
-#include "attribute/filtering/BasicFilteringContext.h"
-#include "attribute/resolver/AttributeExtractor.h"
-#include "attribute/resolver/AttributeResolver.h"
-#include "attribute/resolver/ResolutionContext.h"
-#include "binding/SOAPClient.h"
-#include "metadata/MetadataProviderCriteria.h"
-#include "security/SecurityPolicy.h"
-#include "security/SecurityPolicyProvider.h"
-#include "util/SPConstants.h"
-
-#include <boost/iterator/indirect_iterator.hpp>
-#include <boost/ptr_container/ptr_vector.hpp>
-#include <saml/exceptions.h>
-#include <saml/saml1/binding/SAML1SOAPClient.h>
-#include <saml/saml1/core/Assertions.h>
-#include <saml/saml1/core/Protocols.h>
-#include <saml/saml2/binding/SAML2SOAPClient.h>
-#include <saml/saml2/core/Protocols.h>
-#include <saml/saml2/metadata/Metadata.h>
-#include <saml/saml2/metadata/MetadataCredentialCriteria.h>
-#include <saml/saml2/metadata/MetadataProvider.h>
-#include <xmltooling/XMLToolingConfig.h>
-#include <xmltooling/util/NDC.h>
-#include <xmltooling/util/URLEncoder.h>
-#include <xmltooling/util/XMLHelper.h>
-#include <xercesc/util/XMLUniDefs.hpp>
-
-using namespace shibsp;
-using namespace opensaml::saml1;
-using namespace opensaml::saml1p;
-using namespace opensaml::saml2;
-using namespace opensaml::saml2p;
-using namespace opensaml::saml2md;
-using namespace opensaml;
-using namespace xmltooling;
-using namespace boost;
-using namespace std;
-
-namespace shibsp {
-
-    class SHIBSP_DLLLOCAL QueryContext : public ResolutionContext
-    {
-    public:
-        QueryContext(const Application& application, const Session& session)
-                : m_query(true), m_app(application), m_request(nullptr), m_session(&session), m_metadata(nullptr), m_entity(nullptr), m_nameid(nullptr) {
-            m_protocol = XMLString::transcode(session.getProtocol());
-            m_class = XMLString::transcode(session.getAuthnContextClassRef());
-            m_decl = XMLString::transcode(session.getAuthnContextDeclRef());
-        }
-
-        QueryContext(
-            const Application& application,
-            const GenericRequest* request,
-            const EntityDescriptor* issuer,
-            const XMLCh* protocol,
-            const NameID* nameid=nullptr,
-            const XMLCh* authncontext_class=nullptr,
-            const XMLCh* authncontext_decl=nullptr,
-            const vector<const opensaml::Assertion*>* tokens=nullptr
-            ) : m_query(true), m_app(application), m_request(request), m_session(nullptr), m_metadata(nullptr), m_entity(issuer),
-                m_protocol(protocol), m_nameid(nameid), m_class(authncontext_class), m_decl(authncontext_decl) {
-
-            if (tokens) {
-                for (vector<const opensaml::Assertion*>::const_iterator t = tokens->begin(); t!=tokens->end(); ++t) {
-                    const saml2::Assertion* token2 = dynamic_cast<const saml2::Assertion*>(*t);
-                    if (token2 && !token2->getAttributeStatements().empty()) {
-                        m_query = false;
-                    }
-                    else {
-                        const saml1::Assertion* token1 = dynamic_cast<const saml1::Assertion*>(*t);
-                        if (token1 && !token1->getAttributeStatements().empty()) {
-                            m_query = false;
-                        }
-                    }
-                }
-            }
-        }
-
-        ~QueryContext() {
-            if (m_session) {
-                XMLString::release((XMLCh**)&m_protocol);
-                XMLString::release((XMLCh**)&m_class);
-                XMLString::release((XMLCh**)&m_decl);
-            }
-            if (m_metadata)
-                m_metadata->unlock();
-            for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<shibsp::Attribute>());
-            for_each(m_assertions.begin(), m_assertions.end(), xmltooling::cleanup<opensaml::Assertion>());
-        }
-
-        bool doQuery() const {
-            return m_query;
-        }
-
-        const Application& getApplication() const {
-            return m_app;
-        }
-        const GenericRequest* getRequest() const {
-            return m_request;
-        }
-        const EntityDescriptor* getEntityDescriptor() const {
-            if (m_entity)
-                return m_entity;
-            if (m_session && m_session->getEntityID()) {
-                m_metadata = m_app.getMetadataProvider(false);
-                if (m_metadata) {
-                    m_metadata->lock();
-                    return m_entity = m_metadata->getEntityDescriptor(MetadataProviderCriteria(m_app, m_session->getEntityID())).first;
-                }
-            }
-            return nullptr;
-        }
-        const XMLCh* getProtocol() const {
-            return m_protocol;
-        }
-        const NameID* getNameID() const {
-            return m_session ? m_session->getNameID() : m_nameid;
-        }
-        const XMLCh* getClassRef() const {
-            return m_class;
-        }
-        const XMLCh* getDeclRef() const {
-            return m_decl;
-        }
-        const Session* getSession() const {
-            return m_session;
-        }
-        vector<shibsp::Attribute*>& getResolvedAttributes() {
-            return m_attributes;
-        }
-        vector<opensaml::Assertion*>& getResolvedAssertions() {
-            return m_assertions;
-        }
-
-    private:
-        bool m_query;
-        const Application& m_app;
-        const GenericRequest* m_request;
-        const Session* m_session;
-        mutable MetadataProvider* m_metadata;
-        mutable const EntityDescriptor* m_entity;
-        const XMLCh* m_protocol;
-        const NameID* m_nameid;
-        const XMLCh* m_class;
-        const XMLCh* m_decl;
-        vector<shibsp::Attribute*> m_attributes;
-        vector<opensaml::Assertion*> m_assertions;
-    };
-
-    class SHIBSP_DLLLOCAL QueryResolver : public AttributeResolver
-    {
-    public:
-        QueryResolver(const DOMElement* e);
-        ~QueryResolver() {}
-
-        Lockable* lock() {return this;}
-        void unlock() {}
-
-        ResolutionContext* createResolutionContext(
-            const Application& application,
-            const GenericRequest* request,
-            const EntityDescriptor* issuer,
-            const XMLCh* protocol,
-            const NameID* nameid=nullptr,
-            const XMLCh* authncontext_class=nullptr,
-            const XMLCh* authncontext_decl=nullptr,
-            const vector<const opensaml::Assertion*>* tokens=nullptr,
-            const vector<shibsp::Attribute*>* attributes=nullptr
-            ) const {
-            return new QueryContext(application, request, issuer, protocol, nameid, authncontext_class, authncontext_decl, tokens);
-        }
-
-        ResolutionContext* createResolutionContext(const Application& application, const Session& session) const {
-            return new QueryContext(application,session);
-        }
-
-        void resolveAttributes(ResolutionContext& ctx) const;
-
-        void getAttributeIds(vector<string>& attributes) const {
-            if (!m_exceptionId.empty())
-                attributes.push_back(m_exceptionId.front());
-        }
-
-    private:
-        void SAML1Query(QueryContext& ctx, vector<string>& statusCodes) const;
-        void SAML2Query(QueryContext& ctx, vector<string>& statusCodes) const;
-
-        Category& m_log;
-        string m_policyId;
-        bool m_subjectMatch;
-        ptr_vector<AttributeDesignator> m_SAML1Designators;
-        ptr_vector<saml2::Attribute> m_SAML2Designators;
-        vector<string> m_exceptionId;
-        vector<string> m_statusId;
-    };
-
-    AttributeResolver* SHIBSP_DLLLOCAL QueryResolverFactory(const DOMElement* const & e, bool)
-    {
-        return new QueryResolver(e);
-    }
-
-    static const XMLCh exceptionId[] =  UNICODE_LITERAL_11(e,x,c,e,p,t,i,o,n,I,d);
-    static const XMLCh policyId[] =     UNICODE_LITERAL_8(p,o,l,i,c,y,I,d);
-    static const XMLCh statusId[] =     UNICODE_LITERAL_8(s,t,a,t,u,s,I,d);
-    static const XMLCh subjectMatch[] = UNICODE_LITERAL_12(s,u,b,j,e,c,t,M,a,t,c,h);
-};
-
-QueryResolver::QueryResolver(const DOMElement* e)
-    : m_log(Category::getInstance(SHIBSP_LOGCAT ".AttributeResolver.Query")),
-        m_policyId(XMLHelper::getAttrString(e, nullptr, policyId)),
-        m_subjectMatch(XMLHelper::getAttrBool(e, false, subjectMatch))
-{
-#ifdef _DEBUG
-    xmltooling::NDC ndc("QueryResolver");
-#endif
-
-    DOMElement* child = XMLHelper::getFirstChildElement(e);
-    while (child) {
-        try {
-            if (XMLHelper::isNodeNamed(child, samlconstants::SAML20_NS, saml2::Attribute::LOCAL_NAME)) {
-                auto_ptr<XMLObject> obj(saml2::AttributeBuilder::buildOneFromElement(child));
-                saml2::Attribute* down = dynamic_cast<saml2::Attribute*>(obj.get());
-                if (down) {
-                    m_SAML2Designators.push_back(down);
-                    obj.release();
-                }
-            }
-            else if (XMLHelper::isNodeNamed(child, samlconstants::SAML1_NS, AttributeDesignator::LOCAL_NAME)) {
-                auto_ptr<XMLObject> obj(AttributeDesignatorBuilder::buildOneFromElement(child));
-                AttributeDesignator* down = dynamic_cast<AttributeDesignator*>(obj.get());
-                if (down) {
-                    m_SAML1Designators.push_back(down);
-                    obj.release();
-                }
-            }
-        }
-        catch (const exception& ex) {
-            m_log.error("exception loading attribute designator: %s", ex.what());
-        }
-        child = XMLHelper::getNextSiblingElement(child);
-    }
-
-    string exid(XMLHelper::getAttrString(e, nullptr, exceptionId));
-    if (!exid.empty())
-        m_exceptionId.push_back(exid);
-
-    string stid(XMLHelper::getAttrString(e, nullptr, statusId));
-    if (!stid.empty())
-        m_statusId.push_back(stid);
-}
-
-void QueryResolver::SAML1Query(QueryContext& ctx, vector<string>& statusCodes) const
-{
-#ifdef _DEBUG
-    xmltooling::NDC ndc("query");
-#endif
-
-    int version = XMLString::equals(ctx.getProtocol(), samlconstants::SAML11_PROTOCOL_ENUM) ? 1 : 0;
-    const AttributeAuthorityDescriptor* AA =
-        find_if(ctx.getEntityDescriptor()->getAttributeAuthorityDescriptors(), isValidForProtocol(ctx.getProtocol()));
-    if (!AA) {
-        m_log.warn("no SAML 1.%d AttributeAuthority role found in metadata", version);
-        throw MetadataException("Unable to locate SAML 1 AttributeAuthority role.");
-    }
-
-    const Application& application = ctx.getApplication();
-    const PropertySet* relyingParty = application.getRelyingParty(ctx.getEntityDescriptor());
-
-    // Locate policy key.
-    const char* policyId = m_policyId.empty() ? application.getString("policyId").second : m_policyId.c_str();
-
-    // Set up policy and SOAP client.
-    scoped_ptr<SecurityPolicy> policy(
-        application.getServiceProvider().getSecurityPolicyProvider()->createSecurityPolicy(
-            samlconstants::SAML1_BINDING_SOAP, application, nullptr, policyId
-            )
-        );
-    policy->getAudiences().push_back(relyingParty->getXMLString("entityID").second);
-    MetadataCredentialCriteria mcc(*AA);
-    shibsp::SOAPClient soaper(*policy);
-
-    auto_ptr_XMLCh binding(samlconstants::SAML1_BINDING_SOAP);
-    auto_ptr<saml1p::Response> response;
-    const vector<AttributeService*>& endpoints=AA->getAttributeServices();
-    for (indirect_iterator<vector<AttributeService*>::const_iterator> ep = make_indirect_iterator(endpoints.begin());
-            !response.get() && ep != make_indirect_iterator(endpoints.end()); ++ep) {
-        if (!XMLString::equals(ep->getBinding(), binding.get()) || !ep->getLocation())
-            continue;
-        auto_ptr_char loc(ep->getLocation());
-        try {
-            NameIdentifier* nameid = NameIdentifierBuilder::buildNameIdentifier();
-            nameid->setName(ctx.getNameID()->getName());
-            nameid->setFormat(ctx.getNameID()->getFormat());
-            nameid->setNameQualifier(ctx.getNameID()->getNameQualifier());
-            saml1::Subject* subject = saml1::SubjectBuilder::buildSubject();
-            subject->setNameIdentifier(nameid);
-            saml1p::AttributeQuery* query = saml1p::AttributeQueryBuilder::buildAttributeQuery();
-            query->setSubject(subject);
-            query->setResource(relyingParty->getXMLString("entityID").second);
-            for (ptr_vector<AttributeDesignator>::const_iterator ad = m_SAML1Designators.begin(); ad != m_SAML1Designators.end(); ++ad) {
-                auto_ptr<AttributeDesignator> adwrapper(ad->cloneAttributeDesignator());
-                query->getAttributeDesignators().push_back(adwrapper.get());
-                adwrapper.release();
-            }
-            Request* request = RequestBuilder::buildRequest();
-            request->setAttributeQuery(query);
-            request->setMinorVersion(version);
-
-            SAML1SOAPClient client(soaper, false);
-            client.sendSAML(request, application.getId(), mcc, loc.get());
-            response.reset(client.receiveSAML());
-        }
-        catch (const exception& ex) {
-            m_log.error("exception during SAML query to %s: %s", loc.get(), ex.what());
-            soaper.reset();
-        }
-    }
-
-    if (!response.get()) {
-        m_log.error("unable to obtain a SAML response from attribute authority");
-        throw BindingException("Unable to obtain a SAML response from attribute authority.");
-    }
-    else if (!response->getStatus() || !response->getStatus()->getStatusCode() || response->getStatus()->getStatusCode()->getValue()==nullptr ||
-            *(response->getStatus()->getStatusCode()->getValue()) != saml1p::StatusCode::SUCCESS) {
-        m_log.error("attribute authority returned a SAML error");
-        const saml1p::StatusCode* statusCode = response->getStatus() ? response->getStatus()->getStatusCode() : nullptr;
-        while (statusCode && statusCode->getValue() && statusCode->getValue()->hasLocalPart()) {
-            auto_ptr_char code(statusCode->getValue()->getLocalPart());
-            if (code.get())
-                statusCodes.push_back(code.get());
-            statusCode = statusCode->getStatusCode();
-        }
-        throw FatalProfileException("Attribute authority returned a SAML error.");
-    }
-
-    const vector<saml1::Assertion*>& assertions = const_cast<const saml1p::Response*>(response.get())->getAssertions();
-    if (assertions.empty()) {
-        m_log.warn("response from attribute authority was empty");
-        return;
-    }
-    else if (assertions.size() > 1) {
-        m_log.warn("simple resolver only supports one assertion in the query response");
-    }
-
-    saml1::Assertion* newtoken = assertions.front();
-
-    pair<bool,bool> signedAssertions = relyingParty->getBool("requireSignedAssertions");
-    if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) {
-        m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");
-        throw SecurityPolicyException("Rejected unsigned assertion based on local policy.");
-    }
-
-    try {
-        // We're going to insist that the assertion issuer is the same as the peer.
-        // Reset the policy's message bits and extract them from the assertion.
-        policy->reset(true);
-        policy->setMessageID(newtoken->getAssertionID());
-        policy->setIssueInstant(newtoken->getIssueInstantEpoch());
-        policy->setIssuer(newtoken->getIssuer());
-        policy->evaluate(*newtoken);
-
-        // Now we can check the security status of the policy.
-        if (!policy->isAuthenticated())
-            throw SecurityPolicyException("Security of SAML 1.x query result not established.");
-    }
-    catch (const exception& ex) {
-        m_log.error("assertion failed policy validation: %s", ex.what());
-        throw;
-    }
-
-    newtoken->detach();
-    response.release();  // detach blows away the Response
-    ctx.getResolvedAssertions().push_back(newtoken);
-
-    // Finally, extract and filter the result.
-    try {
-        AttributeExtractor* extractor = application.getAttributeExtractor();
-        if (extractor) {
-            Locker extlocker(extractor);
-            const vector<saml1::AttributeStatement*>& statements = const_cast<const saml1::Assertion*>(newtoken)->getAttributeStatements();
-            for (indirect_iterator<vector<saml1::AttributeStatement*>::const_iterator> s = make_indirect_iterator(statements.begin());
-                    s != make_indirect_iterator(statements.end()); ++s) {
-                if (m_subjectMatch) {
-                    // Check for subject match.
-                    const NameIdentifier* respName = s->getSubject() ? s->getSubject()->getNameIdentifier() : nullptr;
-                    if (!respName || !XMLString::equals(respName->getName(), ctx.getNameID()->getName()) ||
-                        !XMLString::equals(respName->getFormat(), ctx.getNameID()->getFormat()) ||
-                        !XMLString::equals(respName->getNameQualifier(), ctx.getNameID()->getNameQualifier())) {
-                        if (respName)
-                            m_log.warnStream() << "ignoring AttributeStatement without strongly matching NameIdentifier in Subject: " <<
-                                *respName << logging::eol;
-                        else
-                            m_log.warn("ignoring AttributeStatement without NameIdentifier in Subject");
-                        continue;
-                    }
-                }
-                extractor->extractAttributes(application, ctx.getRequest(), AA, *s, ctx.getResolvedAttributes());
-            }
-        }
-
-        AttributeFilter* filter = application.getAttributeFilter();
-        if (filter) {
-            BasicFilteringContext fc(application, ctx.getResolvedAttributes(), AA, ctx.getClassRef(), ctx.getDeclRef());
-            Locker filtlocker(filter);
-            filter->filterAttributes(fc, ctx.getResolvedAttributes());
-        }
-    }
-    catch (const exception& ex) {
-        m_log.error("caught exception extracting/filtering attributes from query result: %s", ex.what());
-        for_each(ctx.getResolvedAttributes().begin(), ctx.getResolvedAttributes().end(), xmltooling::cleanup<shibsp::Attribute>());
-        ctx.getResolvedAttributes().clear();
-        throw;
-    }
-}
-
-void QueryResolver::SAML2Query(QueryContext& ctx, vector<string>& statusCodes) const
-{
-#ifdef _DEBUG
-    xmltooling::NDC ndc("query");
-#endif
-
-    const AttributeAuthorityDescriptor* AA =
-        find_if(ctx.getEntityDescriptor()->getAttributeAuthorityDescriptors(), isValidForProtocol(samlconstants::SAML20P_NS));
-    if (!AA) {
-        m_log.warn("no SAML 2 AttributeAuthority role found in metadata");
-        throw MetadataException("Unable to locate SAML 2.0 AttributeAuthority role.");
-    }
-
-    const Application& application = ctx.getApplication();
-    const PropertySet* relyingParty = application.getRelyingParty(ctx.getEntityDescriptor());
-    pair<bool,bool> signedAssertions = relyingParty->getBool("requireSignedAssertions");
-    pair<bool,const char*> encryption = relyingParty->getString("encryption");
-
-    // Locate policy key.
-    const char* policyId = m_policyId.empty() ? application.getString("policyId").second : m_policyId.c_str();
-
-    // Set up policy and SOAP client.
-    scoped_ptr<SecurityPolicy> policy(
-        application.getServiceProvider().getSecurityPolicyProvider()->createSecurityPolicy(
-            samlconstants::SAML20_PROFILE_QUERY, application, nullptr, policyId
-            )
-        );
-    policy->getAudiences().push_back(relyingParty->getXMLString("entityID").second);
-    MetadataCredentialCriteria mcc(*AA);
-    shibsp::SOAPClient soaper(*policy);
-
-    auto_ptr_XMLCh binding(samlconstants::SAML20_BINDING_SOAP);
-    auto_ptr<saml2p::StatusResponseType> srt;
-    const vector<AttributeService*>& endpoints=AA->getAttributeServices();
-    for (indirect_iterator<vector<AttributeService*>::const_iterator> ep = make_indirect_iterator(endpoints.begin());
-            !srt.get() && ep != make_indirect_iterator(endpoints.end()); ++ep) {
-        if (!XMLString::equals(ep->getBinding(), binding.get())  || !ep->getLocation())
-            continue;
-        auto_ptr_char loc(ep->getLocation());
-        try {
-            auto_ptr<saml2::Subject> subject(saml2::SubjectBuilder::buildSubject());
-
-            // Encrypt the NameID?
-            if (SPConfig::shouldSignOrEncrypt(encryption.first ? encryption.second : "conditional", loc.get(), false)) {
-                try {
-                    auto_ptr<EncryptedID> encrypted(EncryptedIDBuilder::buildEncryptedID());
-                    encrypted->encrypt(
-                        *ctx.getNameID(),
-                        *(application.getMetadataProvider()),
-                        mcc,
-                        false,
-                        relyingParty->getXMLString("encryptionAlg").second
-                        );
-                    subject->setEncryptedID(encrypted.get());
-                    encrypted.release();
-                }
-                catch (const std::exception& ex) {
-                    // If we're encrypting deliberately, failure should be fatal.
-                    if (encryption.first && strcmp(encryption.second, "conditional")) {
-                        throw;
-                    }
-                    // If opportunistically, just log and move on.
-                    m_log.info("Conditional encryption of NameID in AttributeQuery failed: %s", ex.what());
-                    auto_ptr<NameID> namewrapper(ctx.getNameID()->cloneNameID());
-                    subject->setNameID(namewrapper.get());
-                    namewrapper.release();
-                }
-            }
-            else {
-                auto_ptr<NameID> namewrapper(ctx.getNameID()->cloneNameID());
-                subject->setNameID(namewrapper.get());
-                namewrapper.release();
-            }
-
-            saml2p::AttributeQuery* query = saml2p::AttributeQueryBuilder::buildAttributeQuery();
-            query->setSubject(subject.release());
-            Issuer* iss = IssuerBuilder::buildIssuer();
-            iss->setName(relyingParty->getXMLString("entityID").second);
-            query->setIssuer(iss);
-            for (ptr_vector<saml2::Attribute>::const_iterator ad = m_SAML2Designators.begin(); ad != m_SAML2Designators.end(); ++ad) {
-                auto_ptr<saml2::Attribute> adwrapper(ad->cloneAttribute());
-                query->getAttributes().push_back(adwrapper.get());
-                adwrapper.release();
-            }
-
-            SAML2SOAPClient client(soaper, false);
-            client.sendSAML(query, application.getId(), mcc, loc.get());
-            srt.reset(client.receiveSAML());
-        }
-        catch (const exception& ex) {
-            m_log.error("exception during SAML query to %s: %s", loc.get(), ex.what());
-            soaper.reset();
-        }
-    }
-
-    if (!srt.get()) {
-        m_log.error("unable to obtain a SAML response from attribute authority");
-        throw BindingException("Unable to obtain a SAML response from attribute authority.");
-    }
-
-    saml2p::Response* response = dynamic_cast<saml2p::Response*>(srt.get());
-    if (!response) {
-        m_log.error("message was not a samlp:Response");
-        throw FatalProfileException("Attribute authority returned an unrecognized message.");
-    }
-    else if (!response->getStatus() || !response->getStatus()->getStatusCode() ||
-            !XMLString::equals(response->getStatus()->getStatusCode()->getValue(), saml2p::StatusCode::SUCCESS)) {
-        m_log.error("attribute authority returned a SAML error");
-        const saml2p::StatusCode* statusCode = response->getStatus() ? response->getStatus()->getStatusCode() : nullptr;
-        while (statusCode) {
-            auto_ptr_char code(statusCode->getValue());
-            if (code.get())
-                statusCodes.push_back(code.get());
-            statusCode = statusCode->getStatusCode();
-        }
-        throw FatalProfileException("Attribute authority returned a SAML error.");
-    }
-
-    saml2::Assertion* newtoken = nullptr;
-    auto_ptr<saml2::Assertion> newtokenwrapper;
-    const vector<saml2::Assertion*>& assertions = const_cast<const saml2p::Response*>(response)->getAssertions();
-    if (assertions.empty()) {
-        // Check for encryption.
-        const vector<saml2::EncryptedAssertion*>& encassertions = const_cast<const saml2p::Response*>(response)->getEncryptedAssertions();
-        if (encassertions.empty()) {
-            m_log.warn("response from attribute authority was empty");
-            return;
-        }
-        else if (encassertions.size() > 1) {
-            m_log.warn("simple resolver only supports one assertion in the query response");
-        }
-
-        CredentialResolver* cr = application.getCredentialResolver();
-        if (!cr) {
-            m_log.warn("found encrypted assertion, but no CredentialResolver was available");
-            throw FatalProfileException("Assertion was encrypted, but no decryption credentials are available.");
-        }
-
-        // With this flag on, we block unauthenticated ciphertext when decrypting,
-        // unless the protocol was authenticated.
-        pair<bool,bool> authenticatedCipher = application.getBool("requireAuthenticatedEncryption");
-        if (policy->isAuthenticated())
-            authenticatedCipher.second = false;
-
-        // Attempt to decrypt it.
-        try {
-            Locker credlocker(cr);
-            auto_ptr<XMLObject> tokenwrapper(
-                encassertions.front()->decrypt(
-                    *cr, relyingParty->getXMLString("entityID").second, &mcc, authenticatedCipher.first && authenticatedCipher.second
-                    )
-                );
-            newtoken = dynamic_cast<saml2::Assertion*>(tokenwrapper.get());
-            if (newtoken) {
-                tokenwrapper.release();
-                newtokenwrapper.reset(newtoken);
-                if (m_log.isDebugEnabled())
-                    m_log.debugStream() << "decrypted assertion: " << *newtoken << logging::eol;
-            }
-        }
-        catch (const exception& ex) {
-            m_log.error("failed to decrypt assertion: %s", ex.what());
-            throw;
-        }
-    }
-    else {
-        if (assertions.size() > 1)
-            m_log.warn("simple resolver only supports one assertion in the query response");
-        newtoken = assertions.front();
-    }
-
-    if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) {
-        m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");
-        throw SecurityPolicyException("Rejected unsigned assertion based on local policy.");
-    }
-
-    try {
-        // We're going to insist that the assertion issuer is the same as the peer.
-        // Reset the policy's message bits and extract them from the assertion.
-        policy->reset(true);
-        policy->setMessageID(newtoken->getID());
-        policy->setIssueInstant(newtoken->getIssueInstantEpoch());
-        policy->setIssuer(newtoken->getIssuer());
-        policy->evaluate(*newtoken);
-
-        // Now we can check the security status of the policy.
-        if (!policy->isAuthenticated())
-            throw SecurityPolicyException("Security of SAML 2.0 query result not established.");
-
-        if (m_subjectMatch) {
-            // Check for subject match.
-            auto_ptr<NameID> nameIDwrapper;
-            NameID* respName = newtoken->getSubject() ? newtoken->getSubject()->getNameID() : nullptr;
-            if (!respName) {
-                // Check for encryption.
-                EncryptedID* encname = newtoken->getSubject() ? newtoken->getSubject()->getEncryptedID() : nullptr;
-                if (encname) {
-                    CredentialResolver* cr=application.getCredentialResolver();
-                    if (!cr)
-                        m_log.warn("found EncryptedID, but no CredentialResolver was available");
-                    else {
-                        Locker credlocker(cr);
-                        auto_ptr<XMLObject> decryptedID(encname->decrypt(*cr, relyingParty->getXMLString("entityID").second, &mcc));
-                        respName = dynamic_cast<NameID*>(decryptedID.get());
-                        if (respName) {
-                            decryptedID.release();
-                            nameIDwrapper.reset(respName);
-                            if (m_log.isDebugEnabled())
-                                m_log.debugStream() << "decrypted NameID: " << *respName << logging::eol;
-                        }
-                    }
-                }
-            }
-
-            if (!respName || !XMLString::equals(respName->getName(), ctx.getNameID()->getName()) ||
-                !XMLString::equals(respName->getFormat(), ctx.getNameID()->getFormat()) ||
-                !XMLString::equals(respName->getNameQualifier(), ctx.getNameID()->getNameQualifier()) ||
-                !XMLString::equals(respName->getSPNameQualifier(), ctx.getNameID()->getSPNameQualifier())) {
-                if (respName)
-                    m_log.warnStream() << "ignoring Assertion without strongly matching NameID in Subject: " <<
-                        *respName << logging::eol;
-                else
-                    m_log.warn("ignoring Assertion without NameID in Subject");
-                return;
-            }
-        }
-    }
-    catch (const exception& ex) {
-        m_log.error("assertion failed policy validation: %s", ex.what());
-        throw;
-    }
-
-    // If the token's embedded, detach it.
-    if (!newtokenwrapper.get()) {
-        newtoken->detach();
-        srt.release();  // detach blows away the Response, so avoid a double free
-        newtokenwrapper.reset(newtoken);
-    }
-    ctx.getResolvedAssertions().push_back(newtoken);
-    newtokenwrapper.release();
-
-    // Finally, extract and filter the result.
-    try {
-        AttributeExtractor* extractor = application.getAttributeExtractor();
-        if (extractor) {
-            Locker extlocker(extractor);
-            extractor->extractAttributes(application, ctx.getRequest(), AA, *newtoken, ctx.getResolvedAttributes());
-        }
-
-        AttributeFilter* filter = application.getAttributeFilter();
-        if (filter) {
-            BasicFilteringContext fc(application, ctx.getResolvedAttributes(), AA, ctx.getClassRef(), ctx.getDeclRef());
-            Locker filtlocker(filter);
-            filter->filterAttributes(fc, ctx.getResolvedAttributes());
-        }
-    }
-    catch (const exception& ex) {
-        m_log.error("caught exception extracting/filtering attributes from query result: %s", ex.what());
-        for_each(ctx.getResolvedAttributes().begin(), ctx.getResolvedAttributes().end(), xmltooling::cleanup<shibsp::Attribute>());
-        ctx.getResolvedAttributes().clear();
-        throw;
-    }
-}
-
-void QueryResolver::resolveAttributes(ResolutionContext& ctx) const
-{
-#ifdef _DEBUG
-    xmltooling::NDC ndc("resolveAttributes");
-#endif
-
-    QueryContext& qctx = dynamic_cast<QueryContext&>(ctx);
-    if (!qctx.doQuery()) {
-        m_log.debug("found AttributeStatement in input to new session, skipping query");
-        return;
-    }
-
-    vector<string> statusCodes;
-
-    try {
-        if (qctx.getNameID() && qctx.getEntityDescriptor()) {
-            if (XMLString::equals(qctx.getProtocol(), samlconstants::SAML20P_NS)) {
-                m_log.debug("attempting SAML 2.0 attribute query");
-                SAML2Query(qctx, statusCodes);
-            }
-            else if (XMLString::equals(qctx.getProtocol(), samlconstants::SAML11_PROTOCOL_ENUM) ||
-                    XMLString::equals(qctx.getProtocol(), samlconstants::SAML10_PROTOCOL_ENUM)) {
-                m_log.debug("attempting SAML 1.x attribute query");
-                SAML1Query(qctx, statusCodes);
-            }
-            else {
-                m_log.info("SSO protocol does not allow for attribute query");
-            }
-        }
-        else {
-            m_log.warn("can't attempt attribute query, either no NameID or no metadata to use");
-        }
-    }
-    catch (const exception& ex) {
-        // Already logged.
-        if (!m_exceptionId.empty()) {
-            auto_ptr<SimpleAttribute> attr(new SimpleAttribute(m_exceptionId));
-            attr->getValues().push_back(XMLToolingConfig::getConfig().getURLEncoder()->encode(ex.what()));
-            qctx.getResolvedAttributes().push_back(attr.get());
-            attr.release();
-
-            if (!m_statusId.empty() && !statusCodes.empty()) {
-                auto_ptr<SimpleAttribute> attr(new SimpleAttribute(m_statusId));
-                attr->getValues().assign(statusCodes.begin(), statusCodes.end());
-                qctx.getResolvedAttributes().push_back(attr.get());
-                attr.release();
-            }
-        }
-        else {
-            throw; // not exposing the exception as an attribute, so just surface to caller
-        }
-    }
-}
diff --git a/shibsp/attribute/resolver/impl/SimpleAggregationAttributeResolver.cpp b/shibsp/attribute/resolver/impl/SimpleAggregationAttributeResolver.cpp
deleted file mode 100644
index 6d0b12d3..00000000
--- a/shibsp/attribute/resolver/impl/SimpleAggregationAttributeResolver.cpp
+++ /dev/null
@@ -1,765 +0,0 @@
-/**
- * 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
- *
- * 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.
- */
-
-/**
- * SimpleAggregationAttributeResolver.cpp
- *
- * AttributeResolver based on SAML queries to third-party AA sources.
- */
-
-#include "internal.h"
-#include "exceptions.h"
-#include "Application.h"
-#include "ServiceProvider.h"
-#include "SessionCache.h"
-#include "attribute/NameIDAttribute.h"
-#include "attribute/SimpleAttribute.h"
-#include "attribute/filtering/AttributeFilter.h"
-#include "attribute/filtering/BasicFilteringContext.h"
-#include "attribute/resolver/AttributeExtractor.h"
-#include "attribute/resolver/AttributeResolver.h"
-#include "attribute/resolver/ResolutionContext.h"
-#include "binding/SOAPClient.h"
-#include "metadata/MetadataProviderCriteria.h"
-#include "security/SecurityPolicy.h"
-#include "security/SecurityPolicyProvider.h"
-#include "util/SPConstants.h"
-
-#include <boost/algorithm/string.hpp>
-#include <boost/iterator/indirect_iterator.hpp>
-#include <boost/ptr_container/ptr_vector.hpp>
-#include <saml/exceptions.h>
-#include <saml/SAMLConfig.h>
-#include <saml/saml2/binding/SAML2SOAPClient.h>
-#include <saml/saml2/core/Protocols.h>
-#include <saml/saml2/metadata/Metadata.h>
-#include <saml/saml2/metadata/MetadataCredentialCriteria.h>
-#include <saml/saml2/metadata/MetadataProvider.h>
-#include <xmltooling/XMLToolingConfig.h>
-#include <xmltooling/security/TrustEngine.h>
-#include <xmltooling/util/NDC.h>
-#include <xmltooling/util/URLEncoder.h>
-#include <xmltooling/util/XMLHelper.h>
-#include <xercesc/util/XMLUniDefs.hpp>
-
-using namespace shibsp;
-using namespace opensaml::saml2;
-using namespace opensaml::saml2p;
-using namespace opensaml::saml2md;
-using namespace opensaml;
-using namespace xmltooling;
-using namespace boost;
-using namespace std;
-
-namespace shibsp {
-
-    class SHIBSP_DLLLOCAL SimpleAggregationContext : public ResolutionContext
-    {
-    public:
-        SimpleAggregationContext(const Application& application, const Session& session)
-            : m_app(application),
-              m_request(nullptr),
-              m_session(&session),
-              m_nameid(nullptr),
-              m_class(session.getAuthnContextClassRef()),
-              m_decl(session.getAuthnContextDeclRef()),
-              m_inputTokens(nullptr),
-              m_inputAttributes(nullptr) {
-        }
-
-        SimpleAggregationContext(
-            const Application& application,
-            const GenericRequest* request=nullptr,
-            const NameID* nameid=nullptr,
-            const XMLCh* entityID=nullptr,
-            const XMLCh* authncontext_class=nullptr,
-            const XMLCh* authncontext_decl=nullptr,
-            const vector<const opensaml::Assertion*>* tokens=nullptr,
-            const vector<shibsp::Attribute*>* attributes=nullptr
-            ) : m_app(application),
-                m_request(request),
-                m_session(nullptr),
-                m_nameid(nameid),
-                m_entityid(entityID),
-                m_class(authncontext_class),
-                m_decl(authncontext_decl),
-                m_inputTokens(tokens),
-                m_inputAttributes(attributes) {
-        }
-
-        ~SimpleAggregationContext() {
-            for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<shibsp::Attribute>());
-            for_each(m_assertions.begin(), m_assertions.end(), xmltooling::cleanup<opensaml::Assertion>());
-        }
-
-        const Application& getApplication() const {
-            return m_app;
-        }
-        const GenericRequest* getRequest() const {
-            return m_request;
-        }
-        const char* getEntityID() const {
-            return m_session ? m_session->getEntityID() : m_entityid.get();
-        }
-        const NameID* getNameID() const {
-            return m_session ? m_session->getNameID() : m_nameid;
-        }
-        const XMLCh* getClassRef() const {
-            return m_class.get();
-        }
-        const XMLCh* getDeclRef() const {
-            return m_decl.get();
-        }
-        const Session* getSession() const {
-            return m_session;
-        }
-        const vector<shibsp::Attribute*>* getInputAttributes() const {
-            return m_inputAttributes;
-        }
-        const vector<const opensaml::Assertion*>* getInputTokens() const {
-            return m_inputTokens;
-        }
-        vector<shibsp::Attribute*>& getResolvedAttributes() {
-            return m_attributes;
-        }
-        vector<opensaml::Assertion*>& getResolvedAssertions() {
-            return m_assertions;
-        }
-
-    private:
-        const Application& m_app;
-        const GenericRequest* m_request;
-        const Session* m_session;
-        const NameID* m_nameid;
-        auto_ptr_char m_entityid;
-        auto_ptr_XMLCh m_class;
-        auto_ptr_XMLCh m_decl;
-        const vector<const opensaml::Assertion*>* m_inputTokens;
-        const vector<shibsp::Attribute*>* m_inputAttributes;
-        vector<shibsp::Attribute*> m_attributes;
-        vector<opensaml::Assertion*> m_assertions;
-    };
-
-    class SHIBSP_DLLLOCAL SimpleAggregationResolver : public AttributeResolver
-    {
-    public:
-        SimpleAggregationResolver(const DOMElement* e, bool deprecationSupport=true);
-        ~SimpleAggregationResolver() {}
-
-        Lockable* lock() {return this;}
-        void unlock() {}
-
-        ResolutionContext* createResolutionContext(
-            const Application& application,
-            const GenericRequest* request,
-            const EntityDescriptor* issuer,
-            const XMLCh* protocol,
-            const NameID* nameid=nullptr,
-            const XMLCh* authncontext_class=nullptr,
-            const XMLCh* authncontext_decl=nullptr,
-            const vector<const opensaml::Assertion*>* tokens=nullptr,
-            const vector<shibsp::Attribute*>* attributes=nullptr
-            ) const {
-            return new SimpleAggregationContext(
-                application, request, nameid, (issuer ? issuer->getEntityID() : nullptr), authncontext_class, authncontext_decl, tokens, attributes
-                );
-        }
-
-        ResolutionContext* createResolutionContext(const Application& application, const Session& session) const {
-            return new SimpleAggregationContext(application,session);
-        }
-
-        void resolveAttributes(ResolutionContext& ctx) const;
-
-        void getAttributeIds(vector<string>& attributes) const {
-            if (m_extractor)
-                m_extractor->getAttributeIds(attributes);
-            if (!m_exceptionId.empty())
-                attributes.push_back(m_exceptionId.front());
-        }
-
-    private:
-        void doQuery(SimpleAggregationContext& ctx, const char* entityID, const NameID* name) const;
-
-        Category& m_log;
-        string m_policyId;
-        bool m_subjectMatch;
-        vector<string> m_attributeIds;
-        xstring m_format;
-        scoped_ptr<MetadataProvider> m_metadata;
-        scoped_ptr<TrustEngine> m_trust;
-        scoped_ptr<AttributeExtractor> m_extractor;
-        scoped_ptr<AttributeFilter> m_filter;
-        ptr_vector<saml2::Attribute> m_designators;
-        vector< pair<string,bool> > m_sources;
-        vector<string> m_exceptionId;
-    };
-
-    AttributeResolver* SHIBSP_DLLLOCAL SimpleAggregationResolverFactory(const DOMElement* const & e, bool deprecationSupport)
-    {
-        return new SimpleAggregationResolver(e, deprecationSupport);
-    }
-
-    static const XMLCh _AttributeExtractor[] =  UNICODE_LITERAL_18(A,t,t,r,i,b,u,t,e,E,x,t,r,a,c,t,o,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 attributeId[] =          UNICODE_LITERAL_11(a,t,t,r,i,b,u,t,e,I,d);
-    static const XMLCh Entity[] =               UNICODE_LITERAL_6(E,n,t,i,t,y);
-    static const XMLCh EntityReference[] =      UNICODE_LITERAL_15(E,n,t,i,t,y,R,e,f,e,r,e,n,c,e);
-    static const XMLCh exceptionId[] =          UNICODE_LITERAL_11(e,x,c,e,p,t,i,o,n,I,d);
-    static const XMLCh format[] =               UNICODE_LITERAL_6(f,o,r,m,a,t);
-    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 policyId[] =             UNICODE_LITERAL_8(p,o,l,i,c,y,I,d);
-    static const XMLCh subjectMatch[] =         UNICODE_LITERAL_12(s,u,b,j,e,c,t,M,a,t,c,h);
-    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);
-};
-
-SimpleAggregationResolver::SimpleAggregationResolver(const DOMElement* e, bool deprecationSupport)
-    : m_log(Category::getInstance(SHIBSP_LOGCAT ".AttributeResolver.SimpleAggregation")),
-        m_policyId(XMLHelper::getAttrString(e, nullptr, policyId)),
-        m_subjectMatch(XMLHelper::getAttrBool(e, false, subjectMatch))
-{
-#ifdef _DEBUG
-    xmltooling::NDC ndc("SimpleAggregationResolver");
-#endif
-
-    const XMLCh* aid = e ? e->getAttributeNS(nullptr, attributeId) : nullptr;
-    if (aid && *aid) {
-        auto_ptr_char dup(aid);
-        string sdup(dup.get());
-        trim(sdup);
-        split(m_attributeIds, sdup, is_space(), algorithm::token_compress_on);
-
-        aid = e->getAttributeNS(nullptr, format);
-        if (aid && *aid)
-            m_format = aid;
-    }
-
-    string exid(XMLHelper::getAttrString(e, nullptr, exceptionId));
-    if (!exid.empty())
-        m_exceptionId.push_back(exid);
-
-    DOMElement* child = XMLHelper::getFirstChildElement(e, _MetadataProvider);
-    if (child) {
-        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...", t.c_str());
-        m_metadata.reset(SAMLConfig::getConfig().MetadataProviderManager.newPlugin(t.c_str(), child, deprecationSupport));
-        m_metadata->init();
-    }
-
-    child = XMLHelper::getFirstChildElement(e,  _TrustEngine);
-    if (child) {
-        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...", t.c_str());
-        m_trust.reset(XMLToolingConfig::getConfig().TrustEngineManager.newPlugin(t.c_str(), child, deprecationSupport));
-    }
-
-    child = XMLHelper::getFirstChildElement(e,  _AttributeExtractor);
-    if (child) {
-        string t(XMLHelper::getAttrString(child, nullptr, _type));
-        if (t.empty())
-            throw ConfigurationException("AttributeExtractor element missing type attribute.");
-        m_log.info("building AttributeExtractor of type %s...", t.c_str());
-        m_extractor.reset(SPConfig::getConfig().AttributeExtractorManager.newPlugin(t.c_str(), child, deprecationSupport));
-    }
-
-    child = XMLHelper::getFirstChildElement(e,  _AttributeFilter);
-    if (child) {
-        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...", t.c_str());
-        m_filter.reset(SPConfig::getConfig().AttributeFilterManager.newPlugin(t.c_str(), child, deprecationSupport));
-    }
-
-    child = XMLHelper::getFirstChildElement(e);
-    while (child) {
-        if (child->hasChildNodes() && XMLString::equals(child->getLocalName(), Entity)) {
-            aid = child->getFirstChild()->getNodeValue();
-            if (aid && *aid) {
-                auto_ptr_char taid(aid);
-                m_sources.push_back(pair<string,bool>(taid.get(),true));
-            }
-        }
-        else if (child->hasChildNodes() && XMLString::equals(child->getLocalName(), EntityReference)) {
-            aid = child->getFirstChild()->getNodeValue();
-            if (aid && *aid) {
-                auto_ptr_char taid(aid);
-                m_sources.push_back(pair<string,bool>(taid.get(),false));
-            }
-        }
-        else if (XMLHelper::isNodeNamed(child, samlconstants::SAML20_NS, saml2::Attribute::LOCAL_NAME)) {
-            try {
-                auto_ptr<XMLObject> obj(saml2::AttributeBuilder::buildOneFromElement(child));
-                saml2::Attribute* down = dynamic_cast<saml2::Attribute*>(obj.get());
-                if (down) {
-                    m_designators.push_back(down);
-                    obj.release();
-                }
-            }
-            catch (const std::exception& ex) {
-                m_log.error("exception loading attribute designator: %s", ex.what());
-            }
-        }
-        child = XMLHelper::getNextSiblingElement(child);
-    }
-}
-
-void SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const char* entityID, const NameID* name) const
-{
-#ifdef _DEBUG
-    xmltooling::NDC ndc("doQuery");
-#endif
-    const Application& application = ctx.getApplication();
-    MetadataProviderCriteria mc(application, entityID, &AttributeAuthorityDescriptor::ELEMENT_QNAME, samlconstants::SAML20P_NS);
-    Locker mlocker(m_metadata.get());
-    const AttributeAuthorityDescriptor* AA=nullptr;
-    pair<const EntityDescriptor*,const RoleDescriptor*> mdresult =
-        (m_metadata ? m_metadata.get() : application.getMetadataProvider())->getEntityDescriptor(mc);
-    if (!mdresult.first) {
-        m_log.warn("unable to locate metadata for provider (%s)", entityID);
-        throw MetadataException("Unable to locate metadata for provider ($entityID)", namedparams(1, "entityID", entityID));
-    }
-    else if (!(AA=dynamic_cast<const AttributeAuthorityDescriptor*>(mdresult.second))) {
-        m_log.warn("no SAML 2 AttributeAuthority role found in metadata for (%s)", entityID);
-        throw MetadataException("Unable to locate SAML 2.0 AttributeAuthority role for provider ($entityID)", namedparams(1, "entityID", entityID));
-    }
-
-    const PropertySet* relyingParty = application.getRelyingParty(mdresult.first);
-    pair<bool,bool> signedAssertions = relyingParty->getBool("requireSignedAssertions");
-    pair<bool,const char*> encryption = relyingParty->getString("encryption");
-
-    // Locate policy key.
-    const char* policyId = m_policyId.empty() ? application.getString("policyId").second : m_policyId.c_str();
-
-    // Set up policy and SOAP client.
-    scoped_ptr<SecurityPolicy> policy(
-        application.getServiceProvider().getSecurityPolicyProvider()->createSecurityPolicy(
-            samlconstants::SAML20_PROFILE_QUERY, application, nullptr, policyId
-            )
-        );
-    if (m_metadata)
-        policy->setMetadataProvider(m_metadata.get());
-    if (m_trust)
-        policy->setTrustEngine(m_trust.get());
-    policy->getAudiences().push_back(relyingParty->getXMLString("entityID").second);
-
-    MetadataCredentialCriteria mcc(*AA);
-    shibsp::SOAPClient soaper(*policy.get());
-
-    auto_ptr_XMLCh binding(samlconstants::SAML20_BINDING_SOAP);
-    auto_ptr<saml2p::StatusResponseType> srt;
-    const vector<AttributeService*>& endpoints=AA->getAttributeServices();
-    for (indirect_iterator<vector<AttributeService*>::const_iterator> ep = make_indirect_iterator(endpoints.begin());
-            !srt.get() && ep != make_indirect_iterator(endpoints.end()); ++ep) {
-        if (!XMLString::equals(ep->getBinding(), binding.get())  || !ep->getLocation())
-            continue;
-        auto_ptr_char loc(ep->getLocation());
-        try {
-            auto_ptr<saml2::Subject> subject(saml2::SubjectBuilder::buildSubject());
-
-            // Encrypt the NameID?
-            if (SPConfig::shouldSignOrEncrypt(encryption.first ? encryption.second : "conditional", loc.get(), false)) {
-                try {
-                    auto_ptr<EncryptedID> encrypted(EncryptedIDBuilder::buildEncryptedID());
-                    encrypted->encrypt(
-                        *name,
-                        *(policy->getMetadataProvider()),
-                        mcc,
-                        false,
-                        relyingParty->getXMLString("encryptionAlg").second
-                    );
-                    subject->setEncryptedID(encrypted.get());
-                    encrypted.release();
-                }
-                catch (const std::exception& ex) {
-                    // If we're encrypting deliberately, failure should be fatal.
-                    if (encryption.first && strcmp(encryption.second, "conditional")) {
-                        throw;
-                    }
-                    // If opportunistically, just log and move on.
-                    m_log.info("Conditional encryption of NameID in AttributeQuery failed: %s", ex.what());
-                    auto_ptr<NameID> namewrapper(name->cloneNameID());
-                    subject->setNameID(namewrapper.get());
-                    namewrapper.release();
-                }
-            }
-            else {
-                auto_ptr<NameID> namewrapper(name->cloneNameID());
-                subject->setNameID(namewrapper.get());
-                namewrapper.release();
-            }
-
-            saml2p::AttributeQuery* query = saml2p::AttributeQueryBuilder::buildAttributeQuery();
-            query->setSubject(subject.release());
-            Issuer* iss = IssuerBuilder::buildIssuer();
-            iss->setName(relyingParty->getXMLString("entityID").second);
-            query->setIssuer(iss);
-            for (ptr_vector<saml2::Attribute>::const_iterator ad = m_designators.begin(); ad != m_designators.end(); ++ad) {
-                auto_ptr<saml2::Attribute> adwrapper(ad->cloneAttribute());
-                query->getAttributes().push_back(adwrapper.get());
-                adwrapper.release();
-            }
-
-            SAML2SOAPClient client(soaper, false);
-            client.sendSAML(query, application.getId(), mcc, loc.get());
-            srt.reset(client.receiveSAML());
-        }
-        catch (const std::exception& ex) {
-            m_log.error("exception during SAML query to %s: %s", loc.get(), ex.what());
-            soaper.reset();
-        }
-    }
-
-    if (!srt.get()) {
-        m_log.error("unable to obtain a SAML response from attribute authority (%s)", entityID);
-        throw BindingException("Unable to obtain a SAML response from attribute authority.");
-    }
-
-    saml2p::Response* response = dynamic_cast<saml2p::Response*>(srt.get());
-    if (!response) {
-        m_log.error("message was not a samlp:Response");
-        throw FatalProfileException("Attribute authority returned an unrecognized message.");
-    }
-    else if (!response->getStatus() || !response->getStatus()->getStatusCode() ||
-            !XMLString::equals(response->getStatus()->getStatusCode()->getValue(), saml2p::StatusCode::SUCCESS)) {
-        m_log.error("attribute authority (%s) returned a SAML error", entityID);
-        throw FatalProfileException("Attribute authority returned a SAML error.");
-    }
-
-    saml2::Assertion* newtoken = nullptr;
-    auto_ptr<saml2::Assertion> newtokenwrapper;
-    const vector<saml2::Assertion*>& assertions = const_cast<const saml2p::Response*>(response)->getAssertions();
-    if (assertions.empty()) {
-        // Check for encryption.
-        const vector<saml2::EncryptedAssertion*>& encassertions =
-            const_cast<const saml2p::Response*>(response)->getEncryptedAssertions();
-        if (encassertions.empty()) {
-            m_log.warn("response from attribute authority was empty");
-            return;
-        }
-        else if (encassertions.size() > 1) {
-            m_log.warn("simple resolver only supports one assertion in the query response");
-        }
-
-        CredentialResolver* cr=application.getCredentialResolver();
-        if (!cr) {
-            m_log.warn("found encrypted assertion, but no CredentialResolver was available");
-            throw FatalProfileException("Assertion was encrypted, but no decryption credentials are available.");
-        }
-
-        // With this flag on, we block unauthenticated ciphertext when decrypting,
-        // unless the protocol was authenticated.
-        pair<bool,bool> authenticatedCipher = application.getBool("requireAuthenticatedEncryption");
-        if (policy->isAuthenticated())
-            authenticatedCipher.second = false;
-
-        // Attempt to decrypt it.
-        try {
-            Locker credlocker(cr);
-            auto_ptr<XMLObject> tokenwrapper(
-                encassertions.front()->decrypt(
-                    *cr, relyingParty->getXMLString("entityID").second, &mcc, authenticatedCipher.first && authenticatedCipher.second
-                    )
-                );
-            newtoken = dynamic_cast<saml2::Assertion*>(tokenwrapper.get());
-            if (newtoken) {
-                tokenwrapper.release();
-                newtokenwrapper.reset(newtoken);
-                if (m_log.isDebugEnabled())
-                    m_log.debugStream() << "decrypted assertion: " << *newtoken << logging::eol;
-            }
-        }
-        catch (const std::exception& ex) {
-            m_log.error("failed to decrypt assertion: %s", ex.what());
-            throw;
-        }
-    }
-    else {
-        if (assertions.size() > 1)
-            m_log.warn("simple resolver only supports one assertion in the query response");
-        newtoken = assertions.front();
-    }
-
-    if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) {
-        m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");
-        throw SecurityPolicyException("Rejected unsigned assertion based on local policy.");
-    }
-
-    try {
-        // We're going to insist that the assertion issuer is the same as the peer.
-        // Reset the policy's message bits and extract them from the assertion.
-        policy->reset(true);
-        policy->setMessageID(newtoken->getID());
-        policy->setIssueInstant(newtoken->getIssueInstantEpoch());
-        policy->setIssuer(newtoken->getIssuer());
-        policy->evaluate(*newtoken);
-
-        // Now we can check the security status of the policy.
-        if (!policy->isAuthenticated())
-            throw SecurityPolicyException("Security of SAML 2.0 query result not established.");
-
-        if (m_subjectMatch) {
-            // Check for subject match.
-            auto_ptr<NameID> nameIDwrapper;
-            NameID* respName = newtoken->getSubject() ? newtoken->getSubject()->getNameID() : nullptr;
-            if (!respName) {
-                // Check for encryption.
-                EncryptedID* encname = newtoken->getSubject() ? newtoken->getSubject()->getEncryptedID() : nullptr;
-                if (encname) {
-                    CredentialResolver* cr=application.getCredentialResolver();
-                    if (!cr)
-                        m_log.warn("found EncryptedID, but no CredentialResolver was available");
-                    else {
-                        Locker credlocker(cr);
-                        auto_ptr<XMLObject> decryptedID(encname->decrypt(*cr, relyingParty->getXMLString("entityID").second, &mcc));
-                        respName = dynamic_cast<NameID*>(decryptedID.get());
-                        if (respName) {
-                            decryptedID.release();
-                            nameIDwrapper.reset(respName);
-                            if (m_log.isDebugEnabled())
-                                m_log.debugStream() << "decrypted NameID: " << *respName << logging::eol;
-                        }
-                    }
-                }
-            }
-
-            if (!respName || !XMLString::equals(respName->getName(), name->getName()) ||
-                !XMLString::equals(respName->getFormat(), name->getFormat()) ||
-                !XMLString::equals(respName->getNameQualifier(), name->getNameQualifier()) ||
-                !XMLString::equals(respName->getSPNameQualifier(), name->getSPNameQualifier())) {
-                if (respName)
-                    m_log.warnStream() << "ignoring Assertion without strongly matching NameID in Subject: " <<
-                        *respName << logging::eol;
-                else
-                    m_log.warn("ignoring Assertion without NameID in Subject");
-                return;
-            }
-        }
-    }
-    catch (const std::exception& ex) {
-        m_log.error("assertion failed policy validation: %s", ex.what());
-        throw;
-    }
-
-    // If the token's embedded, detach it.
-    if (!newtokenwrapper.get()) {
-        newtoken->detach();
-        srt.release();  // detach blows away the Response, so avoid a double free
-        newtokenwrapper.reset(newtoken);
-    }
-    ctx.getResolvedAssertions().push_back(newtoken);
-    newtokenwrapper.release();
-
-    // Finally, extract and filter the result.
-    try {
-        AttributeExtractor* extractor = m_extractor ? m_extractor.get() : application.getAttributeExtractor();
-        if (extractor) {
-            Locker extlocker(extractor);
-            extractor->extractAttributes(application, ctx.getRequest(), AA, *newtoken, ctx.getResolvedAttributes());
-        }
-
-        AttributeFilter* filter = m_filter ? m_filter.get() : application.getAttributeFilter();
-        if (filter) {
-            BasicFilteringContext fc(application, ctx.getResolvedAttributes(), AA, ctx.getClassRef(), ctx.getDeclRef());
-            Locker filtlocker(filter);
-            filter->filterAttributes(fc, ctx.getResolvedAttributes());
-        }
-    }
-    catch (const std::exception& ex) {
-        m_log.error("caught exception extracting/filtering attributes from query result: %s", ex.what());
-        for_each(ctx.getResolvedAttributes().begin(), ctx.getResolvedAttributes().end(), xmltooling::cleanup<shibsp::Attribute>());
-        ctx.getResolvedAttributes().clear();
-        throw;
-    }
-}
-
-void SimpleAggregationResolver::resolveAttributes(ResolutionContext& ctx) const
-{
-#ifdef _DEBUG
-    xmltooling::NDC ndc("resolveAttributes");
-#endif
-
-    SimpleAggregationContext& qctx = dynamic_cast<SimpleAggregationContext&>(ctx);
-
-    // First we manufacture the appropriate NameID to use.
-    scoped_ptr<NameID> n;
-    for (vector<string>::const_iterator a = m_attributeIds.begin(); !n.get() && a != m_attributeIds.end(); ++a) {
-        const Attribute* attr=nullptr;
-        if (qctx.getSession()) {
-            // Input attributes should be available via multimap.
-            pair<multimap<string,const Attribute*>::const_iterator, multimap<string,const Attribute*>::const_iterator> range =
-                qctx.getSession()->getIndexedAttributes().equal_range(*a);
-            for (; !attr && range.first != range.second; ++range.first) {
-                if (range.first->second->valueCount() > 0)
-                    attr = range.first->second;
-            }
-        }
-        else if (qctx.getInputAttributes()) {
-            // Have to loop over unindexed set.
-            const vector<Attribute*>* matches = qctx.getInputAttributes();
-            for (indirect_iterator<vector<Attribute*>::const_iterator> match = make_indirect_iterator(matches->begin());
-                    !attr && match != make_indirect_iterator(matches->end()); ++match) {
-                if (*a == match->getId() && match->valueCount() > 0)
-                    attr = &(*match);
-            }
-        }
-
-        if (attr) {
-            m_log.debug("using input attribute (%s) as identifier for queries", attr->getId());
-            n.reset(NameIDBuilder::buildNameID());
-            const NameIDAttribute* down = dynamic_cast<const NameIDAttribute*>(attr);
-            if (down) {
-                // We can create a NameID directly from the source material.
-                const NameIDAttribute::Value& v = down->getValues().front();
-                auto_arrayptr<XMLCh> val(fromUTF8(v.m_Name.c_str()));
-                n->setName(val.get());
-
-                if (!v.m_Format.empty()) {
-                    auto_arrayptr<XMLCh> format(fromUTF8(v.m_Format.c_str()));
-                    n->setFormat(format.get());
-                }
-                if (!v.m_NameQualifier.empty()) {
-                    auto_arrayptr<XMLCh> nq(fromUTF8(v.m_NameQualifier.c_str()));
-                    n->setNameQualifier(nq.get());
-                }
-                if (!v.m_SPNameQualifier.empty()) {
-                    auto_arrayptr<XMLCh> spnq(fromUTF8(v.m_SPNameQualifier.c_str()));
-                    n->setSPNameQualifier(spnq.get());
-                }
-                if (!v.m_SPProvidedID.empty()) {
-                    auto_arrayptr<XMLCh> sppid(fromUTF8(v.m_SPProvidedID.c_str()));
-                    n->setSPProvidedID(sppid.get());
-                }
-            }
-            else {
-                // We have to mock up the NameID.
-                auto_arrayptr<XMLCh> val(fromUTF8(attr->getSerializedValues().front().c_str()));
-                n->setName(val.get());
-                if (!m_format.empty())
-                    n->setFormat(m_format.c_str());
-            }
-        }
-    }
-
-    if (!n) {
-        if (qctx.getNameID() && m_attributeIds.empty()) {
-            m_log.debug("using authenticated NameID as identifier for queries");
-        }
-        else {
-            m_log.warn("unable to resolve attributes, no suitable query identifier found");
-            return;
-        }
-    }
-
-    set<string> history;
-
-    // Put initial IdP into history to prevent extra query.
-    if (qctx.getEntityID())
-        history.insert(qctx.getEntityID());
-
-    // Prepare to track exceptions.
-    auto_ptr<SimpleAttribute> exceptAttr;
-    if (!m_exceptionId.empty())
-        exceptAttr.reset(new SimpleAttribute(m_exceptionId));
-
-    // We have a master loop over all the possible sources of material.
-    for (vector< pair<string,bool> >::const_iterator source = m_sources.begin(); source != m_sources.end(); ++source) {
-        if (source->second) {
-            // A literal entityID to query.
-            if (history.count(source->first) == 0) {
-                m_log.debug("issuing SAML query to (%s)", source->first.c_str());
-                try {
-                    doQuery(qctx, source->first.c_str(), n ? n.get() : qctx.getNameID());
-                }
-                catch (const std::exception& ex) {
-                    if (exceptAttr.get())
-                        exceptAttr->getValues().push_back(XMLToolingConfig::getConfig().getURLEncoder()->encode(ex.what()));
-                }
-                history.insert(source->first);
-            }
-            else {
-                m_log.debug("skipping previously queried attribute source (%s)", source->first.c_str());
-            }
-        }
-        else {
-            m_log.debug("using attribute sources referenced in attribute (%s)", source->first.c_str());
-            if (qctx.getSession()) {
-                // Input attributes should be available via multimap.
-                pair<multimap<string,const Attribute*>::const_iterator, multimap<string,const Attribute*>::const_iterator> range =
-                    qctx.getSession()->getIndexedAttributes().equal_range(source->first);
-                for (; range.first != range.second; ++range.first) {
-                    const vector<string>& links = range.first->second->getSerializedValues();
-                    for (vector<string>::const_iterator link = links.begin(); link != links.end(); ++link) {
-                        if (history.count(*link) == 0) {
-                            m_log.debug("issuing SAML query to (%s)", link->c_str());
-                            try {
-                                doQuery(qctx, link->c_str(), n ? n.get() : qctx.getNameID());
-                            }
-                            catch (const std::exception& ex) {
-                                if (exceptAttr.get())
-                                    exceptAttr->getValues().push_back(XMLToolingConfig::getConfig().getURLEncoder()->encode(ex.what()));
-                            }
-                            history.insert(*link);
-                        }
-                        else {
-                            m_log.debug("skipping previously queried attribute source (%s)", link->c_str());
-                        }
-                    }
-                }
-            }
-            else if (qctx.getInputAttributes()) {
-                // Have to loop over unindexed set.
-                const vector<Attribute*>* matches = qctx.getInputAttributes();
-                for (indirect_iterator<vector<Attribute*>::const_iterator> match = make_indirect_iterator(matches->begin());
-                        match != make_indirect_iterator(matches->end()); ++match) {
-                    if (source->first == match->getId()) {
-                        const vector<string>& links = match->getSerializedValues();
-                        for (vector<string>::const_iterator link = links.begin(); link != links.end(); ++link) {
-                            if (history.count(*link) == 0) {
-                                m_log.debug("issuing SAML query to (%s)", link->c_str());
-                                try {
-                                    doQuery(qctx, link->c_str(), n ? n.get() : qctx.getNameID());
-                                }
-                                catch (const std::exception& ex) {
-                                    if (exceptAttr.get())
-                                        exceptAttr->getValues().push_back(XMLToolingConfig::getConfig().getURLEncoder()->encode(ex.what()));
-                                }
-                                history.insert(*link);
-                            }
-                            else {
-                                m_log.debug("skipping previously queried attribute source (%s)", link->c_str());
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    if (exceptAttr.get()) {
-        qctx.getResolvedAttributes().push_back(exceptAttr.get());
-        exceptAttr.release();
-    }
-}
diff --git a/shibsp/attribute/resolver/impl/XMLAttributeExtractor.cpp b/shibsp/attribute/resolver/impl/XMLAttributeExtractor.cpp
deleted file mode 100644
index 927788c8..00000000
--- a/shibsp/attribute/resolver/impl/XMLAttributeExtractor.cpp
+++ /dev/null
@@ -1,1068 +0,0 @@
-/**
- * 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
- *
- * 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.
- */
-
-/**
- * XMLAttributeExtractor.cpp
- *
- * AttributeExtractor based on an XML mapping file.
- */
-
-#include "internal.h"
-#include "exceptions.h"
-#include "Application.h"
-#include "ServiceProvider.h"
-#include "attribute/Attribute.h"
-#include "attribute/AttributeDecoder.h"
-#include "attribute/filtering/AttributeFilter.h"
-#include "attribute/filtering/BasicFilteringContext.h"
-#include "attribute/resolver/AttributeExtractor.h"
-#include "remoting/ddf.h"
-#include "security/SecurityPolicy.h"
-#include "util/SPConstants.h"
-
-#define BOOST_BIND_GLOBAL_PLACEHOLDERS
-#include <boost/bind.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/algorithm/string.hpp>
-#include <boost/iterator/indirect_iterator.hpp>
-#include <boost/ptr_container/ptr_vector.hpp>
-#include <boost/tuple/tuple.hpp>
-#include <saml/SAMLConfig.h>
-#include <saml/saml1/core/Assertions.h>
-#include <saml/saml2/core/Assertions.h>
-#include <saml/saml2/metadata/Metadata.h>
-#include <saml/saml2/metadata/MetadataCredentialCriteria.h>
-#include <saml/saml2/metadata/ObservableMetadataProvider.h>
-#include <xmltooling/XMLToolingConfig.h>
-#include <xmltooling/security/TrustEngine.h>
-#include <xmltooling/util/NDC.h>
-#include <xmltooling/util/ReloadableXMLFile.h>
-#include <xmltooling/util/Threads.h>
-#include <xmltooling/util/XMLHelper.h>
-#include <xercesc/util/XMLUniDefs.hpp>
-
-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;
-using saml2::EncryptedAttribute;
-
-namespace shibsp {
-
-#if defined (_MSC_VER)
-    #pragma warning( push )
-    #pragma warning( disable : 4250 )
-#endif
-
-    class XMLExtractorImpl : public ObservableMetadataProvider::Observer
-    {
-    public:
-        XMLExtractorImpl(const DOMElement* e, Category& log, bool deprecationSupport);
-        ~XMLExtractorImpl() {
-            for (map<const ObservableMetadataProvider*,decoded_t>::iterator i=m_decodedMap.begin(); i!=m_decodedMap.end(); ++i) {
-                i->first->removeObserver(this);
-                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&,DDF>(&DDF::destroy));
-            }
-            if (m_document)
-                m_document->release();
-        }
-
-        void setDocument(DOMDocument* doc) {
-            m_document = doc;
-        }
-
-        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&,DDF>(&DDF::destroy));
-            d.clear();
-        }
-
-        void onEvent(const ObservableMetadataProvider& metadata, const EntityDescriptor& entity) const {
-            // Destroy attributes we cached from this provider and entity.
-            m_attrLock->wrlock();
-            SharedLock wrapper(m_attrLock, false);
-            decoded_t& d = m_decodedMap[&metadata];
-            decoded_t::iterator i = d.find(entity.getEntityID());
-            if (i != d.end()) {
-                for_each(i->second.begin(), i->second.end(), mem_fun_ref<DDF&, DDF>(&DDF::destroy));
-                d.erase(i);
-            }
-        }
-
-
-        void extractAttributes(const Application&, const char*, const char*, const NameIdentifier&, ptr_vector<Attribute>&) const;
-        void extractAttributes(const Application&, const char*, const char*, const NameID&, ptr_vector<Attribute>&) const;
-        void extractAttributes(const Application&, const GenericRequest*, const char*, const char*, const saml1::Attribute&, ptr_vector<Attribute>&) const;
-        void extractAttributes(const Application&, const GenericRequest*, const char*, const char*, const saml2::Attribute&, ptr_vector<Attribute>&) const;
-        void extractAttributes(const Application&, const GenericRequest*, const char*, const char*, const saml1::AttributeStatement&, ptr_vector<Attribute>&) const;
-        void extractAttributes(const Application&, const GenericRequest*, const char*, const char*, const saml2::AttributeStatement&, ptr_vector<Attribute>&) const;
-        void extractAttributes(
-            const Application&, const GenericRequest*, const ObservableMetadataProvider*, const XMLCh*, const char*, const Extensions&, ptr_vector<Attribute>&
-            ) const;
-
-        void getAttributeIds(vector<string>& attributes) const {
-            attributes.insert(attributes.end(), m_attributeIds.begin(), m_attributeIds.end());
-        }
-
-        void generateMetadata(SPSSODescriptor& role) const;
-
-    private:
-        Category& m_log;
-        DOMDocument* m_document;
-        typedef map< pair<xstring,xstring>,pair< boost::shared_ptr<AttributeDecoder>,vector<string> > > attrmap_t;
-        attrmap_t m_attrMap;
-        vector<string> m_attributeIds;
-        vector< boost::tuple<xstring,xstring,bool> > m_requestedAttrs;
-
-        // settings for embedded assertions in metadata
-        string m_policyId;
-        scoped_ptr<AttributeFilter> m_filter;
-        scoped_ptr<MetadataProvider> m_metadata;
-        scoped_ptr<TrustEngine> m_trust;
-        bool m_entityAssertions,m_metaAttrCaching;
-
-        // manages caching of decoded Attributes
-        scoped_ptr<RWLock> m_attrLock;
-        typedef map< xstring,vector<DDF> > decoded_t;
-        mutable map<const ObservableMetadataProvider*,decoded_t> m_decodedMap;
-    };
-
-    class XMLExtractor : public AttributeExtractor, public ReloadableXMLFile
-    {
-    public:
-        XMLExtractor(const DOMElement* e, bool deprecationSupport=true)
-            : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT ".AttributeExtractor.XML"), true, deprecationSupport),
-                m_deprecationSupport(deprecationSupport)
-        {
-            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() {
-            shutdown();
-        }
-
-        void extractAttributes(const Application&, const GenericRequest*, const RoleDescriptor*, const XMLObject&, vector<Attribute*>&) const;
-
-        void getAttributeIds(std::vector<std::string>& attributes) const {
-            if (m_impl)
-                m_impl->getAttributeIds(attributes);
-        }
-
-        void generateMetadata(SPSSODescriptor& role) const {
-            if (m_impl)
-                m_impl->generateMetadata(role);
-        }
-
-    protected:
-        pair<bool,DOMElement*> background_load();
-
-    private:
-        bool m_deprecationSupport;
-        scoped_ptr<XMLExtractorImpl> m_impl;
-
-        void extractAttributes(const Application&, const GenericRequest*, const RoleDescriptor*, const XMLObject&, ptr_vector<Attribute>&) const;
-    };
-
-#if defined (_MSC_VER)
-    #pragma warning( pop )
-#endif
-
-    AttributeExtractor* SHIBSP_DLLLOCAL XMLAttributeExtractorFactory(const DOMElement* const & e, bool)
-    {
-        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 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, bool deprecationSupport)
-    : m_log(log),
-        m_document(nullptr),
-        m_policyId(XMLHelper::getAttrString(e, nullptr, metadataPolicyId)),
-        m_entityAssertions(true),
-        m_metaAttrCaching(XMLHelper::getAttrBool(e, false, metadataAttributeCaching))
-{
-#ifdef _DEBUG
-    xmltooling::NDC ndc("XMLExtractorImpl");
-#endif
-
-    if (!XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEMAP_NS, Attributes))
-        throw ConfigurationException("XML AttributeExtractor requires am:Attributes at root of configuration.");
-
-    DOMElement* child = XMLHelper::getFirstChildElement(e, shibspconstants::SHIB2ATTRIBUTEMAP_NS, _MetadataProvider);
-    if (child) {
-        try {
-            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...", t.c_str());
-            m_metadata.reset(SAMLConfig::getConfig().MetadataProviderManager.newPlugin(t.c_str(), child, deprecationSupport));
-            m_metadata->init();
-        }
-        catch (const 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");
-        }
-    }
-
-    if (m_entityAssertions) {
-        child = XMLHelper::getFirstChildElement(e, shibspconstants::SHIB2ATTRIBUTEMAP_NS, _TrustEngine);
-        if (child) {
-            try {
-                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...", t.c_str());
-                m_trust.reset(XMLToolingConfig::getConfig().TrustEngineManager.newPlugin(t.c_str(), child, deprecationSupport));
-            }
-            catch (const 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");
-            }
-        }
-    }
-
-    if (m_entityAssertions) {
-        child = XMLHelper::getFirstChildElement(e, shibspconstants::SHIB2ATTRIBUTEMAP_NS, _AttributeFilter);
-        if (child) {
-            try {
-                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...", t.c_str());
-                m_filter.reset(SPConfig::getConfig().AttributeFilterManager.newPlugin(t.c_str(), child, deprecationSupport));
-            }
-            catch (const 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");
-            }
-        }
-    }
-
-    child = XMLHelper::getFirstChildElement(e, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME);
-    while (child) {
-        // Check for missing name or id.
-        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(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);
-            continue;
-        }
-        else if (!strcmp(id.get(), "REMOTE_USER")) {
-            m_log.warn("skipping Attribute, id of REMOTE_USER is a reserved name");
-            child = XMLHelper::getNextSiblingElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME);
-            continue;
-        }
-
-        boost::shared_ptr<AttributeDecoder> decoder;
-        try {
-            DOMElement* dchild = XMLHelper::getFirstChildElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, _AttributeDecoder);
-            if (dchild) {
-                scoped_ptr<xmltooling::QName> q(XMLHelper::getXSIType(dchild));
-                if (q)
-                    decoder.reset(SPConfig::getConfig().AttributeDecoderManager.newPlugin(*q, dchild, deprecationSupport));
-            }
-            if (!decoder)
-                decoder.reset(SPConfig::getConfig().AttributeDecoderManager.newPlugin(StringAttributeDecoderType, nullptr, deprecationSupport));
-        }
-        catch (const std::exception& ex) {
-            m_log.error("skipping Attribute (%s), error building AttributeDecoder: %s", id.get(), ex.what());
-        }
-
-        if (!decoder) {
-            child = XMLHelper::getNextSiblingElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME);
-            continue;
-        }
-
-        // Empty NameFormat implies the usual Shib URI naming defaults.
-        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.
-        // Trim the format, or the name only if the format is the default (URI).
-        pair<xstring,xstring> entryKey;
-        if (*format == chNull) {
-            auto_ptr_XMLCh copyName(name);
-            entryKey.first = copyName.get();
-        } else {
-            entryKey.first = name;
-            auto_ptr_XMLCh copyFormat(format);
-            entryKey.second = copyFormat.get();
-        }
-        pair< boost::shared_ptr<AttributeDecoder>,vector<string> >& decl = m_attrMap[entryKey];
-        if (decl.first) {
-            m_log.warn("skipping duplicate Attribute mapping (same name and nameFormat)");
-            child = XMLHelper::getNextSiblingElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME);
-            continue;
-        }
-
-        if (m_log.isInfoEnabled()) {
-            auto_ptr_char n(entryKey.first.c_str());
-            auto_ptr_char f(entryKey.second.c_str());
-            m_log.info("creating mapping for Attribute %s%s%s", n.get(), *f.get() ? ", Format/Namespace:" : "", f.get());
-        }
-
-        decl.first = decoder;
-        decl.second.push_back(id.get());
-        m_attributeIds.push_back(id.get());
-
-        // 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<xstring,xstring,bool>(entryKey.first, entryKey.second, required));
-        }
-
-        if (deprecationSupport) {
-            name = child->getAttributeNS(nullptr, _aliases);
-            if (name && *name) {
-                SPConfig::getConfig().deprecation().warn("attribute mapping rule (%s) uses deprecated aliases feature", id.get());
-                auto_ptr_char aliases(name);
-                string dup(aliases.get());
-                set<string> new_aliases;
-                split(new_aliases, dup, is_space(), algorithm::token_compress_on);
-                set<string>::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);
-    }
-
-    if (m_metaAttrCaching)
-        m_attrLock.reset(RWLock::create());
-}
-
-void XMLExtractorImpl::generateMetadata(SPSSODescriptor& role) const
-{
-    if (m_requestedAttrs.empty())
-        return;
-    int index = 1;
-    const vector<AttributeConsumingService*>& svcs = const_cast<const SPSSODescriptor*>(&role)->getAttributeConsumingServices();
-    for (vector<AttributeConsumingService*>::const_iterator s =svcs.begin(); s != svcs.end(); ++s) {
-        pair<bool,int> 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<EntityDescriptor*>(role.getParent())->getEntityID());
-    static const XMLCh english[] = UNICODE_LITERAL_2(e,n);
-    sn->setLang(english);
-
-    for (vector< boost::tuple<xstring,xstring,bool> >::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(
-    const Application& application,
-    const char* assertingParty,
-    const char* relyingParty,
-    const NameIdentifier& nameid,
-    ptr_vector<Attribute>& attributes
-    ) const
-{
-    const XMLCh* format = nameid.getFormat();
-    if (!format || !*format)
-        format = NameIdentifier::UNSPECIFIED;
-    attrmap_t::const_iterator rule;
-    if ((rule = m_attrMap.find(pair<xstring,xstring>(format,xstring()))) != m_attrMap.end()) {
-        auto_ptr<Attribute> 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()) {
-        auto_ptr_char temp(format);
-        m_log.debug("skipping NameIdentifier with format (%s)", temp.get());
-    }
-}
-
-void XMLExtractorImpl::extractAttributes(
-    const Application& application,
-    const char* assertingParty,
-    const char* relyingParty,
-    const NameID& nameid,
-    ptr_vector<Attribute>& attributes
-    ) const
-{
-    const XMLCh* format = nameid.getFormat();
-    if (!format || !*format)
-        format = NameID::UNSPECIFIED;
-    attrmap_t::const_iterator rule;
-    if ((rule = m_attrMap.find(pair<xstring,xstring>(format,xstring()))) != m_attrMap.end()) {
-        auto_ptr<Attribute> 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()) {
-        auto_ptr_char temp(format);
-        m_log.debug("skipping 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,
-    ptr_vector<Attribute>& attributes
-    ) const
-{
-    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;
-    attrmap_t::const_iterator rule;
-    if ((rule = m_attrMap.find(pair<xstring,xstring>(name,format))) != m_attrMap.end()) {
-        auto_ptr<Attribute> 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()) {
-        auto_ptr_char temp1(name);
-        auto_ptr_char temp2(format);
-        m_log.info("skipping 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,
-    ptr_vector<Attribute>& attributes
-    ) const
-{
-    const XMLCh* name = attr.getName();
-    const XMLCh* format = attr.getNameFormat();
-    if (!name || !*name)
-        return;
-    if (!format || !*format)
-        format = saml2::Attribute::UNSPECIFIED;
-    else if (XMLString::equals(format, saml2::Attribute::URI_REFERENCE))
-        format = &chNull;
-    attrmap_t::const_iterator rule;
-    if ((rule = m_attrMap.find(pair<xstring,xstring>(name,format))) != m_attrMap.end()) {
-        auto_ptr<Attribute> 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 (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<xstring,xstring>(name,xstring()))) != m_attrMap.end()) {
-            auto_ptr<Attribute> 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);
-        m_log.info("skipping 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<Attribute>& attributes
-    ) const
-{
-    static void (XMLExtractorImpl::* extract)(
-        const Application&, const GenericRequest*, const char*, const char*, const saml1::Attribute&, ptr_vector<Attribute>&
-        ) 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<Attribute>& attributes
-    ) const
-{
-    static void (XMLExtractorImpl::* extract)(
-        const Application&, const GenericRequest*, const char*, const char*, const saml2::Attribute&, ptr_vector<Attribute>&
-        ) 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,
-    ptr_vector<Attribute>& attributes
-    ) const
-{
-
-    const XMLCh* cacheID = nullptr;
-    if (observable && m_metaAttrCaching && dynamic_cast<const EntityDescriptor*>(ext.getParent())) {
-        cacheID = dynamic_cast<const EntityDescriptor*>(ext.getParent())->getEntityID();
-    }
-
-    const vector<XMLObject*>& exts = ext.getUnknownXMLObjects();
-    for (vector<XMLObject*>::const_iterator i = exts.begin(); i != exts.end(); ++i) {
-        const EntityAttributes* container = dynamic_cast<const EntityAttributes*>(*i);
-        if (!container)
-            continue;
-
-        map<const ObservableMetadataProvider*,decoded_t>::iterator cacheEntry;
-
-        // Check for cached result.
-        if (cacheID) {
-            m_attrLock->rdlock();
-            cacheEntry = m_decodedMap.find(observable);
-            if (cacheEntry == m_decodedMap.end()) {
-                // We need to elevate the lock and retry.
-                m_attrLock->unlock();
-                m_attrLock->wrlock();
-                cacheEntry = m_decodedMap.find(observable);
-                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);
-
-                    // Prime the map reference with an empty decoded map.
-                    cacheEntry = m_decodedMap.insert(make_pair(observable,decoded_t())).first;
-
-                    // 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();
-                }
-            }
-        }
-
-        if (cacheID) {
-            // We're holding the lock, so check the cache.
-            decoded_t::iterator d = cacheEntry->second.find(cacheID);
-            if (d != cacheEntry->second.end()) {
-                SharedLock locker(m_attrLock, false);   // pop the lock when we're done
-                for (vector<DDF>::iterator obj = d->second.begin(); obj != d->second.end(); ++obj) {
-                    auto_ptr<Attribute> wrapper(Attribute::unmarshall(*obj));
-                    m_log.debug("recovered cached metadata attribute (%s)", wrapper->getId());
-                    attributes.push_back(wrapper.get());
-                    wrapper.release();
-                }
-                break;
-            }
-        }
-
-        // Add a guard for the lock if we're caching.
-        SharedLock locker(cacheID ? m_attrLock.get() : nullptr, false);
-
-        // Use a holding area to support caching.
-        ptr_vector<Attribute> holding;
-
-        // 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<Attribute>&
-            ) 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<saml2::Assertion*>& asserts = container->getAssertions();
-            for (indirect_iterator<vector<saml2::Assertion*>::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()) {
-                    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());
-                    }
-                    continue;
-                }
-                else {
-                    // Check subject.
-                    const NameID* subject = assert->getSubject() ? assert->getSubject()->getNameID() : nullptr;
-                    if (!subject ||
-                            !XMLString::equals(subject->getFormat(), NameID::ENTITY) ||
-                            !XMLString::equals(subject->getName(), entityID)) {
-                        if (m_log.isDebugEnabled()) {
-                            auto_ptr_char eid(entityID);
-                            m_log.debug("skipping assertion with improper Subject in metadata extension for entity (%s)", eid.get());
-                        }
-                        continue;
-                    }
-                }
-
-                try {
-                    // Set up and evaluate a policy for an AA asserting attributes to us.
-                    shibsp::SecurityPolicy policy(application, &AttributeAuthorityDescriptor::ELEMENT_QNAME, false, m_policyId.c_str());
-                    Locker locker(m_metadata.get());
-                    if (m_metadata)
-                        policy.setMetadataProvider(m_metadata.get());
-                    if (m_trust)
-                        policy.setTrustEngine(m_trust.get());
-                    // Populate recipient as audience.
-                    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());
-
-                    // Look up metadata for issuer.
-                    if (policy.getIssuer() && policy.getMetadataProvider()) {
-                        if (policy.getIssuer()->getFormat() && !XMLString::equals(policy.getIssuer()->getFormat(), saml2::NameIDType::ENTITY)) {
-                            m_log.debug("non-system entity issuer, skipping metadata lookup");
-                        }
-                        else {
-                            m_log.debug("searching metadata for entity assertion issuer...");
-                            pair<const EntityDescriptor*,const RoleDescriptor*> lookup;
-                            MetadataProvider::Criteria& mc = policy.getMetadataProviderCriteria();
-                            mc.entityID_unicode = policy.getIssuer()->getName();
-                            mc.role = &AttributeAuthorityDescriptor::ELEMENT_QNAME;
-                            mc.protocol = samlconstants::SAML20P_NS;
-                            lookup = policy.getMetadataProvider()->getEntityDescriptor(mc);
-                            if (!lookup.first) {
-                                auto_ptr_char iname(policy.getIssuer()->getName());
-                                m_log.debug("no metadata found, can't establish identity of issuer (%s)", iname.get());
-                            }
-                            else if (!lookup.second) {
-                                m_log.debug("unable to find compatible AA role in metadata");
-                            }
-                            else {
-                                policy.setIssuerMetadata(lookup.second);
-                            }
-                        }
-                    }
-
-                    // Authenticate the assertion. We have to clone and marshall it to establish the signature for verification.
-                    scoped_ptr<saml2::Assertion> tokencopy(assert->cloneAssertion());
-                    tokencopy->marshall();
-                    policy.evaluate(*tokencopy);
-                    if (!policy.isAuthenticated()) {
-                        if (m_log.isDebugEnabled()) {
-                            auto_ptr_char tempid(tokencopy->getID());
-                            auto_ptr_char eid(entityID);
-                            m_log.debug(
-                                "failed to authenticate assertion (%s) in metadata extension for entity (%s)", tempid.get(), eid.get()
-                                );
-                        }
-                        continue;
-                    }
-
-                    // Override the asserting/relying party names based on this new issuer.
-                    const EntityDescriptor* inlineEntity =
-                        policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(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<Attribute> holding2;
-                    const vector<saml2::Attribute*>& attrs2 =
-                        const_cast<const saml2::AttributeStatement*>(tokencopy->getAttributeStatements().front())->getAttributes();
-                    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()) {
-
-                        // The filter API uses an unsafe container, so we have to transfer everything into one and back.
-                        vector<Attribute*> unsafe_holding2;
-
-                        // Use a local exception context since the container is unsafe.
-                        try {
-                            while (!holding2.empty()) {
-                                ptr_vector<Attribute>::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<Attribute> ptr(unsafe_holding2.back());
-                                unsafe_holding2.pop_back();
-                                holding2.push_back(ptr.get());
-                                ptr.release();
-                            }
-                        }
-                        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(unsafe_holding2.begin(), unsafe_holding2.end(), xmltooling::cleanup<Attribute>());
-                            holding2.clear();   // in case the exception was during transfer between containers
-                        }
-                    }
-
-                    if (!holding2.empty()) {
-                        // Copy them over to the main holding tank, which transfers ownership.
-                        holding.transfer(holding.end(), holding2);
-                    }
-                }
-                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 eid(entityID);
-                        m_log.debug(
-                            "exception authenticating assertion (%s) in metadata extension for entity (%s): %s",
-                            tempid.get(),
-                            eid.get(),
-                            ex.what()
-                            );
-                    }
-                    continue;
-                }
-            }
-        }
-
-        if (!holding.empty()) {
-            if (cacheID) {
-                locker.release();   // unguard to upgrade lock
-                m_attrLock->unlock();
-                m_attrLock->wrlock();
-                SharedLock locker2(m_attrLock, false);   // pop the lock when we're done
-                if (cacheEntry->second.count(cacheID) == 0) {
-                    static void (vector<DDF>::* push_back)(DDF const &) = &vector<DDF>::push_back;
-                    vector<DDF>& marshalled = cacheEntry->second[cacheID];
-                    for_each(
-                        holding.begin(), holding.end(),
-                        boost::bind(push_back, boost::ref(marshalled), boost::bind(&Attribute::marshall, _1))
-                        );
-                }
-            }
-
-            // 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 GenericRequest* request, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<Attribute*>& attributes
-    ) const
-{
-    if (!m_impl)
-        return;
-
-    ptr_vector<Attribute> 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<Attribute>::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<Attribute>& attributes
-    ) const
-{
-    static void (XMLExtractor::* extractEncrypted)(
-        const Application&, const GenericRequest*, const RoleDescriptor*, const XMLObject&, ptr_vector<Attribute>&
-        ) const = &XMLExtractor::extractAttributes;
-    static void (XMLExtractorImpl::* extractV1Statement)(
-        const Application&, const GenericRequest*, const char*, const char*, const saml1::AttributeStatement&, ptr_vector<Attribute>&
-        ) const = &XMLExtractorImpl::extractAttributes;
-
-    const EntityDescriptor* entity = issuer ? dynamic_cast<const EntityDescriptor*>(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<const saml2::AttributeStatement*>(&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<saml2::EncryptedAttribute*>& 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<const saml1::AttributeStatement*>(&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<const saml2::Assertion*>(&xmlObject);
-        if (token2) {
-            auto_ptr_char assertingParty(entity ? entity->getEntityID() : nullptr);
-            const vector<saml2::AttributeStatement*>& statements = token2->getAttributeStatements();
-            for (indirect_iterator<vector<saml2::AttributeStatement*>::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<saml2::EncryptedAttribute*>& encattrs = const_cast<const saml2::AttributeStatement&>(*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<const saml1::Assertion*>(&xmlObject);
-        if (token1) {
-            auto_ptr_char assertingParty(entity ? entity->getEntityID() : nullptr);
-            const vector<saml1::AttributeStatement*>& statements = token1->getAttributeStatements();
-            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;
-        }
-
-        throw AttributeExtractionException("Unable to extract attributes, unknown object type.");
-    }
-
-    // Check for metadata.
-    if (XMLString::equals(xmlObject.getElementQName().getNamespaceURI(), samlconstants::SAML20MD_NS)) {
-        const RoleDescriptor* roleToExtract = dynamic_cast<const RoleDescriptor*>(&xmlObject);
-        const EntityDescriptor* entityToExtract = roleToExtract ? dynamic_cast<const EntityDescriptor*>(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<const ObservableMetadataProvider*>(application.getMetadataProvider(false)),
-                entityToExtract->getEntityID(),
-                relyingParty,
-                *ext,
-                attributes
-                );
-        }
-        const EntitiesDescriptor* group = dynamic_cast<const EntitiesDescriptor*>(entityToExtract->getParent());
-        while (group) {
-            ext = group->getExtensions();
-            if (ext) {
-                m_impl->extractAttributes(
-                    application,
-                    request,
-                    dynamic_cast<const ObservableMetadataProvider*>(application.getMetadataProvider(false)),
-                    nullptr,   // not an entity, so inline assertions won't be processed
-                    relyingParty,
-                    *ext,
-                    attributes
-                    );
-            }
-            group = dynamic_cast<const EntitiesDescriptor*>(group->getParent());
-        }
-        return;
-    }
-
-    // Check for attributes.
-    if (XMLString::equals(xmlObject.getElementQName().getLocalPart(), saml1::Attribute::LOCAL_NAME)) {
-        auto_ptr_char assertingParty(entity ? entity->getEntityID() : nullptr);
-        const saml2::Attribute* attr2 = dynamic_cast<const saml2::Attribute*>(&xmlObject);
-        if (attr2)
-            return m_impl->extractAttributes(application, request, assertingParty.get(), relyingParty, *attr2, attributes);
-
-        const saml1::Attribute* attr1 = dynamic_cast<const saml1::Attribute*>(&xmlObject);
-        if (attr1)
-            return m_impl->extractAttributes(application, request, assertingParty.get(), relyingParty, *attr1, attributes);
-
-        throw AttributeExtractionException("Unable to extract attributes, unknown object type.");
-    }
-
-    if (XMLString::equals(xmlObject.getElementQName().getLocalPart(), EncryptedAttribute::LOCAL_NAME)) {
-        const EncryptedAttribute* encattr = dynamic_cast<const EncryptedAttribute*>(&xmlObject);
-        if (encattr) {
-            const XMLCh* recipient = application.getXMLString("entityID").second;
-            CredentialResolver* cr = application.getCredentialResolver();
-            if (!cr) {
-                m_log.warn("found encrypted attribute, but no CredentialResolver was available");
-                return;
-            }
-
-            try {
-                Locker credlocker(cr);
-                if (issuer) {
-                    MetadataCredentialCriteria mcc(*issuer);
-                    scoped_ptr<XMLObject> decrypted(encattr->decrypt(*cr, recipient, &mcc));
-                    if (m_log.isDebugEnabled())
-                        m_log.debugStream() << "decrypted Attribute: " << *decrypted << logging::eol;
-                    return extractAttributes(application, request, issuer, *decrypted, attributes);
-                }
-                else {
-                    scoped_ptr<XMLObject> decrypted(encattr->decrypt(*cr, recipient));
-                    if (m_log.isDebugEnabled())
-                        m_log.debugStream() << "decrypted Attribute: " << *decrypted << logging::eol;
-                    return extractAttributes(application, request, issuer, *decrypted, attributes);
-                }
-            }
-            catch (std::exception& ex) {
-                m_log.error("failed to decrypt Attribute: %s", ex.what());
-                return;
-            }
-        }
-    }
-
-    // Check for NameIDs.
-    const NameID* name2 = dynamic_cast<const NameID*>(&xmlObject);
-    if (name2) {
-        auto_ptr_char assertingParty(entity ? entity->getEntityID() : nullptr);
-        return m_impl->extractAttributes(application, assertingParty.get(), relyingParty, *name2, attributes);
-    }
-
-    const NameIdentifier* name1 = dynamic_cast<const NameIdentifier*>(&xmlObject);
-    if (name1) {
-        auto_ptr_char assertingParty(entity ? entity->getEntityID() : nullptr);
-        return m_impl->extractAttributes(application, assertingParty.get(), relyingParty, *name1, attributes);
-    }
-
-    m_log.debug("unable to extract attributes, unknown XML object type: %s", xmlObject.getElementQName().toString().c_str());
-}
-
-pair<bool,DOMElement*> XMLExtractor::background_load()
-{
-    // Load from source using base class.
-    pair<bool,DOMElement*> raw = ReloadableXMLFile::load();
-
-    // If we own it, wrap it.
-    XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : nullptr);
-
-    scoped_ptr<XMLExtractorImpl> impl(new XMLExtractorImpl(raw.second, m_log, m_deprecationSupport));
-
-    // If we held the document, transfer it to the impl. If we didn't, it's a no-op.
-    impl->setDocument(docjanitor.release());
-
-    // 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*)nullptr);
-}

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list