</complexContent>
</complexType>
- <complexType name="AttributeTargetedStringMatchType">
+ <complexType name="AttributeTargetedStringMatchType" abstract="true">
<complexContent>
<extension base="basic:StringMatchType">
<attribute name="attributeID" type="string">
attribute/filtering/OrMatchFunctor.cpp \
attribute/filtering/AttributeIssuerStringFunctor.cpp \
attribute/filtering/AttributeRequesterStringFunctor.cpp \
+ attribute/filtering/AttributeScopeStringFunctor.cpp \
+ attribute/filtering/AttributeValueStringFunctor.cpp \
attribute/filtering/AuthenticationMethodStringFunctor.cpp \
attribute/resolver/impl/ChainingAttributeResolver.cpp \
attribute/resolver/impl/QueryAttributeResolver.cpp \
virtual void clearSerializedValues()=0;
/**
+ * Gets the string equivalent of the value at the specified position (starting from zero).
+ *
+ * @param index position of value
+ * @return the specified value in its "string" form, or NULL if undefined
+ */
+ virtual const char* getString(size_t index) const {
+ return m_serialized[index].c_str();
+ }
+
+ /**
+ * Gets the "scope" of the value at the specified position (starting from zero).
+ *
+ * @param index position of value
+ * @return the specified value's "scope", or NULL if attribute is unscoped
+ */
+ virtual const char* getScope(size_t index) const {
+ return NULL;
+ }
+
+ /**
* Removes the value at the specified position (starting from zero).
*
* @param index position of value to remove
m_serialized.clear();
}
+ const char* getString(size_t index) const {
+ return m_values[index].m_Name.c_str();
+ }
+
+ const char* getScope(size_t index) const {
+ return m_values[index].m_NameQualifier.c_str();
+ }
+
void removeValue(size_t index) {
Attribute::removeValue(index);
if (index < m_values.size())
m_serialized.clear();
}
+ const char* getString(size_t index) const {
+ return m_values[index].first.c_str();
+ }
+
+ const char* getScope(size_t index) const {
+ return m_values[index].second.c_str();
+ }
+
void removeValue(size_t index) {
Attribute::removeValue(index);
if (index < m_values.size())
/**
* Constructor.
*
- * @param app reference to Application
- * @param role metadata role of attribute issuer, if any
+ * @param app reference to Application
+ * @param attributes attributes being filtered
+ * @param role metadata role of Attribute issuer, if any
* @param authncontext_class method/category of authentication event, if known
- * @param authncontext_decl specifics of authentication event, if known
+ * @param authncontext_decl specifics of authentication event, if known
*/
BasicFilteringContext(
const Application& app,
+ const std::multimap<std::string,Attribute*>& attributes,
const opensaml::saml2md::RoleDescriptor* role=NULL,
const char* authncontext_class=NULL,
const char* authncontext_decl=NULL
- ) : m_app(app), m_role(role), m_issuer(NULL), m_class(authncontext_class), m_decl(authncontext_decl) {
+ ) : m_app(app), m_attributes(attributes), m_role(role), m_issuer(NULL), m_class(authncontext_class), m_decl(authncontext_decl) {
if (role)
m_issuer = dynamic_cast<opensaml::saml2md::EntityDescriptor*>(role->getParent())->getEntityID();
}
const opensaml::saml2md::RoleDescriptor* getAttributeIssuerMetadata() const {
return m_role;
}
+ const std::multimap<std::string,Attribute*>& getAttributes() const {
+ return m_attributes;
+ }
private:
const Application& m_app;
+ const std::multimap<std::string,Attribute*>& m_attributes;
const opensaml::saml2md::RoleDescriptor* m_role;
const XMLCh* m_issuer;
const char* m_class;
* @return SAML metadata for the attribute issuing role, or NULL
*/
virtual const opensaml::saml2md::RoleDescriptor* getAttributeIssuerMetadata() const=0;
+
+ /**
+ * Returns the set of Attributes being filtered.
+ *
+ * <p>No modifications should be performed, access is provided only for use by
+ * MatchFunctors based on the presence of Attribute data.
+ *
+ * @return an immutable map of Attributes.
+ */
+ virtual const std::multimap<std::string,Attribute*>& getAttributes() const=0;
+
};
};
/** Matches the principal's authentication method/class or context reference. */
extern SHIBSP_API xmltooling::QName AuthenticationMethodStringType;
+ /** Matches an attribute's string value. */
+ extern SHIBSP_API xmltooling::QName AttributeValueStringType;
+
+ /** Matches an attribute's "scope". */
+ extern SHIBSP_API xmltooling::QName AttributeScopeStringType;
+
/**
* Registers MatchFunctor classes into the runtime.
*/
--- /dev/null
+/*
+ * Copyright 2001-2007 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.
+ */
+
+/**
+ * AttributeScopeStringFunctor.cpp
+ *
+ * A match function that matches the scope of an attribute value against the specified value.
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "attribute/Attribute.h"
+#include "attribute/filtering/FilteringContext.h"
+#include "attribute/filtering/FilterPolicyContext.h"
+
+using namespace shibsp;
+using namespace std;
+
+namespace shibsp {
+
+ static const XMLCh attributeID[] = UNICODE_LITERAL_11(a,t,t,r,i,b,u,t,e,I,D);
+ static const XMLCh value[] = UNICODE_LITERAL_5(v,a,l,u,e);
+
+ /**
+ * A match function that matches the scope of an attribute value against the specified value.
+ */
+ class SHIBSP_DLLLOCAL AttributeScopeStringFunctor : public MatchFunctor
+ {
+ xmltooling::auto_ptr_char m_value;
+ xmltooling::auto_ptr_char m_attributeID;
+
+ bool hasScope(const FilteringContext& filterContext) const;
+
+ public:
+ AttributeScopeStringFunctor(const DOMElement* e)
+ : m_value(e ? e->getAttributeNS(NULL,value) : NULL), m_attributeID(e ? e->getAttributeNS(NULL,attributeID) : NULL) {
+ if (!m_value.get() || !*m_value.get())
+ throw ConfigurationException("AttributeScopeString MatchFunctor requires non-empty value attribute.");
+ }
+
+ bool evaluatePolicyRequirement(const FilteringContext& filterContext) const {
+ if (!m_attributeID.get() || !*m_attributeID.get())
+ throw AttributeFilteringException("No attributeID specified.");
+ return hasScope(filterContext);
+ }
+
+ bool evaluatePermitValue(const FilteringContext& filterContext, const Attribute& attribute, size_t index) const {
+ if (!XMLString::equals(m_attributeID.get(), attribute.getId()))
+ return hasScope(filterContext);
+ return XMLString::equals(attribute.getScope(index), m_value.get());
+ }
+ };
+
+ MatchFunctor* SHIBSP_DLLLOCAL AttributeScopeStringFactory(const std::pair<const FilterPolicyContext*,const DOMElement*>& p)
+ {
+ return new AttributeScopeStringFunctor(p.second);
+ }
+
+};
+
+bool AttributeScopeStringFunctor::hasScope(const FilteringContext& filterContext) const
+{
+ size_t count;
+ pair<multimap<string,Attribute*>::const_iterator,multimap<string,Attribute*>::const_iterator> attrs =
+ filterContext.getAttributes().equal_range(m_attributeID.get());
+ for (; attrs.first != attrs.second; ++attrs.first) {
+ count = attrs.first->second->valueCount();
+ for (size_t index = 0; index < count; ++index) {
+ if (XMLString::equals(attrs.first->second->getScope(index), m_value.get()))
+ return true;
+ }
+ }
+ return false;
+}
--- /dev/null
+/*
+ * Copyright 2001-2007 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.
+ */
+
+/**
+ * AttributeValueStringFunctor.cpp
+ *
+ * A match function that matches the value of an attribute against the specified value.
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "attribute/Attribute.h"
+#include "attribute/filtering/FilteringContext.h"
+#include "attribute/filtering/FilterPolicyContext.h"
+
+using namespace shibsp;
+using namespace std;
+
+namespace shibsp {
+
+ static const XMLCh attributeID[] = UNICODE_LITERAL_11(a,t,t,r,i,b,u,t,e,I,D);
+ static const XMLCh value[] = UNICODE_LITERAL_5(v,a,l,u,e);
+
+ /**
+ * A match function that matches the value of an attribute against the specified value.
+ */
+ class SHIBSP_DLLLOCAL AttributeValueStringFunctor : public MatchFunctor
+ {
+ xmltooling::auto_ptr_char m_value;
+ xmltooling::auto_ptr_char m_attributeID;
+
+ bool hasValue(const FilteringContext& filterContext) const;
+ bool matches(const Attribute& attribute, size_t index) const;
+
+ public:
+ AttributeValueStringFunctor(const DOMElement* e)
+ : m_value(e ? e->getAttributeNS(NULL,value) : NULL), m_attributeID(e ? e->getAttributeNS(NULL,attributeID) : NULL) {
+ if (!m_value.get() || !*m_value.get())
+ throw ConfigurationException("AttributeValueString MatchFunctor requires non-empty value attribute.");
+ }
+
+ bool evaluatePolicyRequirement(const FilteringContext& filterContext) const {
+ if (!m_attributeID.get() || !*m_attributeID.get())
+ throw AttributeFilteringException("No attributeID specified.");
+ return hasValue(filterContext);
+ }
+
+ bool evaluatePermitValue(const FilteringContext& filterContext, const Attribute& attribute, size_t index) const {
+ if (!XMLString::equals(m_attributeID.get(), attribute.getId()))
+ return hasValue(filterContext);
+ return matches(attribute, index);
+ }
+ };
+
+ MatchFunctor* SHIBSP_DLLLOCAL AttributeValueStringFactory(const std::pair<const FilterPolicyContext*,const DOMElement*>& p)
+ {
+ return new AttributeValueStringFunctor(p.second);
+ }
+
+};
+
+bool AttributeValueStringFunctor::hasValue(const FilteringContext& filterContext) const
+{
+ size_t count;
+ pair<multimap<string,Attribute*>::const_iterator,multimap<string,Attribute*>::const_iterator> attrs =
+ filterContext.getAttributes().equal_range(m_attributeID.get());
+ for (; attrs.first != attrs.second; ++attrs.first) {
+ count = attrs.first->second->valueCount();
+ for (size_t index = 0; index < count; ++index) {
+ if (matches(*(attrs.first->second), index))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AttributeValueStringFunctor::matches(const Attribute& attribute, size_t index) const
+{
+ const char* val = attribute.getString(index);
+ if (!val)
+ return false;
+ if (attribute.isCaseSensitive())
+ return !strcmp(m_value.get(), val);
+
+#ifdef HAVE_STRCASECMP
+ return !strcasecmp(m_value.get(), val);
+#else
+ return !stricmp(m_value.get(), val);
+#endif
+}
DECL_FACTORY(AttributeRequesterString);
DECL_FACTORY(AttributeIssuerString);
DECL_FACTORY(AuthenticationMethodString);
+ DECL_FACTORY(AttributeValueString);
+ DECL_FACTORY(AttributeScopeString);
static const XMLCh ANY[] = UNICODE_LITERAL_3(A,N,Y);
static const XMLCh AND[] = UNICODE_LITERAL_3(A,N,D);
static const XMLCh AttributeRequesterString[] = UNICODE_LITERAL_24(A,t,t,r,i,b,u,t,e,R,e,q,u,e,s,t,e,r,S,t,r,i,n,g);
static const XMLCh AttributeIssuerString[] = UNICODE_LITERAL_21(A,t,t,r,i,b,u,t,e,I,s,s,u,e,r,S,t,r,i,n,g);
static const XMLCh AuthenticationMethodString[] = UNICODE_LITERAL_26(A,u,t,h,e,n,t,i,c,a,t,i,o,n,M,e,t,h,o,d,S,t,r,i,n,g);
+ static const XMLCh AttributeValueString[] = UNICODE_LITERAL_20(A,t,t,r,i,b,u,t,e,V,a,l,u,e,S,t,r,i,n,g);
+ static const XMLCh AttributeScopeString[] = UNICODE_LITERAL_20(A,t,t,r,i,b,u,t,e,S,c,o,p,e,S,t,r,i,n,g);
};
DECL_BASIC_QNAME(AnyMatchFunctor, ANY);
DECL_BASIC_QNAME(AttributeRequesterString, AttributeRequesterString);
DECL_BASIC_QNAME(AttributeIssuerString, AttributeIssuerString);
DECL_BASIC_QNAME(AuthenticationMethodString, AuthenticationMethodString);
+DECL_BASIC_QNAME(AttributeValueString, AttributeValueString);
+DECL_BASIC_QNAME(AttributeScopeString, AttributeScopeString);
void SHIBSP_API shibsp::registerMatchFunctors()
{
REGISTER_FACTORY(AttributeRequesterString);
REGISTER_FACTORY(AttributeIssuerString);
REGISTER_FACTORY(AuthenticationMethodString);
+ REGISTER_FACTORY(AttributeValueString);
+ REGISTER_FACTORY(AttributeScopeString);
}
AttributeFilter* filter = ctx.getApplication().getAttributeFilter();
if (filter) {
- BasicFilteringContext fc(ctx.getApplication(), AA, ctx.getClassRef(), ctx.getDeclRef());
+ BasicFilteringContext fc(ctx.getApplication(), ctx.getResolvedAttributes(), AA, ctx.getClassRef(), ctx.getDeclRef());
Locker filtlocker(filter);
filter->filterAttributes(fc, ctx.getResolvedAttributes());
}
AttributeFilter* filter = ctx.getApplication().getAttributeFilter();
if (filter) {
- BasicFilteringContext fc(ctx.getApplication(), AA, ctx.getClassRef(), ctx.getDeclRef());
+ BasicFilteringContext fc(ctx.getApplication(), ctx.getResolvedAttributes(), AA, ctx.getClassRef(), ctx.getDeclRef());
Locker filtlocker(filter);
filter->filterAttributes(fc, ctx.getResolvedAttributes());
}
NameIdentifier* n = ssoStatement->getSubject()->getNameIdentifier();
+ // Now we have to extract the authentication details for attribute and session setup.
+
+ // Session expiration for SAML 1.x is purely SP-driven, and the method is mapped to a ctx class.
+ const PropertySet* sessionProps = application.getPropertySet("Sessions");
+ pair<bool,unsigned int> lifetime = sessionProps ? sessionProps->getUnsignedInt("lifetime") : make_pair(true,28800);
+ if (!lifetime.first)
+ lifetime.second = 28800;
+ auto_ptr_char authnInstant(
+ ssoStatement->getAuthenticationInstant() ? ssoStatement->getAuthenticationInstant()->getRawData() : NULL
+ );
+ auto_ptr_char authnMethod(ssoStatement->getAuthenticationMethod());
+
// 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.
multimap<string,Attribute*> resolvedAttributes;
AttributeFilter* filter = application.getAttributeFilter();
if (filter && !resolvedAttributes.empty()) {
- BasicFilteringContext fc(application, policy.getIssuerMetadata());
+ BasicFilteringContext fc(application, resolvedAttributes, policy.getIssuerMetadata(), authnMethod.get());
Locker filtlocker(filter);
try {
filter->filterAttributes(fc, resolvedAttributes);
}
}
- // First, normalize the SAML 1.x NameIdentifier...
+ // Normalize the SAML 1.x NameIdentifier...
auto_ptr<NameID> nameid(n ? NameIDBuilder::buildNameID() : NULL);
if (n) {
nameid->setName(n->getName());
nameid->setNameQualifier(n->getNameQualifier());
}
- // Now we have to extract the authentication details for session setup.
-
- // Session expiration for SAML 1.x is purely SP-driven, and the method is mapped to a ctx class.
- const PropertySet* sessionProps = application.getPropertySet("Sessions");
- pair<bool,unsigned int> lifetime = sessionProps ? sessionProps->getUnsignedInt("lifetime") : make_pair(true,28800);
- if (!lifetime.first)
- lifetime.second = 28800;
- auto_ptr_char authnInstant(
- ssoStatement->getAuthenticationInstant() ? ssoStatement->getAuthenticationInstant()->getRawData() : NULL
- );
- auto_ptr_char authnMethod(ssoStatement->getAuthenticationMethod());
-
const EntityDescriptor* issuerMetadata =
policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL;
auto_ptr<ResolutionContext> ctx(
// 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.
+ // Now we have to extract the authentication details for session setup.
+
+ // Session expiration for SAML 2.0 is jointly IdP- and SP-driven.
+ time_t sessionExp = ssoStatement->getSessionNotOnOrAfter() ? ssoStatement->getSessionNotOnOrAfterEpoch() : 0;
+ const PropertySet* sessionProps = application.getPropertySet("Sessions");
+ pair<bool,unsigned int> lifetime = sessionProps ? sessionProps->getUnsignedInt("lifetime") : make_pair(true,28800);
+ if (!lifetime.first)
+ lifetime.second = 28800;
+ if (lifetime.second != 0) {
+ if (sessionExp == 0)
+ sessionExp = now + lifetime.second; // IdP says nothing, calulate based on SP.
+ else
+ sessionExp = min(sessionExp, now + lifetime.second); // Use the lowest.
+ }
+
+ // Other details...
+ const AuthnContext* authnContext = ssoStatement->getAuthnContext();
+ auto_ptr_char authnClass((authnContext && authnContext->getAuthnContextClassRef()) ? authnContext->getAuthnContextClassRef()->getReference() : NULL);
+ auto_ptr_char authnDecl((authnContext && authnContext->getAuthnContextDeclRef()) ? authnContext->getAuthnContextDeclRef()->getReference() : NULL);
+ auto_ptr_char index(ssoStatement->getSessionIndex());
+ auto_ptr_char authnInstant(ssoStatement->getAuthnInstant() ? ssoStatement->getAuthnInstant()->getRawData() : NULL);
+
multimap<string,Attribute*> resolvedAttributes;
AttributeExtractor* extractor = application.getAttributeExtractor();
if (extractor) {
AttributeFilter* filter = application.getAttributeFilter();
if (filter && !resolvedAttributes.empty()) {
- BasicFilteringContext fc(application, policy.getIssuerMetadata());
+ BasicFilteringContext fc(application, resolvedAttributes, policy.getIssuerMetadata(), authnClass.get(), authnDecl.get());
Locker filtlocker(filter);
try {
filter->filterAttributes(fc, resolvedAttributes);
}
try {
- // Now we have to extract the authentication details for session setup.
-
- // Session expiration for SAML 2.0 is jointly IdP- and SP-driven.
- time_t sessionExp = ssoStatement->getSessionNotOnOrAfter() ? ssoStatement->getSessionNotOnOrAfterEpoch() : 0;
- const PropertySet* sessionProps = application.getPropertySet("Sessions");
- pair<bool,unsigned int> lifetime = sessionProps ? sessionProps->getUnsignedInt("lifetime") : make_pair(true,28800);
- if (!lifetime.first)
- lifetime.second = 28800;
- if (lifetime.second != 0) {
- if (sessionExp == 0)
- sessionExp = now + lifetime.second; // IdP says nothing, calulate based on SP.
- else
- sessionExp = min(sessionExp, now + lifetime.second); // Use the lowest.
- }
-
- // Other details...
- const AuthnContext* authnContext = ssoStatement->getAuthnContext();
- auto_ptr_char authnClass((authnContext && authnContext->getAuthnContextClassRef()) ? authnContext->getAuthnContextClassRef()->getReference() : NULL);
- auto_ptr_char authnDecl((authnContext && authnContext->getAuthnContextDeclRef()) ? authnContext->getAuthnContextDeclRef()->getReference() : NULL);
- auto_ptr_char index(ssoStatement->getSessionIndex());
- auto_ptr_char authnInstant(ssoStatement->getAuthnInstant() ? ssoStatement->getAuthnInstant()->getRawData() : NULL);
-
const EntityDescriptor* issuerMetadata =
policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL;
auto_ptr<ResolutionContext> ctx(
>\r
</File>\r
<File\r
+ RelativePath=".\attribute\filtering\impl\AttributeScopeStringFunctor.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\attribute\filtering\impl\AttributeValueStringFunctor.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\attribute\filtering\impl\AuthenticationMethodStringFunctor.cpp"\r
>\r
</File>\r