Revise attribute APIs to use vectors in place of multimaps.
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Sun, 5 Aug 2007 21:42:40 +0000 (21:42 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Sun, 5 Aug 2007 21:42:40 +0000 (21:42 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@2383 cb58f699-b61c-0410-a6fe-9272a202ed29

21 files changed:
adfs/adfs.cpp
apache/mod_apache.cpp
shibsp/ServiceProvider.cpp
shibsp/SessionCache.h
shibsp/attribute/filtering/AttributeFilter.h
shibsp/attribute/filtering/BasicFilteringContext.h
shibsp/attribute/filtering/impl/ChainingAttributeFilter.cpp
shibsp/attribute/filtering/impl/XMLAttributeFilter.cpp
shibsp/attribute/resolver/AttributeExtractor.h
shibsp/attribute/resolver/AttributeResolver.h
shibsp/attribute/resolver/ResolutionContext.h
shibsp/attribute/resolver/impl/ChainingAttributeResolver.cpp
shibsp/attribute/resolver/impl/QueryAttributeResolver.cpp
shibsp/attribute/resolver/impl/XMLAttributeExtractor.cpp
shibsp/handler/AssertionConsumerService.h
shibsp/handler/impl/AssertionConsumerService.cpp
shibsp/handler/impl/SAML1Consumer.cpp
shibsp/handler/impl/SAML2Consumer.cpp
shibsp/impl/RemotedSessionCache.cpp
shibsp/impl/StorageServiceSessionCache.cpp
shibsp/impl/XMLAccessControl.cpp

index 6570271..cbbd56d 100644 (file)
@@ -561,7 +561,7 @@ string ADFSConsumer::implementProtocol(
 
     // We've successfully "accepted" the SSO token.
     // To complete processing, we need to extract and resolve attributes and then create the session.
-    multimap<string,Attribute*> resolvedAttributes;
+    vector<Attribute*> resolvedAttributes;
     AttributeExtractor* extractor = application.getAttributeExtractor();
     if (extractor) {
         m_log.debug("extracting pushed attributes...");
@@ -591,7 +591,7 @@ string ADFSConsumer::implementProtocol(
             catch (exception& ex) {
                 m_log.error("caught exception filtering attributes: %s", ex.what());
                 m_log.error("dumping extracted attributes due to filtering exception");
-                for_each(resolvedAttributes.begin(), resolvedAttributes.end(), cleanup_pair<string,shibsp::Attribute>());
+                for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
                 resolvedAttributes.clear();
             }
         }
@@ -625,7 +625,7 @@ string ADFSConsumer::implementProtocol(
         tokens.insert(tokens.end(), ctx->getResolvedAssertions().begin(), ctx->getResolvedAssertions().end());
 
         // Copy over new attributes, and transfer ownership.
-        resolvedAttributes.insert(ctx->getResolvedAttributes().begin(), ctx->getResolvedAttributes().end());
+        resolvedAttributes.insert(resolvedAttributes.end(), ctx->getResolvedAttributes().begin(), ctx->getResolvedAttributes().end());
         ctx->getResolvedAttributes().clear();
     }
 
@@ -644,11 +644,11 @@ string ADFSConsumer::implementProtocol(
             &tokens,
             &resolvedAttributes
             );
-        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), cleanup_pair<string,Attribute>());
+        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
         return key;
     }
     catch (exception&) {
-        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), cleanup_pair<string,Attribute>());
+        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
         throw;
     }
 }
index b7be829..dc638f9 100644 (file)
@@ -964,8 +964,8 @@ bool htAccessControl::authorized(const SPRequest& request, const Session* sessio
             }
             
             // Find the attribute(s) matching the require rule.
-            pair<multimap<string,Attribute*>::const_iterator,multimap<string,Attribute*>::const_iterator> attrs =
-                session->getAttributes().equal_range(w);
+            pair<multimap<string,const Attribute*>::const_iterator,multimap<string,const Attribute*>::const_iterator> attrs =
+                session->getIndexedAttributes().equal_range(w);
             if (attrs.first == attrs.second) {
                 request.log(SPRequest::SPWarn, string("htAccessControl rule requires attribute (") + w + "), not found in session");
                 continue;
index 4b74096..5af4e4b 100644 (file)
@@ -380,8 +380,8 @@ pair<bool,long> ServiceProvider::doExport(SPRequest& request, bool requireSessio
 
         // Export the attributes.
         bool remoteUserSet = false;
-        const multimap<string,Attribute*>& attributes = session->getAttributes();
-        for (multimap<string,Attribute*>::const_iterator a = attributes.begin(); a!=attributes.end(); ++a) {
+        const multimap<string,const Attribute*>& attributes = session->getIndexedAttributes();
+        for (multimap<string,const Attribute*>::const_iterator a = attributes.begin(); a!=attributes.end(); ++a) {
             const vector<string>& vals = a->second->getSerializedValues();
 
             // See if this needs to be set as the REMOTE_USER value.
index 930b2a7..91de942 100644 (file)
@@ -115,9 +115,16 @@ namespace shibsp {
         /**
          * Returns the resolved attributes associated with the session.
          * 
+         * @return an immutable array of attributes
+         */
+        virtual const std::vector<Attribute*>& getAttributes() const=0;
+
+        /**
+         * Returns the resolved attributes associated with the session, indexed by ID
+         * 
          * @return an immutable map of attributes keyed by attribute ID
          */
-        virtual const std::multimap<std::string,Attribute*>& getAttributes() const=0;
+        virtual const std::multimap<std::string,const Attribute*>& getIndexedAttributes() const=0;
         
         /**
          * Returns the identifiers of the assertion(s) cached by the session.
@@ -203,7 +210,7 @@ namespace shibsp {
          * @param authncontext_class    method/category of authentication event, if known
          * @param authncontext_decl specifics of authentication event, if known
          * @param tokens            assertions to cache with session, if any
-         * @param attributes        optional map of resolved Attributes to cache with session
+         * @param attributes        optional array of resolved Attributes to cache with session
          * @return  newly created session's key
          */
         virtual std::string insert(
@@ -218,7 +225,7 @@ namespace shibsp {
             const XMLCh* authncontext_class=NULL,
             const XMLCh* authncontext_decl=NULL,
             const std::vector<const opensaml::Assertion*>* tokens=NULL,
-            const std::multimap<std::string,Attribute*>* attributes=NULL
+            const std::vector<Attribute*>* attributes=NULL
             )=0;
 
         /**
index 7eeb63d..75521a3 100644 (file)
@@ -44,11 +44,11 @@ namespace shibsp {
          * Filters values out of a set of attributes.
          * 
          * @param context       a FilteringContext interface
-         * @param attributes    a mutable map containing the attributes to filter
+         * @param attributes    a mutable array containing the attributes to filter
          * 
          * @throws AttributeFileringException thrown if there is a problem filtering attributes
          */
-        virtual void filterAttributes(const FilteringContext& context, std::multimap<std::string,Attribute*>& attributes) const=0;
+        virtual void filterAttributes(const FilteringContext& context, std::vector<Attribute*>& attributes) const=0;
     };
 
     /**
index 721d638..2207941 100644 (file)
@@ -41,13 +41,15 @@ namespace shibsp {
          */
         BasicFilteringContext(
             const Application& app,
-            const std::multimap<std::string,Attribute*>& attributes,
+            const std::vector<Attribute*>& attributes,
             const opensaml::saml2md::RoleDescriptor* role=NULL,
             const XMLCh* authncontext_class=NULL,
             const XMLCh* authncontext_decl=NULL
-            ) : m_app(app), m_attributes(attributes), m_role(role), m_issuer(NULL), m_class(authncontext_class), m_decl(authncontext_decl) {
+            ) : m_app(app), m_role(role), m_issuer(NULL), m_class(authncontext_class), m_decl(authncontext_decl) {
             if (role)
                 m_issuer = dynamic_cast<opensaml::saml2md::EntityDescriptor*>(role->getParent())->getEntityID();
+            for (std::vector<Attribute*>::const_iterator a = attributes.begin(); a != attributes.end(); ++a)
+                m_attributes.insert(std::make_pair((*a)->getId(), *a));
         }
 
         virtual ~BasicFilteringContext() {}
@@ -79,7 +81,7 @@ namespace shibsp {
 
     private:
         const Application& m_app;
-        const std::multimap<std::string,Attribute*>& m_attributes;
+        std::multimap<std::string,Attribute*> m_attributes;
         const opensaml::saml2md::RoleDescriptor* m_role;
         const XMLCh* m_issuer;
         const XMLCh* m_class;
index 7842a59..f9ba21e 100644 (file)
@@ -47,7 +47,7 @@ namespace shibsp {
         void unlock() {
         }
         
-        void filterAttributes(const FilteringContext& context, multimap<string,Attribute*>& attributes) const {
+        void filterAttributes(const FilteringContext& context, vector<Attribute*>& attributes) const {
             for (vector<AttributeFilter*>::const_iterator i=m_filters.begin(); i!=m_filters.end(); ++i) {
                 Locker locker(*i);
                 (*i)->filterAttributes(context, attributes);
index 743a322..0e50fbb 100644 (file)
@@ -69,7 +69,7 @@ namespace shibsp {
             m_document = doc;
         }
 
-        void filterAttributes(const FilteringContext& context, multimap<string,Attribute*>& attributes) const;
+        void filterAttributes(const FilteringContext& context, vector<Attribute*>& attributes) const;
 
     private:
         MatchFunctor* buildFunctor(
@@ -95,7 +95,7 @@ namespace shibsp {
             delete m_impl;
         }
         
-        void filterAttributes(const FilteringContext& context, multimap<string,Attribute*>& attributes) const {
+        void filterAttributes(const FilteringContext& context, vector<Attribute*>& attributes) const {
             m_impl->filterAttributes(context, attributes);
         }
 
@@ -280,7 +280,7 @@ pair<string,const MatchFunctor*> XMLFilterImpl::buildAttributeRule(const DOMElem
     return make_pair(string(),(MatchFunctor*)NULL);
 }
 
-void XMLFilterImpl::filterAttributes(const FilteringContext& context, multimap<string,Attribute*>& attributes) const
+void XMLFilterImpl::filterAttributes(const FilteringContext& context, vector<Attribute*>& attributes) const
 {
     auto_ptr_char issuer(context.getAttributeIssuer());
 
@@ -288,7 +288,7 @@ void XMLFilterImpl::filterAttributes(const FilteringContext& context, multimap<s
 
     if (m_policies.empty()) {
         m_log.warn("no filter policies were loaded, filtering out all attributes from (%s)", issuer.get() ? issuer.get() : "unknown source");
-        for_each(attributes.begin(), attributes.end(), cleanup_pair<string,Attribute>());
+        for_each(attributes.begin(), attributes.end(), xmltooling::cleanup<Attribute>());
         attributes.clear();
         return;
     }
@@ -299,26 +299,30 @@ void XMLFilterImpl::filterAttributes(const FilteringContext& context, multimap<s
     for (vector<Policy>::const_iterator p=m_policies.begin(); p!=m_policies.end(); ++p) {
         if (p->m_applies->evaluatePolicyRequirement(context)) {
             // Loop over the attributes and look for possible rules to run.
-            for (multimap<string,Attribute*>::iterator a=attributes.begin(); a!=attributes.end();) {
+            for (vector<Attribute*>::size_type a=0; a<attributes.size();) {
                 bool ruleFound = false;
-                pair<Policy::rules_t::const_iterator,Policy::rules_t::const_iterator> rules = p->m_rules.equal_range(a->second->getId());
+                Attribute* attr = attributes[a];
+                pair<Policy::rules_t::const_iterator,Policy::rules_t::const_iterator> rules = p->m_rules.equal_range(attr->getId());
                 if (rules.first != rules.second) {
                     ruleFound = true;
                     // Run each rule in sequence.
-                    m_log.debug("applying filtering rule(s) for attribute (%s) from (%s)", a->second->getId(), issuer.get() ? issuer.get() : "unknown source");
+                    m_log.debug(
+                        "applying filtering rule(s) for attribute (%s) from (%s)",
+                        attr->getId(), issuer.get() ? issuer.get() : "unknown source"
+                        );
                     for (; rules.first!=rules.second; ++rules.first) {
-                        count = a->second->valueCount();
+                        count = attr->valueCount();
                         for (index=0; index < count;) {
                             // The return value tells us whether to index past the accepted value, or stay put and decrement the count.
-                            if (rules.first->second->evaluatePermitValue(context, *(a->second), index)) {
+                            if (rules.first->second->evaluatePermitValue(context, *attr, index)) {
                                 index++;
                             }
                             else {
                                 m_log.warn(
                                     "filtered value at position (%lu) of attribute (%s) from (%s)",
-                                    index, a->second->getId(), issuer.get() ? issuer.get() : "unknown source"
+                                    index, attr->getId(), issuer.get() ? issuer.get() : "unknown source"
                                     );
-                                a->second->removeValue(index);
+                                attr->removeValue(index);
                                 count--;
                             }
                         }
@@ -329,39 +333,41 @@ void XMLFilterImpl::filterAttributes(const FilteringContext& context, multimap<s
                 if (rules.first != rules.second) {
                     // Run each rule in sequence.
                     if (!ruleFound) {
-                        m_log.debug("applying wildcard rule(s) for attribute (%s) from (%s)", a->second->getId(), issuer.get() ? issuer.get() : "unknown source");
+                        m_log.debug(
+                            "applying wildcard rule(s) for attribute (%s) from (%s)",
+                            attr->getId(), issuer.get() ? issuer.get() : "unknown source"
+                            );
                         ruleFound = true;
                     }
                     for (; rules.first!=rules.second; ++rules.first) {
-                        count = a->second->valueCount();
+                        count = attr->valueCount();
                         for (index=0; index < count;) {
                             // The return value tells us whether to index past the accepted value, or stay put and decrement the count.
-                            if (rules.first->second->evaluatePermitValue(context, *(a->second), index)) {
+                            if (rules.first->second->evaluatePermitValue(context, *attr, index)) {
                                 index++;
                             }
                             else {
                                 m_log.warn(
                                     "filtered value at position (%lu) of attribute (%s) from (%s)",
-                                    index, a->second->getId(), issuer.get() ? issuer.get() : "unknown source"
+                                    index, attr->getId(), issuer.get() ? issuer.get() : "unknown source"
                                     );
-                                a->second->removeValue(index);
+                                attr->removeValue(index);
                                 count--;
                             }
                         }
                     }
                 }
 
-                if (!ruleFound || a->second->valueCount() == 0) {
+                if (!ruleFound || attr->valueCount() == 0) {
                     if (!ruleFound) {
                         // No rule found, so we're filtering it out.
                         m_log.warn(
                             "no rule found, filtering out values of attribute (%s) from (%s)",
-                            a->second->getId(), issuer.get() ? issuer.get() : "unknown source"
+                            attr->getId(), issuer.get() ? issuer.get() : "unknown source"
                             );
                     }
-                    multimap<string,Attribute*>::iterator dead = a++;
-                    delete dead->second;
-                    attributes.erase(dead);
+                    delete attr;
+                    attributes.erase(attributes.begin() + a);
                 }
                 else {
                     ++a;
index 7975f8c..e5adb5a 100644 (file)
@@ -49,7 +49,7 @@ namespace shibsp {
          * @param application   Application performing the extraction
          * @param issuer        source of object, if known
          * @param xmlObject     object to extract
-         * @param attributes    a map to populate with the extracted attributes, keyed by id
+         * @param attributes    an array to populate with the extracted attributes
          * 
          * @throws AttributeExtractionException thrown if there is a problem extracting attributes
          */
@@ -57,7 +57,7 @@ namespace shibsp {
             const Application& application,
             const opensaml::saml2md::RoleDescriptor* issuer,
             const xmltooling::XMLObject& xmlObject,
-            std::multimap<std::string,Attribute*>& attributes
+            std::vector<Attribute*>& attributes
             ) const=0;
 
         /**
index 4376c89..41646ce 100644 (file)
@@ -65,7 +65,7 @@ namespace shibsp {
          * @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        map of previously resolved attributes, if any
+         * @param attributes        array of previously resolved attributes, if any
          * @return  newly created ResolutionContext, owned by caller
          */
         virtual ResolutionContext* createResolutionContext(
@@ -76,7 +76,7 @@ namespace shibsp {
             const XMLCh* authncontext_class=NULL,
             const XMLCh* authncontext_decl=NULL,
             const std::vector<const opensaml::Assertion*>* tokens=NULL,
-            const std::multimap<std::string,Attribute*>* attributes=NULL
+            const std::vector<Attribute*>* attributes=NULL
             ) const=0;
 
         /**
index ecd20f1..760246a 100644 (file)
@@ -51,7 +51,7 @@ namespace shibsp {
          * 
          * @return  a mutable array of Attributes.
          */
-        virtual std::multimap<std::string,Attribute*>& getResolvedAttributes()=0;
+        virtual std::vector<Attribute*>& getResolvedAttributes()=0;
 
         /**
          * Returns the set of assertions resolved and added to the context.
index 6579762..117c1a9 100644 (file)
@@ -42,11 +42,11 @@ namespace shibsp {
     {
         ~ChainingContext() {
             for_each(m_contexts.begin(), m_contexts.end(), xmltooling::cleanup<ResolutionContext>());
-            for_each(m_attributes.begin(), m_attributes.end(), cleanup_pair<string,shibsp::Attribute>());
+            for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<shibsp::Attribute>());
             for_each(m_assertions.begin(), m_assertions.end(), xmltooling::cleanup<opensaml::Assertion>());
         }
 
-        multimap<string,shibsp::Attribute*>& getResolvedAttributes() {
+        vector<shibsp::Attribute*>& getResolvedAttributes() {
             return m_attributes;
         }
         vector<opensaml::Assertion*>& getResolvedAssertions() {
@@ -54,7 +54,7 @@ namespace shibsp {
         }
 
         vector<ResolutionContext*> m_contexts;
-        multimap<string,shibsp::Attribute*> m_attributes;
+        vector<shibsp::Attribute*> m_attributes;
         vector<opensaml::Assertion*> m_assertions;
     };
 
@@ -82,7 +82,7 @@ namespace shibsp {
             const XMLCh* authncontext_class=NULL,
             const XMLCh* authncontext_decl=NULL,
             const vector<const opensaml::Assertion*>* tokens=NULL,
-            const multimap<string,shibsp::Attribute*>* attributes=NULL
+            const vector<shibsp::Attribute*>* attributes=NULL
             ) const {
             auto_ptr<ChainingContext> chain(new ChainingContext());
             for (vector<AttributeResolver*>::const_iterator i=m_resolvers.begin(); i!=m_resolvers.end(); ++i)
@@ -147,7 +147,7 @@ void ChainingAttributeResolver::resolveAttributes(ResolutionContext& ctx) const
     vector<ResolutionContext*>::iterator ictx = chain.m_contexts.begin();
     for (vector<AttributeResolver*>::const_iterator i=m_resolvers.begin(); i!=m_resolvers.end(); ++i, ++ictx) {
         (*i)->resolveAttributes(*(*ictx));
-        chain.getResolvedAttributes().insert((*ictx)->getResolvedAttributes().begin(), (*ictx)->getResolvedAttributes().end());
+        chain.getResolvedAttributes().insert(chain.getResolvedAttributes().end(), (*ictx)->getResolvedAttributes().begin(), (*ictx)->getResolvedAttributes().end());
         (*ictx)->getResolvedAttributes().clear();
         chain.getResolvedAssertions().insert(chain.getResolvedAssertions().end(), (*ictx)->getResolvedAssertions().begin(), (*ictx)->getResolvedAssertions().end());
         (*ictx)->getResolvedAssertions().clear();
index f0debc4..825af50 100644 (file)
@@ -78,7 +78,7 @@ namespace shibsp {
             const XMLCh* authncontext_class=NULL,
             const XMLCh* authncontext_decl=NULL,
             const vector<const opensaml::Assertion*>* tokens=NULL,
-            const multimap<string,Attribute*>* attributes=NULL
+            const vector<Attribute*>* attributes=NULL
             ) : m_query(true), m_app(application), m_session(NULL), m_metadata(NULL), m_entity(issuer),
                 m_protocol(protocol), m_nameid(nameid), m_class(authncontext_class), m_decl(authncontext_decl) {
 
@@ -106,7 +106,7 @@ namespace shibsp {
             }
             if (m_metadata)
                 m_metadata->unlock();
-            for_each(m_attributes.begin(), m_attributes.end(), cleanup_pair<string,shibsp::Attribute>());
+            for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<shibsp::Attribute>());
             for_each(m_assertions.begin(), m_assertions.end(), xmltooling::cleanup<opensaml::Assertion>());
         }
     
@@ -144,7 +144,7 @@ namespace shibsp {
         const Session* getSession() const {
             return m_session;
         }
-        multimap<string,shibsp::Attribute*>& getResolvedAttributes() {
+        vector<shibsp::Attribute*>& getResolvedAttributes() {
             return m_attributes;
         }
         vector<opensaml::Assertion*>& getResolvedAssertions() {
@@ -161,7 +161,7 @@ namespace shibsp {
         const NameID* m_nameid;
         const XMLCh* m_class;
         const XMLCh* m_decl;
-        multimap<string,shibsp::Attribute*> m_attributes;
+        vector<shibsp::Attribute*> m_attributes;
         vector<opensaml::Assertion*> m_assertions;
     };
     
@@ -185,7 +185,7 @@ namespace shibsp {
             const XMLCh* authncontext_class=NULL,
             const XMLCh* authncontext_decl=NULL,
             const vector<const opensaml::Assertion*>* tokens=NULL,
-            const multimap<string,shibsp::Attribute*>* attributes=NULL
+            const vector<shibsp::Attribute*>* attributes=NULL
             ) const {
             return new QueryContext(application,issuer,protocol,nameid,authncontext_class,authncontext_decl,tokens,attributes);
         }
@@ -364,7 +364,7 @@ bool QueryResolver::SAML1Query(QueryContext& ctx) const
     }
     catch (exception& ex) {
         m_log.error("caught exception extracting/filtering attributes from query result: %s", ex.what());
-        for_each(ctx.getResolvedAttributes().begin(), ctx.getResolvedAttributes().end(), cleanup_pair<string,shibsp::Attribute>());
+        for_each(ctx.getResolvedAttributes().begin(), ctx.getResolvedAttributes().end(), xmltooling::cleanup<shibsp::Attribute>());
         ctx.getResolvedAttributes().clear();
     }
 
@@ -481,7 +481,7 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
     }
     catch (exception& ex) {
         m_log.error("caught exception extracting/filtering attributes from query result: %s", ex.what());
-        for_each(ctx.getResolvedAttributes().begin(), ctx.getResolvedAttributes().end(), cleanup_pair<string,shibsp::Attribute>());
+        for_each(ctx.getResolvedAttributes().begin(), ctx.getResolvedAttributes().end(), xmltooling::cleanup<shibsp::Attribute>());
         ctx.getResolvedAttributes().clear();
     }
 
index 44bf5e4..e0942e2 100644 (file)
@@ -67,16 +67,16 @@ namespace shibsp {
         }
 
         void extractAttributes(
-            const Application& application, const char* assertingParty, const NameIdentifier& nameid, multimap<string,Attribute*>& attributes
+            const Application& application, const char* assertingParty, const NameIdentifier& nameid, vector<Attribute*>& attributes
             ) const;
         void extractAttributes(
-            const Application& application, const char* assertingParty, const NameID& nameid, multimap<string,Attribute*>& attributes
+            const Application& application, const char* assertingParty, const NameID& nameid, vector<Attribute*>& attributes
             ) const;
         void extractAttributes(
-            const Application& application, const char* assertingParty, const saml1::Attribute& attr, multimap<string,Attribute*>& attributes
+            const Application& application, const char* assertingParty, const saml1::Attribute& attr, vector<Attribute*>& attributes
             ) const;
         void extractAttributes(
-            const Application& application, const char* assertingParty, const saml2::Attribute& attr, multimap<string,Attribute*>& attributes
+            const Application& application, const char* assertingParty, const saml2::Attribute& attr, vector<Attribute*>& attributes
             ) const;
 
         void getAttributeIds(vector<string>& attributes) const {
@@ -106,7 +106,7 @@ namespace shibsp {
         }
         
         void extractAttributes(
-            const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, multimap<string,Attribute*>& attributes
+            const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<Attribute*>& attributes
             ) const;
 
         void getAttributeIds(std::vector<std::string>& attributes) const {
@@ -231,7 +231,7 @@ XMLExtractorImpl::XMLExtractorImpl(const DOMElement* e, Category& log) : m_log(l
 }
 
 void XMLExtractorImpl::extractAttributes(
-    const Application& application, const char* assertingParty, const NameIdentifier& nameid, multimap<string,Attribute*>& attributes
+    const Application& application, const char* assertingParty, const NameIdentifier& nameid, vector<Attribute*>& attributes
     ) const
 {
 #ifdef HAVE_GOOD_STL
@@ -251,12 +251,12 @@ void XMLExtractorImpl::extractAttributes(
 #endif
         Attribute* a = rule->second.first->decode(rule->second.second.c_str(), &nameid, assertingParty, application.getString("entityID").second);
         if (a)
-            attributes.insert(make_pair(rule->second.second, a));
+            attributes.push_back(a);
     }
 }
 
 void XMLExtractorImpl::extractAttributes(
-    const Application& application, const char* assertingParty, const NameID& nameid, multimap<string,Attribute*>& attributes
+    const Application& application, const char* assertingParty, const NameID& nameid, vector<Attribute*>& attributes
     ) const
 {
 #ifdef HAVE_GOOD_STL
@@ -276,12 +276,12 @@ void XMLExtractorImpl::extractAttributes(
 #endif
         Attribute* a = rule->second.first->decode(rule->second.second.c_str(), &nameid, assertingParty, application.getString("entityID").second);
         if (a)
-            attributes.insert(make_pair(rule->second.second, a));
+            attributes.push_back(a);
     }
 }
 
 void XMLExtractorImpl::extractAttributes(
-    const Application& application, const char* assertingParty, const saml1::Attribute& attr, multimap<string,Attribute*>& attributes
+    const Application& application, const char* assertingParty, const saml1::Attribute& attr, vector<Attribute*>& attributes
     ) const
 {
 #ifdef HAVE_GOOD_STL
@@ -305,12 +305,12 @@ void XMLExtractorImpl::extractAttributes(
 #endif
         Attribute* a = rule->second.first->decode(rule->second.second.c_str(), &attr, assertingParty, application.getString("entityID").second);
         if (a)
-            attributes.insert(make_pair(rule->second.second, a));
+            attributes.push_back(a);
     }
 }
 
 void XMLExtractorImpl::extractAttributes(
-    const Application& application, const char* assertingParty, const saml2::Attribute& attr, multimap<string,Attribute*>& attributes
+    const Application& application, const char* assertingParty, const saml2::Attribute& attr, vector<Attribute*>& attributes
     ) const
 {
 #ifdef HAVE_GOOD_STL
@@ -336,12 +336,12 @@ void XMLExtractorImpl::extractAttributes(
 #endif
         Attribute* a = rule->second.first->decode(rule->second.second.c_str(), &attr, assertingParty, application.getString("entityID").second);
         if (a)
-            attributes.insert(make_pair(rule->second.second, a));
+            attributes.push_back(a);
     }
 }
 
 void XMLExtractor::extractAttributes(
-    const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, multimap<string,Attribute*>& attributes
+    const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<Attribute*>& attributes
     ) const
 {
     if (!m_impl)
index bbedd6c..c933c89 100644 (file)
@@ -106,7 +106,7 @@ namespace shibsp {
             const XMLCh* authncontext_class=NULL,
             const XMLCh* authncontext_decl=NULL,
             const std::vector<const opensaml::Assertion*>* tokens=NULL,
-            const std::multimap<std::string,Attribute*>* attributes=NULL
+            const std::vector<Attribute*>* attributes=NULL
             ) const;
 #endif
         
index c8037b7..8d7c0fe 100644 (file)
@@ -249,7 +249,7 @@ ResolutionContext* AssertionConsumerService::resolveAttributes(
     const XMLCh* authncontext_class,
     const XMLCh* authncontext_decl,
     const vector<const Assertion*>* tokens,
-    const multimap<string,Attribute*>* attributes
+    const vector<Attribute*>* attributes
     ) const
 {
     try {
index 8b44d5c..a4e5303 100644 (file)
@@ -206,7 +206,7 @@ string SAML1Consumer::implementProtocol(
 
     // We've successfully "accepted" at least one SSO token, along with any additional valid tokens.
     // To complete processing, we need to extract and resolve attributes and then create the session.
-    multimap<string,Attribute*> resolvedAttributes;
+    vector<Attribute*> resolvedAttributes;
     AttributeExtractor* extractor = application.getAttributeExtractor();
     if (extractor) {
         m_log.debug("extracting pushed attributes...");
@@ -238,7 +238,7 @@ string SAML1Consumer::implementProtocol(
             catch (exception& ex) {
                 m_log.error("caught exception filtering attributes: %s", ex.what());
                 m_log.error("dumping extracted attributes due to filtering exception");
-                for_each(resolvedAttributes.begin(), resolvedAttributes.end(), cleanup_pair<string,shibsp::Attribute>());
+                for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
                 resolvedAttributes.clear();
             }
         }
@@ -273,7 +273,7 @@ string SAML1Consumer::implementProtocol(
         tokens.insert(tokens.end(), ctx->getResolvedAssertions().begin(), ctx->getResolvedAssertions().end());
 
         // Copy over new attributes, and transfer ownership.
-        resolvedAttributes.insert(ctx->getResolvedAttributes().begin(), ctx->getResolvedAttributes().end());
+        resolvedAttributes.insert(resolvedAttributes.end(), ctx->getResolvedAttributes().begin(), ctx->getResolvedAttributes().end());
         ctx->getResolvedAttributes().clear();
     }
 
@@ -296,11 +296,11 @@ string SAML1Consumer::implementProtocol(
             &tokens,
             &resolvedAttributes
             );
-        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), cleanup_pair<string,Attribute>());
+        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
         return key;
     }
     catch (exception&) {
-        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), cleanup_pair<string,Attribute>());
+        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
         throw;
     }
 }
index 2bae0f5..a82b3be 100644 (file)
@@ -335,7 +335,7 @@ string SAML2Consumer::implementProtocol(
     else
         sessionExp = min(sessionExp, now + lifetime.second);    // Use the lowest.
 
-    multimap<string,Attribute*> resolvedAttributes;
+    vector<Attribute*> resolvedAttributes;
     AttributeExtractor* extractor = application.getAttributeExtractor();
     if (extractor) {
         m_log.debug("extracting pushed attributes...");
@@ -374,7 +374,7 @@ string SAML2Consumer::implementProtocol(
         catch (exception& ex) {
             m_log.error("caught exception filtering attributes: %s", ex.what());
             m_log.error("dumping extracted attributes due to filtering exception");
-            for_each(resolvedAttributes.begin(), resolvedAttributes.end(), cleanup_pair<string,shibsp::Attribute>());
+            for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
             resolvedAttributes.clear();
         }
     }
@@ -400,7 +400,7 @@ string SAML2Consumer::implementProtocol(
             tokens.insert(tokens.end(), ctx->getResolvedAssertions().begin(), ctx->getResolvedAssertions().end());
 
             // Copy over new attributes, and transfer ownership.
-            resolvedAttributes.insert(ctx->getResolvedAttributes().begin(), ctx->getResolvedAttributes().end());
+            resolvedAttributes.insert(resolvedAttributes.end(), ctx->getResolvedAttributes().begin(), ctx->getResolvedAttributes().end());
             ctx->getResolvedAttributes().clear();
         }
 
@@ -425,14 +425,14 @@ string SAML2Consumer::implementProtocol(
         if (ownedName)
             delete ssoName;
         for_each(ownedtokens.begin(), ownedtokens.end(), xmltooling::cleanup<saml2::Assertion>());
-        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), cleanup_pair<string,Attribute>());
+        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
         return key;
     }
     catch (exception&) {
         if (ownedName)
             delete ssoName;
         for_each(ownedtokens.begin(), ownedtokens.end(), xmltooling::cleanup<saml2::Assertion>());
-        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), cleanup_pair<string,Attribute>());
+        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
         throw;
     }
 }
index 04364e0..e7bdbc9 100644 (file)
@@ -61,7 +61,7 @@ namespace shibsp {
         ~RemotedSession() {\r
             delete m_lock;\r
             m_obj.destroy();\r
-            for_each(m_attributes.begin(), m_attributes.end(), cleanup_pair<string,Attribute>());\r
+            for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());\r
         }\r
         \r
         Lockable* lock() {\r
@@ -99,11 +99,16 @@ namespace shibsp {
         const char* getAuthnContextDeclRef() const {\r
             return m_obj["authncontext_decl"].string();\r
         }\r
-        const multimap<string,Attribute*>& getAttributes() const {\r
+        const vector<Attribute*>& getAttributes() const {\r
             if (m_attributes.empty())\r
                 unmarshallAttributes();\r
             return m_attributes;\r
         }\r
+        const multimap<string,const Attribute*>& getIndexedAttributes() const {\r
+            if (m_attributes.empty())\r
+                unmarshallAttributes();\r
+            return m_attributeIndex;\r
+        }\r
         const vector<const char*>& getAssertionIDs() const {\r
             if (m_ids.empty()) {\r
                 DDF ids = m_obj["assertions"];\r
@@ -125,7 +130,8 @@ namespace shibsp {
 \r
         int m_version;\r
         mutable DDF m_obj;\r
-        mutable multimap<string,Attribute*> m_attributes;\r
+        mutable vector<Attribute*> m_attributes;\r
+        mutable multimap<string,const Attribute*> m_attributeIndex;\r
         mutable vector<const char*> m_ids;\r
         time_t m_expires,m_lastAccess;\r
         RemotedCache* m_cache;\r
@@ -170,7 +176,8 @@ void RemotedSession::unmarshallAttributes() const
     while (!attr.isnull()) {\r
         try {\r
             attribute = Attribute::unmarshall(attr);\r
-            m_attributes.insert(make_pair(attribute->getId(),attribute));\r
+            m_attributes.push_back(attribute);\r
+            m_attributeIndex.insert(make_pair(attribute->getId(),attribute));\r
             if (m_cache->m_log.isDebugEnabled())\r
                 m_cache->m_log.debug("unmarshalled attribute (ID: %s) with %d value%s",\r
                     attribute->getId(), attr.first().integer(), attr.first().integer()!=1 ? "s" : "");\r
@@ -237,8 +244,9 @@ void RemotedSession::validate(const Application& application, const char* client
     if (out.isstruct()) {\r
         // We got an updated record back.\r
         m_ids.clear();\r
-        for_each(m_attributes.begin(), m_attributes.end(), cleanup_const_pair<string,Attribute>());\r
+        for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());\r
         m_attributes.clear();\r
+        m_attributeIndex.clear();\r
         m_obj.destroy();\r
         m_obj = out;\r
     }\r
index 38d5989..c1e7256 100644 (file)
@@ -106,11 +106,16 @@ namespace shibsp {
         const char* getAuthnContextDeclRef() const {
             return m_obj["authncontext_decl"].string();
         }
-        const multimap<string,Attribute*>& getAttributes() const {
+        const vector<Attribute*>& getAttributes() const {
             if (m_attributes.empty())
                 unmarshallAttributes();
             return m_attributes;
         }
+        const multimap<string,const Attribute*>& getIndexedAttributes() const {
+            if (m_attributes.empty())
+                unmarshallAttributes();
+            return m_attributeIndex;
+        }
         const vector<const char*>& getAssertionIDs() const {
             if (m_ids.empty()) {
                 DDF ids = m_obj["assertions"];
@@ -132,7 +137,8 @@ namespace shibsp {
 
         DDF m_obj;
         saml2::NameID* m_nameid;
-        mutable multimap<string,Attribute*> m_attributes;
+        mutable vector<Attribute*> m_attributes;
+        mutable multimap<string,const Attribute*> m_attributeIndex;
         mutable vector<const char*> m_ids;
         mutable map<string,Assertion*> m_tokens;
         SSCache* m_cache;
@@ -158,7 +164,7 @@ namespace shibsp {
             const XMLCh* authncontext_class=NULL,
             const XMLCh* authncontext_decl=NULL,
             const vector<const Assertion*>* tokens=NULL,
-            const multimap<string,Attribute*>* attributes=NULL
+            const vector<Attribute*>* attributes=NULL
             );
         Session* find(const char* key, const Application& application, const char* client_addr=NULL, time_t* timeout=NULL);
         void remove(const char* key, const Application& application);
@@ -200,7 +206,7 @@ StoredSession::~StoredSession()
 {
     m_obj.destroy();
     delete m_nameid;
-    for_each(m_attributes.begin(), m_attributes.end(), cleanup_pair<string,Attribute>());
+    for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());
     for_each(m_tokens.begin(), m_tokens.end(), cleanup_pair<string,Assertion>());
 }
 
@@ -212,7 +218,8 @@ void StoredSession::unmarshallAttributes() const
     while (!attr.isnull()) {
         try {
             attribute = Attribute::unmarshall(attr);
-            m_attributes.insert(make_pair(attribute->getId(), attribute));
+            m_attributes.push_back(attribute);
+            m_attributeIndex.insert(make_pair(attribute->getId(), attribute));
             if (m_cache->m_log.isDebugEnabled())
                 m_cache->m_log.debug("unmarshalled attribute (ID: %s) with %d value%s",
                     attribute->getId(), attr.first().integer(), attr.first().integer()!=1 ? "s" : "");
@@ -289,8 +296,9 @@ void StoredSession::addAttributes(const vector<Attribute*>& attributes)
             in >> newobj;
 
             m_ids.clear();
-            for_each(m_attributes.begin(), m_attributes.end(), cleanup_const_pair<string,Attribute>());
+            for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());
             m_attributes.clear();
+            m_attributeIndex.clear();
             newobj["version"].integer(ver);
             m_obj.destroy();
             m_obj = newobj;
@@ -412,8 +420,9 @@ void StoredSession::addAssertion(Assertion* assertion)
             in >> newobj;
 
             m_ids.clear();
-            for_each(m_attributes.begin(), m_attributes.end(), cleanup_const_pair<string,Attribute>());
+            for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());
             m_attributes.clear();
+            m_attributeIndex.clear();
             newobj["version"].integer(ver);
             m_obj.destroy();
             m_obj = newobj;
@@ -534,7 +543,7 @@ string SSCache::insert(
     const XMLCh* authncontext_class,
     const XMLCh* authncontext_decl,
     const vector<const Assertion*>* tokens,
-    const multimap<string,Attribute*>* attributes
+    const vector<Attribute*>* attributes
     )
 {
 #ifdef _DEBUG
@@ -634,8 +643,8 @@ string SSCache::insert(
     if (attributes) {
         DDF attr;
         DDF attrlist = obj.addmember("attributes").list();
-        for (multimap<string,Attribute*>::const_iterator a=attributes->begin(); a!=attributes->end(); ++a) {
-            attr = a->second->marshall();
+        for (vector<Attribute*>::const_iterator a=attributes->begin(); a!=attributes->end(); ++a) {
+            attr = (*a)->marshall();
             attrlist.add(attr);
         }
     }
@@ -697,8 +706,8 @@ string SSCache::insert(
             ") for (applicationId: " <<
                 application.getId() <<
             ") {";
-        for (multimap<string,Attribute*>::const_iterator a=attributes->begin(); a!=attributes->end(); ++a)
-            xlog->log.infoStream() << "\t" << a->second->getId() << " (" << a->second->valueCount() << " values)";
+        for (vector<Attribute*>::const_iterator a=attributes->begin(); a!=attributes->end(); ++a)
+            xlog->log.infoStream() << "\t" << (*a)->getId() << " (" << (*a)->valueCount() << " values)";
         xlog->log.info("}");
     }
 
index 7f51df8..9f223c9 100644 (file)
@@ -159,8 +159,8 @@ bool Rule::authorized(const SPRequest& request, const Session* session) const
     }\r
     \r
     // Find the attribute(s) matching the require rule.\r
-    pair<multimap<string,Attribute*>::const_iterator, multimap<string,Attribute*>::const_iterator> attrs =\r
-        session->getAttributes().equal_range(m_alias);\r
+    pair<multimap<string,const Attribute*>::const_iterator, multimap<string,const Attribute*>::const_iterator> attrs =\r
+        session->getIndexedAttributes().equal_range(m_alias);\r
     if (attrs.first == attrs.second) {\r
         request.log(SPRequest::SPWarn, string("rule requires attribute (") + m_alias + "), not found in session");\r
         return false;\r