From 3a8b7bdca16b8cd200a1a9644951799f4c09fa83 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Fri, 6 May 2016 16:33:56 -0400 Subject: [PATCH] CPPOST-96 - EntityMatcher implementation based on RPI registrationAuthority extension https://issues.shibboleth.net/jira/browse/CPPOST-96 --- Projects/vc10/saml/saml.vcxproj | 5 +- Projects/vc10/saml/saml.vcxproj.filters | 9 +- saml/Makefile.am | 3 +- saml/saml2/metadata/EntityMatcher.h | 5 +- saml/saml2/metadata/impl/NameEntityMatcher.cpp | 2 + .../impl/RegistrationAuthorityEntityMatcher.cpp | 130 +++++++++++++++++++++ 6 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 saml/saml2/metadata/impl/RegistrationAuthorityEntityMatcher.cpp diff --git a/Projects/vc10/saml/saml.vcxproj b/Projects/vc10/saml/saml.vcxproj index df88d15..81170ab 100644 --- a/Projects/vc10/saml/saml.vcxproj +++ b/Projects/vc10/saml/saml.vcxproj @@ -1,4 +1,4 @@ - + @@ -184,6 +184,7 @@ + @@ -342,4 +343,4 @@ - + \ No newline at end of file diff --git a/Projects/vc10/saml/saml.vcxproj.filters b/Projects/vc10/saml/saml.vcxproj.filters index 3c9ef8b..88371d6 100644 --- a/Projects/vc10/saml/saml.vcxproj.filters +++ b/Projects/vc10/saml/saml.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -375,6 +375,9 @@ Source Files\saml2\metadata\impl + + Source Files\saml2\metadata\impl + @@ -531,6 +534,6 @@ - + - + \ No newline at end of file diff --git a/saml/Makefile.am b/saml/Makefile.am index dd4a818..e2956b2 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -159,8 +159,9 @@ libsaml_la_SOURCES = \ saml2/metadata/impl/NameEntityMatcher.cpp \ saml2/metadata/impl/NullMetadataProvider.cpp \ saml2/metadata/impl/ObservableMetadataProvider.cpp \ - saml2/metadata/impl/SignatureMetadataFilter.cpp \ saml2/metadata/impl/RequireValidUntilMetadataFilter.cpp \ + saml2/metadata/impl/SignatureMetadataFilter.cpp \ + saml2/metadata/impl/RegistrationAuthorityEntityMatcher.cpp \ saml2/metadata/impl/WhitelistMetadataFilter.cpp \ saml2/metadata/impl/XMLMetadataProvider.cpp \ saml2/binding/impl/SAML2Artifact.cpp \ diff --git a/saml/saml2/metadata/EntityMatcher.h b/saml/saml2/metadata/EntityMatcher.h index d15c2a2..b447125 100644 --- a/saml/saml2/metadata/EntityMatcher.h +++ b/saml/saml2/metadata/EntityMatcher.h @@ -62,8 +62,11 @@ namespace opensaml { /** EntityMatcher that matches based on name. */ #define NAME_ENTITY_MATCHER "Name" - /** EntityMatcher that applies a set of input attributes. */ + /** EntityMatcher that matches based on entity attributes. */ #define ENTITYATTR_ENTITY_MATCHER "EntityAttributes" + + /** EntityMatcher that matches based on RPI registrationAuthority. */ + #define REGAUTH_ENTITY_MATCHER "RegistrationAuthority" }; }; diff --git a/saml/saml2/metadata/impl/NameEntityMatcher.cpp b/saml/saml2/metadata/impl/NameEntityMatcher.cpp index 7eb65b0..4966d99 100644 --- a/saml/saml2/metadata/impl/NameEntityMatcher.cpp +++ b/saml/saml2/metadata/impl/NameEntityMatcher.cpp @@ -57,6 +57,7 @@ namespace opensaml { } SAML_DLLLOCAL PluginManager::Factory EntityAttributesEntityMatcherFactory; + SAML_DLLLOCAL PluginManager::Factory RegistrationAuthorityEntityMatcherFactory; }; }; @@ -64,6 +65,7 @@ void SAML_API opensaml::saml2md::registerEntityMatchers() { SAMLConfig::getConfig().EntityMatcherManager.registerFactory(NAME_ENTITY_MATCHER, NameEntityMatcherFactory); SAMLConfig::getConfig().EntityMatcherManager.registerFactory(ENTITYATTR_ENTITY_MATCHER, EntityAttributesEntityMatcherFactory); + SAMLConfig::getConfig().EntityMatcherManager.registerFactory(REGAUTH_ENTITY_MATCHER, RegistrationAuthorityEntityMatcherFactory); } EntityMatcher::EntityMatcher() diff --git a/saml/saml2/metadata/impl/RegistrationAuthorityEntityMatcher.cpp b/saml/saml2/metadata/impl/RegistrationAuthorityEntityMatcher.cpp new file mode 100644 index 0000000..2b51c24 --- /dev/null +++ b/saml/saml2/metadata/impl/RegistrationAuthorityEntityMatcher.cpp @@ -0,0 +1,130 @@ +/** + * Licensed to the University Corporation for Advanced Internet + * Development, Inc. (UCAID) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * UCAID licenses this file to you 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. + */ + +/** + * RegistrationAuthorityEntityMatcher.cpp + * + * EntityMatcher that matches based on RPI registrationAuthority. + */ + +#include "internal.h" +#include "saml2/metadata/EntityMatcher.h" +#include "saml2/metadata/Metadata.h" + +#include +#include +#include +#include +#include + +using namespace opensaml::saml2md; +using namespace opensaml::saml2; +using namespace opensaml; +using namespace xmltooling::logging; +using namespace xmltooling; +using namespace boost::lambda; +using namespace boost; +using namespace std; + +namespace opensaml { + namespace saml2md { + class SAML_DLLLOCAL RegistrationAuthorityEntityMatcher : public EntityMatcher + { + public: + RegistrationAuthorityEntityMatcher(const DOMElement* e); + ~RegistrationAuthorityEntityMatcher() {} + + bool matches(const EntityDescriptor& entity) const; + + private: + set m_authorities; + Category& m_log; + }; + + EntityMatcher* SAML_DLLLOCAL RegistrationAuthorityEntityMatcherFactory(const DOMElement* const & e) + { + return new RegistrationAuthorityEntityMatcher(e); + } + }; +}; + + +RegistrationAuthorityEntityMatcher::RegistrationAuthorityEntityMatcher(const DOMElement* e) + : m_log(Category::getInstance(SAML_LOGCAT ".EntityMatcher.RegistrationAuthority")) +{ + // Check for shorthand syntax. + if (e && e->hasAttributeNS(nullptr, RegistrationInfo::REGAUTHORITY_ATTRIB_NAME)) { + m_authorities.insert(e->getAttributeNS(nullptr, RegistrationInfo::REGAUTHORITY_ATTRIB_NAME)); + } + + const DOMElement* child = XMLHelper::getFirstChildElement(e, RegistrationInfo::REGAUTHORITY_ATTRIB_NAME); + while (child) { + const XMLCh* text = child->getTextContent(); + if (text && *text) { + m_authorities.insert(text); + } + child = XMLHelper::getNextSiblingElement(child, RegistrationInfo::REGAUTHORITY_ATTRIB_NAME); + } + + if (m_authorities.empty()) + throw XMLToolingException("RegistrationAuthority EntityMatcher requires at least one authority to match."); +} + +bool RegistrationAuthorityEntityMatcher::matches(const EntityDescriptor& entity) const +{ + bool extFound = false; + + const Extensions* exts = entity.getExtensions(); + if (exts) { + const vector& children = exts->getUnknownXMLObjects(); + const XMLObject* xo = find_if(children, ll_dynamic_cast(_1) != ((RegistrationInfo*)nullptr)); + if (xo) { + extFound = true; + const RegistrationInfo* regInfo = dynamic_cast(xo); + if (regInfo->getRegistrationAuthority() && m_authorities.find(regInfo->getRegistrationAuthority()) != m_authorities.end()) { + return true; + } + } + } + + const EntitiesDescriptor* group = dynamic_cast(entity.getParent()); + while (group) { + exts = group->getExtensions(); + if (exts) { + const vector& children = exts->getUnknownXMLObjects(); + const XMLObject* xo = find_if(children, ll_dynamic_cast(_1) != ((RegistrationInfo*)nullptr)); + if (xo) { + extFound = true; + const RegistrationInfo* regInfo = dynamic_cast(xo); + if (regInfo->getRegistrationAuthority() && m_authorities.find(regInfo->getRegistrationAuthority()) != m_authorities.end()) { + return true; + } + } + } + group = dynamic_cast(group->getParent()); + } + + if (!extFound && m_log.isDebugEnabled()) { + auto_ptr_char id (entity.getEntityID()); + m_log.debug("no RegistrationAuthority extension found for (%s)", id.get()); + } + + return false; +} -- 2.1.4