From: Scott Cantor Date: Mon, 20 Aug 2007 21:29:28 +0000 (+0000) Subject: Move all attribute work into base class. X-Git-Tag: 2.0-beta1~35 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-sp.git;a=commitdiff_plain;h=8093c5987011df54e4bed80656853a37c607d99f Move all attribute work into base class. --- diff --git a/adfs/adfs.cpp b/adfs/adfs.cpp index efdfc7d..6fc91a4 100644 --- a/adfs/adfs.cpp +++ b/adfs/adfs.cpp @@ -50,10 +50,6 @@ #include #ifndef SHIBSP_LITE -# include -# include -# include -# include # include # include # include @@ -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 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()); - resolvedAttributes.clear(); - } - } - } // Normalize the SAML 1.x NameIdentifier... auto_ptr nameid(n ? saml2::NameIDBuilder::buildNameID() : NULL); @@ -605,52 +566,39 @@ string ADFSConsumer::implementProtocol( nameid->setNameQualifier(n->getNameQualifier()); } - const EntityDescriptor* issuerMetadata = - policy.getIssuerMetadata() ? dynamic_cast(policy.getIssuerMetadata()->getParent()) : NULL; - auto_ptr ctx( + // The context will handle deleting attributes and new tokens. + auto_ptr 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()); - return key; - } - catch (exception&) { - for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup()); - throw; - } + return application.getServiceProvider().getSessionCache()->insert( + now + lifetime.second, + application, + httpRequest.getRemoteAddr().c_str(), + policy.getIssuerMetadata() ? dynamic_cast(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 diff --git a/shibsp/handler/AssertionConsumerService.h b/shibsp/handler/AssertionConsumerService.h index c933c89..90d363d 100644 --- a/shibsp/handler/AssertionConsumerService.h +++ b/shibsp/handler/AssertionConsumerService.h @@ -27,6 +27,7 @@ #include #ifndef SHIBSP_LITE # include +# include # include #endif #include @@ -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. * *

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* tokens=NULL, - const std::vector* attributes=NULL + const std::vector* tokens=NULL ) const; #endif diff --git a/shibsp/handler/impl/AssertionConsumerService.cpp b/shibsp/handler/impl/AssertionConsumerService.cpp index 8d7c0fe..7d675b6 100644 --- a/shibsp/handler/impl/AssertionConsumerService.cpp +++ b/shibsp/handler/impl/AssertionConsumerService.cpp @@ -29,6 +29,10 @@ # include #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& attributes) : m_attributes(attributes) { + } + + virtual ~DummyContext() { + for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup()); + } + + vector& getResolvedAttributes() { + return m_attributes; + } + vector& getResolvedAssertions() { + return m_tokens; + } + +private: + vector m_attributes; + static vector m_tokens; // never any tokens, so just share an empty vector +}; + +vector 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* tokens, - const vector* attributes + const vector* tokens ) const { + // First we do the extraction of any pushed information. + vector 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_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()); + 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 ctx( - resolver->createResolutionContext(application, issuer, protocol, nameid, authncontext_class, authncontext_decl, tokens, attributes) + resolver->createResolutionContext( + application, + dynamic_cast(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 diff --git a/shibsp/handler/impl/SAML1Consumer.cpp b/shibsp/handler/impl/SAML1Consumer.cpp index a4e5303..92c78e2 100644 --- a/shibsp/handler/impl/SAML1Consumer.cpp +++ b/shibsp/handler/impl/SAML1Consumer.cpp @@ -28,10 +28,6 @@ # 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 # include @@ -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 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_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()); - resolvedAttributes.clear(); - } - } - } // Normalize the SAML 1.x NameIdentifier... auto_ptr nameid(n ? NameIDBuilder::buildNameID() : NULL); @@ -252,57 +211,44 @@ string SAML1Consumer::implementProtocol( nameid->setNameQualifier(n->getNameQualifier()); } - const EntityDescriptor* issuerMetadata = - policy.getIssuerMetadata() ? dynamic_cast(policy.getIssuerMetadata()->getParent()) : NULL; + // The context will handle deleting attributes and new tokens. auto_ptr 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()); - return key; - } - catch (exception&) { - for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup()); - throw; - } + return application.getServiceProvider().getSessionCache()->insert( + now + lifetime.second, + application, + httpRequest.getRemoteAddr().c_str(), + policy.getIssuerMetadata() ? dynamic_cast(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 diff --git a/shibsp/handler/impl/SAML2Consumer.cpp b/shibsp/handler/impl/SAML2Consumer.cpp index a82b3be..534544d 100644 --- a/shibsp/handler/impl/SAML2Consumer.cpp +++ b/shibsp/handler/impl/SAML2Consumer.cpp @@ -28,10 +28,6 @@ # 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 # include @@ -335,73 +331,26 @@ string SAML2Consumer::implementProtocol( else sessionExp = min(sessionExp, now + lifetime.second); // Use the lowest. - vector 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_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()); - resolvedAttributes.clear(); - } - } - try { - const EntityDescriptor* issuerMetadata = - policy.getIssuerMetadata() ? dynamic_cast(policy.getIssuerMetadata()->getParent()) : NULL; + // The context will handle deleting attributes and new tokens. auto_ptr 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(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()); - for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup()); return key; } catch (exception&) { if (ownedName) delete ssoName; for_each(ownedtokens.begin(), ownedtokens.end(), xmltooling::cleanup()); - for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup()); throw; } }