From 3905eb61129d5ad9fb033a2e2c258650d1f9b408 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Fri, 22 May 2009 20:34:10 +0000 Subject: [PATCH] Add EntityRole filter. --- saml/Makefile.am | 1 + saml/saml.vcproj | 4 + saml/saml2/metadata/MetadataFilter.h | 25 +-- .../metadata/impl/EntityRoleMetadataFilter.cpp | 203 +++++++++++++++++++++ saml/saml2/metadata/impl/MetadataProvider.cpp | 6 +- 5 files changed, 227 insertions(+), 12 deletions(-) create mode 100644 saml/saml2/metadata/impl/EntityRoleMetadataFilter.cpp diff --git a/saml/Makefile.am b/saml/Makefile.am index 050e4df..09daad3 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -144,6 +144,7 @@ libsaml_la_SOURCES = \ saml2/metadata/impl/BlacklistMetadataFilter.cpp \ saml2/metadata/impl/ChainingMetadataProvider.cpp \ saml2/metadata/impl/DynamicMetadataProvider.cpp \ + saml2/metadata/impl/EntityRoleMetadataFilter.cpp \ saml2/metadata/impl/MetadataImpl.cpp \ saml2/metadata/impl/MetadataProvider.cpp \ saml2/metadata/impl/MetadataSchemaValidators.cpp \ diff --git a/saml/saml.vcproj b/saml/saml.vcproj index 08f1dc3..5b35035 100644 --- a/saml/saml.vcproj +++ b/saml/saml.vcproj @@ -520,6 +520,10 @@ > + + diff --git a/saml/saml2/metadata/MetadataFilter.h b/saml/saml2/metadata/MetadataFilter.h index 81762e7..305f9da 100644 --- a/saml/saml2/metadata/MetadataFilter.h +++ b/saml/saml2/metadata/MetadataFilter.h @@ -1,6 +1,6 @@ /* - * Copyright 2001-2007 Internet2 - * + * Copyright 2001-2009 Internet2 + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,7 +16,7 @@ /** * @file saml/saml2/metadata/MetadataFilter.h - * + * * Processes metadata after it's been unmarshalled. */ @@ -32,10 +32,10 @@ namespace opensaml { namespace saml2md { - + /** * A metadata filter is used to process metadata after resolution and unmarshalling. - * + * * Some filters might remove everything but identity provider roles, decreasing the data a service provider * needs to work with, or a filter could be used to perform integrity checking on the retrieved metadata by * verifying a digital signature. @@ -47,18 +47,18 @@ namespace opensaml { MetadataFilter() {} public: virtual ~MetadataFilter() {} - + /** * Returns an identifying string for the filter. - * + * * @return the ID string */ virtual const char* getId() const=0; - + /** * Filters the given metadata. Exceptions should generally not be thrown to * signal the removal of information, only for systemic processing failure. - * + * * @param xmlObject the metadata to be filtered. */ virtual void doFilter(xmltooling::XMLObject& xmlObject) const=0; @@ -68,7 +68,7 @@ namespace opensaml { * Registers MetadataFilter classes into the runtime. */ void SAML_API registerMetadataFilters(); - + /** MetadataFilter that deletes blacklisted entities. */ #define BLACKLIST_METADATA_FILTER "Blacklist" @@ -80,7 +80,10 @@ namespace opensaml { /** MetadataFilter that enforces expiration requirements. */ #define REQUIREVALIDUNTIL_METADATA_FILTER "RequireValidUntil" - + + /** MetadataFilter that removes non-retained roles. */ + #define ENTITYROLE_METADATA_FILTER "EntityRoleWhiteList" + DECL_XMLTOOLING_EXCEPTION(MetadataFilterException,SAML_EXCEPTIONAPI(SAML_API),opensaml::saml2md,MetadataException,Exceptions related to metadata filtering); }; }; diff --git a/saml/saml2/metadata/impl/EntityRoleMetadataFilter.cpp b/saml/saml2/metadata/impl/EntityRoleMetadataFilter.cpp new file mode 100644 index 0000000..fd48b7d --- /dev/null +++ b/saml/saml2/metadata/impl/EntityRoleMetadataFilter.cpp @@ -0,0 +1,203 @@ +/* + * Copyright 2009 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * EntityRoleMetadataFilter.cpp + * + * Removes non-whitelisted roles from a metadata instance + */ + +#include "internal.h" +#include "saml2/metadata/Metadata.h" +#include "saml2/metadata/MetadataFilter.h" + +#include +#include + +using namespace opensaml::saml2md; +using namespace xmltooling::logging; +using namespace xmltooling; +using namespace std; + +namespace opensaml { + namespace saml2md { + + class SAML_DLLLOCAL EntityRoleMetadataFilter : public MetadataFilter + { + public: + EntityRoleMetadataFilter(const DOMElement* e); + ~EntityRoleMetadataFilter() {} + + const char* getId() const { return ENTITYROLE_METADATA_FILTER; } + void doFilter(XMLObject& xmlObject) const; + + private: + void doFilter(EntityDescriptor& entity) const; + void doFilter(EntitiesDescriptor& entities) const; + + bool m_removeRolelessEntityDescriptors, m_removeEmptyEntitiesDescriptors; + set m_roles; + bool m_idp, m_sp, m_authn, m_attr, m_pdp, m_authnq, m_attrq, m_authzq; + }; + + MetadataFilter* SAML_DLLLOCAL EntityRoleMetadataFilterFactory(const DOMElement* const & e) + { + return new EntityRoleMetadataFilter(e); + } + + }; +}; + +static const XMLCh RetainedRole[] = UNICODE_LITERAL_12(R,e,t,a,i,n,e,d,R,o,l,e); +static const XMLCh removeRolelessEntityDescriptors[] = UNICODE_LITERAL_31(r,e,m,o,v,e,R,o,l,e,l,e,s,s,E,n,t,i,t,y,D,e,s,c,r,i,p,t,o,r,s); +static const XMLCh removeEmptyEntitiesDescriptors[] = UNICODE_LITERAL_30(r,e,m,o,v,e,E,m,p,t,y,E,n,t,i,t,i,e,s,D,e,s,c,r,i,p,t,o,r,s); + +EntityRoleMetadataFilter::EntityRoleMetadataFilter(const DOMElement* e) + : m_removeRolelessEntityDescriptors(true), m_removeEmptyEntitiesDescriptors(true), + m_idp(false), m_sp(false), m_authn(false), m_attr(false), m_pdp(false), m_authnq(false), m_attrq(false), m_authzq(false) +{ + const XMLCh* flag = e ? e->getAttributeNS(NULL, removeRolelessEntityDescriptors) : NULL; + if (flag && (*flag == chLatin_f || *flag == chDigit_0)) + m_removeRolelessEntityDescriptors = false; + flag = e ? e->getAttributeNS(NULL, removeEmptyEntitiesDescriptors) : NULL; + if (flag && (*flag == chLatin_f || *flag == chDigit_0)) + m_removeEmptyEntitiesDescriptors = false; + + e = XMLHelper::getFirstChildElement(e, RetainedRole); + while (e) { + auto_ptr q(XMLHelper::getNodeValueAsQName(e)); + if (q.get()) { + if (*q == IDPSSODescriptor::ELEMENT_QNAME) + m_idp = true; + else if (*q == SPSSODescriptor::ELEMENT_QNAME) + m_sp = true; + else if (*q == AuthnAuthorityDescriptor::ELEMENT_QNAME) + m_authn = true; + else if (*q == AttributeAuthorityDescriptor::ELEMENT_QNAME) + m_attr = true; + else if (*q == PDPDescriptor::ELEMENT_QNAME) + m_pdp = true; + else if (*q == AuthnQueryDescriptorType::TYPE_QNAME) + m_authnq = true; + else if (*q == AttributeQueryDescriptorType::TYPE_QNAME) + m_attrq = true; + else if (*q == AuthzDecisionQueryDescriptorType::TYPE_QNAME) + m_authzq = true; + else + m_roles.insert(*q.get()); + } + e = XMLHelper::getNextSiblingElement(e, RetainedRole); + } +} + +void EntityRoleMetadataFilter::doFilter(XMLObject& xmlObject) const +{ +#ifdef _DEBUG + NDC ndc("doFilter"); +#endif + + try { + doFilter(dynamic_cast(xmlObject)); + return; + } + catch (bad_cast) { + } + + try { + doFilter(dynamic_cast(xmlObject)); + return; + } + catch (bad_cast) { + } + + throw MetadataFilterException("EntityRoleWhiteList MetadataFilter was given an improper metadata instance to filter."); +} + +void EntityRoleMetadataFilter::doFilter(EntitiesDescriptor& entities) const +{ + Category& log=Category::getInstance(SAML_LOGCAT".MetadataFilter.EntityRoleWhiteList"); + + VectorOf(EntityDescriptor) v=entities.getEntityDescriptors(); + for (VectorOf(EntityDescriptor)::size_type i=0; i(*v[i]); + if (e.getIDPSSODescriptors().empty() && + e.getSPSSODescriptors().empty() && + e.getAuthnAuthorityDescriptors().empty() && + e.getAttributeAuthorityDescriptors().empty() && + e.getPDPDescriptors().empty() && + e.getAuthnQueryDescriptorTypes().empty() && + e.getAttributeQueryDescriptorTypes().empty() && + e.getAuthzDecisionQueryDescriptorTypes().empty() && + e.getRoleDescriptors().empty()) { + auto_ptr_char temp(e.getEntityID()); + log.debug("filtering out role-less entity (%s)", temp.get()); + v.erase(v.begin() + i); + continue; + } + } + i++; + } + + VectorOf(EntitiesDescriptor) groups=entities.getEntitiesDescriptors(); + for (VectorOf(EntitiesDescriptor)::size_type j=0; jgetEntitiesDescriptors().empty() && group->getEntityDescriptors().empty()) { + auto_ptr_char temp(entities.getName()); + auto_ptr_char temp2(group->getName()); + log.debug( + "filtering out empty EntitiesDescriptor (%s) from EntitiesDescriptor (%s)", + temp2.get() ? temp2.get() : "unnamed", + temp.get() ? temp.get() : "unnamed" + ); + groups.erase(groups.begin() + j); + } + else { + j++; + } + } +} + +void EntityRoleMetadataFilter::doFilter(EntityDescriptor& entity) const +{ + if (!m_idp) + entity.getIDPSSODescriptors().clear(); + if (!m_sp) + entity.getSPSSODescriptors().clear(); + if (!m_authn) + entity.getAuthnAuthorityDescriptors().clear(); + if (!m_attr) + entity.getAttributeAuthorityDescriptors().clear(); + if (!m_pdp) + entity.getPDPDescriptors().clear(); + if (!m_authnq) + entity.getAuthnQueryDescriptorTypes().clear(); + if (!m_attrq) + entity.getAttributeQueryDescriptorTypes().clear(); + if (!m_authzq) + entity.getAuthzDecisionQueryDescriptorTypes().clear(); + + VectorOf(RoleDescriptor) v = entity.getRoleDescriptors(); + for (VectorOf(RoleDescriptor)::size_type i=0; igetSchemaType(); + if (!type || m_roles.find(*type) != m_roles.end()) + v.erase(v.begin() + i); + else + i++; + } +} diff --git a/saml/saml2/metadata/impl/MetadataProvider.cpp b/saml/saml2/metadata/impl/MetadataProvider.cpp index 0741b62..e0efc7a 100644 --- a/saml/saml2/metadata/impl/MetadataProvider.cpp +++ b/saml/saml2/metadata/impl/MetadataProvider.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Internet2 + * Copyright 2001-2009 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,6 +45,7 @@ namespace opensaml { SAML_DLLLOCAL PluginManager::Factory WhitelistMetadataFilterFactory; SAML_DLLLOCAL PluginManager::Factory SignatureMetadataFilterFactory; SAML_DLLLOCAL PluginManager::Factory RequireValidUntilMetadataFilterFactory; + SAML_DLLLOCAL PluginManager::Factory EntityRoleMetadataFilterFactory; }; }; @@ -63,6 +64,9 @@ void SAML_API opensaml::saml2md::registerMetadataFilters() SAMLConfig::getConfig().MetadataFilterManager.registerFactory(WHITELIST_METADATA_FILTER, WhitelistMetadataFilterFactory); SAMLConfig::getConfig().MetadataFilterManager.registerFactory(SIGNATURE_METADATA_FILTER, SignatureMetadataFilterFactory); SAMLConfig::getConfig().MetadataFilterManager.registerFactory(REQUIREVALIDUNTIL_METADATA_FILTER, RequireValidUntilMetadataFilterFactory); + // additional name matching Java code + SAMLConfig::getConfig().MetadataFilterManager.registerFactory("RequiredValidUntil", RequireValidUntilMetadataFilterFactory); + SAMLConfig::getConfig().MetadataFilterManager.registerFactory(ENTITYROLE_METADATA_FILTER, EntityRoleMetadataFilterFactory); } static const XMLCh _MetadataFilter[] = UNICODE_LITERAL_14(M,e,t,a,d,a,t,a,F,i,l,t,e,r); -- 2.1.4