Move all attribute work into base class.
authorScott Cantor <cantor.2@osu.edu>
Mon, 20 Aug 2007 21:29:28 +0000 (21:29 +0000)
committerScott Cantor <cantor.2@osu.edu>
Mon, 20 Aug 2007 21:29:28 +0000 (21:29 +0000)
adfs/adfs.cpp
shibsp/handler/AssertionConsumerService.h
shibsp/handler/impl/AssertionConsumerService.cpp
shibsp/handler/impl/SAML1Consumer.cpp
shibsp/handler/impl/SAML2Consumer.cpp

index efdfc7d..6fc91a4 100644 (file)
 #include <xercesc/util/XMLUniDefs.hpp>
 
 #ifndef SHIBSP_LITE
-# include <shibsp/attribute/Attribute.h>
-# include <shibsp/attribute/filtering/AttributeFilter.h>
-# include <shibsp/attribute/filtering/BasicFilteringContext.h>
-# include <shibsp/attribute/resolver/AttributeExtractor.h>
 # include <shibsp/attribute/resolver/ResolutionContext.h>
 # include <saml/SAMLConfig.h>
 # include <saml/saml1/core/Assertions.h>
@@ -561,41 +557,6 @@ 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.
-    vector<Attribute*> resolvedAttributes;
-    AttributeExtractor* extractor = application.getAttributeExtractor();
-    if (extractor) {
-        m_log.debug("extracting pushed attributes...");
-        Locker extlocker(extractor);
-        if (n) {
-            try {
-                extractor->extractAttributes(application, policy.getIssuerMetadata(), *n, resolvedAttributes);
-            }
-            catch (exception& ex) {
-                m_log.error("caught exception extracting attributes: %s", ex.what());
-            }
-        }
-        try {
-            extractor->extractAttributes(application, policy.getIssuerMetadata(), *token, resolvedAttributes);
-        }
-        catch (exception& ex) {
-            m_log.error("caught exception extracting attributes: %s", ex.what());
-        }
-
-        AttributeFilter* filter = application.getAttributeFilter();
-        if (filter && !resolvedAttributes.empty()) {
-            BasicFilteringContext fc(application, resolvedAttributes, policy.getIssuerMetadata(), ssoStatement->getAuthenticationMethod());
-            Locker filtlocker(filter);
-            try {
-                filter->filterAttributes(fc, resolvedAttributes);
-            }
-            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(), xmltooling::cleanup<shibsp::Attribute>());
-                resolvedAttributes.clear();
-            }
-        }
-    }
 
     // Normalize the SAML 1.x NameIdentifier...
     auto_ptr<saml2::NameID> nameid(n ? saml2::NameIDBuilder::buildNameID() : NULL);
@@ -605,52 +566,39 @@ string ADFSConsumer::implementProtocol(
         nameid->setNameQualifier(n->getNameQualifier());
     }
 
-    const EntityDescriptor* issuerMetadata =
-        policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL;
-    auto_ptr<ResolutionContext> ctx(
+    // The context will handle deleting attributes and new tokens.
+        auto_ptr<ResolutionContext> ctx(
         resolveAttributes(
             application,
-            issuerMetadata,
+            policy.getIssuerMetadata(),
             m_protocol.get(),
+            n,
             nameid.get(),
             ssoStatement->getAuthenticationMethod(),
             NULL,
-            &tokens,
-            &resolvedAttributes
+            &tokens
             )
         );
 
     if (ctx.get()) {
         // Copy over any new tokens, but leave them in the context for cleanup.
         tokens.insert(tokens.end(), ctx->getResolvedAssertions().begin(), ctx->getResolvedAssertions().end());
-
-        // Copy over new attributes, and transfer ownership.
-        resolvedAttributes.insert(resolvedAttributes.end(), ctx->getResolvedAttributes().begin(), ctx->getResolvedAttributes().end());
-        ctx->getResolvedAttributes().clear();
     }
 
-    try {
-        string key = application.getServiceProvider().getSessionCache()->insert(
-            now + lifetime.second,
-            application,
-            httpRequest.getRemoteAddr().c_str(),
-            issuerMetadata,
-            m_protocol.get(),
-            nameid.get(),
-            ssoStatement->getAuthenticationInstant() ? ssoStatement->getAuthenticationInstant()->getRawData() : NULL,
-            NULL,
-            ssoStatement->getAuthenticationMethod(),
-            NULL,
-            &tokens,
-            &resolvedAttributes
-            );
-        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
-        return key;
-    }
-    catch (exception&) {
-        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
-        throw;
-    }
+    return application.getServiceProvider().getSessionCache()->insert(
+        now + lifetime.second,
+        application,
+        httpRequest.getRemoteAddr().c_str(),
+        policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL,
+        m_protocol.get(),
+        nameid.get(),
+        ssoStatement->getAuthenticationInstant() ? ssoStatement->getAuthenticationInstant()->getRawData() : NULL,
+        NULL,
+        ssoStatement->getAuthenticationMethod(),
+        NULL,
+        &tokens,
+        ctx.get() ? &ctx->getResolvedAttributes() : NULL
+        );
 }
 
 #endif
index c933c89..90d363d 100644 (file)
@@ -27,6 +27,7 @@
 #include <shibsp/handler/RemotedHandler.h>
 #ifndef SHIBSP_LITE
 # include <saml/binding/MessageDecoder.h>
+# include <saml/saml1/core/Assertions.h>
 # include <saml/saml2/metadata/Metadata.h>
 #endif
 #include <xmltooling/unicode.h>
@@ -85,28 +86,30 @@ namespace shibsp {
             ) const=0;
 
         /**
-         * Attempt SSO-initiated attribute resolution using the supplied information.
+         * Attempt SSO-initiated attribute resolution using the supplied information,
+         * including NameID and token extraction and filtering followed by
+         * secondary resolution.
          * 
          * <p>The caller must free the returned context handle.
          * 
-         * @param application   reference to application receiving message
-         * @param issuer        source of SSO tokens
-         * @param protocol      SSO protocol used
-         * @param nameid        identifier of principal
+         * @param application           reference to application receiving message
+         * @param issuer                source of SSO tokens
+         * @param protocol              SSO protocol used
+         * @param v1nameid              identifier of principal in SAML 1.x form, if any
+         * @param nameid                identifier of principal in SAML 2.0 form
          * @param authncontext_class    method/category of authentication event, if known
-         * @param authncontext_decl specifics of authentication event, if known
-         * @param tokens        available assertions, if any
-         * @param attributes    attributes already extracted, if any
+         * @param authncontext_decl     specifics of authentication event, if known
+         * @param tokens                available assertions, if any
          */
         ResolutionContext* resolveAttributes(
             const Application& application,
-            const opensaml::saml2md::EntityDescriptor* issuer=NULL,
+            const opensaml::saml2md::RoleDescriptor* issuer=NULL,
             const XMLCh* protocol=NULL,
+            const opensaml::saml1::NameIdentifier* v1nameid=NULL,
             const opensaml::saml2::NameID* nameid=NULL,
             const XMLCh* authncontext_class=NULL,
             const XMLCh* authncontext_decl=NULL,
-            const std::vector<const opensaml::Assertion*>* tokens=NULL,
-            const std::vector<Attribute*>* attributes=NULL
+            const std::vector<const opensaml::Assertion*>* tokens=NULL
             ) const;
 #endif
         
index 8d7c0fe..7d675b6 100644 (file)
 
 # include <ctime>
 #ifndef SHIBSP_LITE
+# include "attribute/Attribute.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 "security/SecurityPolicy.h"
@@ -241,29 +245,112 @@ void AssertionConsumerService::checkAddress(
 }
 
 #ifndef SHIBSP_LITE
+
+class SHIBSP_DLLLOCAL DummyContext : public ResolutionContext
+{
+public:
+    DummyContext(const vector<Attribute*>& attributes) : m_attributes(attributes) {
+    }
+
+    virtual ~DummyContext() {
+        for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());
+    }
+
+    vector<Attribute*>& getResolvedAttributes() {
+        return m_attributes;
+    }
+    vector<Assertion*>& getResolvedAssertions() {
+        return m_tokens;
+    }
+
+private:
+    vector<Attribute*> m_attributes;
+    static vector<Assertion*> m_tokens; // never any tokens, so just share an empty vector
+};
+
+vector<Assertion*> DummyContext::m_tokens;
+
 ResolutionContext* AssertionConsumerService::resolveAttributes(
     const Application& application,
-    const saml2md::EntityDescriptor* issuer,
+    const saml2md::RoleDescriptor* issuer,
     const XMLCh* protocol,
+    const saml1::NameIdentifier* v1nameid,
     const saml2::NameID* nameid,
     const XMLCh* authncontext_class,
     const XMLCh* authncontext_decl,
-    const vector<const Assertion*>* tokens,
-    const vector<Attribute*>* attributes
+    const vector<const Assertion*>* tokens
     ) const
 {
+    // First we do the extraction of any pushed information.
+    vector<Attribute*> resolvedAttributes;
+    AttributeExtractor* extractor = application.getAttributeExtractor();
+    if (extractor) {
+        m_log.debug("extracting pushed attributes...");
+        Locker extlocker(extractor);
+        if (v1nameid) {
+            try {
+                extractor->extractAttributes(application, issuer, *v1nameid, resolvedAttributes);
+            }
+            catch (exception& ex) {
+                m_log.error("caught exception extracting attributes: %s", ex.what());
+            }
+        }
+        else if (nameid) {
+            try {
+                extractor->extractAttributes(application, issuer, *nameid, resolvedAttributes);
+            }
+            catch (exception& ex) {
+                m_log.error("caught exception extracting attributes: %s", ex.what());
+            }
+        }
+        if (tokens) {
+            for (vector<const Assertion*>::const_iterator t = tokens->begin(); t!=tokens->end(); ++t) {
+                try {
+                    extractor->extractAttributes(application, issuer, *(*t), resolvedAttributes);
+                }
+                catch (exception& ex) {
+                    m_log.error("caught exception extracting attributes: %s", ex.what());
+                }
+            }
+        }
+
+        AttributeFilter* filter = application.getAttributeFilter();
+        if (filter && !resolvedAttributes.empty()) {
+            BasicFilteringContext fc(application, resolvedAttributes, issuer, authncontext_class);
+            Locker filtlocker(filter);
+            try {
+                filter->filterAttributes(fc, resolvedAttributes);
+            }
+            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(), xmltooling::cleanup<shibsp::Attribute>());
+                resolvedAttributes.clear();
+            }
+        }
+    }
+    
     try {
         AttributeResolver* resolver = application.getAttributeResolver();
-        if (!resolver) {
+        if (!resolver && !resolvedAttributes.empty()) {
             m_log.info("no AttributeResolver available, skipping resolution");
-            return NULL;
+            return new DummyContext(resolvedAttributes);
         }
         
         m_log.debug("resolving attributes...");
 
         Locker locker(resolver);
         auto_ptr<ResolutionContext> ctx(
-            resolver->createResolutionContext(application, issuer, protocol, nameid, authncontext_class, authncontext_decl, tokens, attributes)
+            resolver->createResolutionContext(
+                application,
+                dynamic_cast<const saml2md::EntityDescriptor*>(issuer->getParent()),
+                protocol,
+                nameid,
+                authncontext_class,
+                authncontext_decl,
+                tokens,
+                &resolvedAttributes
+                )
             );
         resolver->resolveAttributes(*ctx.get());
         return ctx.release();
@@ -272,6 +359,8 @@ ResolutionContext* AssertionConsumerService::resolveAttributes(
         m_log.error("attribute resolution failed: %s", ex.what());
     }
     
+    if (!resolvedAttributes.empty())
+        return new DummyContext(resolvedAttributes);
     return NULL;
 }
 #endif
index a4e5303..92c78e2 100644 (file)
 # include "Application.h"
 # include "ServiceProvider.h"
 # include "SessionCache.h"
-# include "attribute/Attribute.h"
-# include "attribute/filtering/AttributeFilter.h"
-# include "attribute/filtering/BasicFilteringContext.h"
-# include "attribute/resolver/AttributeExtractor.h"
 # include "attribute/resolver/ResolutionContext.h"
 # include <saml/saml1/core/Assertions.h>
 # include <saml/saml1/core/Protocols.h>
@@ -206,43 +202,6 @@ 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.
-    vector<Attribute*> resolvedAttributes;
-    AttributeExtractor* extractor = application.getAttributeExtractor();
-    if (extractor) {
-        m_log.debug("extracting pushed attributes...");
-        Locker extlocker(extractor);
-        if (n) {
-            try {
-                extractor->extractAttributes(application, policy.getIssuerMetadata(), *n, resolvedAttributes);
-            }
-            catch (exception& ex) {
-                m_log.error("caught exception extracting attributes: %s", ex.what());
-            }
-        }
-        for (vector<const opensaml::Assertion*>::const_iterator t = tokens.begin(); t!=tokens.end(); ++t) {
-            try {
-                extractor->extractAttributes(application, policy.getIssuerMetadata(), *(*t), resolvedAttributes);
-            }
-            catch (exception& ex) {
-                m_log.error("caught exception extracting attributes: %s", ex.what());
-            }
-        }
-
-        AttributeFilter* filter = application.getAttributeFilter();
-        if (filter && !resolvedAttributes.empty()) {
-            BasicFilteringContext fc(application, resolvedAttributes, policy.getIssuerMetadata(), ssoStatement->getAuthenticationMethod());
-            Locker filtlocker(filter);
-            try {
-                filter->filterAttributes(fc, resolvedAttributes);
-            }
-            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(), xmltooling::cleanup<shibsp::Attribute>());
-                resolvedAttributes.clear();
-            }
-        }
-    }
 
     // Normalize the SAML 1.x NameIdentifier...
     auto_ptr<NameID> nameid(n ? NameIDBuilder::buildNameID() : NULL);
@@ -252,57 +211,44 @@ string SAML1Consumer::implementProtocol(
         nameid->setNameQualifier(n->getNameQualifier());
     }
 
-    const EntityDescriptor* issuerMetadata =
-        policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL;
+    // The context will handle deleting attributes and new tokens.
     auto_ptr<ResolutionContext> ctx(
         resolveAttributes(
             application,
-            issuerMetadata,
+            policy.getIssuerMetadata(),
             (!response->getMinorVersion().first || response->getMinorVersion().second==1) ?
                 samlconstants::SAML11_PROTOCOL_ENUM : samlconstants::SAML10_PROTOCOL_ENUM,
+            n,
             nameid.get(),
             ssoStatement->getAuthenticationMethod(),
             NULL,
-            &tokens,
-            &resolvedAttributes
+            &tokens
             )
         );
 
     if (ctx.get()) {
         // Copy over any new tokens, but leave them in the context for cleanup.
         tokens.insert(tokens.end(), ctx->getResolvedAssertions().begin(), ctx->getResolvedAssertions().end());
-
-        // Copy over new attributes, and transfer ownership.
-        resolvedAttributes.insert(resolvedAttributes.end(), ctx->getResolvedAttributes().begin(), ctx->getResolvedAttributes().end());
-        ctx->getResolvedAttributes().clear();
     }
 
     // Now merge in bad tokens for caching.
     tokens.insert(tokens.end(), badtokens.begin(), badtokens.end());
 
-    try {
-        string key = application.getServiceProvider().getSessionCache()->insert(
-            now + lifetime.second,
-            application,
-            httpRequest.getRemoteAddr().c_str(),
-            issuerMetadata,
-            (!response->getMinorVersion().first || response->getMinorVersion().second==1) ?
-                samlconstants::SAML11_PROTOCOL_ENUM : samlconstants::SAML10_PROTOCOL_ENUM,
-            nameid.get(),
-            ssoStatement->getAuthenticationInstant() ? ssoStatement->getAuthenticationInstant()->getRawData() : NULL,
-            NULL,
-            ssoStatement->getAuthenticationMethod(),
-            NULL,
-            &tokens,
-            &resolvedAttributes
-            );
-        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
-        return key;
-    }
-    catch (exception&) {
-        for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
-        throw;
-    }
+    return application.getServiceProvider().getSessionCache()->insert(
+        now + lifetime.second,
+        application,
+        httpRequest.getRemoteAddr().c_str(),
+        policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL,
+        (!response->getMinorVersion().first || response->getMinorVersion().second==1) ?
+            samlconstants::SAML11_PROTOCOL_ENUM : samlconstants::SAML10_PROTOCOL_ENUM,
+        nameid.get(),
+        ssoStatement->getAuthenticationInstant() ? ssoStatement->getAuthenticationInstant()->getRawData() : NULL,
+        NULL,
+        ssoStatement->getAuthenticationMethod(),
+        NULL,
+        &tokens,
+        ctx.get() ? &ctx->getResolvedAttributes() : NULL
+        );
 }
 
 #endif
index a82b3be..534544d 100644 (file)
 # include "Application.h"
 # include "ServiceProvider.h"
 # include "SessionCache.h"
-# include "attribute/Attribute.h"
-# include "attribute/filtering/AttributeFilter.h"
-# include "attribute/filtering/BasicFilteringContext.h"
-# include "attribute/resolver/AttributeExtractor.h"
 # include "attribute/resolver/ResolutionContext.h"
 # include <saml/saml2/core/Protocols.h>
 # include <saml/saml2/profile/BrowserSSOProfileValidator.h>
@@ -335,73 +331,26 @@ string SAML2Consumer::implementProtocol(
     else
         sessionExp = min(sessionExp, now + lifetime.second);    // Use the lowest.
 
-    vector<Attribute*> resolvedAttributes;
-    AttributeExtractor* extractor = application.getAttributeExtractor();
-    if (extractor) {
-        m_log.debug("extracting pushed attributes...");
-        Locker extlocker(extractor);
-        try {
-            extractor->extractAttributes(application, policy.getIssuerMetadata(), *ssoName, resolvedAttributes);
-        }
-        catch (exception& ex) {
-            m_log.error("caught exception extracting attributes: %s", ex.what());
-        }
-        for (vector<const opensaml::Assertion*>::const_iterator t = tokens.begin(); t!=tokens.end(); ++t) {
-            try {
-                extractor->extractAttributes(application, policy.getIssuerMetadata(), *(*t), resolvedAttributes);
-            }
-            catch (exception& ex) {
-                m_log.error("caught exception extracting attributes: %s", ex.what());
-            }
-        }
-    }
-
     const AuthnContext* authnContext = ssoStatement->getAuthnContext();
 
-    AttributeFilter* filter = application.getAttributeFilter();
-    if (filter && !resolvedAttributes.empty()) {
-        BasicFilteringContext fc(
-            application,
-            resolvedAttributes,
-            policy.getIssuerMetadata(),
-            (authnContext && authnContext->getAuthnContextClassRef()) ? authnContext->getAuthnContextClassRef()->getReference() : NULL,
-            (authnContext && authnContext->getAuthnContextDeclRef()) ? authnContext->getAuthnContextDeclRef()->getReference() : NULL
-            );
-        Locker filtlocker(filter);
-        try {
-            filter->filterAttributes(fc, resolvedAttributes);
-        }
-        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(), xmltooling::cleanup<shibsp::Attribute>());
-            resolvedAttributes.clear();
-        }
-    }
-
     try {
-        const EntityDescriptor* issuerMetadata =
-            policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL;
+        // The context will handle deleting attributes and new tokens.
         auto_ptr<ResolutionContext> ctx(
             resolveAttributes(
                 application,
-                issuerMetadata,
+                policy.getIssuerMetadata(),
                 samlconstants::SAML20P_NS,
+                NULL,
                 ssoName,
                 (authnContext && authnContext->getAuthnContextClassRef()) ? authnContext->getAuthnContextClassRef()->getReference() : NULL,
                 (authnContext && authnContext->getAuthnContextDeclRef()) ? authnContext->getAuthnContextDeclRef()->getReference() : NULL,
-                &tokens,
-                &resolvedAttributes
+                &tokens
                 )
             );
 
         if (ctx.get()) {
             // Copy over any new tokens, but leave them in the context for cleanup.
             tokens.insert(tokens.end(), ctx->getResolvedAssertions().begin(), ctx->getResolvedAssertions().end());
-
-            // Copy over new attributes, and transfer ownership.
-            resolvedAttributes.insert(resolvedAttributes.end(), ctx->getResolvedAttributes().begin(), ctx->getResolvedAttributes().end());
-            ctx->getResolvedAttributes().clear();
         }
 
         // Now merge in bad tokens for caching.
@@ -411,7 +360,7 @@ string SAML2Consumer::implementProtocol(
             sessionExp,
             application,
             httpRequest.getRemoteAddr().c_str(),
-            issuerMetadata,
+            policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL,
             samlconstants::SAML20P_NS,
             ssoName,
             ssoStatement->getAuthnInstant() ? ssoStatement->getAuthnInstant()->getRawData() : NULL,
@@ -419,20 +368,18 @@ string SAML2Consumer::implementProtocol(
             (authnContext && authnContext->getAuthnContextClassRef()) ? authnContext->getAuthnContextClassRef()->getReference() : NULL,
             (authnContext && authnContext->getAuthnContextDeclRef()) ? authnContext->getAuthnContextDeclRef()->getReference() : NULL,
             &tokens,
-            &resolvedAttributes
+            ctx.get() ? &ctx->getResolvedAttributes() : NULL
             );
 
         if (ownedName)
             delete ssoName;
         for_each(ownedtokens.begin(), ownedtokens.end(), xmltooling::cleanup<saml2::Assertion>());
-        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(), xmltooling::cleanup<shibsp::Attribute>());
         throw;
     }
 }