<!-- A persistent id attribute that supports personalized anonymous access. -->
- <!-- First, the deprecated version, decoded as a scoped string: -->
+ <!-- First, the deprecated/incorrect version, decoded as a scoped string: -->
<Attribute name="urn:mace:dir:attribute-def:eduPersonTargetedID" id="targeted-id">
<AttributeDecoder xsi:type="ScopedAttributeDecoder"/>
<!-- <AttributeDecoder xsi:type="NameIDFromScopedAttributeDecoder" formatter="$NameQualifier!$SPNameQualifier!$Name" defaultQualifiers="true"/> -->
</Attribute>
- <!-- Second, an alternate decoder that will turn the deprecated form into the newer form. -->
+ <!-- Second, an alternate decoder that will decode the incorrect form into the newer form. -->
<!--
<Attribute name="urn:mace:dir:attribute-def:eduPersonTargetedID" id="persistent-id">
<AttributeDecoder xsi:type="NameIDFromScopedAttributeDecoder" formatter="$NameQualifier!$SPNameQualifier!$Name" defaultQualifiers="true"/>
<afp:AttributeFilterPolicyGroup
xmlns="urn:mace:shibboleth:2.0:afp:mf:basic"
+ xmlns:saml="urn:mace:shibboleth:2.0:afp:mf:saml"
xmlns:basic="urn:mace:shibboleth:2.0:afp:mf:basic"
xmlns:afp="urn:mace:shibboleth:2.0:afp"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Rule xsi:type="NOT">
<Rule xsi:type="AttributeValueRegex" regex="@"/>
</Rule>
- <Rule xsi:type="saml:AttributeScopeMatchesShibMDScope" xmlns:saml="urn:mace:shibboleth:2.0:afp:mf:saml"/>
+ <Rule xsi:type="saml:AttributeScopeMatchesShibMDScope"/>
</afp:PermitValueRule>
<afp:AttributeFilterPolicy>
<afp:AttributeRule attributeID="targeted-id">
<afp:PermitValueRuleReference ref="ScopingRules"/>
</afp:AttributeRule>
-
+
+ <!-- Require NameQualifier/SPNameQualifier match IdP and SP entityID respectively. -->
+ <afp:AttributeRule attributeID="persistent-id">
+ <afp:PermitValueRule xsi:type="saml:NameIDQualifierString"/>
+ </afp:AttributeRule>
+
<!-- Catch-all that passes everything else through unmolested. -->
<afp:AttributeRule attributeID="*">
<afp:PermitValueRule xsi:type="ANY"/>
<extension base="afp:MatchFunctorType" />
</complexContent>
</complexType>
+
+ <complexType name="NameIDQualifierString">
+ <annotation>
+ <documentation>
+ A match function that ensures that a NameID-valued attribute's qualifier(s), if set, match particular values.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="afp:MatchFunctorType">
+ <attribute name="attributeID" type="string">
+ <annotation>
+ <documentation>
+ 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.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="NameQualifier" type="string">
+ <annotation>
+ <documentation>
+ A value to require in the NameQualifier field, or if omitted, require that it match the issuing IdP's entityID.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="SPNameQualifier" type="string">
+ <annotation>
+ <documentation>
+ A value to require in the SPNameQualifier field, or if omitted, require that it match the SP's entityID.
+ </documentation>
+ </annotation>
+ </attribute>
+ </extension>
+ </complexContent>
+ </complexType>
+
</schema>
\ No newline at end of file
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 \
/*
- * 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.
/** 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.
*/
const XMLCh* BasicFilteringContext::getAttributeRequester() const
{
- return m_app.getXMLString("entityID").second;
+ if (getAttributeIssuerMetadata()) {
+ return getApplication().getRelyingParty(
+ dynamic_cast<const EntityDescriptor*>(getAttributeIssuerMetadata()->getParent())
+ )->getXMLString("entityID").second;
+ }
+ return getApplication().getRelyingParty(getAttributeIssuer())->getXMLString("entityID").second;
}
const XMLCh* BasicFilteringContext::getAttributeIssuer() const
/*
- * 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.
DECL_FACTORY(AttributeIssuerInEntityGroup);
DECL_FACTORY(AttributeRequesterInEntityGroup);
DECL_FACTORY(AttributeScopeMatchesShibMDScope);
+ DECL_FACTORY(NameIDQualifierString);
static const XMLCh ANY[] = UNICODE_LITERAL_3(A,N,Y);
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);
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()
{
REGISTER_FACTORY(AttributeIssuerInEntityGroup);
REGISTER_FACTORY(AttributeRequesterInEntityGroup);
REGISTER_FACTORY(AttributeScopeMatchesShibMDScope);
+ REGISTER_FACTORY(NameIDQualifierString);
}
MatchFunctor::MatchFunctor()
--- /dev/null
+/*\r
+ * Copyright 2010 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * NameIDQualifierStringFunctor.cpp\r
+ * \r
+ * A match function that ensures that a NameID-valued attribute's qualifier(s)\r
+ * match particular values.\r
+ */\r
+\r
+#include "internal.h"\r
+#include "exceptions.h"\r
+#include "attribute/NameIDAttribute.h"\r
+#include "attribute/filtering/FilteringContext.h"\r
+#include "attribute/filtering/FilterPolicyContext.h"\r
+#include "attribute/filtering/MatchFunctor.h"\r
+\r
+#include <saml/saml2/core/Assertions.h>\r
+#include <xmltooling/util/XMLHelper.h>\r
+\r
+using namespace shibsp;\r
+using namespace xmltooling::logging;\r
+using namespace xmltooling;\r
+using namespace std;\r
+using opensaml::saml2::NameID;\r
+\r
+namespace shibsp {\r
+\r
+ static const XMLCh attributeID[] = UNICODE_LITERAL_11(a,t,t,r,i,b,u,t,e,I,D);\r
+\r
+ /**\r
+ * A match function that ensures that a NameID-valued attribute's qualifier(s)\r
+ * match particular values.\r
+ */\r
+ class SHIBSP_DLLLOCAL NameIDQualifierStringFunctor : public MatchFunctor\r
+ {\r
+ string m_attributeID,m_matchNameQualifier,m_matchSPNameQualifier;\r
+\r
+ bool hasValue(const FilteringContext& filterContext) const;\r
+ bool matches(const FilteringContext& filterContext, const Attribute& attribute, size_t index) const;\r
+\r
+ public:\r
+ NameIDQualifierStringFunctor(const DOMElement* e)\r
+ : m_attributeID(XMLHelper::getAttrString(e, nullptr, attributeID)),\r
+ m_matchNameQualifier(XMLHelper::getAttrString(e, nullptr, NameID::NAMEQUALIFIER_ATTRIB_NAME)),\r
+ m_matchSPNameQualifier(XMLHelper::getAttrString(e, nullptr, NameID::SPNAMEQUALIFIER_ATTRIB_NAME)) {\r
+ }\r
+\r
+ virtual ~NameIDQualifierStringFunctor() {\r
+ }\r
+\r
+ bool evaluatePolicyRequirement(const FilteringContext& filterContext) const {\r
+ if (m_attributeID.empty())\r
+ throw AttributeFilteringException("No attributeID specified.");\r
+ return hasValue(filterContext);\r
+ }\r
+\r
+ bool evaluatePermitValue(const FilteringContext& filterContext, const Attribute& attribute, size_t index) const {\r
+ if (m_attributeID.empty() || m_attributeID == attribute.getId())\r
+ return matches(filterContext, attribute, index);\r
+ return hasValue(filterContext);\r
+ }\r
+ };\r
+\r
+ MatchFunctor* SHIBSP_DLLLOCAL NameIDQualifierStringFactory(const std::pair<const FilterPolicyContext*,const DOMElement*>& p)\r
+ {\r
+ return new NameIDQualifierStringFunctor(p.second);\r
+ }\r
+\r
+};\r
+\r
+bool NameIDQualifierStringFunctor::hasValue(const FilteringContext& filterContext) const\r
+{\r
+ size_t count;\r
+ pair<multimap<string,Attribute*>::const_iterator,multimap<string,Attribute*>::const_iterator> attrs =\r
+ filterContext.getAttributes().equal_range(m_attributeID);\r
+ for (; attrs.first != attrs.second; ++attrs.first) {\r
+ count = attrs.first->second->valueCount();\r
+ for (size_t index = 0; index < count; ++index) {\r
+ if (matches(filterContext, *(attrs.first->second), index))\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+}\r
+\r
+bool NameIDQualifierStringFunctor::matches(const FilteringContext& filterContext, const Attribute& attribute, size_t index) const\r
+{\r
+ const NameIDAttribute* nameattr = dynamic_cast<const NameIDAttribute*>(&attribute);\r
+ if (!nameattr) {\r
+ Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").warn(\r
+ "NameIDQualifierString MatchFunctor applied to non-NameID-valued attribute (%s)", attribute.getId()\r
+ );\r
+ return false;\r
+ }\r
+\r
+ const NameIDAttribute::Value& val = nameattr->getValues()[index];\r
+ if (!val.m_NameQualifier.empty()) {\r
+ if (m_matchNameQualifier.empty()) {\r
+ auto_ptr_char issuer(filterContext.getAttributeIssuer());\r
+ if (issuer.get() && *issuer.get()) {\r
+ if (val.m_NameQualifier != issuer.get()) {\r
+ Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").warn(\r
+ "NameIDQualifierString MatchFunctor rejecting NameQualifier (%s), should be (%s)",\r
+ val.m_NameQualifier.c_str(), issuer.get()\r
+ );\r
+ return false;\r
+ }\r
+ }\r
+ else {\r
+ Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").warn(\r
+ "NameIDQualifierString MatchFunctor rejecting NameQualifier (%s), attribute issuer unknown",\r
+ val.m_NameQualifier.c_str()\r
+ );\r
+ return false;\r
+ }\r
+ }\r
+ else if (m_matchNameQualifier != val.m_NameQualifier) {\r
+ Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").warn(\r
+ "NameIDQualifierString MatchFunctor rejecting NameQualifier (%s), should be (%s)",\r
+ val.m_NameQualifier.c_str(), m_matchNameQualifier.c_str()\r
+ );\r
+ return false;\r
+ }\r
+ }\r
+ if (!val.m_SPNameQualifier.empty()) {\r
+ if (m_matchSPNameQualifier.empty()) {\r
+ auto_ptr_char req(filterContext.getAttributeRequester());\r
+ if (req.get() && *req.get()) {\r
+ if (val.m_SPNameQualifier != req.get()) {\r
+ Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").warn(\r
+ "NameIDQualifierString MatchFunctor rejecting SPNameQualifier (%s), should be (%s)",\r
+ val.m_SPNameQualifier.c_str(), req.get()\r
+ );\r
+ return false;\r
+ }\r
+ }\r
+ else {\r
+ Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").warn(\r
+ "NameIDQualifierString MatchFunctor rejecting SPNameQualifier (%s), attribute requester unknown",\r
+ val.m_SPNameQualifier.c_str()\r
+ );\r
+ return false;\r
+ }\r
+ }\r
+ else if (m_matchSPNameQualifier != val.m_SPNameQualifier) {\r
+ Category::getInstance(SHIBSP_LOGCAT".AttributeFilter").warn(\r
+ "NameIDQualifierString MatchFunctor rejecting SPNameQualifier (%s), should be (%s)",\r
+ val.m_SPNameQualifier.c_str(), m_matchSPNameQualifier.c_str()\r
+ );\r
+ return false;\r
+ }\r
+ }\r
+\r
+ return true;\r
+}\r
<ClCompile Include="AbstractSPRequest.cpp" />\r
<ClCompile Include="Application.cpp" />\r
<ClCompile Include="attribute\Base64AttributeDecoder.cpp" />\r
+ <ClCompile Include="attribute\filtering\impl\NameIDQualifierStringFunctor.cpp" />\r
<ClCompile Include="binding\impl\XMLProtocolProvider.cpp" />\r
<ClCompile Include="handler\impl\DiscoveryFeed.cpp" />\r
<ClCompile Include="handler\impl\LogoutInitiator.cpp" />\r
<ClCompile Include="attribute\Base64AttributeDecoder.cpp">\r
<Filter>Source Files\attribute</Filter>\r
</ClCompile>\r
+ <ClCompile Include="attribute\filtering\impl\NameIDQualifierStringFunctor.cpp">\r
+ <Filter>Source Files\attribute\filtering\impl</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="remoting\impl\SocketListener.h">\r