Collapse entity/role lookup in metadata API.
authorScott Cantor <cantor.2@osu.edu>
Thu, 8 Nov 2007 06:45:22 +0000 (06:45 +0000)
committerScott Cantor <cantor.2@osu.edu>
Thu, 8 Nov 2007 06:45:22 +0000 (06:45 +0000)
adfs/adfs.cpp
shibsp/attribute/resolver/impl/QueryAttributeResolver.cpp
shibsp/handler/impl/AssertionConsumerService.cpp
shibsp/handler/impl/SAML2Logout.cpp
shibsp/handler/impl/SAML2LogoutInitiator.cpp
shibsp/handler/impl/SAML2SessionInitiator.cpp
shibsp/handler/impl/Shib1SessionInitiator.cpp
shibsp/handler/impl/StatusHandler.cpp
shibsp/impl/StorageServiceSessionCache.cpp
util/mdquery.cpp
util/resolvertest.cpp

index 9b4d452..3c0fdff 100644 (file)
@@ -437,18 +437,19 @@ pair<bool,long> ADFSSessionInitiator::doRequest(
     // Use metadata to invoke the SSO service directly.
     MetadataProvider* m=app.getMetadataProvider();
     Locker locker(m);
-    const EntityDescriptor* entity=m->getEntityDescriptor(entityID);
-    if (!entity) {
+    MetadataProvider::Criteria mc(entityID, &IDPSSODescriptor::ELEMENT_QNAME, m_binding.get());
+    pair<const EntityDescriptor*,const RoleDescriptor*> entity=m->getEntityDescriptor(mc);
+    if (!entity.first) {
         m_log.error("unable to locate metadata for provider (%s)", entityID);
-        throw MetadataException("Unable to locate metadata for identity provider ($entityID)",
-            namedparams(1, "entityID", entityID));
+        throw MetadataException("Unable to locate metadata for identity provider ($entityID)", namedparams(1, "entityID", entityID));
     }
-    const IDPSSODescriptor* role=find_if(entity->getIDPSSODescriptors(), isValidForProtocol(m_binding.get()));
-    if (!role) {
+    else if (!entity.second) {
         m_log.error("unable to locate ADFS-aware identity provider role for provider (%s)", entityID);
         return make_pair(false,0);
     }
-    const EndpointType* ep=EndpointManager<SingleSignOnService>(role->getSingleSignOnServices()).getByBinding(m_binding.get());
+    const EndpointType* ep = EndpointManager<SingleSignOnService>(
+        dynamic_cast<const IDPSSODescriptor*>(entity.second)->getSingleSignOnServices()
+        ).getByBinding(m_binding.get());
     if (!ep) {
         m_log.error("unable to locate compatible SSO service for provider (%s)", entityID);
         return make_pair(false,0);
@@ -727,23 +728,18 @@ pair<bool,long> ADFSLogoutInitiator::doRequest(
             throw ConfigurationException("Missing entityID parameter.");
 
         // With a session in hand, we can create a request message, if we can find a compatible endpoint.
-        Locker metadataLocker(application.getMetadataProvider());
-        const EntityDescriptor* entity = application.getMetadataProvider()->getEntityDescriptor(entityID);
-        if (!entity) {
-            throw MetadataException(
-                "Unable to locate metadata for identity provider ($entityID)",
-                namedparams(1, "entityID", entityID)
-                );
-        }
-        const IDPSSODescriptor* role = find_if(entity->getIDPSSODescriptors(), isValidForProtocol(m_binding.get()));
-        if (!role) {
-            throw MetadataException(
-                "Unable to locate ADFS IdP role for identity provider ($entityID).",
-                namedparams(1, "entityID", entityID)
-                );
-        }
-
-        const EndpointType* ep = EndpointManager<SingleLogoutService>(role->getSingleLogoutServices()).getByBinding(m_binding.get());
+        MetadataProvider* m=application.getMetadataProvider();
+        Locker locker(m);
+        MetadataProvider::Criteria mc(entityID, &IDPSSODescriptor::ELEMENT_QNAME, m_binding.get());
+        pair<const EntityDescriptor*,const RoleDescriptor*> entity=m->getEntityDescriptor(mc);
+        if (!entity.first)
+            throw MetadataException("Unable to locate metadata for identity provider ($entityID)", namedparams(1, "entityID", entityID));
+        else if (!entity.second)
+            throw MetadataException("Unable to locate ADFS IdP role for identity provider ($entityID).", namedparams(1, "entityID", entityID));
+
+        const EndpointType* ep = EndpointManager<SingleLogoutService>(
+            dynamic_cast<const IDPSSODescriptor*>(entity.second)->getSingleLogoutServices()
+            ).getByBinding(m_binding.get());
         if (!ep) {
             throw MetadataException(
                 "Unable to locate ADFS single logout service for identity provider ($entityID).",
index bf8df1b..e6ccb70 100644 (file)
@@ -121,10 +121,10 @@ namespace shibsp {
             if (m_entity)
                 return m_entity;
             if (m_session && m_session->getEntityID()) {
-                m_metadata = m_app.getMetadataProvider();
+                m_metadata = m_app.getMetadataProvider(false);
                 if (m_metadata) {
                     m_metadata->lock();
-                    return m_entity = m_metadata->getEntityDescriptor(m_session->getEntityID());
+                    return m_entity = m_metadata->getEntityDescriptor(MetadataProvider::Criteria(m_session->getEntityID())).first;
                 }
             }
             return NULL;
index 169636d..57dacb3 100644 (file)
 # include <saml/saml1/core/Assertions.h>
 # include <saml/util/CommonDomainCookie.h>
 using namespace samlconstants;
+using opensaml::saml2md::MetadataProvider;
+using opensaml::saml2md::RoleDescriptor;
 using opensaml::saml2md::EntityDescriptor;
 using opensaml::saml2md::IDPSSODescriptor;
 using opensaml::saml2md::SPSSODescriptor;
-using opensaml::saml2md::isValidForProtocol;
 #else
 # include "lite/CommonDomainCookie.h"
 #endif
@@ -425,19 +426,18 @@ void AssertionConsumerService::extractMessageDetails(const Assertion& assertion,
 
     if (policy.getIssuer() && !policy.getIssuerMetadata() && policy.getMetadataProvider()) {
         m_log.debug("searching metadata for assertion issuer...");
-        const EntityDescriptor* entity = policy.getMetadataProvider()->getEntityDescriptor(policy.getIssuer()->getName());
-        if (entity) {
-            m_log.debug("matched assertion issuer against metadata, searching for applicable role...");
-            const IDPSSODescriptor* idp=find_if(entity->getIDPSSODescriptors(), isValidForProtocol(protocol));
-            if (idp)
-                policy.setIssuerMetadata(idp);
-            else if (m_log.isWarnEnabled())
-                m_log.warn("unable to find compatible IdP role in metadata");
-        }
-        else if (m_log.isWarnEnabled()) {
+        MetadataProvider::Criteria mc(policy.getIssuer()->getName(), &IDPSSODescriptor::ELEMENT_QNAME, protocol);
+        pair<const EntityDescriptor*,const RoleDescriptor*> entity = policy.getMetadataProvider()->getEntityDescriptor(mc);
+        if (!entity.first) {
             auto_ptr_char iname(policy.getIssuer()->getName());
             m_log.warn("no metadata found, can't establish identity of issuer (%s)", iname.get());
         }
+        else if (!entity.second) {
+            m_log.warn("unable to find compatible IdP role in metadata");
+        }
+        else {
+            policy.setIssuerMetadata(entity.second);
+        }
     }
 }
 
index 9f4108a..23b5421 100644 (file)
@@ -293,15 +293,16 @@ pair<bool,long> SAML2Logout::doRequest(
         }
 
         // We need metadata to issue a response.
-        Locker metadataLocker(application.getMetadataProvider());
-        const EntityDescriptor* entity = application.getMetadataProvider()->getEntityDescriptor(request.getParameter("entityID"));
-        if (!entity) {
+        MetadataProvider* m = application.getMetadataProvider();
+        Locker metadataLocker(m);
+        MetadataProvider::Criteria mc(request.getParameter("entityID"), &IDPSSODescriptor::ELEMENT_QNAME, samlconstants::SAML20P_NS);
+        pair<const EntityDescriptor*,const RoleDescriptor*> entity = m->getEntityDescriptor(mc);
+        if (!entity.first) {
             throw MetadataException(
                 "Unable to locate metadata for identity provider ($entityID)", namedparams(1, "entityID", request.getParameter("entityID"))
                 );
         }
-        const IDPSSODescriptor* idp = find_if(entity->getIDPSSODescriptors(), isValidForProtocol(samlconstants::SAML20P_NS));
-        if (!idp) {
+        else if (!entity.second) {
             throw MetadataException(
                 "Unable to locate SAML 2.0 IdP role for identity provider ($entityID).",
                 namedparams(1, "entityID", request.getParameter("entityID"))
@@ -312,7 +313,7 @@ pair<bool,long> SAML2Logout::doRequest(
         if (worked1 && worked2) {
             // Successful LogoutResponse. Has to be front-channel or we couldn't be here.
             return sendResponse(
-                reqid.get(), StatusCode::SUCCESS, NULL, NULL, request.getParameter("RelayState"), idp, application, response, true
+                reqid.get(), StatusCode::SUCCESS, NULL, NULL, request.getParameter("RelayState"), entity.second, application, response, true
                 );
         }
 
@@ -320,7 +321,7 @@ pair<bool,long> SAML2Logout::doRequest(
             reqid.get(),
             StatusCode::RESPONDER, NULL, "Unable to fully destroy principal's session.",
             request.getParameter("RelayState"),
-            idp,
+            entity.second,
             application,
             response,
             true
index eddd725..06edde9 100644 (file)
@@ -83,7 +83,7 @@ namespace shibsp {
         string m_appId;
 #ifndef SHIBSP_LITE
         LogoutRequest* buildRequest(
-            const Application& application, const Session& session, const IDPSSODescriptor& role, const MessageEncoder* encoder=NULL
+            const Application& application, const Session& session, const RoleDescriptor& role, const MessageEncoder* encoder=NULL
             ) const;
 
         XMLCh* m_outgoing;
@@ -287,22 +287,22 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
     pair<bool,long> ret = make_pair(false,0);
     try {
         // With a session in hand, we can create a LogoutRequest message, if we can find a compatible endpoint.
-        Locker metadataLocker(application.getMetadataProvider());
-        const EntityDescriptor* entity = application.getMetadataProvider()->getEntityDescriptor(session->getEntityID());
-        if (!entity) {
+        MetadataProvider* m = application.getMetadataProvider();
+        Locker metadataLocker(m);
+        MetadataProvider::Criteria mc(session->getEntityID(), &IDPSSODescriptor::ELEMENT_QNAME, samlconstants::SAML20P_NS);
+        pair<const EntityDescriptor*,const RoleDescriptor*> entity = m->getEntityDescriptor(mc);
+        if (!entity.first) {
             throw MetadataException(
-                "Unable to locate metadata for identity provider ($entityID)",
-                namedparams(1, "entityID", session->getEntityID())
+                "Unable to locate metadata for identity provider ($entityID)", namedparams(1, "entityID", session->getEntityID())
                 );
         }
-        const IDPSSODescriptor* role = find_if(entity->getIDPSSODescriptors(), isValidForProtocol(samlconstants::SAML20P_NS));
-        if (!role) {
+        else if (!entity.second) {
             throw MetadataException(
-                "Unable to locate SAML 2.0 IdP role for identity provider ($entityID).",
-                namedparams(1, "entityID", session->getEntityID())
+                "Unable to locate SAML 2.0 IdP role for identity provider ($entityID).", namedparams(1, "entityID", session->getEntityID())
                 );
         }
 
+        const IDPSSODescriptor* role = dynamic_cast<const IDPSSODescriptor*>(entity.second);
         const EndpointType* ep=NULL;
         const MessageEncoder* encoder=NULL;
         vector<const XMLCh*>::const_iterator b;
@@ -396,7 +396,7 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
 #ifndef SHIBSP_LITE
 
 LogoutRequest* SAML2LogoutInitiator::buildRequest(
-    const Application& application, const Session& session, const IDPSSODescriptor& role, const MessageEncoder* encoder
+    const Application& application, const Session& session, const RoleDescriptor& role, const MessageEncoder* encoder
     ) const
 {
     auto_ptr<LogoutRequest> msg(LogoutRequestBuilder::buildLogoutRequest());
index 1e1e0e2..2832221 100644 (file)
@@ -403,19 +403,19 @@ pair<bool,long> SAML2SessionInitiator::doRequest(
     // Use metadata to locate the IdP's SSO service.
     MetadataProvider* m=app.getMetadataProvider();
     Locker locker(m);
-    const EntityDescriptor* entity=m->getEntityDescriptor(entityID);
-    if (!entity) {
+    MetadataProvider::Criteria mc(entityID, &IDPSSODescriptor::ELEMENT_QNAME, samlconstants::SAML20P_NS);
+    pair<const EntityDescriptor*,const RoleDescriptor*> entity=m->getEntityDescriptor(mc);
+    if (!entity.first) {
         m_log.error("unable to locate metadata for provider (%s)", entityID);
-        throw MetadataException("Unable to locate metadata for identity provider ($entityID)",
-            namedparams(1, "entityID", entityID));
+        throw MetadataException("Unable to locate metadata for identity provider ($entityID)", namedparams(1, "entityID", entityID));
     }
-    const IDPSSODescriptor* role=find_if(entity->getIDPSSODescriptors(), isValidForProtocol(samlconstants::SAML20P_NS));
-    if (!role) {
+    else if (!entity.second) {
         m_log.error("unable to locate SAML 2.0 identity provider role for provider (%s)", entityID);
         return make_pair(false,0);
     }
 
     // Loop over the supportable outgoing bindings.
+    const IDPSSODescriptor* role = dynamic_cast<const IDPSSODescriptor*>(entity.second);
     const EndpointType* ep=NULL;
     const MessageEncoder* encoder=NULL;
     vector<const XMLCh*>::const_iterator b;
@@ -486,9 +486,7 @@ pair<bool,long> SAML2SessionInitiator::doRequest(
 
     auto_ptr_char dest(ep->getLocation());
 
-    long ret = sendMessage(
-        *encoder, req.get(), relayState.c_str(), dest.get(), role, app, httpResponse, role->WantAuthnRequestsSigned()
-        );
+    long ret = sendMessage(*encoder, req.get(), relayState.c_str(), dest.get(), role, app, httpResponse, role->WantAuthnRequestsSigned());
     req.release();  // freed by encoder
     return make_pair(true,ret);
 #else
index a7155b8..f370e77 100644 (file)
@@ -224,20 +224,19 @@ pair<bool,long> Shib1SessionInitiator::doRequest(
     // Use metadata to invoke the SSO service directly.
     MetadataProvider* m=app.getMetadataProvider();
     Locker locker(m);
-    const EntityDescriptor* entity=m->getEntityDescriptor(entityID);
-    if (!entity) {
+    MetadataProvider::Criteria mc(entityID, &IDPSSODescriptor::ELEMENT_QNAME, shibspconstants::SHIB1_PROTOCOL_ENUM);
+    pair<const EntityDescriptor*,const RoleDescriptor*> entity = m->getEntityDescriptor(mc);
+    if (!entity.first) {
         m_log.error("unable to locate metadata for provider (%s)", entityID);
-        throw MetadataException("Unable to locate metadata for identity provider ($entityID)",
-            namedparams(1, "entityID", entityID));
+        throw MetadataException("Unable to locate metadata for identity provider ($entityID)", namedparams(1, "entityID", entityID));
     }
-    const IDPSSODescriptor* role=find_if(entity->getIDPSSODescriptors(), isValidForProtocol(shibspconstants::SHIB1_PROTOCOL_ENUM));
-    if (!role) {
+    else if (!entity.second) {
         m_log.error("unable to locate Shibboleth-aware identity provider role for provider (%s)", entityID);
         return make_pair(false,0);
     }
-    const EndpointType* ep=EndpointManager<SingleSignOnService>(role->getSingleSignOnServices()).getByBinding(
-        shibspconstants::SHIB1_AUTHNREQUEST_PROFILE_URI
-        );
+    const EndpointType* ep=EndpointManager<SingleSignOnService>(
+        dynamic_cast<const IDPSSODescriptor*>(entity.second)->getSingleSignOnServices()
+        ).getByBinding(shibspconstants::SHIB1_AUTHNREQUEST_PROFILE_URI);
     if (!ep) {
         m_log.error("unable to locate compatible SSO service for provider (%s)", entityID);
         return make_pair(false,0);
index 0b8215a..8862f58 100644 (file)
@@ -399,8 +399,9 @@ pair<bool,long> StatusHandler::processMessage(
         const PropertySet* relyingParty=NULL;
         param=httpRequest.getParameter("entityID");
         if (param) {
-            Locker mlock(application.getMetadataProvider());
-            relyingParty = application.getRelyingParty(application.getMetadataProvider()->getEntityDescriptor(param));
+            MetadataProvider* m = application.getMetadataProvider();
+            Locker mlock(m);
+            relyingParty = application.getRelyingParty(m->getEntityDescriptor(MetadataProvider::Criteria(param)).first);
         }
         if (!relyingParty)
             relyingParty = application.getRelyingParty(NULL);
index 8a7c0d1..5aa9a7e 100644 (file)
@@ -769,13 +769,16 @@ Session* SSCache::find(const char* key, const Application& application, const ch
                 "Your IP address ($1) does not match the address recorded at the time the session was established.",
                 params(1,client_addr)
                 );
-            string eid(obj["entity_id"].string());
-            obj.destroy();
-            if (eid.empty())
+            const char* eid = obj["entity_id"].string();
+            if (!eid) {
+                obj.destroy();
                 throw ex;
+            }
+            string eid2(eid);
+            obj.destroy();
             MetadataProvider* m=application.getMetadataProvider();
             Locker locker(m);
-            annotateException(&ex,m->getEntityDescriptor(eid.c_str(),false)); // throws it
+            annotateException(&ex,m->getEntityDescriptor(MetadataProvider::Criteria(eid2.c_str(),NULL,NULL,false)).first); // throws it
         }
     }
 
@@ -786,13 +789,16 @@ Session* SSCache::find(const char* key, const Application& application, const ch
         m_log.info("session timed out (ID: %s)", key);
         remove(key, application);
         RetryableProfileException ex("Your session has expired, and you must re-authenticate.");
-        string eid(obj["entity_id"].string());
-        obj.destroy();
-        if (eid.empty())
+        const char* eid = obj["entity_id"].string();
+        if (!eid) {
+            obj.destroy();
             throw ex;
+        }
+        string eid2(eid);
+        obj.destroy();
         MetadataProvider* m=application.getMetadataProvider();
         Locker locker(m);
-        annotateException(&ex,m->getEntityDescriptor(eid.c_str(),false)); // throws it
+        annotateException(&ex,m->getEntityDescriptor(MetadataProvider::Criteria(eid2.c_str(),NULL,NULL,false)).first); // throws it
     }
     
     auto_ptr_XMLCh exp(obj["expires"].string());
@@ -803,13 +809,16 @@ Session* SSCache::find(const char* key, const Application& application, const ch
             m_log.info("session expired (ID: %s)", key);
             remove(key, application);
             RetryableProfileException ex("Your session has expired, and you must re-authenticate.");
-            string eid(obj["entity_id"].string());
-            obj.destroy();
-            if (eid.empty())
+            const char* eid = obj["entity_id"].string();
+            if (!eid) {
+                obj.destroy();
                 throw ex;
+            }
+            string eid2(eid);
+            obj.destroy();
             MetadataProvider* m=application.getMetadataProvider();
             Locker locker(m);
-            annotateException(&ex,m->getEntityDescriptor(eid.c_str(),false)); // throws it
+            annotateException(&ex,m->getEntityDescriptor(MetadataProvider::Criteria(eid2.c_str(),NULL,NULL,false)).first); // throws it
         }
     }
     
index b11aa1d..00e1e49 100644 (file)
@@ -153,26 +153,25 @@ int main(int argc,char* argv[])
     }\r
 \r
     app->getMetadataProvider()->lock();\r
-    const EntityDescriptor* entity = app->getMetadataProvider()->getEntityDescriptor(entityID, strict);\r
-    if (entity) {\r
-        if (rname) {\r
-            const XMLCh* ns = rns ? XMLString::transcode(rns) : samlconstants::SAML20MD_NS;\r
-            auto_ptr_XMLCh n(rname);\r
-            QName q(ns, n.get());\r
-            const RoleDescriptor* role = entity->getRoleDescriptor(q, protocol);\r
-            if (role) {\r
-                XMLHelper::serialize(role->marshall(), cout, true);\r
-            }\r
-            else {\r
-                log.error("compatible role %s not found for (%s)", q.toString().c_str(), entityID);\r
-            }\r
-        }\r
-        else {\r
-            XMLHelper::serialize(entity->marshall(), cout, true);\r
-        }\r
+    MetadataProvider::Criteria mc(entityID, NULL, NULL, strict);\r
+    if (rname) {\r
+        const XMLCh* ns = rns ? XMLString::transcode(rns) : samlconstants::SAML20MD_NS;\r
+        auto_ptr_XMLCh n(rname);\r
+        QName q(ns, n.get());\r
+        mc.role = &q;\r
+        mc.protocol = protocol;\r
+        const RoleDescriptor* role = app->getMetadataProvider()->getEntityDescriptor(mc).second;\r
+        if (role)\r
+            XMLHelper::serialize(role->marshall(), cout, true);\r
+        else\r
+            log.error("compatible role %s not found for (%s)", q.toString().c_str(), entityID);\r
     }\r
     else {\r
-        log.error("no metadata found for (%s)", entityID);\r
+        const EntityDescriptor* entity = app->getMetadataProvider()->getEntityDescriptor(mc).first;\r
+        if (entity)\r
+            XMLHelper::serialize(entity->marshall(), cout, true);\r
+        else\r
+            log.error("no metadata found for (%s)", entityID);\r
     }\r
 \r
     app->getMetadataProvider()->unlock();\r
index 7430372..d818e80 100644 (file)
@@ -215,8 +215,9 @@ int main(int argc,char* argv[])
 
             MetadataProvider* m=app->getMetadataProvider();
             xmltooling::Locker mlocker(m);
-            const EntityDescriptor* site=m->getEntityDescriptor(issuer.get());
-            if (!site)
+            MetadataProvider::Criteria mc(i_param, &IDPSSODescriptor::ELEMENT_QNAME, protocol);
+            pair<const EntityDescriptor*,const RoleDescriptor*> site=m->getEntityDescriptor(mc);
+            if (!site.first)
                 throw MetadataException("Unable to locate metadata for IdP ($1).", params(1,i_param));
 
             // Build NameID(s).
@@ -233,9 +234,7 @@ int main(int argc,char* argv[])
 
             ResolverTest rt(NULL, a_param);
             try {
-                ctx = rt.resolveAttributes(
-                    *app, find_if(site->getIDPSSODescriptors(), isValidForProtocol(protocol)), protocol, v1name, v2name.get(), NULL, NULL, NULL
-                    );
+                ctx = rt.resolveAttributes(*app, site.second, protocol, v1name, v2name.get(), NULL, NULL, NULL);
             }
             catch (...) {
                 delete v1name;
@@ -287,8 +286,9 @@ int main(int argc,char* argv[])
 
             MetadataProvider* m=app->getMetadataProvider();
             xmltooling::Locker mlocker(m);
-            const EntityDescriptor* site=m->getEntityDescriptor(issuer);
-            if (!site) {
+            MetadataProvider::Criteria mc(issuer, &IDPSSODescriptor::ELEMENT_QNAME, protocol);
+            pair<const EntityDescriptor*,const RoleDescriptor*> site=m->getEntityDescriptor(mc);
+            if (!site.first) {
                 auto_ptr_char temp(issuer);
                 throw MetadataException("Unable to locate metadata for IdP ($1).", params(1,temp.get()));
             }
@@ -296,9 +296,7 @@ int main(int argc,char* argv[])
             vector<const Assertion*> tokens(1, dynamic_cast<Assertion*>(token.get()));
             ResolverTest rt(NULL, a_param);
             try {
-                ctx = rt.resolveAttributes(
-                    *app, find_if(site->getIDPSSODescriptors(), isValidForProtocol(protocol)), protocol, v1name, v2name, NULL, NULL, &tokens
-                    );
+                ctx = rt.resolveAttributes(*app, site.second, protocol, v1name, v2name, NULL, NULL, &tokens);
             }
             catch (...) {
                 if (v1name)