From: Scott Cantor Date: Mon, 6 Dec 2010 19:19:39 +0000 (+0000) Subject: https://issues.shibboleth.net/jira/browse/SSPCPP-320 X-Git-Tag: 2.4~3 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-sp.git;a=commitdiff_plain;h=4a98078497d1fcebe185604b1392c28ad756f597 https://issues.shibboleth.net/jira/browse/SSPCPP-320 --- diff --git a/configs/attribute-map.xml b/configs/attribute-map.xml index 4a54e90..dc61901 100644 --- a/configs/attribute-map.xml +++ b/configs/attribute-map.xml @@ -28,13 +28,13 @@ - + - + + + + + diff --git a/schemas/shibboleth-2.0-afp-mf-saml.xsd b/schemas/shibboleth-2.0-afp-mf-saml.xsd index 921d778..ab6b457 100644 --- a/schemas/shibboleth-2.0-afp-mf-saml.xsd +++ b/schemas/shibboleth-2.0-afp-mf-saml.xsd @@ -57,4 +57,39 @@ + + + + + A match function that ensures that a NameID-valued attribute's qualifier(s), if set, match particular values. + + + + + + + + The ID of the attribute whose qualifiers should be matched. If no attribute ID is specified the + ID of the containing attribute rule is assumed. + + + + + + + A value to require in the NameQualifier field, or if omitted, require that it match the issuing IdP's entityID. + + + + + + + A value to require in the SPNameQualifier field, or if omitted, require that it match the SP's entityID. + + + + + + + \ No newline at end of file diff --git a/shibsp/Makefile.am b/shibsp/Makefile.am index 612ba34..9766dbd 100644 --- a/shibsp/Makefile.am +++ b/shibsp/Makefile.am @@ -192,6 +192,7 @@ libshibsp_la_SOURCES = \ attribute/filtering/impl/AttributeScopeRegexFunctor.cpp \ attribute/filtering/impl/AttributeValueRegexFunctor.cpp \ attribute/filtering/impl/AuthenticationMethodRegexFunctor.cpp \ + attribute/filtering/impl/NameIDQualifierStringFunctor.cpp \ attribute/filtering/impl/NumberOfAttributeValuesFunctor.cpp \ attribute/filtering/impl/AttributeIssuerInEntityGroupFunctor.cpp \ attribute/filtering/impl/AttributeRequesterInEntityGroupFunctor.cpp \ diff --git a/shibsp/attribute/filtering/MatchFunctor.h b/shibsp/attribute/filtering/MatchFunctor.h index a802d3d..1fd976e 100644 --- a/shibsp/attribute/filtering/MatchFunctor.h +++ b/shibsp/attribute/filtering/MatchFunctor.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2009 Internet2 + * Copyright 2001-2010 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -118,6 +118,9 @@ namespace shibsp { /** Matches based on metadata Scope extensions. */ extern SHIBSP_API xmltooling::QName AttributeScopeMatchesShibMDScopeType; + /** Matches based on NameID NameQualifiers. */ + extern SHIBSP_API xmltooling::QName NameIDQualifierStringType; + /** * Registers MatchFunctor classes into the runtime. */ diff --git a/shibsp/attribute/filtering/impl/BasicFilteringContext.cpp b/shibsp/attribute/filtering/impl/BasicFilteringContext.cpp index 06dada7..1fd98ac 100644 --- a/shibsp/attribute/filtering/impl/BasicFilteringContext.cpp +++ b/shibsp/attribute/filtering/impl/BasicFilteringContext.cpp @@ -74,7 +74,12 @@ const XMLCh* BasicFilteringContext::getAuthnContextDeclRef() const const XMLCh* BasicFilteringContext::getAttributeRequester() const { - return m_app.getXMLString("entityID").second; + if (getAttributeIssuerMetadata()) { + return getApplication().getRelyingParty( + dynamic_cast(getAttributeIssuerMetadata()->getParent()) + )->getXMLString("entityID").second; + } + return getApplication().getRelyingParty(getAttributeIssuer())->getXMLString("entityID").second; } const XMLCh* BasicFilteringContext::getAttributeIssuer() const diff --git a/shibsp/attribute/filtering/impl/MatchFunctor.cpp b/shibsp/attribute/filtering/impl/MatchFunctor.cpp index a2e7e45..bdb8779 100644 --- a/shibsp/attribute/filtering/impl/MatchFunctor.cpp +++ b/shibsp/attribute/filtering/impl/MatchFunctor.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2009 Internet2 + * Copyright 2001-2010 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,6 +62,7 @@ namespace shibsp { DECL_FACTORY(AttributeIssuerInEntityGroup); DECL_FACTORY(AttributeRequesterInEntityGroup); DECL_FACTORY(AttributeScopeMatchesShibMDScope); + DECL_FACTORY(NameIDQualifierString); static const XMLCh ANY[] = UNICODE_LITERAL_3(A,N,Y); @@ -82,6 +83,7 @@ namespace shibsp { static const XMLCh AttributeIssuerInEntityGroup[] = UNICODE_LITERAL_28(A,t,t,r,i,b,u,t,e,I,s,s,u,e,r,I,n,E,n,t,i,t,y,G,r,o,u,p); static const XMLCh AttributeRequesterInEntityGroup[] = UNICODE_LITERAL_31(A,t,t,r,i,b,u,t,e,R,e,q,u,e,s,t,e,r,I,n,E,n,t,i,t,y,G,r,o,u,p); static const XMLCh AttributeScopeMatchesShibMDScope[] = UNICODE_LITERAL_32(A,t,t,r,i,b,u,t,e,S,c,o,p,e,M,a,t,c,h,e,s,S,h,i,b,M,D,S,c,o,p,e); + static const XMLCh NameIDQualifierString[] = UNICODE_LITERAL_21(N,a,m,e,I,D,Q,u,a,l,i,f,i,e,r,S,t,r,i,n,g); }; DECL_BASIC_QNAME(AnyMatchFunctor, ANY); @@ -102,6 +104,7 @@ DECL_BASIC_QNAME(NumberOfAttributeValues, NumberOfAttributeValues); DECL_SAML_QNAME(AttributeIssuerInEntityGroup, AttributeIssuerInEntityGroup); DECL_SAML_QNAME(AttributeRequesterInEntityGroup, AttributeRequesterInEntityGroup); DECL_SAML_QNAME(AttributeScopeMatchesShibMDScope, AttributeScopeMatchesShibMDScope); +DECL_SAML_QNAME(NameIDQualifierString, NameIDQualifierString); void SHIBSP_API shibsp::registerMatchFunctors() { @@ -125,6 +128,7 @@ void SHIBSP_API shibsp::registerMatchFunctors() REGISTER_FACTORY(AttributeIssuerInEntityGroup); REGISTER_FACTORY(AttributeRequesterInEntityGroup); REGISTER_FACTORY(AttributeScopeMatchesShibMDScope); + REGISTER_FACTORY(NameIDQualifierString); } MatchFunctor::MatchFunctor() diff --git a/shibsp/attribute/filtering/impl/NameIDQualifierStringFunctor.cpp b/shibsp/attribute/filtering/impl/NameIDQualifierStringFunctor.cpp new file mode 100644 index 0000000..66735d9 --- /dev/null +++ b/shibsp/attribute/filtering/impl/NameIDQualifierStringFunctor.cpp @@ -0,0 +1,169 @@ +/* + * Copyright 2010 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. + */ + +/** + * NameIDQualifierStringFunctor.cpp + * + * A match function that ensures that a NameID-valued attribute's qualifier(s) + * match particular values. + */ + +#include "internal.h" +#include "exceptions.h" +#include "attribute/NameIDAttribute.h" +#include "attribute/filtering/FilteringContext.h" +#include "attribute/filtering/FilterPolicyContext.h" +#include "attribute/filtering/MatchFunctor.h" + +#include +#include + +using namespace shibsp; +using namespace xmltooling::logging; +using namespace xmltooling; +using namespace std; +using opensaml::saml2::NameID; + +namespace shibsp { + + static const XMLCh attributeID[] = UNICODE_LITERAL_11(a,t,t,r,i,b,u,t,e,I,D); + + /** + * A match function that ensures that a NameID-valued attribute's qualifier(s) + * match particular values. + */ + class SHIBSP_DLLLOCAL NameIDQualifierStringFunctor : public MatchFunctor + { + string m_attributeID,m_matchNameQualifier,m_matchSPNameQualifier; + + bool hasValue(const FilteringContext& filterContext) const; + bool matches(const FilteringContext& filterContext, const Attribute& attribute, size_t index) const; + + public: + NameIDQualifierStringFunctor(const DOMElement* e) + : m_attributeID(XMLHelper::getAttrString(e, nullptr, attributeID)), + m_matchNameQualifier(XMLHelper::getAttrString(e, nullptr, NameID::NAMEQUALIFIER_ATTRIB_NAME)), + m_matchSPNameQualifier(XMLHelper::getAttrString(e, nullptr, NameID::SPNAMEQUALIFIER_ATTRIB_NAME)) { + } + + virtual ~NameIDQualifierStringFunctor() { + } + + bool evaluatePolicyRequirement(const FilteringContext& filterContext) const { + if (m_attributeID.empty()) + throw AttributeFilteringException("No attributeID specified."); + return hasValue(filterContext); + } + + bool evaluatePermitValue(const FilteringContext& filterContext, const Attribute& attribute, size_t index) const { + if (m_attributeID.empty() || m_attributeID == attribute.getId()) + return matches(filterContext, attribute, index); + return hasValue(filterContext); + } + }; + + MatchFunctor* SHIBSP_DLLLOCAL NameIDQualifierStringFactory(const std::pair& p) + { + return new NameIDQualifierStringFunctor(p.second); + } + +}; + +bool NameIDQualifierStringFunctor::hasValue(const FilteringContext& filterContext) const +{ + size_t count; + pair::const_iterator,multimap::const_iterator> attrs = + filterContext.getAttributes().equal_range(m_attributeID); + for (; attrs.first != attrs.second; ++attrs.first) { + count = attrs.first->second->valueCount(); + for (size_t index = 0; index < count; ++index) { + if (matches(filterContext, *(attrs.first->second), index)) + return true; + } + } + return false; +} + +bool NameIDQualifierStringFunctor::matches(const FilteringContext& filterContext, const Attribute& attribute, size_t index) const +{ + const NameIDAttribute* nameattr = dynamic_cast(&attribute); + if (!nameattr) { + Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").warn( + "NameIDQualifierString MatchFunctor applied to non-NameID-valued attribute (%s)", attribute.getId() + ); + return false; + } + + const NameIDAttribute::Value& val = nameattr->getValues()[index]; + if (!val.m_NameQualifier.empty()) { + if (m_matchNameQualifier.empty()) { + auto_ptr_char issuer(filterContext.getAttributeIssuer()); + if (issuer.get() && *issuer.get()) { + if (val.m_NameQualifier != issuer.get()) { + Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").warn( + "NameIDQualifierString MatchFunctor rejecting NameQualifier (%s), should be (%s)", + val.m_NameQualifier.c_str(), issuer.get() + ); + return false; + } + } + else { + Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").warn( + "NameIDQualifierString MatchFunctor rejecting NameQualifier (%s), attribute issuer unknown", + val.m_NameQualifier.c_str() + ); + return false; + } + } + else if (m_matchNameQualifier != val.m_NameQualifier) { + Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").warn( + "NameIDQualifierString MatchFunctor rejecting NameQualifier (%s), should be (%s)", + val.m_NameQualifier.c_str(), m_matchNameQualifier.c_str() + ); + return false; + } + } + if (!val.m_SPNameQualifier.empty()) { + if (m_matchSPNameQualifier.empty()) { + auto_ptr_char req(filterContext.getAttributeRequester()); + if (req.get() && *req.get()) { + if (val.m_SPNameQualifier != req.get()) { + Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").warn( + "NameIDQualifierString MatchFunctor rejecting SPNameQualifier (%s), should be (%s)", + val.m_SPNameQualifier.c_str(), req.get() + ); + return false; + } + } + else { + Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").warn( + "NameIDQualifierString MatchFunctor rejecting SPNameQualifier (%s), attribute requester unknown", + val.m_SPNameQualifier.c_str() + ); + return false; + } + } + else if (m_matchSPNameQualifier != val.m_SPNameQualifier) { + Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").warn( + "NameIDQualifierString MatchFunctor rejecting SPNameQualifier (%s), should be (%s)", + val.m_SPNameQualifier.c_str(), m_matchSPNameQualifier.c_str() + ); + return false; + } + } + + return true; +} diff --git a/shibsp/shibsp.vcxproj b/shibsp/shibsp.vcxproj index 8839b82..c2be54c 100644 --- a/shibsp/shibsp.vcxproj +++ b/shibsp/shibsp.vcxproj @@ -182,6 +182,7 @@ + diff --git a/shibsp/shibsp.vcxproj.filters b/shibsp/shibsp.vcxproj.filters index b52f78e..15b7d70 100644 --- a/shibsp/shibsp.vcxproj.filters +++ b/shibsp/shibsp.vcxproj.filters @@ -381,6 +381,9 @@ Source Files\attribute + + Source Files\attribute\filtering\impl +