using namespace shibsp;
using namespace xmltooling;
using namespace std;
+using xercesc::RegularExpression;
+using xercesc::XMLException;
extern "C" module MODULE_VAR_EXPORT mod_shib;
Lockable* lock() {return this;}
void unlock() {}
bool authorized(const SPRequest& request, const Session* session) const;
+private:
+ bool checkAttribute(const SPRequest& request, const Attribute* attr, const char* toMatch, RegularExpression* re) const;
};
AccessControl* htAccessFactory(const xercesc::DOMElement* const & e)
return grps;
}
+bool htAccessControl::checkAttribute(const SPRequest& request, const Attribute* attr, const char* toMatch, RegularExpression* re) const
+{
+ bool caseSensitive = attr->isCaseSensitive();
+ const vector<string>& vals = attr->getSerializedValues();
+ for (vector<string>::const_iterator v=vals.begin(); v!=vals.end(); ++v) {
+ if (re) {
+ auto_ptr<XMLCh> trans(fromUTF8(v->c_str()));
+ if (re->matches(trans.get())) {
+ request.log(SPRequest::SPDebug,
+ string("htAccessControl plugin expecting regexp ") + toMatch + ", got " + *v + ": authorization granted"
+ );
+ return true;
+ }
+ }
+ else if ((caseSensitive && *v == toMatch) || (!caseSensitive && !strcasecmp(v->c_str(), toMatch))) {
+ request.log(SPRequest::SPDebug,
+ string("htAccessControl plugin expecting ") + toMatch + ", got " + *v + ": authorization granted."
+ );
+ return true;
+ }
+ else {
+ request.log(SPRequest::SPDebug,
+ string("htAccessControl plugin expecting ") + toMatch + ", got " + *v + ": authorization not granted."
+ );
+ }
+ }
+ return false;
+}
+
bool htAccessControl::authorized(const SPRequest& request, const Session* session) const
{
// Make sure the object is our type.
try {
// To do regex matching, we have to convert from UTF-8.
auto_ptr<XMLCh> trans(fromUTF8(w));
- xercesc::RegularExpression re(trans.get());
+ RegularExpression re(trans.get());
auto_ptr<XMLCh> trans2(fromUTF8(remote_user.c_str()));
if (re.matches(trans2.get())) {
request.log(SPRequest::SPDebug, string("htAccessControl plugin accepting user (") + w + ")");
SHIB_AP_CHECK_IS_OK;
}
}
- catch (xercesc::XMLException& ex) {
+ catch (XMLException& ex) {
auto_ptr_char tmp(ex.getMessage());
request.log(SPRequest::SPError,
string("htAccessControl plugin caught exception while parsing regular expression (") + w + "): " + tmp.get());
continue;
}
- // Find the attribute matching the require rule.
- map<string,const Attribute*>::const_iterator attr = session->getAttributes().find(w);
- if (attr == session->getAttributes().end()) {
+ // Find the attribute(s) matching the require rule.
+ pair<multimap<string,Attribute*>::const_iterator,multimap<string,Attribute*>::const_iterator> attrs =
+ session->getAttributes().equal_range(w);
+ if (attrs.first == attrs.second) {
request.log(SPRequest::SPWarn, string("htAccessControl rule requires attribute (") + w + "), not found in session");
continue;
}
bool regexp=false;
- bool caseSensitive = attr->second->isCaseSensitive();
- const vector<string>& vals = attr->second->getSerializedValues();
while (!auth_OK[x] && *t) {
w=ap_getword_conf(sta->m_req->pool,&t);
}
try {
- auto_ptr<xercesc::RegularExpression> re;
+ auto_ptr<RegularExpression> re;
if (regexp) {
delete re.release();
auto_ptr<XMLCh> trans(fromUTF8(w));
re=temp;
}
- for (vector<string>::const_iterator v=vals.begin(); !auth_OK[x] && v!=vals.end(); ++v) {
- if (regexp) {
- auto_ptr<XMLCh> trans(fromUTF8(v->c_str()));
- if (re->matches(trans.get())) {
- request.log(SPRequest::SPDebug,
- string("htAccessControl plugin expecting ") + w + ", got " + *v + ": authorization granted"
- );
- SHIB_AP_CHECK_IS_OK;
- }
- }
- else if ((caseSensitive && *v == w) || (!caseSensitive && !strcasecmp(v->c_str(),w))) {
- request.log(SPRequest::SPDebug,
- string("htAccessControl plugin expecting ") + w + ", got " + *v + ": authorization granted."
- );
+ for (; !auth_OK[x] && attrs.first!=attrs.second; ++attrs.first) {
+ if (checkAttribute(request, attrs.first->second, w, regexp ? re.get() : NULL)) {
SHIB_AP_CHECK_IS_OK;
}
- else {
- request.log(SPRequest::SPDebug,
- string("htAccessControl plugin expecting ") + w + ", got " + *v + ": authorization not granted."
- );
- }
}
}
- catch (xercesc::XMLException& ex) {
+ catch (XMLException& ex) {
auto_ptr_char tmp(ex.getMessage());
request.log(SPRequest::SPError,
string("htAccessControl plugin caught exception while parsing regular expression (") + w + "): " + tmp.get()
shibboleth.xml \
native.logger \
shibd.logger \
- resolver-simple.xml \
+ attribute-map.xml \
example-metadata.xml
# While BUILTCONFIGFILES are processed, these are not; so we should pull
shibboleth.xml: ${srcdir}/shibboleth.xml.in Makefile ${top_builddir}/config.status
$(MAKE) do-build-file FILE=$@
-resolver-simple.xml: ${srcdir}/resolver-simple.xml.in Makefile ${top_builddir}/config.status
+attribute-map.xml: ${srcdir}/attribute-map.xml.in Makefile ${top_builddir}/config.status
$(MAKE) do-build-file FILE=$@
example-metadata.xml: ${srcdir}/example-metadata.xml.in Makefile ${top_builddir}/config.status
shibd.logger \
native.logger \
shibboleth.xml \
- resolver-simple.xml \
+ attribute-map.xml \
example-metadata.xml
-EXTRA_DIST = .cvsignore \
+EXTRA_DIST =
shibboleth.xml.in \
+ attribute-map.xml.in \
+ example-metadata.xml.in \
native.logger.in \
shibd.logger.in \
apache.config.in \
sessionError.html \
metadataError.html \
sslError.html \
- resolver-simple.xml.in \
- example-metadata.xml.in \
sp-example.key \
sp-example.crt
--- /dev/null
+<Attributes xmlns="urn:mace:shibboleth:2.0:attribute-map"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:mace:shibboleth:2.0:attribute-map @-PKGXMLDIR-@/shibboleth-2.0-attribute-map.xsd">
+
+ <!-- First some useful eduPerson attributes that many sites might use. -->
+
+ <Attribute name="urn:mace:dir:attribute-def:eduPersonPrincipalName" id="REMOTE_USER">
+ <AttributeDecoder xsi:type="ScopedAttributeDecoder"/>
+ </Attribute>
+
+ <Attribute name="urn:mace:dir:attribute-def:eduPersonScopedAffiliation" id="affiliation">
+ <AttributeDecoder xsi:type="ScopedAttributeDecoder" caseSensitive="false"/>
+ </Attribute>
+
+ <Attribute name="urn:mace:dir:attribute-def:eduPersonAffiliation" id="unscoped-affiliation">
+ <AttributeDecoder xsi:type="ScopedAttributeDecoder" caseSensitive="false"/>
+ </Attribute>
+
+ <Attribute name="urn:mace:dir:attribute-def:eduPersonEntitlement" id="entitlement"/>
+
+ <!-- A persistent id attribute that supports personalized anonymous access. -->
+
+ <!-- First, the deprecated version: -->
+ <Attribute name="urn:mace:dir:attribute-def:eduPersonTargetedID" id="REMOTE_USER">
+ <AttributeDecoder xsi:type="ScopedAttributeDecoder"/>
+ </Attribute>
+
+ <!-- Second, the new version (note the OID-style name): -->
+ <Attribute name="urn:oid:1.3.6.1.4.1.5923.1.1.1.10" id="REMOTE_USER">
+ <AttributeDecoder xsi:type="NameIDAttributeDecoder" formatter="$Name!!$NameQualifier!!$SPNameQualifier"/>
+ </Attribute>
+
+ <!-- Third, the SAML 2.0 NameID Format: -->
+ <Attribute name="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" id="REMOTE_USER">
+ <AttributeDecoder xsi:type="NameIDAttributeDecoder" formatter="$Name!!$NameQualifier!!$SPNameQualifier"/>
+ </Attribute>
+
+ <!-- Some more eduPerson attributes, uncomment these to use them... -->
+ <!--
+ <Attribute name="urn:mace:dir:attribute-def:eduPersonPrimaryAffiliation" id="primary-affiliation">
+ <AttributeDecoder xsi:type="StringAttributeDecoder" caseSensitive="false"/>
+ </Attribute>
+ <Attribute name="urn:mace:dir:attribute-def:eduPersonNickname" id="nickname"/>
+ <Attribute name="urn:mace:dir:attribute-def:eduPersonPrimaryOrgUnitDN" id="primary-orgunit-dn"/>
+ <Attribute name="urn:mace:dir:attribute-def:eduPersonOrgUnitDN" id="orgunit-dn"/>
+ <Attribute name="urn:mace:dir:attribute-def:eduPersonOrgDN" id="org-dn"/>
+ -->
+
+ <!--Examples of LDAP-based attributes, uncomment to use these... -->
+ <!--
+ <Attribute name="urn:mace:dir:attribute-def:cn" id="cn"/>
+ <Attribute name="urn:mace:dir:attribute-def:sn" id="sn"/>
+ <Attribute name="urn:mace:dir:attribute-def:givenName" id="givenName"/>
+ <Attribute name="urn:mace:dir:attribute-def:mail" id="mail"/>
+ <Attribute name="urn:mace:dir:attribute-def:telephoneNumber" id="telephoneNumber"/>
+ <Attribute name="urn:mace:dir:attribute-def:title" id="title"/>
+ <Attribute name="urn:mace:dir:attribute-def:initials" id="initials"/>
+ <Attribute name="urn:mace:dir:attribute-def:description" id="description"/>
+ <Attribute name="urn:mace:dir:attribute-def:carLicense" id="carLicense"/>
+ <Attribute name="urn:mace:dir:attribute-def:departmentNumber" id="departmentNumber"/>
+ <Attribute name="urn:mace:dir:attribute-def:displayName" id="displayName"/>
+ <Attribute name="urn:mace:dir:attribute-def:employeeNumber" id="employeeNumber"/>
+ <Attribute name="urn:mace:dir:attribute-def:employeeType" id="employeeType"/>
+ <Attribute name="urn:mace:dir:attribute-def:preferredLanguage" id="preferredLanguage"/>
+ <Attribute name="urn:mace:dir:attribute-def:manager" id="manager"/>
+ <Attribute name="urn:mace:dir:attribute-def:seeAlso" id="seeAlso"/>
+ <Attribute name="urn:mace:dir:attribute-def:facsimileTelephoneNumber" id="facsimileTelephoneNumber"/>
+ <Attribute name="urn:mace:dir:attribute-def:street" id="street"/>
+ <Attribute name="urn:mace:dir:attribute-def:postOfficeBox" id="postOfficeBox"/>
+ <Attribute name="urn:mace:dir:attribute-def:postalCode" id="postalCode"/>
+ <Attribute name="urn:mace:dir:attribute-def:st" id="st"/>
+ <Attribute name="urn:mace:dir:attribute-def:l" id="l"/>
+ <Attribute name="urn:mace:dir:attribute-def:ou" id="ou"/>
+ <Attribute name="urn:mace:dir:attribute-def:businessCategory" id="businessCategory"/>
+ <Attribute name="urn:mace:dir:attribute-def:physicalDeliveryOfficeName" id="physicalDeliveryOfficeName"/>
+ -->
+
+</Attributes>
+++ /dev/null
-<ar:AttributeResolver xmlns:ar="urn:mace:shibboleth:2.0:resolver:simple"
- xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="urn:mace:shibboleth:2.0:resolver:simple @-PKGXMLDIR-@/shibboleth-2.0-simple-resolver.xsd"
- allowQuery="true">
-
- <!--
- Built-in decoders that can extract SAML Attribute data.
- Custom decoders can be configured here as well.
- -->
- <ar:AttributeDecoder id="Simple" type="Simple"/>
- <ar:AttributeDecoder id="Scoped" type="Scoped"/>
- <ar:AttributeDecoder id="NameID" type="NameID" formatter="$Name!!$NameQualifier!!$SPNameQualifier"/>
-
- <!--
- The simple resolver just enumerates SAML Attribute elements, each one
- referencing a specific Attribute by its name on the wire, and its local
- "friendly" ID. All Attributes that should be visible to an application
- should be listed, or they will be ignored by the resolver.
- -->
-
- <!-- First some useful eduPerson attributes that many sites might use. -->
-
- <saml:Attribute Name="urn:mace:dir:attribute-def:eduPersonPrincipalName" FriendlyName="REMOTE_USER" ar:decoderId="Scoped"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:eduPersonScopedAffiliation" FriendlyName="affiliation" ar:decoderId="Scoped"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:eduPersonAffiliation" FriendlyName="unscoped-affiliation" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:eduPersonEntitlement" FriendlyName="entitlement" ar:decoderId="Simple"/>
-
- <!-- A persistent id attribute that supports personalized anonymous access. -->
-
- <!-- First, the deprecated version: -->
- <saml:Attribute Name="urn:mace:dir:attribute-def:eduPersonTargetedID" FriendlyName="REMOTE_USER" ar:decoderId="Scoped"/>
-
- <!-- Second, the new version (note the OID-style name): -->
- <saml:Attribute Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.10" FriendlyName="REMOTE_USER" ar:decoderId="NameID"/>
-
- <!-- Third, the SAML 2.0 NameID Format: -->
- <saml:Attribute Name="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" FriendlyName="REMOTE_USER" ar:decoderId="NameID"/>
-
- <!-- Some more eduPerson attributes, uncomment these to use them... -->
- <!--
- <saml:Attribute Name="urn:mace:dir:attribute-def:eduPersonNickname" FriendlyName="nickname" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:eduPersonPrimaryAffiliation" FriendlyName="primary-affiliation" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:eduPersonPrimaryOrgUnitDN" FriendlyName="primary-orgunit-dn" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:eduPersonOrgUnitDN" FriendlyName="orgunit-dn" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:eduPersonOrgDN" FriendlyName="org-dn" ar:decoderId="Simple"/>
- -->
-
- <!--Examples of LDAP-based attributes, uncomment to use these... -->
- <!--
- <saml:Attribute Name="urn:mace:dir:attribute-def:cn" FriendlyName="cn" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:sn" FriendlyName="sn" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:givenName" FriendlyName="givenName" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:mail" FriendlyName="mail" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:telephoneNumber" FriendlyName="telephoneNumber" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:title" FriendlyName="title" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:initials" FriendlyName="initials" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:description" FriendlyName="description" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:carLicense" FriendlyName="carLicense" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:departmentNumber" FriendlyName="departmentNumber" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:displayName" FriendlyName="displayName" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:employeeNumber" FriendlyName="employeeNumber" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:employeeType" FriendlyName="employeeType" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:preferredLanguage" FriendlyName="preferredLanguage" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:manager" FriendlyName="manager" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:seeAlso" FriendlyName="seeAlso" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:facsimileTelephoneNumber" FriendlyName="facsimileTelephoneNumber" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:street" FriendlyName="street" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:postOfficeBox" FriendlyName="postOfficeBox" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:postalCode" FriendlyName="postalCode" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:st" FriendlyName="st" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:l" FriendlyName="l" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:ou" FriendlyName="ou" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:businessCategory" FriendlyName="businessCategory" ar:decoderId="Simple"/>
- <saml:Attribute Name="urn:mace:dir:attribute-def:physicalDeliveryOfficeName" FriendlyName="physicalDeliveryOfficeName" ar:decoderId="Simple"/>
- -->
-
-</ar::AttributeResolver>
-<SPConfig xmlns="urn:mace:shibboleth:sp:config:2.0"
- xmlns:conf="urn:mace:shibboleth:sp:config:2.0"
+<SPConfig xmlns="urn:mace:shibboleth:2.0:native:sp:config"
+ xmlns:conf="urn:mace:shibboleth:2.0:native:sp:config"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
<TrustEngine type="PKIX"/>
</TrustEngine>
- <!-- Built-in attribute resolver to extract data from SAML assertions. -->
- <AttributeResolver type="Simple" path="@-PKGSYSCONFDIR-@/resolver-simple.xml"/>
+ <!-- Map to extract attributes from SAML assertions. -->
+ <AttributeExtractor type="XML" path="@-PKGSYSCONFDIR-@/attribute-map.xml"/>
<!-- Simple file-based resolver for key/certificate information. -->
<CredentialResolver type="File">
static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e);
}
-PluginManager<RequestMapper,const xercesc::DOMElement*>::Factory SunRequestMapFactory;
+PluginManager<RequestMapper,string,const xercesc::DOMElement*>::Factory SunRequestMapFactory;
extern "C" NSAPI_PUBLIC void nsapi_shib_exit(void*)
{
catalog.xml \
shibboleth.xsd \
shibboleth-metadata-1.0.xsd \
- shibboleth-spconfig-2.0.xsd \
- shibboleth-2.0-attribute-resolver.xsd \
+ shibboleth-2.0-native-sp-config-2.0.xsd \
+ shibboleth-2.0-afp.xsd \
+ shibboleth-2.0-afp-mf-basic.xsd \
+ shibboleth-2.0-afp-mf-saml.xsd \
+ shibboleth-2.0-attribute-map.xsd \
shibboleth-2.0-simple-resolver.xsd \
metadata_v12_to_v13.xsl \
metadata_v13_to_v12.xsl \
<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<system systemId="urn:mace:shibboleth:metadata:1.0" uri="@-PKGXMLDIR-@/shibboleth-metadata-1.0.xsd"/>
- <system systemId="urn:mace:shibboleth:sp:config:2.0" uri="@-PKGXMLDIR-@/shibboleth-spconfig-2.0.xsd"/>
- <system systemId="urn:mace:shibboleth:2.0:resolver" uri="@-PKGXMLDIR-@/shibboleth-2.0-attribute-resolver.xsd"/>
- <system systemId="urn:mace:shibboleth:2.0:resolver:simple" uri="@-PKGXMLDIR-@/shibboleth-2.0-simple-resolver.xsd"/>
+ <system systemId="urn:mace:shibboleth:2.0:native:sp:config" uri="@-PKGXMLDIR-@/shibboleth-2.0-native-sp-config.xsd"/>
+ <system systemId="urn:mace:shibboleth:2.0:afp" uri="@-PKGXMLDIR-@/shibboleth-2.0-afp.xsd"/>
+ <system systemId="urn:mace:shibboleth:2.0:afp:mf:basic" uri="@-PKGXMLDIR-@/shibboleth-2.0-afp-mf-basic.xsd"/>
+ <system systemId="urn:mace:shibboleth:2.0:afp:mf:saml" uri="@-PKGXMLDIR-@/shibboleth-2.0-afp-mf-saml.xsd"/>
+ <system systemId="urn:mace:shibboleth:2.0:attribute-map" uri="@-PKGXMLDIR-@/shibboleth-2.0-attribute-map.xsd"/>
<system systemId="urn:mace:shibboleth:1.0" uri="@-PKGXMLDIR-@/shibboleth.xsd"/>
</catalog>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<schema targetNamespace="urn:mace:shibboleth:2.0:afp:mf:basic" xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:basic="urn:mace:shibboleth:2.0:afp:mf:basic" xmlns:afp="urn:mace:shibboleth:2.0:afp">
+
+ <import namespace="urn:mace:shibboleth:2.0:afp" schemaLocation="classpath:/schema/shibboleth-2.0-afp.xsd" />
+
+ <!-- Blanket Match Function -->
+ <complexType name="ANY">
+ <annotation>
+ <documentation>A match function that evaluates to true.</documentation>
+ </annotation>
+ <complexContent>
+ <extension base="afp:MatchFunctorType" />
+ </complexContent>
+ </complexType>
+
+ <!-- Boolean Match Functions -->
+ <complexType name="AND">
+ <annotation>
+ <documentation>
+ A match function that performs a logical AND on the results of all contained matching functions.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="afp:MatchFunctorType">
+ <choice minOccurs="2" maxOccurs="unbounded">
+ <element name="Rule" type="afp:MatchFunctorType">
+ <annotation>
+ <documentation>
+ The set of match function rules to be ANDed.
+ </documentation>
+ </annotation>
+ </element>
+ <element name="RuleReference" type="afp:ReferenceType">
+ <annotation>
+ <documentation>
+ The set of match function rules to be ANDed.
+ </documentation>
+ </annotation>
+ </element>
+ </choice>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <complexType name="OR">
+ <annotation>
+ <documentation>
+ A match function that performs a logical OR on the results of all contained matching functions.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="afp:MatchFunctorType">
+ <choice minOccurs="2" maxOccurs="unbounded">
+ <element name="Rule" type="afp:MatchFunctorType">
+ <annotation>
+ <documentation>
+ The set of match function rules to be ANDed.
+ </documentation>
+ </annotation>
+ </element>
+ <element name="RuleReference" type="afp:ReferenceType">
+ <annotation>
+ <documentation>
+ The set of match function rules to be ANDed.
+ </documentation>
+ </annotation>
+ </element>
+ </choice>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <complexType name="NOT">
+ <annotation>
+ <documentation>
+ A match function that performs a logical NOT on the resultof the contained matching function.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="afp:MatchFunctorType">
+ <choice>
+ <element name="Rule" type="afp:MatchFunctorType">
+ <annotation>
+ <documentation>
+ The set of match function rules to be ANDed.
+ </documentation>
+ </annotation>
+ </element>
+ <element name="RuleReference" type="afp:ReferenceType">
+ <annotation>
+ <documentation>
+ The set of match function rules to be ANDed.
+ </documentation>
+ </annotation>
+ </element>
+ </choice>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Literal String Match Functions -->
+ <complexType name="AttributeRequesterString">
+ <annotation>
+ <documentation>
+ A match function that matches the attribute request against the specified value.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="basic:StringMatchType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="AttributeIssuerString">
+ <annotation>
+ <documentation>
+ A match function that matches the attribute issuer against the specified value.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="basic:StringMatchType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="PrincipalNameString">
+ <annotation>
+ <documentation>A match function that matches the principal name against the specified value.</documentation>
+ </annotation>
+ <complexContent>
+ <extension base="basic:StringMatchType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="AuthenticationMethodString">
+ <annotation>
+ <documentation>
+ A match function that matches the authentication method against the specified value.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="basic:StringMatchType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="AttributeValueString">
+ <annotation>
+ <documentation>
+ A match function that matches the value of an attribute against the specified value. This match
+ evaluates to true if the attribute contains the specified value.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="basic:AttributeTargetedStringMatchType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="AttributeScopeString">
+ <annotation>
+ <documentation>
+ A match function that matches the attribute scope against the specified value.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="basic:AttributeTargetedStringMatchType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="AttributeTargetedStringMatchType">
+ <complexContent>
+ <extension base="basic:StringMatchType">
+ <attribute name="attributeID" type="string">
+ <annotation>
+ <documentation>
+ The ID of the attribute whose value should be matched. If no attribute ID is specified the
+ ID of the containing attribute rule is assumed.
+ </documentation>
+ </annotation>
+ </attribute>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <complexType name="StringMatchType" abstract="true">
+ <complexContent>
+ <extension base="afp:MatchFunctorType">
+ <attribute name="value" type="string" use="required">
+ <annotation>
+ <documentation>The string value to match.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="ignoreCase" type="boolean" default="false">
+ <annotation>
+ <documentation>
+ A boolean flag indicating whether case should be ignored when evaluating the match.
+ </documentation>
+ </annotation>
+ </attribute>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Regular Expression Match Functions -->
+ <complexType name="AttributeRequesterRegex">
+ <annotation>
+ <documentation>
+ A match function that matches the attribute requester against the specified regular expression.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="basic:RegexMatchType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="AttributeIssuerRegex">
+ <annotation>
+ <documentation>
+ A match function that matches the attribute issuer against the specified regular expression.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="basic:RegexMatchType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="PrincipalNameRegex">
+ <annotation>
+ <documentation>
+ A match function that matches the principal name against the specified regular expression.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="basic:RegexMatchType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="AuthenticationMethodRegex">
+ <annotation>
+ <documentation>
+ A match function that matches the authentication method against the specified regular expression.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="basic:RegexMatchType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="AttributeValueRegex">
+ <annotation>
+ <documentation>
+ A match function that matches an attribute value against the specified regular expression. This function
+ evaluates to true if any value matches the given expression
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="basic:AttributeTargetedRegexMatchType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="AttributeScopeRegex">
+ <annotation>
+ <documentation>
+ A match function that matches the attribute scope against the specified regular expression.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="basic:AttributeTargetedRegexMatchType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="AttributeTargetedRegexMatchType">
+ <complexContent>
+ <extension base="basic:RegexMatchType">
+ <attribute name="attributeID" type="string">
+ <annotation>
+ <documentation>
+ The ID of the attribute whose value should be matched. If no attribute ID is specified the
+ ID of the containing attribute rule is assumed.
+ </documentation>
+ </annotation>
+ </attribute>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <complexType name="RegexMatchType" abstract="true">
+ <complexContent>
+ <extension base="afp:MatchFunctorType">
+ <attribute name="regex" type="string" use="required">
+ <annotation>
+ <documentation>The regular expression values are matched against.</documentation>
+ </annotation>
+ </attribute>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Misc. Functions -->
+ <complexType name="Script">
+ <annotation>
+ <documentation>
+ A match function that evaluates a script to determine if some criteria is met. The script MUST return a
+ boolean.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="afp:MatchFunctorType">
+ <choice>
+ <element name="Script" type="string" minOccurs="0">
+ <annotation>
+ <documentation>The script to evaluate to construct the attribute.</documentation>
+ </annotation>
+ </element>
+ <element name="ScriptFile" type="string" minOccurs="0">
+ <annotation>
+ <documentation>
+ The filesystem path to the script to evaluate to construct the attribute.
+ </documentation>
+ </annotation>
+ </element>
+ </choice>
+ <attribute name="language" type="string" default="javascript">
+ <annotation>
+ <documentation>
+ The JSR-233 name for the scripting language that will be used. By default "javascript" is
+ supported.
+ </documentation>
+ </annotation>
+ </attribute>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <complexType name="NumberOfAttributeValues">
+ <annotation>
+ <documentation>
+ A match function that evaluates to true if the given attribute has as a number of values that falls
+ between the minimum and maximum. This method may be used as a sanity check to ensure that an unexpected
+ number of values did not come from the attribute resolver and be released.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="afp:MatchFunctorType">
+ <attribute name="attributeID" type="string">
+ <annotation>
+ <documentation>The ID of the attribute whose value should be matched.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="minimum" type="nonNegativeInteger" default="0">
+ <annotation>
+ <documentation>Minimum number of values an attribute may have.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="maximum" type="positiveInteger" default="2147483647">
+ <annotation>
+ <documentation>Maximum number of values an attribute may have.</documentation>
+ </annotation>
+ </attribute>
+ </extension>
+ </complexContent>
+ </complexType>
+
+</schema>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<schema targetNamespace="urn:mace:shibboleth:2.0:afp:mf:saml" xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:saml="urn:mace:shibboleth:2.0:afp:mf:saml" xmlns:afp="urn:mace:shibboleth:2.0:afp">
+
+ <import namespace="urn:mace:shibboleth:2.0:afp" schemaLocation="classpath:/schema/shibboleth-2.0-afp.xsd" />
+
+ <annotation>
+ <documentation>
+ A set of SAML specific match functions. These match functions only operate against a SAMLFilterContext.
+ </documentation>
+ </annotation>
+
+ <complexType name="AttributeRequesterInEntityGroup">
+ <annotation>
+ <documentation>
+ A match function that evaluates to true if the attribute requester is found in metadata and is a member
+ of the given entity group.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="saml:EntityGroupMatchType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="AttributeIssuerInEntityGroup">
+ <annotation>
+ <documentation>
+ A match function that evaluates to true if the attribute producer is found in metadata and is a member
+ of the given entity group.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="saml:EntityGroupMatchType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="EntityGroupMatchType">
+ <complexContent>
+ <extension base="afp:MatchFunctorType">
+ <attribute name="groupID" type="string" use="required">
+ <annotation>
+ <documentation>The entity group ID that an entity must be in.</documentation>
+ </annotation>
+ </attribute>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <complexType name="AttributeScopeMatchesShibMDScope">
+ <annotation>
+ <documentation>
+ A match function that ensures that an attributes value's scope matches a scope given in metadata for the entity or role.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="afp:MatchFunctorType" />
+ </complexContent>
+ </complexType>
+</schema>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<schema targetNamespace="urn:mace:shibboleth:2.0:afp" xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:afp="urn:mace:shibboleth:2.0:afp" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">\r
+\r
+ <import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="classpath:/schema/xmldsig-core-schema.xsd" />\r
+\r
+ <annotation>
+ <documentation>Schema for the attribute filter policies.</documentation>
+ </annotation>
+
+ <element name="AttributeFilterPolicyGroup" type="afp:AttributeFilterPolicyGroupType">
+ <annotation>
+ <documentation>
+ Root element of the attribute filter policy. Represents a named group of filter policies.
+ </documentation>
+ </annotation>
+ </element>
+ <complexType name="AttributeFilterPolicyGroupType">
+ <complexContent>
+ <extension base="afp:IndentityType">
+ <sequence>
+ <element ref="afp:PolicyRequirementRule" minOccurs="0" maxOccurs="unbounded">
+ <annotation>
+ <documentation>
+ Defines a set of applications requirements that may be reused across multiple filter
+ policies.
+ </documentation>
+ </annotation>
+ </element>
+ <element ref="afp:AttributeRule" minOccurs="0" maxOccurs="unbounded">
+ <annotation>
+ <documentation>
+ Defines an attribute rule that may be reused across multiple filter policies.
+ </documentation>
+ </annotation>
+ </element>
+ <element ref="afp:PermitValueRule" minOccurs="0" maxOccurs="unbounded">
+ <annotation>
+ <documentation>
+ Defines an attribute value filter that may be reused across multiple attribtue rules.
+ </documentation>
+ </annotation>
+ </element>\r
+ <element ref="afp:AttributeFilterPolicy" minOccurs="0" maxOccurs="unbounded">
+ <annotation>
+ <documentation>
+ A policy that defines the set of attribute value filters that will be applied if its
+ application requirements are met.
+ </documentation>
+ </annotation>
+ </element>
+ <element ref="ds:Signature" minOccurs="0">
+ <annotation>
+ <documentation>
+ Digital signature for the policy. Policies that are fetched from an external source,
+ such as a federation site, should be signed.
+ </documentation>
+ </annotation>
+ </element>\r
+ </sequence>\r
+ </extension>
+ </complexContent>\r
+ </complexType>
+
+ <element name="AttributeFilterPolicy" type="afp:AttributeFilterPolicyType">
+ <annotation>
+ <documentation>
+ A policy that defines a set of attribute value filters rules that should be used if given requirements
+ are met.
+ </documentation>
+ </annotation>
+ </element>
+ <complexType name="AttributeFilterPolicyType">
+ <complexContent>
+ <extension base="afp:IndentityType">
+ <sequence>
+ <choice>
+ <element ref="afp:PolicyRequirementRule">
+ <annotation>
+ <documentation>
+ A requirement that if met signals that this filter policy should be used.
+ </documentation>
+ </annotation>
+ </element>
+ <element name="PolicyRequirementRuleReference" type="afp:ReferenceType">
+ <annotation>
+ <documentation>
+ Rerfence to a PolicyRequirement defined within this policy group or another.
+ </documentation>
+ </annotation>
+ </element>
+ </choice>
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element ref="afp:AttributeRule">
+ <annotation>
+ <documentation>
+ A rule that describes how values of an attribute will be filtered.
+ </documentation>
+ </annotation>
+ </element>
+ <element name="AttributeRuleReference" type="afp:ReferenceType">
+ <annotation>
+ <documentation>
+ Rerfence to a AttribtueRule defined within this policy group or another.
+ </documentation>
+ </annotation>
+ </element>
+ </choice>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>\r
+\r
+ <element name="AttributeRule" type="afp:AttributeRuleType">
+ <annotation>
+ <documentation>A rule that describes how values of an attribute will be filtered.</documentation>
+ </annotation>
+ </element>\r
+ <complexType name="AttributeRuleType">
+ <complexContent>
+ <extension base="afp:IndentityType">
+ <choice>
+ <element ref="afp:PermitValueRule">
+ <annotation>
+ <documentation>
+ A filter for attribute values. If the filter evaluates to true the value is permitted,
+ otherwise it is filtered out.
+ </documentation>
+ </annotation>
+ </element>
+ <element name="PermitValueRuleReference" type="afp:ReferenceType">
+ <annotation>
+ <documentation>
+ Rerfence to a PermitValueRule defined within this policy group or another.
+ </documentation>
+ </annotation>
+ </element>
+ </choice>
+ <attribute name="attributeID" type="string" use="required">
+ <annotation>
+ <documentation>The ID of the attribute to which this rule applies.</documentation>
+ </annotation>
+ </attribute>
+ </extension>
+ </complexContent>\r
+ </complexType>
+
+ <element name="PolicyRequirementRule" type="afp:MatchFunctorType">
+ <annotation>
+ <documentation>A requirement that if met signals that a filter policy should be used.</documentation>
+ </annotation>
+ </element>
+ <element name="PermitValueRule" type="afp:MatchFunctorType">
+ <annotation>
+ <documentation>
+ A filter for attribtue values. If the filter evaluates to true the value is permitted, otherwise it is
+ filtered out.
+ </documentation>
+ </annotation>
+ </element>
+ <complexType name="MatchFunctorType" abstract="true">
+ <complexContent>
+ <extension base="afp:IndentityType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="IndentityType">
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>An ID, unique within the policy and component type.</documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+
+ <complexType name="ReferenceType">
+ <attribute name="ref" type="string">
+ <annotation>
+ <documentation>Used to reference a globally defined policy component.</documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+
+</schema>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<schema targetNamespace="urn:mace:shibboleth:2.0:attribute-map"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:am="urn:mace:shibboleth:2.0:attribute-map">
+
+ <annotation>
+ <documentation>
+ This schema maps SAML attributes into Shibboleth internal attributes.
+ </documentation>
+ </annotation>
+
+ <simpleType name="string">
+ <restriction base="string">
+ <minLength value="1"/>
+ </restriction>
+ </simpleType>
+
+ <element name="Attributes">
+ <annotation>
+ <documentation>The set of SAML 1/2 attribute mappings.</documentation>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element name="Attribute" type="am:AttributeType" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+ </element>
+
+ <complexType name="AttributeType">
+ <annotation>
+ <documentation>Rule for mapping a SAML 1/2 attribute to an internal attribute.</documentation>
+ </annotation>
+ <sequence>
+ <element name="AttributeDecoder" type="am:AttributeDecoderType" minOccurs="0"/>
+ </sequence>
+ <attribute name="id" type="am:string" use="required">
+ <annotation>
+ <documentation>The internal attribute ID to which this SAML attribute maps.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="am:string" use="required">
+ <annotation>
+ <documentation>The SAML 1 AttributeName or SAML 2 Name of the attribute.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="nameFormat" type="am:string">
+ <annotation>
+ <documentation>The SAML 1 Namespace or SAML 2 NameFormat of the attribute.</documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+
+ <complexType name="AttributeDecoderType" abstract="true">
+ <annotation>
+ <documentation>
+ Decodes a SAML attribute into its Shibboleth-internal representation.
+ </documentation>
+ </annotation>
+ <attribute name="caseSensitive" type="boolean" default="true">
+ <annotation>
+ <documentation>
+ Flag controlling case sensitivity when comparisons to the attribute's values are done.
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+
+ <complexType name="StringAttributeDecoder">
+ <annotation>
+ <documentation>
+ Decoder for attributes with string values.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="am:AttributeDecoderType" />
+ </complexContent>
+ </complexType>
+
+ <complexType name="ScopedAttributeDecoder">
+ <annotation>
+ <documentation>
+ Decoder for attributes with scoped values.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="am:AttributeDecoderType">
+ <attribute name="scopeDelimiter" type="am:string" default="@">
+ <annotation>
+ <documentation>
+ The character(s) used to delimit the scoped information from the scope.
+ </documentation>
+ </annotation>
+ </attribute>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <complexType name="NameIDAttributeDecoder">
+ <annotation>
+ <documentation>
+ Decoder for attributes with NameID values.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="am:AttributeDecoderType">
+ <attribute name="formatter" type="am:string" default="$Name!!$NameQualifier!!$SPNameQualifier">
+ <annotation>
+ <documentation>
+ The pattern used to generate string versions of the attribute's values.
+ </documentation>
+ </annotation>
+ </attribute>
+ </extension>
+ </complexContent>
+ </complexType>
+
+</schema>
\ No newline at end of file
+++ /dev/null
-<schema targetNamespace="urn:mace:shibboleth:2.0:resolver" xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:resolver="urn:mace:shibboleth:2.0:resolver">
-
- <annotation>
- <documentation>Shibboleth 2.0 Attribute Resolver configuration schema</documentation>
- </annotation>
-
- <element name="AttributeResolver" type="resolver:AttributeResolverType">
- <annotation>
- <documentation>Root of the attribute resolver configuration file.</documentation>
- </annotation>
- <keyref name="AttributeDefinitionAttributeDefinitionDependencyRef"
- refer="resolver:AttributeDefinitionDependencyKey">
- <selector xpath="./resolver:AttributeDefinition/resolver:AttributeDefinitionDependency" />
- <field xpath="@ref" />
- </keyref>
- <keyref name="DataConnectorAttributeDefinitionDependencyRef"
- refer="resolver:AttributeDefinitionDependencyKey">
- <selector xpath="./resolver:DataConnector/resolver:AttributeDefinitionDependency" />
- <field xpath="@ref" />
- </keyref>
- <keyref name="PrincipalConnectorAttributeDefinitionDependencyRef"
- refer="resolver:AttributeDefinitionDependencyKey">
- <selector xpath="./resolver:PrincipalConnector/resolver:AttributeDefinitionDependency" />
- <field xpath="@ref" />
- </keyref>
- <key name="AttributeDefinitionDependencyKey">
- <selector xpath="./resolver:AttributeDefinition" />
- <field xpath="@id" />
- </key>
-
- <keyref name="AttributeDefinitionDataConnectorDependencyRef" refer="resolver:DataConnectorDependencyKey">
- <selector xpath="./resolver:AttributeDefinition/resolver:DataConnectorDependency" />
- <field xpath="@ref" />
- </keyref>
- <keyref name="DataConnectorDataConnectorDependencyRef" refer="resolver:DataConnectorDependencyKey">
- <selector xpath="./resolver:DataConnector/resolver:DataConnectorDependency" />
- <field xpath="@ref" />
- </keyref>
- <keyref name="FailoverDataConnectorDataConnectorDependencyRef" refer="resolver:DataConnectorDependencyKey">
- <selector xpath="./resolver:DataConnector/resolver:FailoverDataConnector" />
- <field xpath="@ref" />
- </keyref>
- <keyref name="PrincipalConnectorDataConnectorDependencyRef" refer="resolver:DataConnectorDependencyKey">
- <selector xpath="./resolver:PrincipalConnector/resolver:DataConnectorDependency" />
- <field xpath="@ref" />
- </keyref>
- <key name="DataConnectorDependencyKey">
- <selector xpath="./resolver:DataConnector" />
- <field xpath="@id" />
- </key>
- </element>
- <complexType name="AttributeResolverType">
- <choice minOccurs="0" maxOccurs="unbounded">
- <element ref="resolver:AttributeDefinition" />
- <element ref="resolver:DataConnector" />
- <element ref="resolver:PrincipalConnector" />
- </choice>
- </complexType>
-
- <element name="AttributeDefinition" type="resolver:BaseAttributeDefinitionType">
- <annotation>
- <documentation>Defines an attribute definition within this resolver.</documentation>
- </annotation>
- </element>
- <complexType name="BaseAttributeDefinitionType">
- <annotation>
- <documentation>
- Attribute definition define the finished attributes to be released by the resolver.
- </documentation>
- </annotation>
- <complexContent>
- <extension base="resolver:BaseResolutionPlugInType">
- <sequence>
- <element ref="resolver:AttributeEncoder" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <attribute name="dependencyOnly" type="boolean" default="false">
- <annotation>
- <documentation>
- A boolean flag that indicates whether this attribute definition is only defined becaue its
- data is needed elsewhere within the resolver and as such should not be released outside the
- resolver.
- </documentation>
- </annotation>
- </attribute>
- </extension>
- </complexContent>
- </complexType>
-
- <element name="AttributeEncoder" type="resolver:BaseAttributeEncoderType">
- <annotation>
- <documentation>Defines an encoder for an attribute.</documentation>
- </annotation>
- </element>
- <complexType name="BaseAttributeEncoderType">
- <annotation>
- <documentation>
- An attribute encoder is responsible for converting an attribute, and it's values, into a protocol
- specific representation such as a SAML 1 Attribute or a SAML 2 NameID.
- </documentation>
- </annotation>
- </complexType>
-
- <element name="DataConnector" type="resolver:BaseDataConnectorType">
- <annotation>
- <documentation>
- Defines a data connector which is used to pull information from local infrastructure.
- </documentation>
- </annotation>
- </element>
- <complexType name="BaseDataConnectorType">
- <annotation>
- <documentation>
- Data connectors pull information from local infrastructure, such as databases and LDAP directories, and
- make these raw attributes available to attribute definitions for finishing.
- </documentation>
- </annotation>
- <complexContent>
- <extension base="resolver:BaseResolutionPlugInType">
- <sequence>
- <element ref="resolver:FailoverDataConnector" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- </extension>
- </complexContent>
- </complexType>
-
- <element name="PrincipalConnector" type="resolver:BasePrincipalConnectorType">
- <annotation>
- <documentation>
- Principal connectors convert a subject's NameID into an internal principal name for use within attribute
- definitions and data connectors.
- </documentation>
- </annotation>
- </element>
- <complexType name="BasePrincipalConnectorType">
- <annotation>
- <documentation>
- Principal connectors convert a subject's NameID into an internal principal name for use within attribute
- definitions and data connectors.
- </documentation>
- </annotation>
- <complexContent>
- <extension base="resolver:BaseResolutionPlugInType">
- <sequence>
- <element name="RelyingParty" type="string" minOccurs="0" maxOccurs="unbounded">
- <annotation>
- <documentation>The relying party for which this connector is valid.</documentation>
- </annotation>
- </element>
- </sequence>
- <attribute name="nameIDFormat" type="anyURI" use="required">
- <annotation>
- <documentation>The format of the NameID for which this connector is valid.</documentation>
- </annotation>
- </attribute>
- </extension>
- </complexContent>
- </complexType>
-
- <complexType name="BaseResolutionPlugInType" abstract="true">
- <annotation>
- <documentation>
- A base type for all attribute resolver plugins: data and principal connectors and attribute definitions
- </documentation>
- </annotation>
- <choice minOccurs="0" maxOccurs="unbounded">
- <element ref="resolver:AttributeDefinitionDependency" minOccurs="0" maxOccurs="unbounded" />
- <element ref="resolver:DataConnectorDependency" minOccurs="0" maxOccurs="unbounded" />
- </choice>
- <attribute name="id" type="string" use="required">
- <annotation>
- <documentation>A unique identifier for this definition.</documentation>
- </annotation>
- </attribute>
- <attribute name="propagateErrors" type="boolean" default="true">
- <annotation>
- <documentation>
- A boolean flag indiciating whether errors within a definition should be propogated outside the
- resolver. Errors exposed outside the resolver will likely result in an error being returned to the
- relying party.
- </documentation>
- </annotation>
- </attribute>
- </complexType>
-
- <element name="AttributeDefinitionDependency" type="resolver:PluginDependencyType">
- <annotation>
- <documentation>Defines a dependency on a specific attribute definition.</documentation>
- </annotation>
- </element>
- <element name="DataConnectorDependency" type="resolver:PluginDependencyType">
- <annotation>
- <documentation>Defines a dependency on a specific data connector.</documentation>
- </annotation>
- </element>
- <element name="FailoverDataConnector" type="resolver:PluginDependencyType">
- <annotation>
- <documentation>Defines a data connector to use should the parent data connector fail.</documentation>
- </annotation>
- </element>
- <complexType name="PluginDependencyType">
- <annotation>
- <documentation>A type that represents a reference to another plugin</documentation>
- </annotation>
- <attribute name="ref" type="string" use="required" />
- </complexType>
-
-</schema>
\ No newline at end of file
<?xml version="1.0" encoding="US-ASCII"?>\r
-<schema targetNamespace="urn:mace:shibboleth:sp:config:2.0"\r
+<schema targetNamespace="urn:mace:shibboleth:2.0:native:sp:config"\r
xmlns="http://www.w3.org/2001/XMLSchema"\r
xmlns:conf="urn:mace:shibboleth:sp:config:2.0"\r
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"\r
\r
<annotation>\r
<documentation>\r
- 2.0 schema for XML-based configuration of Shibboleth SP instances.\r
+ 2.0 schema for XML-based configuration of Shibboleth Native SP instances.\r
First appearing in Shibboleth 2.0 release.\r
</documentation>\r
</annotation>\r
<element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>
<element name="MetadataProvider" type="conf:PluggableType"/>
<element name="TrustEngine" type="conf:PluggableType"/>\r
- <element name="AttributeResolver" type="conf:PluggableType"/>\r
+ <element name="AttributeExtractor" type="conf:PluggableType" minOccurs="0"/>\r
+ <element name="AttributeResolver" type="conf:PluggableType" minOccurs="0"/>\r
+ <element name="AttributeFilter" type="conf:PluggableType" minOccurs="0"/>\r
<element name="CredentialResolver" type="conf:PluggableType" minOccurs="0"/>\r
<element ref="conf:Application" minOccurs="0" maxOccurs="unbounded"/>\r
</sequence>\r
<attribute name="entityID" type="anyURI" use="required"/>\r
<attribute name="policyId" type="conf:string" use="required"/>\r
<attribute name="homeURL" type="anyURI" default="/"/>\r
- <attribute name="attributeIds" type="conf:listOfStrings"/>\r
<anyAttribute namespace="##other" processContents="lax"/>\r
</complexType>\r
</element>\r
<element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>\r
<element name="MetadataProvider" type="conf:PluggableType" minOccurs="0"/>\r
<element name="TrustEngine" type="conf:PluggableType" minOccurs="0"/>\r
+ <element name="AttributeExtractor" type="conf:PluggableType" minOccurs="0"/>\r
<element name="AttributeResolver" type="conf:PluggableType" minOccurs="0"/>\r
+ <element name="AttributeFilter" type="conf:PluggableType" minOccurs="0"/>\r
<element name="CredentialResolver" type="conf:PluggableType" minOccurs="0"/>\r
</sequence>\r
<attribute name="id" type="conf:string" use="required"/>\r
<attribute name="entityID" type="anyURI"/>\r
<attribute name="policyId" type="conf:string"/>\r
<attribute name="homeURL" type="anyURI" default="/"/>\r
- <attribute name="attributeIds" type="conf:listOfStrings"/>\r
<anyAttribute namespace="##other" processContents="lax"/>\r
</complexType>\r
</element>\r
+++ /dev/null
-<schema targetNamespace="urn:mace:shibboleth:2.0:resolver:simple" xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:resolver="urn:mace:shibboleth:2.0:resolver:simple"
- xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
-
- <annotation>
- <documentation>Shibboleth 2.0 Simple Attribute Resolver configuration schema</documentation>
- </annotation>
-
- <import namespace="urn:oasis:names:tc:SAML:2.0:assertion" schemaLocation="saml-schema-assertion-2.0.xsd"/>
-
- <element name="AttributeResolver" type="resolver:AttributeResolverType">
- <annotation>
- <documentation>Root of the simple attribute resolver configuration file.</documentation>
- </annotation>
- </element>
- <complexType name="AttributeResolverType">
- <sequence>
- <element ref="resolver:AttributeDecoder" maxOccurs="unbounded"/>
- <element ref="saml:Attribute" maxOccurs="unbounded"/>
- </sequence>
- <attribute name="allowQuery" type="boolean" default="true"/>
- </complexType>
-
- <element name="AttributeDecoder">
- <annotation>
- <documentation>Instantiates decoders for use by Attribute definitions.</documentation>
- </annotation>
- <complexType>
- <sequence>
- <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- <attribute name="type" type="resolver:string" use="required"/>
- <attribute name="id" type="ID" use="required"/>
- <anyAttribute namespace="##any" processContents="lax"/>
- </complexType>
- </element>
-
- <simpleType name="string">
- <restriction base="string">
- <minLength value="1"/>
- </restriction>
- </simpleType>
-
- <attribute name="decoderId" type="IDREF"/>
-</schema>
namespace shibsp {
+ class SHIBSP_API AttributeExtractor;
class SHIBSP_API AttributeResolver;
class SHIBSP_API Handler;
class SHIBSP_API ServiceProvider;
virtual xmltooling::TrustEngine* getTrustEngine() const=0;
/**
- * Returns an AttributeResolver for use with this Application.
+ * Returns an AttributeExtractor for use with this Application.
*
- * @return an AttributeResolver, or NULL
+ * @return an AttributeExtractor, or NULL
*/
- virtual AttributeResolver* getAttributeResolver() const=0;
+ virtual AttributeExtractor* getAttributeExtractor() const=0;
/**
- * Returns a set of attribute IDs to resolve for the Application.
- *
- * @return a set of attribute IDs, or an empty set
+ * Returns an AttributeResolver for use with this Application.
+ *
+ * @return an AttributeResolver, or NULL
*/
- virtual const std::set<std::string>* getAttributeIds() const=0;
+ virtual AttributeResolver* getAttributeResolver() const=0;
/**
* Returns the CredentialResolver instance associated with this Application.
attribute/SimpleAttribute.h
attrresinclude_HEADERS = \
+ attribute/resolver/AttributeExtractor.h \
attribute/resolver/AttributeResolver.h \
attribute/resolver/ResolutionContext.h
SPConfig.cpp \
attribute/Attribute.cpp \
attribute/NameIDAttributeDecoder.cpp \
- attribute/SimpleAttributeDecoder.cpp \
attribute/ScopedAttributeDecoder.cpp \
- attribute/resolver/impl/AttributeResolver.cpp \
- attribute/resolver/impl/SimpleAttributeResolver.cpp \
+ attribute/StringAttributeDecoder.cpp \
+ attribute/resolver/impl/QueryAttributeResolver.cpp \
+ attribute/resolver/impl/XMLAttributeExtractor.cpp \
binding/impl/ArtifactResolver.cpp \
binding/impl/SOAPClient.cpp \
handler/impl/AbstractHandler.cpp \
#include "SessionCache.h"
#include "SPConfig.h"
#include "attribute/AttributeDecoder.h"
+#include "attribute/resolver/AttributeExtractor.h"
#include "attribute/resolver/AttributeResolver.h"
#include "binding/ArtifactResolver.h"
#include "handler/SessionInitiator.h"
using namespace log4cpp;
DECL_XMLTOOLING_EXCEPTION_FACTORY(AttributeException,shibsp);
+DECL_XMLTOOLING_EXCEPTION_FACTORY(AttributeExtractionException,shibsp);
+DECL_XMLTOOLING_EXCEPTION_FACTORY(AttributeFilteringException,shibsp);
DECL_XMLTOOLING_EXCEPTION_FACTORY(AttributeResolutionException,shibsp);
DECL_XMLTOOLING_EXCEPTION_FACTORY(ConfigurationException,shibsp);
DECL_XMLTOOLING_EXCEPTION_FACTORY(ListenerException,shibsp);
XMLToolingConfig::getConfig().getTemplateEngine()->setTagPrefix("shibmlp");
REGISTER_XMLTOOLING_EXCEPTION_FACTORY(AttributeException,shibsp);
+ REGISTER_XMLTOOLING_EXCEPTION_FACTORY(AttributeExtractionException,shibsp);
+ REGISTER_XMLTOOLING_EXCEPTION_FACTORY(AttributeFilteringException,shibsp);
REGISTER_XMLTOOLING_EXCEPTION_FACTORY(AttributeResolutionException,shibsp);
REGISTER_XMLTOOLING_EXCEPTION_FACTORY(ConfigurationException,shibsp);
REGISTER_XMLTOOLING_EXCEPTION_FACTORY(ListenerException,shibsp);
registerAccessControls();
registerAttributeDecoders();
+ registerAttributeExtractors();
registerAttributeFactories();
registerAttributeResolvers();
registerHandlers();
RequestMapperManager.deregisterFactories();
ListenerServiceManager.deregisterFactories();
HandlerManager.deregisterFactories();
- AttributeResolverManager.deregisterFactories();
AttributeDecoderManager.deregisterFactories();
+ AttributeExtractorManager.deregisterFactories();
+ AttributeResolverManager.deregisterFactories();
Attribute::deregisterFactories();
AccessControlManager.deregisterFactories();
class SHIBSP_API AccessControl;
class SHIBSP_API AttributeDecoder;
+ class SHIBSP_API AttributeExtractor;
class SHIBSP_API AttributeResolver;
class SHIBSP_API Handler;
class SHIBSP_API ListenerService;
/**
* Manages factories for AccessControl plugins.
*/
- xmltooling::PluginManager<AccessControl,const xercesc::DOMElement*> AccessControlManager;
+ xmltooling::PluginManager<AccessControl,std::string,const xercesc::DOMElement*> AccessControlManager;
/**
* Manages factories for AttributeDecoder plugins.
*/
- xmltooling::PluginManager<AttributeDecoder,const xercesc::DOMElement*> AttributeDecoderManager;
+ xmltooling::PluginManager<AttributeDecoder,xmltooling::QName,const xercesc::DOMElement*> AttributeDecoderManager;
+
+ /**
+ * Manages factories for AttributeExtractor plugins.
+ */
+ xmltooling::PluginManager<AttributeExtractor,std::string,const xercesc::DOMElement*> AttributeExtractorManager;
/**
* Manages factories for AttributeResolver plugins.
*/
- xmltooling::PluginManager<AttributeResolver,const xercesc::DOMElement*> AttributeResolverManager;
+ xmltooling::PluginManager<AttributeResolver,std::string,const xercesc::DOMElement*> AttributeResolverManager;
/**
* Manages factories for Handler plugins that implement AssertionConsumerService functionality.
*/
- xmltooling::PluginManager< Handler,std::pair<const xercesc::DOMElement*,const char*> > AssertionConsumerServiceManager;
+ xmltooling::PluginManager< Handler,std::string,std::pair<const xercesc::DOMElement*,const char*> > AssertionConsumerServiceManager;
/**
* Manages factories for Handler plugins that implement customized functionality.
*/
- xmltooling::PluginManager< Handler,std::pair<const xercesc::DOMElement*,const char*> > HandlerManager;
+ xmltooling::PluginManager< Handler,std::string,std::pair<const xercesc::DOMElement*,const char*> > HandlerManager;
/**
* Manages factories for ListenerService plugins.
*/
- xmltooling::PluginManager<ListenerService,const xercesc::DOMElement*> ListenerServiceManager;
+ xmltooling::PluginManager<ListenerService,std::string,const xercesc::DOMElement*> ListenerServiceManager;
/**
* Manages factories for Handler plugins that implement ManageNameIDService functionality.
*/
- xmltooling::PluginManager< Handler,std::pair<const xercesc::DOMElement*,const char*> > ManageNameIDServiceManager;
+ xmltooling::PluginManager< Handler,std::string,std::pair<const xercesc::DOMElement*,const char*> > ManageNameIDServiceManager;
/**
* Manages factories for RequestMapper plugins.
*/
- xmltooling::PluginManager<RequestMapper,const xercesc::DOMElement*> RequestMapperManager;
+ xmltooling::PluginManager<RequestMapper,std::string,const xercesc::DOMElement*> RequestMapperManager;
/**
* Manages factories for ServiceProvider plugins.
*/
- xmltooling::PluginManager<ServiceProvider,const xercesc::DOMElement*> ServiceProviderManager;
+ xmltooling::PluginManager<ServiceProvider,std::string,const xercesc::DOMElement*> ServiceProviderManager;
/**
* Manages factories for SessionCache plugins.
*/
- xmltooling::PluginManager<SessionCache,const xercesc::DOMElement*> SessionCacheManager;
+ xmltooling::PluginManager<SessionCache,std::string,const xercesc::DOMElement*> SessionCacheManager;
/**
* Manages factories for Handler plugins that implement SessionInitiator functionality.
*/
- xmltooling::PluginManager< SessionInitiator,std::pair<const xercesc::DOMElement*,const char*> > SessionInitiatorManager;
+ xmltooling::PluginManager< SessionInitiator,std::string,std::pair<const xercesc::DOMElement*,const char*> > SessionInitiatorManager;
/**
* Manages factories for Handler plugins that implement SingleLogoutService functionality.
*/
- xmltooling::PluginManager< Handler,std::pair<const xercesc::DOMElement*,const char*> > SingleLogoutServiceManager;
+ xmltooling::PluginManager< Handler,std::string,std::pair<const xercesc::DOMElement*,const char*> > SingleLogoutServiceManager;
protected:
SPConfig() : attribute_value_delimeter(';'), m_serviceProvider(NULL), m_artifactResolver(NULL), m_features(0) {}
using namespace std;
namespace shibsp {
- SHIBSP_DLLLOCAL PluginManager<ServiceProvider,const DOMElement*>::Factory XMLServiceProviderFactory;
+ SHIBSP_DLLLOCAL PluginManager<ServiceProvider,string,const DOMElement*>::Factory XMLServiceProviderFactory;
long SHIBSP_DLLLOCAL sendError(SPRequest& request, const Application* app, const char* page, TemplateParameters& tp, bool mayRedirect=false)
{
}
// Export the attributes.
- const map<string,const Attribute*>& attributes = session->getAttributes();
- for (map<string,const Attribute*>::const_iterator a = attributes.begin(); a!=attributes.end(); ++a) {
+ const multimap<string,Attribute*>& attributes = session->getAttributes();
+ for (multimap<string,Attribute*>::const_iterator a = attributes.begin(); a!=attributes.end(); ++a) {
const vector<string>& vals = a->second->getSerializedValues();
- if (!strcmp(a->second->getId(), "REMOTE_USER") && !vals.empty())
+ if (a->first == "REMOTE_USER" && !vals.empty())
request.setRemoteUser(vals.front().c_str());
else {
- string header(request.getSecureHeader(a->second->getId()));
+ string header(request.getSecureHeader(a->first.c_str()));
for (vector<string>::const_iterator v = vals.begin(); v!=vals.end(); ++v) {
if (!header.empty())
header += ";";
header += (*v);
}
}
- request.setHeader(a->second->getId(), header.c_str());
+ request.setHeader(a->first.c_str(), header.c_str());
}
}
\r
namespace shibsp {\r
\r
- SHIBSP_DLLLOCAL PluginManager<SessionCache,const DOMElement*>::Factory RemotedCacheFactory;\r
- SHIBSP_DLLLOCAL PluginManager<SessionCache,const DOMElement*>::Factory StorageServiceCacheFactory;\r
+ SHIBSP_DLLLOCAL PluginManager<SessionCache,std::string,const DOMElement*>::Factory RemotedCacheFactory;\r
+ SHIBSP_DLLLOCAL PluginManager<SessionCache,std::string,const DOMElement*>::Factory StorageServiceCacheFactory;\r
\r
static const XMLCh cacheTimeout[] = UNICODE_LITERAL_12(c,a,c,h,e,T,i,m,e,o,u,t);\r
}\r
*
* @return an immutable map of attributes keyed by attribute ID
*/
- virtual const std::map<std::string,const Attribute*>& getAttributes() const=0;
+ virtual const std::multimap<std::string,Attribute*>& getAttributes() const=0;
/**
* Adds additional attributes to the session.
* @param authncontext_class method/category of authentication event, if known
* @param authncontext_decl specifics of authentication event, if known
* @param tokens assertions to cache with session, if any
- * @param attributes optional set of resolved Attributes to cache with session
+ * @param attributes optional map of resolved Attributes to cache with session
* @return newly created session's key
*/
virtual std::string insert(
const char* authncontext_class=NULL,
const char* authncontext_decl=NULL,
const std::vector<const opensaml::Assertion*>* tokens=NULL,
- const std::vector<Attribute*>* attributes=NULL
+ const std::multimap<std::string,Attribute*>* attributes=NULL
)=0;
/**
*/
#include "internal.h"
+#include "SPConfig.h"
#include "attribute/AttributeDecoder.h"
#include "attribute/SimpleAttribute.h"
#include "attribute/ScopedAttribute.h"
#include "attribute/NameIDAttribute.h"
+#include "util/SPConstants.h"
-#include <shibsp/SPConfig.h>
+#include <xercesc/util/XMLUniDefs.hpp>
using namespace shibsp;
using namespace xmltooling;
return new NameIDAttribute(in);
}
- SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,const DOMElement*>::Factory SimpleAttributeDecoderFactory;
- SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,const DOMElement*>::Factory ScopedAttributeDecoderFactory;
- SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,const DOMElement*>::Factory NameIDAttributeDecoderFactory;
+ SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,QName,const DOMElement*>::Factory StringAttributeDecoderFactory;
+ SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,QName,const DOMElement*>::Factory ScopedAttributeDecoderFactory;
+ SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,QName,const DOMElement*>::Factory NameIDAttributeDecoderFactory;
+
+ static const XMLCh _StringAttributeDecoder[] = UNICODE_LITERAL_22(S,t,r,i,n,g,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
+ static const XMLCh _ScopedAttributeDecoder[] = UNICODE_LITERAL_22(S,c,o,p,e,d,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
+ static const XMLCh _NameIDAttributeDecoder[] = UNICODE_LITERAL_22(N,a,m,e,I,D,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
+
+ static const XMLCh caseSensitive[] = UNICODE_LITERAL_13(c,a,s,e,S,e,n,s,i,t,i,v,e);
};
+QName shibsp::StringAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _StringAttributeDecoder);
+QName shibsp::ScopedAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _ScopedAttributeDecoder);
+QName shibsp::NameIDAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _NameIDAttributeDecoder);
+
void shibsp::registerAttributeDecoders()
{
SPConfig& conf = SPConfig::getConfig();
- conf.AttributeDecoderManager.registerFactory(SIMPLE_ATTRIBUTE_DECODER, SimpleAttributeDecoderFactory);
- conf.AttributeDecoderManager.registerFactory(SCOPED_ATTRIBUTE_DECODER, ScopedAttributeDecoderFactory);
- conf.AttributeDecoderManager.registerFactory(NAMEID_ATTRIBUTE_DECODER, NameIDAttributeDecoderFactory);
+ conf.AttributeDecoderManager.registerFactory(StringAttributeDecoderType, StringAttributeDecoderFactory);
+ conf.AttributeDecoderManager.registerFactory(ScopedAttributeDecoderType, ScopedAttributeDecoderFactory);
+ conf.AttributeDecoderManager.registerFactory(NameIDAttributeDecoderType, NameIDAttributeDecoderFactory);
}
void shibsp::registerAttributeFactories()
throw AttributeException("No registered factory for Attribute of type ($1).", xmltooling::params(1,in.name()));
return (i->second)(in);
}
+
+AttributeDecoder::AttributeDecoder(const DOMElement *e) : m_caseSensitive(true)
+{
+ if (e) {
+ const XMLCh* flag = e->getAttributeNS(NULL,caseSensitive);
+ if (flag && (*flag == chLatin_f || *flag == chDigit_0))
+ m_caseSensitive = false;
+ }
+}
*
* @param id Attribute identifier
*/
- Attribute(const char* id) : m_id(id ? id : "") {
+ Attribute(const char* id) : m_id(id ? id : ""), m_caseSensitive(true) {
}
/**
*
* @param in input object containing marshalled Attribute
*/
- Attribute(DDF& in) {
+ Attribute(DDF& in) : m_caseSensitive(in["case_insensitive"].isnull()) {
const char* id = in.first().name();
if (id && *id)
m_id = id;
}
/**
+ * Sets whether case sensitivity should apply to basic value comparisons.
+ *
+ * @param caseSensitive true iff value comparisons should be case sensitive
+ */
+ void setCaseSensitive(bool caseSensitive) {
+ m_caseSensitive = caseSensitive;
+ }
+
+ /**
* Indicates whether case sensitivity should apply to basic value comparisons.
*
* @return true iff value comparisons should be case sensitive
*/
- virtual bool isCaseSensitive() const {
- return true;
+ bool isCaseSensitive() const {
+ return m_caseSensitive;
}
/**
virtual DDF marshall() const {
DDF ddf(NULL);
ddf.structure().addmember(m_id.c_str()).list();
+ if (!m_caseSensitive)
+ ddf.addmember("case_insensitive");
return ddf;
}
private:
static std::map<std::string,AttributeFactory*> m_factoryMap;
std::string m_id;
+ bool m_caseSensitive;
};
#if defined (_MSC_VER)
{
MAKE_NONCOPYABLE(AttributeDecoder);
protected:
- AttributeDecoder() {}
+ /**
+ * Constructor.
+ *
+ * @param e root of DOM to configure the decoder
+ */
+ AttributeDecoder(const xercesc::DOMElement* e);
+
+ /** Flag for case sensitivity of decoded attributes. */
+ bool m_caseSensitive;
+
public:
virtual ~AttributeDecoder() {}
) const=0;
};
- /** Decodes SimpleAttributes */
- #define SIMPLE_ATTRIBUTE_DECODER "Simple"
+
+ /** Decodes into a SimpleAttribute. */
+ extern SHIBSP_API xmltooling::QName StringAttributeDecoderType;
- /** Decodes ScopedAttributes */
- #define SCOPED_ATTRIBUTE_DECODER "Scoped"
+ /** Decodes into a ScopedAttribute. */
+ extern SHIBSP_API xmltooling::QName ScopedAttributeDecoderType;
- /** Decodes NameIDAttributes */
- #define NAMEID_ATTRIBUTE_DECODER "NameID"
+ /** Decodes into a NameIDAttribute. */
+ extern SHIBSP_API xmltooling::QName NameIDAttributeDecoderType;
/** Registers built-in AttributeDecoders into the runtime. */
void registerAttributeDecoders();
class SHIBSP_DLLLOCAL NameIDAttributeDecoder : virtual public AttributeDecoder\r
{\r
public:\r
- NameIDAttributeDecoder(const DOMElement* e) : m_formatter(e ? e->getAttributeNS(NULL,formatter) : NULL) {}\r
+ NameIDAttributeDecoder(const DOMElement* e) : AttributeDecoder(e), m_formatter(e ? e->getAttributeNS(NULL,formatter) : NULL) {}\r
~NameIDAttributeDecoder() {}\r
\r
shibsp::Attribute* decode(\r
auto_ptr<NameIDAttribute> nameid(\r
new NameIDAttribute(id, (m_formatter.get() && *m_formatter.get()) ? m_formatter.get() : DEFAULT_NAMEID_FORMATTER)\r
);\r
+ nameid->setCaseSensitive(m_caseSensitive);\r
vector<NameIDAttribute::Value>& dest = nameid->getValues();\r
vector<XMLObject*>::const_iterator v,stop;\r
\r
*
* @param id Attribute identifier
*/
- ScopedAttribute(const char* id) : Attribute(id), m_caseSensitive(true) {}
+ ScopedAttribute(const char* id) : Attribute(id) {}
/**
* Constructs based on a remoted ScopedAttribute.
*
* @param in input object containing marshalled ScopedAttribute
*/
- ScopedAttribute(DDF& in) : Attribute(in), m_caseSensitive(in["case_insensitive"].isnull()) {
+ ScopedAttribute(DDF& in) : Attribute(in) {
DDF val = in.first().first();
while (val.name() && val.string()) {
m_values.push_back(std::make_pair(val.name(), val.string()));
virtual ~ScopedAttribute() {}
- bool isCaseSensitive() const {
- return m_caseSensitive;
- }
-
/**
* Returns the set of values encoded as UTF-8 strings.
*
DDF marshall() const {
DDF ddf = Attribute::marshall();
ddf.name("Scoped");
- if (!m_caseSensitive)
- ddf.addmember("case_insensitive");
DDF vlist = ddf.first();
for (std::vector< std::pair<std::string,std::string> >::const_iterator i=m_values.begin(); i!=m_values.end(); ++i) {
DDF val = DDF(i->first.c_str()).string(i->second.c_str());
}
private:
- bool m_caseSensitive;
std::vector< std::pair<std::string,std::string> > m_values;
};
using namespace std;\r
\r
namespace shibsp {\r
+ static const XMLCh Scope[] = UNICODE_LITERAL_5(S,c,o,p,e);\r
+ static const XMLCh scopeDelimeter[] = UNICODE_LITERAL_14(s,c,o,p,e,D,e,l,i,m,e,t,e,r);\r
+\r
class SHIBSP_DLLLOCAL ScopedAttributeDecoder : virtual public AttributeDecoder\r
{\r
public:\r
- ScopedAttributeDecoder(const DOMElement* e) {}\r
+ ScopedAttributeDecoder(const DOMElement* e) : AttributeDecoder(e), m_delimeter('@') {\r
+ if (e) {\r
+ if (e->hasAttributeNS(NULL,scopeDelimeter)) {\r
+ auto_ptr_char d(e->getAttributeNS(NULL,scopeDelimeter));\r
+ m_delimeter = *(d.get());\r
+ }\r
+ }\r
+ }\r
~ScopedAttributeDecoder() {}\r
\r
shibsp::Attribute* decode(\r
const char* id, const XMLObject* xmlObject, const char* assertingParty=NULL, const char* relyingParty=NULL\r
) const;\r
+\r
+ private:\r
+ char m_delimeter;\r
};\r
\r
AttributeDecoder* SHIBSP_DLLLOCAL ScopedAttributeDecoderFactory(const DOMElement* const & e)\r
{\r
return new ScopedAttributeDecoder(e);\r
}\r
-\r
- static const XMLCh Scope[] = UNICODE_LITERAL_5(S,c,o,p,e);\r
};\r
\r
shibsp::Attribute* ScopedAttributeDecoder::decode(\r
const XMLCh* xmlscope;\r
QName scopeqname(NULL,Scope);\r
auto_ptr<ScopedAttribute> scoped(new ScopedAttribute(id));\r
+ scoped->setCaseSensitive(m_caseSensitive);\r
vector< pair<string,string> >& dest = scoped->getValues();\r
vector<XMLObject*>::const_iterator v,stop;\r
\r
delete[] scope;\r
}\r
else {\r
- scope = strchr(val, '@');\r
+ scope = strchr(val, m_delimeter);\r
if (scope) {\r
*scope++ = 0;\r
if (*scope)\r
}\r
}\r
\r
- if (val && *val && *val!='@') {\r
- scope = strchr(val, '@');\r
+ if (val && *val && *val!=m_delimeter) {\r
+ scope = strchr(val, m_delimeter);\r
if (scope) {\r
*scope++ = 0;\r
if (*scope)\r
log.warn("ignoring NameID with no scope");\r
}\r
else {\r
- log.warn("ignoring NameID with no scope delimiter (@)");\r
+ log.warn("ignoring NameID with no scope delimiter (%c)", m_delimeter);\r
}\r
}\r
else {\r
*
* @param id Attribute identifier
*/
- SimpleAttribute(const char* id) : Attribute(id), m_caseSensitive(true) {}
+ SimpleAttribute(const char* id) : Attribute(id) {}
/**
* Constructs based on a remoted SimpleAttribute.
*
* @param in input object containing marshalled SimpleAttribute
*/
- SimpleAttribute(DDF& in) : Attribute(in), m_caseSensitive(in["case_insensitive"].isnull()) {
+ SimpleAttribute(DDF& in) : Attribute(in) {
DDF val = in.first().first();
while (val.string()) {
m_serialized.push_back(val.string());
virtual ~SimpleAttribute() {}
- bool isCaseSensitive() const {
- return m_caseSensitive;
- }
-
/**
* Returns the set of values encoded as UTF-8 strings.
*
DDF marshall() const {
DDF ddf = Attribute::marshall();
- if (!m_caseSensitive)
- ddf.addmember("case_insensitive");
DDF vlist = ddf.first();
for (std::vector<std::string>::const_iterator i=m_serialized.begin(); i!=m_serialized.end(); ++i)
vlist.add(DDF(NULL).string(i->c_str()));
return ddf;
}
-
- private:
- bool m_caseSensitive;
};
};
*/\r
\r
/**\r
- * SimpleAttributeDecoder.cpp\r
+ * StringAttributeDecoder.cpp\r
* \r
* Decodes SAML into SimpleAttributes\r
*/\r
using namespace std;\r
\r
namespace shibsp {\r
- class SHIBSP_DLLLOCAL SimpleAttributeDecoder : virtual public AttributeDecoder\r
+ class SHIBSP_DLLLOCAL StringAttributeDecoder : virtual public AttributeDecoder\r
{\r
public:\r
- SimpleAttributeDecoder(const DOMElement* e) {}\r
- ~SimpleAttributeDecoder() {}\r
+ StringAttributeDecoder(const DOMElement* e) : AttributeDecoder(e) {}\r
+ ~StringAttributeDecoder() {}\r
\r
shibsp::Attribute* decode(\r
const char* id, const XMLObject* xmlObject, const char* assertingParty=NULL, const char* relyingParty=NULL\r
) const;\r
};\r
\r
- AttributeDecoder* SHIBSP_DLLLOCAL SimpleAttributeDecoderFactory(const DOMElement* const & e)\r
+ AttributeDecoder* SHIBSP_DLLLOCAL StringAttributeDecoderFactory(const DOMElement* const & e)\r
{\r
- return new SimpleAttributeDecoder(e);\r
+ return new StringAttributeDecoder(e);\r
}\r
};\r
\r
-shibsp::Attribute* SimpleAttributeDecoder::decode(\r
+shibsp::Attribute* StringAttributeDecoder::decode(\r
const char* id, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty\r
) const\r
{\r
char* val;\r
auto_ptr<SimpleAttribute> simple(new SimpleAttribute(id));\r
+ simple->setCaseSensitive(m_caseSensitive);\r
vector<string>& dest = simple->getValues();\r
vector<XMLObject*>::const_iterator v,stop;\r
\r
}\r
}\r
else {\r
- log.warn("XMLObject type not recognized by SimpleAttributeDecoder, no values returned");\r
+ log.warn("XMLObject type not recognized by StringAttributeDecoder, no values returned");\r
return NULL;\r
}\r
}\r
val = toUTF8(saml1name->getName());\r
}\r
else {\r
- log.warn("XMLObject type not recognized by SimpleAttributeDecoder, no values returned");\r
+ log.warn("XMLObject type not recognized by StringAttributeDecoder, no values returned");\r
return NULL;\r
}\r
}\r
--- /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.
+ */
+
+/**
+ * @file shibsp/attribute/resolver/AttributeExtractor.h
+ *
+ * A service that extracts and decodes attributes from XML objects.
+ */
+
+#ifndef __shibsp_extractor_h__
+#define __shibsp_extractor_h__
+
+#include <shibsp/base.h>
+
+#include <saml/saml2/metadata/Metadata.h>
+#include <xmltooling/Lockable.h>
+
+namespace shibsp {
+
+ class SHIBSP_API Application;
+ class SHIBSP_API Attribute;
+
+ /**
+ * A service that extracts and decodes attributes from XML objects.
+ */
+ class SHIBSP_API AttributeExtractor : public virtual xmltooling::Lockable
+ {
+ MAKE_NONCOPYABLE(AttributeExtractor);
+ protected:
+ AttributeExtractor() {}
+ public:
+ virtual ~AttributeExtractor() {}
+
+ /**
+ * Extracts the attributes found in an XMLObject.
+ *
+ * @param application Application performing the extraction
+ * @param issuer source of object, if known
+ * @param xmlObject object to extract
+ * @param attributes a map to populate with the extracted attributes, keyed by id
+ *
+ * @throws AttributeExtractionException thrown if there is a problem extracting attributes
+ */
+ virtual void extractAttributes(
+ const Application& application,
+ const opensaml::saml2md::RoleDescriptor* issuer,
+ const xmltooling::XMLObject& xmlObject,
+ std::multimap<std::string,Attribute*>& attributes
+ ) const=0;
+ };
+
+ /**
+ * Registers AttributeExtractor classes into the runtime.
+ */
+ void SHIBSP_API registerAttributeExtractors();
+
+ /** AttributeExtractor based on an XML mapping schema. */
+ #define XML_ATTRIBUTE_EXTRACTOR "XML"
+};
+
+#endif /* __shibsp_extractor_h__ */
/**
* @file shibsp/attribute/resolver/AttributeResolver.h
*
- * The service that resolves the attributes for a particular subject.
+ * A service that transforms or resolves additional attributes for a particular subject.
*/
#ifndef __shibsp_resolver_h__
* Attributes can be supplied while creating the session.
*
* @param application reference to Application that owns the eventual Session
- * @param client_addr network address of client
* @param issuer issuing metadata of assertion issuer, if known
* @param nameid principal identifier, normalized to SAML 2, if any
* @param tokens assertions initiating the session, if any
+ * @param attributes map of previously resolved attributes, if any
* @return newly created ResolutionContext, owned by caller
*/
virtual ResolutionContext* createResolutionContext(
const Application& application,
- const char* client_addr,
const opensaml::saml2md::EntityDescriptor* issuer,
const opensaml::saml2::NameID* nameid,
- const std::vector<const opensaml::Assertion*>* tokens=NULL
+ const std::vector<const opensaml::Assertion*>* tokens=NULL,
+ const std::multimap<std::string,Attribute*>* attributes=NULL
) const=0;
/**
/**
- * Gets the attributes for a given subject and returns them in the supplied context.
+ * Resolves attributes for a given subject and returns them in the supplied context.
*
* @param ctx resolution context to use to resolve attributes
- * @param attributes set of attributes to resolve or NULL to resolve all attributes
*
* @throws AttributeResolutionException thrown if there is a problem resolving the attributes for the subject
*/
- virtual void resolveAttributes(ResolutionContext& ctx, const std::set<std::string>* attributes=NULL) const=0;
+ virtual void resolveAttributes(ResolutionContext& ctx) const=0;
};
#if defined (_MSC_VER)
*/
void SHIBSP_API registerAttributeResolvers();
- /** AttributeResolver based on a simple mapping of SAML information. */
- #define SIMPLE_ATTRIBUTE_RESOLVER "Simple"
+ /** AttributeResolver based on SAML queries to an IdP during SSO. */
+ #define QUERY_ATTRIBUTE_RESOLVER "Query"
};
#endif /* __shibsp_resolver_h__ */
#include <shibsp/base.h>
#include <saml/Assertion.h>
-#include <saml/saml2/metadata/Metadata.h>
namespace shibsp {
ResolutionContext() {}
public:
virtual ~ResolutionContext() {}
-
- /**
- * Returns the application resolving the attributes.
- *
- * @return the resolving application
- */
- virtual const Application& getApplication() const=0;
-
- /**
- * Returns the address of the client associated with the subject.
- *
- * @return the client's network address
- */
- virtual const char* getClientAddress() const=0;
-
- /**
- * Returns the metadata for the IdP associated with the subject, if any.
- *
- * @return the IdP's metadata, or NULL
- */
- virtual const opensaml::saml2md::EntityDescriptor* getEntityDescriptor() const=0;
-
- /**
- * Returns the NameID associated with the subject
- *
- * <p>SAML 1.x identifiers will be promoted to the 2.0 type.
- *
- * @return a SAML 2.0 NameID associated with the subject, if any
- */
- virtual const opensaml::saml2::NameID* getNameID() const=0;
-
- /**
- * Returns unresolved tokens associated with the subject, if any.
- *
- * @return pointer to an array of tokens, or NULL
- */
- virtual const std::vector<const opensaml::Assertion*>* getTokens() const=0;
-
- /**
- * Returns the active session associated with the subject, if any.
- *
- * @return the active, locked session, or NULL
- */
- virtual const Session* getSession() const=0;
/**
* Returns the set of Attributes resolved and added to the context.
*
* @return a mutable array of Attributes.
*/
- virtual std::vector<Attribute*>& getResolvedAttributes()=0;
+ virtual std::multimap<std::string,Attribute*>& getResolvedAttributes()=0;
/**
* Returns the set of assertions resolved and added to the context.
+++ /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.
- */
-
-/**
- * AttributeResolver.cpp
- *
- * The service that resolves the attributes for a particular subject.
- */
-
-#include "internal.h"
-#include "attribute/resolver/AttributeResolver.h"
-
-#include <xercesc/dom/DOM.hpp>
-
-using namespace shibsp;
-using namespace xmltooling;
-using namespace xercesc;
-using namespace std;
-
-namespace shibsp {
- SHIBSP_DLLLOCAL PluginManager<AttributeResolver,const DOMElement*>::Factory SimpleAttributeResolverFactory;
-};
-
-void SHIBSP_API shibsp::registerAttributeResolvers()
-{
- SPConfig& conf=SPConfig::getConfig();
- conf.AttributeResolverManager.registerFactory(SIMPLE_ATTRIBUTE_RESOLVER, SimpleAttributeResolverFactory);
-}
--- /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.
+ */
+
+/**
+ * QueryAttributeResolver.cpp
+ *
+ * AttributeResolver based on SAML queries.
+ */
+
+#include "internal.h"
+#include "Application.h"
+#include "ServiceProvider.h"
+#include "SessionCache.h"
+#include "attribute/Attribute.h"
+#include "attribute/resolver/AttributeExtractor.h"
+#include "attribute/resolver/AttributeResolver.h"
+#include "attribute/resolver/ResolutionContext.h"
+#include "binding/SOAPClient.h"
+#include "util/SPConstants.h"
+
+#include <log4cpp/Category.hh>
+#include <saml/exceptions.h>
+#include <saml/binding/SecurityPolicy.h>
+#include <saml/saml1/binding/SAML1SOAPClient.h>
+#include <saml/saml1/core/Assertions.h>
+#include <saml/saml1/core/Protocols.h>
+#include <saml/saml1/profile/AssertionValidator.h>
+#include <saml/saml2/binding/SAML2SOAPClient.h>
+#include <saml/saml2/core/Protocols.h>
+#include <saml/saml2/metadata/Metadata.h>
+#include <saml/saml2/metadata/MetadataProvider.h>
+#include <saml/saml2/profile/AssertionValidator.h>
+#include <xmltooling/util/NDC.h>
+#include <xmltooling/util/XMLHelper.h>
+#include <xercesc/util/XMLUniDefs.hpp>
+
+using namespace shibsp;
+using namespace opensaml::saml1;
+using namespace opensaml::saml1p;
+using namespace opensaml::saml2;
+using namespace opensaml::saml2p;
+using namespace opensaml::saml2md;
+using namespace opensaml;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace shibsp {
+
+ class SHIBSP_DLLLOCAL QueryContext : public ResolutionContext
+ {
+ public:
+ QueryContext(const Application& application, const Session& session)
+ : m_query(true), m_app(application), m_session(&session), m_metadata(NULL), m_entity(NULL), m_nameid(session.getNameID()) {
+ }
+
+ QueryContext(
+ const Application& application,
+ const EntityDescriptor* issuer,
+ const NameID* nameid,
+ const vector<const opensaml::Assertion*>* tokens=NULL,
+ const multimap<string,Attribute*>* attributes=NULL
+ ) : m_query(true), m_app(application), m_session(NULL), m_metadata(NULL), m_entity(issuer), m_nameid(nameid) {
+
+ if (tokens) {
+ for (vector<const opensaml::Assertion*>::const_iterator t = tokens->begin(); t!=tokens->end(); ++t) {
+ const saml2::Assertion* token2 = dynamic_cast<const saml2::Assertion*>(*t);
+ if (token2 && !token2->getAttributeStatements().empty()) {
+ m_query = false;
+ }
+ else {
+ const saml1::Assertion* token1 = dynamic_cast<const saml1::Assertion*>(*t);
+ if (token1 && !token1->getAttributeStatements().empty()) {
+ m_query = false;
+ }
+ }
+ }
+ }
+ }
+
+ ~QueryContext() {
+ if (m_metadata)
+ m_metadata->unlock();
+ for_each(m_attributes.begin(), m_attributes.end(), cleanup_pair<string,shibsp::Attribute>());
+ for_each(m_assertions.begin(), m_assertions.end(), xmltooling::cleanup<opensaml::Assertion>());
+ }
+
+ bool doQuery() const {
+ return m_query;
+ }
+
+ const Application& getApplication() const {
+ return m_app;
+ }
+ const EntityDescriptor* getEntityDescriptor() const {
+ if (m_entity)
+ return m_entity;
+ if (m_session && m_session->getEntityID()) {
+ m_metadata = m_app.getMetadataProvider();
+ if (m_metadata) {
+ m_metadata->lock();
+ return m_entity = m_metadata->getEntityDescriptor(m_session->getEntityID());
+ }
+ }
+ return NULL;
+ }
+ const NameID* getNameID() const {
+ return m_nameid;
+ }
+ const Session* getSession() const {
+ return m_session;
+ }
+ multimap<string,shibsp::Attribute*>& getResolvedAttributes() {
+ return m_attributes;
+ }
+ vector<opensaml::Assertion*>& getResolvedAssertions() {
+ return m_assertions;
+ }
+
+ private:
+ bool m_query;
+ const Application& m_app;
+ const Session* m_session;
+ mutable MetadataProvider* m_metadata;
+ mutable const EntityDescriptor* m_entity;
+ const NameID* m_nameid;
+ multimap<string,shibsp::Attribute*> m_attributes;
+ vector<opensaml::Assertion*> m_assertions;
+ };
+
+ class SHIBSP_DLLLOCAL QueryResolver : public AttributeResolver
+ {
+ public:
+ QueryResolver(const DOMElement* e);
+ ~QueryResolver() {
+ for_each(m_SAML1Designators.begin(), m_SAML1Designators.end(), xmltooling::cleanup<AttributeDesignator>());
+ for_each(m_SAML2Designators.begin(), m_SAML2Designators.end(), xmltooling::cleanup<saml2::Attribute>());
+ }
+
+ ResolutionContext* createResolutionContext(
+ const Application& application,
+ const EntityDescriptor* issuer,
+ const NameID* nameid,
+ const vector<const opensaml::Assertion*>* tokens=NULL,
+ const multimap<string,shibsp::Attribute*>* attributes=NULL
+ ) const {
+ return new QueryContext(application,issuer,nameid,tokens,attributes);
+ }
+
+ ResolutionContext* createResolutionContext(const Application& application, const Session& session) const {
+ return new QueryContext(application,session);
+ }
+
+ Lockable* lock() {return this;}
+ void unlock() {}
+
+ void resolveAttributes(ResolutionContext& ctx) const;
+
+ private:
+ bool SAML1Query(QueryContext& ctx) const;
+ bool SAML2Query(QueryContext& ctx) const;
+
+ Category& m_log;
+ vector<AttributeDesignator*> m_SAML1Designators;
+ vector<saml2::Attribute*> m_SAML2Designators;
+ };
+
+ AttributeResolver* SHIBSP_DLLLOCAL QueryResolverFactory(const DOMElement* const & e)
+ {
+ return new QueryResolver(e);
+ }
+
+};
+
+void SHIBSP_API shibsp::registerAttributeResolvers()
+{
+ SPConfig::getConfig().AttributeResolverManager.registerFactory(QUERY_ATTRIBUTE_RESOLVER, QueryResolverFactory);
+}
+
+QueryResolver::QueryResolver(const DOMElement* e) : m_log(Category::getInstance(SHIBSP_LOGCAT".AttributeResolver"))
+{
+#ifdef _DEBUG
+ xmltooling::NDC ndc("QueryResolver");
+#endif
+
+ DOMElement* child = XMLHelper::getFirstChildElement(e);
+ while (child) {
+ try {
+ if (XMLHelper::isNodeNamed(e, samlconstants::SAML20_NS, saml2::Attribute::LOCAL_NAME)) {
+ auto_ptr<XMLObject> obj(saml2::AttributeBuilder::buildOneFromElement(child));
+ saml2::Attribute* down = dynamic_cast<saml2::Attribute*>(obj.get());
+ if (down) {
+ m_SAML2Designators.push_back(down);
+ obj.release();
+ }
+ }
+ else if (XMLHelper::isNodeNamed(e, samlconstants::SAML1P_NS, AttributeDesignator::LOCAL_NAME)) {
+ auto_ptr<XMLObject> obj(AttributeDesignatorBuilder::buildOneFromElement(child));
+ AttributeDesignator* down = dynamic_cast<AttributeDesignator*>(obj.get());
+ if (down) {
+ m_SAML1Designators.push_back(down);
+ obj.release();
+ }
+ }
+ }
+ catch (exception& ex) {
+ m_log.error("exception loading attribute designator: %s", ex.what());
+ }
+ child = XMLHelper::getNextSiblingElement(child);
+ }
+}
+
+bool QueryResolver::SAML1Query(QueryContext& ctx) const
+{
+#ifdef _DEBUG
+ xmltooling::NDC ndc("query");
+#endif
+
+ int version = 1;
+ const AttributeAuthorityDescriptor* AA = ctx.getEntityDescriptor()->getAttributeAuthorityDescriptor(samlconstants::SAML11_PROTOCOL_ENUM);
+ if (!AA) {
+ AA = ctx.getEntityDescriptor()->getAttributeAuthorityDescriptor(samlconstants::SAML10_PROTOCOL_ENUM);
+ version = 0;
+ }
+ if (!AA) {
+ m_log.info("no SAML 1.x AttributeAuthority role found in metadata");
+ return false;
+ }
+
+ shibsp::SecurityPolicy policy(ctx.getApplication());
+ MetadataCredentialCriteria mcc(*AA);
+ shibsp::SOAPClient soaper(policy);
+ const PropertySet* policySettings =
+ ctx.getApplication().getServiceProvider().getPolicySettings(ctx.getApplication().getString("policyId").second);
+ pair<bool,bool> signedAssertions = policySettings->getBool("signedAssertions");
+
+ auto_ptr_XMLCh binding(samlconstants::SAML1_BINDING_SOAP);
+ saml1p::Response* response=NULL;
+ const vector<AttributeService*>& endpoints=AA->getAttributeServices();
+ for (vector<AttributeService*>::const_iterator ep=endpoints.begin(); !response && ep!=endpoints.end(); ++ep) {
+ try {
+ if (!XMLString::equals((*ep)->getBinding(),binding.get()))
+ continue;
+ auto_ptr_char loc((*ep)->getLocation());
+ auto_ptr_XMLCh issuer(ctx.getApplication().getString("entityID").second);
+ NameIdentifier* nameid = NameIdentifierBuilder::buildNameIdentifier();
+ nameid->setName(ctx.getNameID()->getName());
+ nameid->setFormat(ctx.getNameID()->getFormat());
+ nameid->setNameQualifier(ctx.getNameID()->getNameQualifier());
+ saml1::Subject* subject = saml1::SubjectBuilder::buildSubject();
+ subject->setNameIdentifier(nameid);
+ saml1p::AttributeQuery* query = saml1p::AttributeQueryBuilder::buildAttributeQuery();
+ query->setSubject(subject);
+ query->setResource(issuer.get());
+ for (vector<AttributeDesignator*>::const_iterator ad = m_SAML1Designators.begin(); ad!=m_SAML1Designators.end(); ++ad)
+ query->getAttributeDesignators().push_back((*ad)->cloneAttributeDesignator());
+ Request* request = RequestBuilder::buildRequest();
+ request->setAttributeQuery(query);
+ request->setMinorVersion(version);
+
+ SAML1SOAPClient client(soaper);
+ client.sendSAML(request, mcc, loc.get());
+ response = client.receiveSAML();
+ }
+ catch (exception& ex) {
+ m_log.error("exception making SAML query: %s", ex.what());
+ soaper.reset();
+ }
+ }
+
+ if (!response) {
+ m_log.error("unable to successfully query for attributes");
+ return false;
+ }
+
+ const vector<saml1::Assertion*>& assertions = const_cast<const saml1p::Response*>(response)->getAssertions();
+ if (assertions.size()>1)
+ m_log.warn("simple resolver only supports one assertion in the query response");
+
+ auto_ptr<saml1p::Response> wrapper(response);
+ saml1::Assertion* newtoken = assertions.front();
+
+ if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) {
+ m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");
+ return true;
+ }
+
+ try {
+ policy.evaluate(*newtoken);
+ if (!policy.isSecure())
+ throw SecurityPolicyException("Security of SAML 1.x query result not established.");
+ saml1::AssertionValidator tokval(ctx.getApplication().getAudiences(), time(NULL));
+ tokval.validateAssertion(*newtoken);
+ }
+ catch (exception& ex) {
+ m_log.error("assertion failed policy/validation: %s", ex.what());
+ return true;
+ }
+
+ newtoken->detach();
+ wrapper.release();
+ ctx.getResolvedAssertions().push_back(newtoken);
+
+ // Finally, extract and filter the result.
+ try {
+ AttributeExtractor* extractor = ctx.getApplication().getAttributeExtractor();
+ if (extractor) {
+ Locker extlocker(extractor);
+ extractor->extractAttributes(ctx.getApplication(), AA, *newtoken, ctx.getResolvedAttributes());
+ }
+ }
+ catch (exception& ex) {
+ m_log.error("caught exception extracting/filtering attributes from query result: %s", ex.what());
+ }
+
+ return true;
+}
+
+bool QueryResolver::SAML2Query(QueryContext& ctx) const
+{
+#ifdef _DEBUG
+ xmltooling::NDC ndc("query");
+#endif
+
+ const AttributeAuthorityDescriptor* AA = ctx.getEntityDescriptor()->getAttributeAuthorityDescriptor(samlconstants::SAML20P_NS);
+ if (!AA) {
+ m_log.info("no SAML 2 AttributeAuthority role found in metadata");
+ return false;
+ }
+
+ shibsp::SecurityPolicy policy(ctx.getApplication());
+ MetadataCredentialCriteria mcc(*AA);
+ shibsp::SOAPClient soaper(policy);
+ const PropertySet* policySettings =
+ ctx.getApplication().getServiceProvider().getPolicySettings(ctx.getApplication().getString("policyId").second);
+ pair<bool,bool> signedAssertions = policySettings->getBool("signedAssertions");
+
+ auto_ptr_XMLCh binding(samlconstants::SAML20_BINDING_SOAP);
+ saml2p::StatusResponseType* srt=NULL;
+ const vector<AttributeService*>& endpoints=AA->getAttributeServices();
+ for (vector<AttributeService*>::const_iterator ep=endpoints.begin(); !srt && ep!=endpoints.end(); ++ep) {
+ try {
+ if (!XMLString::equals((*ep)->getBinding(),binding.get()))
+ continue;
+ auto_ptr_char loc((*ep)->getLocation());
+ auto_ptr_XMLCh issuer(ctx.getApplication().getString("entityID").second);
+ saml2::Subject* subject = saml2::SubjectBuilder::buildSubject();
+ subject->setNameID(ctx.getNameID()->cloneNameID());
+ saml2p::AttributeQuery* query = saml2p::AttributeQueryBuilder::buildAttributeQuery();
+ query->setSubject(subject);
+ Issuer* iss = IssuerBuilder::buildIssuer();
+ iss->setName(issuer.get());
+ query->setIssuer(iss);
+ for (vector<saml2::Attribute*>::const_iterator ad = m_SAML2Designators.begin(); ad!=m_SAML2Designators.end(); ++ad)
+ query->getAttributes().push_back((*ad)->cloneAttribute());
+
+ SAML2SOAPClient client(soaper);
+ client.sendSAML(query, mcc, loc.get());
+ srt = client.receiveSAML();
+ }
+ catch (exception& ex) {
+ m_log.error("exception making SAML query: %s", ex.what());
+ soaper.reset();
+ }
+ }
+
+ if (!srt) {
+ m_log.error("unable to successfully query for attributes");
+ return false;
+ }
+ saml2p::Response* response = dynamic_cast<saml2p::Response*>(srt);
+ if (!response) {
+ delete srt;
+ m_log.error("message was not a samlp:Response");
+ return true;
+ }
+
+ const vector<saml2::Assertion*>& assertions = const_cast<const saml2p::Response*>(response)->getAssertions();
+ if (assertions.size()>1)
+ m_log.warn("simple resolver only supports one assertion in the query response");
+
+ auto_ptr<saml2p::Response> wrapper(response);
+ saml2::Assertion* newtoken = assertions.front();
+
+ if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) {
+ m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");
+ return true;
+ }
+
+ try {
+ policy.evaluate(*newtoken);
+ if (!policy.isSecure())
+ throw SecurityPolicyException("Security of SAML 2.0 query result not established.");
+ saml2::AssertionValidator tokval(ctx.getApplication().getAudiences(), time(NULL));
+ tokval.validateAssertion(*newtoken);
+ }
+ catch (exception& ex) {
+ m_log.error("assertion failed policy/validation: %s", ex.what());
+ return true;
+ }
+
+ newtoken->detach();
+ wrapper.release();
+ ctx.getResolvedAssertions().push_back(newtoken);
+
+ // Finally, extract and filter the result.
+ try {
+ AttributeExtractor* extractor = ctx.getApplication().getAttributeExtractor();
+ if (extractor) {
+ Locker extlocker(extractor);
+ extractor->extractAttributes(ctx.getApplication(), AA, *newtoken, ctx.getResolvedAttributes());
+ }
+ }
+ catch (exception& ex) {
+ m_log.error("caught exception extracting/filtering attributes from query result: %s", ex.what());
+ }
+
+ return true;
+}
+
+void QueryResolver::resolveAttributes(ResolutionContext& ctx) const
+{
+#ifdef _DEBUG
+ xmltooling::NDC ndc("resolveAttributes");
+#endif
+
+ QueryContext& qctx = dynamic_cast<QueryContext&>(ctx);
+ if (!qctx.doQuery()) {
+ m_log.debug("found AttributeStatement in input to new session, skipping query");
+ return;
+ }
+
+ if (qctx.getNameID() && qctx.getEntityDescriptor()) {
+ m_log.debug("attempting SAML 2.0 attribute query");
+ if (!SAML2Query(qctx)) {
+ m_log.debug("attempting SAML 1.x attribute query");
+ SAML1Query(qctx);
+ }
+ }
+ m_log.warn("can't attempt attribute query, either no NameID or no metadata to use");
+}
+++ /dev/null
-/*\r
- * Copyright 2001-2007 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
- * SimpleAttributeResolver.cpp\r
- * \r
- * AttributeResolver based on a simple mapping of SAML information.\r
- */\r
-\r
-#include "internal.h"\r
-#include "Application.h"\r
-#include "ServiceProvider.h"\r
-#include "SessionCache.h"\r
-#include "attribute/AttributeDecoder.h"\r
-#include "attribute/resolver/AttributeResolver.h"\r
-#include "attribute/resolver/ResolutionContext.h"\r
-#include "binding/SOAPClient.h"\r
-#include "util/SPConstants.h"\r
-\r
-#include <saml/binding/SecurityPolicy.h>\r
-#include <saml/saml1/binding/SAML1SOAPClient.h>\r
-#include <saml/saml1/core/Assertions.h>\r
-#include <saml/saml1/core/Protocols.h>\r
-#include <saml/saml1/profile/AssertionValidator.h>\r
-#include <saml/saml2/binding/SAML2SOAPClient.h>\r
-#include <saml/saml2/core/Protocols.h>\r
-#include <saml/saml2/metadata/Metadata.h>\r
-#include <saml/saml2/metadata/MetadataProvider.h>\r
-#include <saml/saml2/profile/AssertionValidator.h>\r
-#include <xmltooling/util/NDC.h>\r
-#include <xmltooling/util/ReloadableXMLFile.h>\r
-#include <xmltooling/util/XMLHelper.h>\r
-#include <xercesc/util/XMLUniDefs.hpp>\r
-\r
-using namespace shibsp;\r
-using namespace opensaml::saml1;\r
-using namespace opensaml::saml1p;\r
-using namespace opensaml::saml2;\r
-using namespace opensaml::saml2p;\r
-using namespace opensaml::saml2md;\r
-using namespace opensaml;\r
-using namespace xmltooling;\r
-using namespace log4cpp;\r
-using namespace std;\r
-\r
-namespace shibsp {\r
-\r
- class SHIBSP_DLLLOCAL SimpleContext : public ResolutionContext\r
- {\r
- public:\r
- SimpleContext(const Application& application, const Session& session)\r
- : m_app(application), m_session(&session), m_client_addr(NULL), m_metadata(NULL), m_entity(NULL),\r
- m_nameid(session.getNameID()), m_tokens(NULL) {\r
- }\r
- \r
- SimpleContext(\r
- const Application& application,\r
- const char* client_addr,\r
- const EntityDescriptor* issuer,\r
- const NameID* nameid,\r
- const vector<const opensaml::Assertion*>* tokens=NULL\r
- ) : m_app(application), m_session(NULL), m_client_addr(client_addr), m_metadata(NULL), m_entity(issuer),\r
- m_nameid(nameid), m_tokens(tokens) {\r
- }\r
- \r
- ~SimpleContext() {\r
- if (m_metadata)\r
- m_metadata->unlock();\r
- for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<shibsp::Attribute>());\r
- for_each(m_assertions.begin(), m_assertions.end(), xmltooling::cleanup<opensaml::Assertion>());\r
- }\r
- \r
- const Application& getApplication() const {\r
- return m_app;\r
- }\r
- const char* getClientAddress() const {\r
- return m_session ? m_session->getClientAddress() : m_client_addr;\r
- }\r
- const EntityDescriptor* getEntityDescriptor() const {\r
- if (m_entity)\r
- return m_entity;\r
- if (m_session && m_session->getEntityID()) {\r
- m_metadata = m_app.getMetadataProvider();\r
- if (m_metadata) {\r
- m_metadata->lock();\r
- return m_entity = m_metadata->getEntityDescriptor(m_session->getEntityID());\r
- }\r
- }\r
- return NULL;\r
- }\r
- const NameID* getNameID() const {\r
- return m_nameid;\r
- }\r
- const vector<const opensaml::Assertion*>* getTokens() const {\r
- return m_tokens;\r
- }\r
- const Session* getSession() const {\r
- return m_session;\r
- } \r
- vector<shibsp::Attribute*>& getResolvedAttributes() {\r
- return m_attributes;\r
- }\r
- vector<opensaml::Assertion*>& getResolvedAssertions() {\r
- return m_assertions;\r
- }\r
-\r
- private:\r
- const Application& m_app;\r
- const Session* m_session;\r
- const char* m_client_addr;\r
- mutable MetadataProvider* m_metadata;\r
- mutable const EntityDescriptor* m_entity;\r
- const NameID* m_nameid;\r
- const vector<const opensaml::Assertion*>* m_tokens;\r
- vector<shibsp::Attribute*> m_attributes;\r
- vector<opensaml::Assertion*> m_assertions;\r
- };\r
- \r
-#if defined (_MSC_VER)\r
- #pragma warning( push )\r
- #pragma warning( disable : 4250 )\r
-#endif\r
-\r
- class SimpleResolverImpl\r
- {\r
- public:\r
- SimpleResolverImpl(const DOMElement* e, Category& log);\r
- ~SimpleResolverImpl() {\r
- for_each(m_decoderMap.begin(), m_decoderMap.end(), cleanup_pair<string,AttributeDecoder>());\r
- if (m_document)\r
- m_document->release();\r
- }\r
-\r
- void setDocument(DOMDocument* doc) {\r
- m_document = doc;\r
- }\r
-\r
- void query(\r
- ResolutionContext& ctx, const NameIdentifier& nameid, const set<string>* attributes=NULL\r
- ) const;\r
- void query(\r
- ResolutionContext& ctx, const NameID& nameid, const set<string>* attributes=NULL\r
- ) const;\r
- void resolve(\r
- ResolutionContext& ctx, const saml1::Assertion* token, const set<string>* attributes=NULL\r
- ) const;\r
- void resolve(\r
- ResolutionContext& ctx, const saml2::Assertion* token, const set<string>* attributes=NULL\r
- ) const;\r
-\r
- bool m_allowQuery;\r
-\r
- private:\r
- void populateQuery(saml1p::AttributeQuery& query, const string& id) const;\r
- void populateQuery(saml2p::AttributeQuery& query, const string& id) const;\r
-\r
- Category& m_log;\r
- DOMDocument* m_document;\r
- map<string,AttributeDecoder*> m_decoderMap;\r
-#ifdef HAVE_GOOD_STL\r
- typedef map< pair<xstring,xstring>,pair<const AttributeDecoder*,string> > attrmap_t;\r
-#else\r
- typedef map< pair<string,string>,pair<const AttributeDecoder*,string> > attrmap_t;\r
-#endif\r
- attrmap_t m_attrMap;\r
- };\r
- \r
- class SimpleResolver : public AttributeResolver, public ReloadableXMLFile\r
- {\r
- public:\r
- SimpleResolver(const DOMElement* e) : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT".AttributeResolver")), m_impl(NULL) {\r
- load();\r
- }\r
- ~SimpleResolver() {\r
- delete m_impl;\r
- }\r
- \r
- ResolutionContext* createResolutionContext(\r
- const Application& application,\r
- const char* client_addr,\r
- const EntityDescriptor* issuer,\r
- const NameID* nameid,\r
- const vector<const opensaml::Assertion*>* tokens=NULL\r
- ) const {\r
- return new SimpleContext(application,client_addr,issuer,nameid,tokens);\r
- }\r
-\r
- ResolutionContext* createResolutionContext(const Application& application, const Session& session) const {\r
- return new SimpleContext(application,session);\r
- }\r
- \r
- void resolveAttributes(ResolutionContext& ctx, const set<string>* attributes=NULL) const;\r
-\r
- protected:\r
- pair<bool,DOMElement*> load();\r
- SimpleResolverImpl* m_impl;\r
- };\r
-\r
-#if defined (_MSC_VER)\r
- #pragma warning( pop )\r
-#endif\r
-\r
- AttributeResolver* SHIBSP_DLLLOCAL SimpleAttributeResolverFactory(const DOMElement* const & e)\r
- {\r
- return new SimpleResolver(e);\r
- }\r
- \r
- static const XMLCh SIMPLE_NS[] = {\r
- chLatin_u, chLatin_r, chLatin_n, chColon, chLatin_m, chLatin_a, chLatin_c, chLatin_e, chColon,\r
- chLatin_s, chLatin_h, chLatin_i, chLatin_b, chLatin_b, chLatin_o, chLatin_l, chLatin_e, chLatin_t, chLatin_h, chColon,\r
- chDigit_2, chPeriod, chDigit_0, chColon,\r
- chLatin_r, chLatin_e, chLatin_s, chLatin_o, chLatin_l, chLatin_v, chLatin_e, chLatin_r, chColon,\r
- chLatin_s, chLatin_i, chLatin_m, chLatin_p, chLatin_l, chLatin_e, chNull\r
- };\r
- static const XMLCh _AttributeDecoder[] = UNICODE_LITERAL_16(A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);\r
- static const XMLCh _AttributeResolver[] = UNICODE_LITERAL_17(A,t,t,r,i,b,u,t,e,R,e,s,o,l,v,e,r);\r
- static const XMLCh allowQuery[] = UNICODE_LITERAL_10(a,l,l,o,w,Q,u,e,r,y);\r
- static const XMLCh decoderId[] = UNICODE_LITERAL_9(d,e,c,o,d,e,r,I,d);\r
- static const XMLCh _id[] = UNICODE_LITERAL_2(i,d);\r
- static const XMLCh _type[] = UNICODE_LITERAL_4(t,y,p,e);\r
-};\r
-\r
-SimpleResolverImpl::SimpleResolverImpl(const DOMElement* e, Category& log) : m_log(log), m_document(NULL), m_allowQuery(true)\r
-{\r
-#ifdef _DEBUG\r
- xmltooling::NDC ndc("SimpleResolverImpl");\r
-#endif\r
- \r
- if (!XMLHelper::isNodeNamed(e, SIMPLE_NS, _AttributeResolver))\r
- throw ConfigurationException("Simple resolver requires resolver:AttributeResolver at root of configuration.");\r
- \r
- const XMLCh* flag = e->getAttributeNS(NULL,allowQuery);\r
- if (flag && (*flag==chLatin_f || *flag==chDigit_0)) {\r
- m_log.info("SAML attribute queries disabled");\r
- m_allowQuery = false;\r
- }\r
-\r
- DOMElement* child = XMLHelper::getFirstChildElement(e, SIMPLE_NS, _AttributeDecoder);\r
- while (child) {\r
- auto_ptr_char id(child->getAttributeNS(NULL, _id));\r
- auto_ptr_char type(child->getAttributeNS(NULL, _type));\r
- try {\r
- m_log.info("building AttributeDecoder (%s) of type %s", id.get(), type.get());\r
- m_decoderMap[id.get()] = SPConfig::getConfig().AttributeDecoderManager.newPlugin(type.get(), child);\r
- }\r
- catch (exception& ex) {\r
- m_log.error("error building AttributeDecoder (%s): %s", id.get(), ex.what());\r
- }\r
- child = XMLHelper::getNextSiblingElement(child, SIMPLE_NS, _AttributeDecoder);\r
- }\r
- \r
- child = XMLHelper::getFirstChildElement(e, samlconstants::SAML20_NS, saml2::Attribute::LOCAL_NAME);\r
- while (child) {\r
- // Check for missing Name.\r
- const XMLCh* name = child->getAttributeNS(NULL, saml2::Attribute::NAME_ATTRIB_NAME);\r
- if (!name || !*name) {\r
- m_log.warn("skipping saml:Attribute declared with no Name");\r
- child = XMLHelper::getNextSiblingElement(child, samlconstants::SAML20_NS, saml2::Attribute::LOCAL_NAME);\r
- continue;\r
- }\r
-\r
- const AttributeDecoder* decoder=NULL;\r
- auto_ptr_char id(child->getAttributeNS(NULL, saml2::Attribute::FRIENDLYNAME_ATTRIB_NAME));\r
- auto_ptr_char d(child->getAttributeNS(SIMPLE_NS, decoderId));\r
- if (!id.get() || !*id.get() || !d.get() || !*d.get() || !(decoder=m_decoderMap[d.get()])) {\r
- m_log.warn("skipping saml:Attribute declared with no FriendlyName or resolvable AttributeDecoder");\r
- child = XMLHelper::getNextSiblingElement(child, samlconstants::SAML20_NS, saml2::Attribute::LOCAL_NAME);\r
- continue;\r
- }\r
- \r
- // Empty NameFormat implies the usual Shib URI naming defaults.\r
- const XMLCh* format = child->getAttributeNS(NULL, saml2::Attribute::NAMEFORMAT_ATTRIB_NAME);\r
- if (!format || XMLString::equals(format, shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI) ||\r
- XMLString::equals(format, saml2::Attribute::URI_REFERENCE))\r
- format = &chNull; // ignore default Format/Namespace values\r
-\r
- // Fetch/create the map entry and see if it's a duplicate rule.\r
-#ifdef HAVE_GOOD_STL\r
- pair<const AttributeDecoder*,string>& decl = m_attrMap[make_pair(name,format)];\r
-#else\r
- auto_ptr_char n(name);\r
- auto_ptr_char f(format);\r
- pair<const AttributeDecoder*,string>& decl = m_attrMap[make_pair(n.get(),f.get())];\r
-#endif\r
- if (decl.first) {\r
- m_log.warn("skipping duplicate saml:Attribute declaration (same Name and NameFormat)");\r
- child = XMLHelper::getNextSiblingElement(child, samlconstants::SAML20_NS, saml2::Attribute::LOCAL_NAME);\r
- continue;\r
- }\r
-\r
- if (m_log.isInfoEnabled()) {\r
-#ifdef HAVE_GOOD_STL\r
- auto_ptr_char n(name);\r
- auto_ptr_char f(format);\r
-#endif\r
- m_log.info("creating declaration for Attribute %s%s%s", n.get(), *f.get() ? ", Format/Namespace:" : "", f.get());\r
- }\r
- \r
- decl.first = decoder;\r
- decl.second = id.get();\r
- \r
- child = XMLHelper::getNextSiblingElement(child, samlconstants::SAML20_NS, saml2::Attribute::LOCAL_NAME);\r
- }\r
-}\r
-\r
-void SimpleResolverImpl::resolve(\r
- ResolutionContext& ctx, const saml1::Assertion* token, const set<string>* attributes\r
- ) const\r
-{\r
- vector<shibsp::Attribute*>& resolved = ctx.getResolvedAttributes();\r
-\r
- auto_ptr_char assertingParty(ctx.getEntityDescriptor() ? ctx.getEntityDescriptor()->getEntityID() : NULL);\r
- const char* relyingParty = ctx.getApplication().getString("entityID").second;\r
-\r
-#ifdef HAVE_GOOD_STL\r
- map< pair<xstring,xstring>,pair<const AttributeDecoder*,string> >::const_iterator rule;\r
-#else\r
- map< pair<string,string>,pair<const AttributeDecoder*,string> >::const_iterator rule;\r
-#endif\r
-\r
- const XMLCh* name;\r
- const XMLCh* format;\r
- \r
- // Check the NameID based on the format.\r
- if (ctx.getNameID()) {\r
- format = ctx.getNameID()->getFormat();\r
- if (!format || !*format)\r
- format = NameID::UNSPECIFIED;\r
-#ifdef HAVE_GOOD_STL\r
- if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) {\r
-#else\r
- auto_ptr_char temp(format);\r
- if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {\r
-#endif\r
- if (!attributes || attributes->count(rule->second.second)) {\r
- resolved.push_back(\r
- rule->second.first->decode(\r
- rule->second.second.c_str(), ctx.getNameID(), assertingParty.get(), relyingParty\r
- )\r
- );\r
- }\r
- }\r
- }\r
-\r
- const vector<saml1::AttributeStatement*>& statements = token->getAttributeStatements();\r
- for (vector<saml1::AttributeStatement*>::const_iterator s = statements.begin(); s!=statements.end(); ++s) {\r
- const vector<saml1::Attribute*>& attrs = const_cast<const saml1::AttributeStatement*>(*s)->getAttributes();\r
- for (vector<saml1::Attribute*>::const_iterator a = attrs.begin(); a!=attrs.end(); ++a) {\r
- name = (*a)->getAttributeName();\r
- format = (*a)->getAttributeNamespace();\r
- if (!name || !*name)\r
- continue;\r
- if (!format || XMLString::equals(format, shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI))\r
- format = &chNull;\r
-#ifdef HAVE_GOOD_STL\r
- if ((rule=m_attrMap.find(make_pair(name,format))) != m_attrMap.end()) {\r
-#else\r
- auto_ptr_char temp1(name);\r
- auto_ptr_char temp2(format);\r
- if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) {\r
-#endif\r
- if (!attributes || attributes->count(rule->second.second)) {\r
- resolved.push_back(\r
- rule->second.first->decode(rule->second.second.c_str(), *a, assertingParty.get(), relyingParty)\r
- );\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-void SimpleResolverImpl::resolve(\r
- ResolutionContext& ctx, const saml2::Assertion* token, const set<string>* attributes\r
- ) const\r
-{\r
- vector<shibsp::Attribute*>& resolved = ctx.getResolvedAttributes();\r
-\r
- auto_ptr_char assertingParty(ctx.getEntityDescriptor() ? ctx.getEntityDescriptor()->getEntityID() : NULL);\r
- const char* relyingParty = ctx.getApplication().getString("entityID").second;\r
-\r
-#ifdef HAVE_GOOD_STL\r
- map< pair<xstring,xstring>,pair<const AttributeDecoder*,string> >::const_iterator rule;\r
-#else\r
- map< pair<string,string>,pair<const AttributeDecoder*,string> >::const_iterator rule;\r
-#endif\r
-\r
- const XMLCh* name;\r
- const XMLCh* format;\r
- \r
- // Check the NameID based on the format.\r
- if (ctx.getNameID()) {\r
- format = ctx.getNameID()->getFormat();\r
- if (!format || !*format)\r
- format = NameID::UNSPECIFIED;\r
-#ifdef HAVE_GOOD_STL\r
- if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) {\r
-#else\r
- auto_ptr_char temp(format);\r
- if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {\r
-#endif\r
- if (!attributes || attributes->count(rule->second.second)) {\r
- resolved.push_back(\r
- rule->second.first->decode(\r
- rule->second.second.c_str(), ctx.getNameID(), assertingParty.get(), relyingParty\r
- )\r
- );\r
- }\r
- }\r
- }\r
-\r
- const vector<saml2::AttributeStatement*>& statements = token->getAttributeStatements();\r
- for (vector<saml2::AttributeStatement*>::const_iterator s = statements.begin(); s!=statements.end(); ++s) {\r
- const vector<saml2::Attribute*>& attrs = const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();\r
- for (vector<saml2::Attribute*>::const_iterator a = attrs.begin(); a!=attrs.end(); ++a) {\r
- name = (*a)->getName();\r
- format = (*a)->getNameFormat();\r
- if (!name || !*name)\r
- continue;\r
- if (!format || !*format)\r
- format = saml2::Attribute::UNSPECIFIED;\r
- else if (XMLString::equals(format, saml2::Attribute::URI_REFERENCE))\r
- format = &chNull;\r
-#ifdef HAVE_GOOD_STL\r
- if ((rule=m_attrMap.find(make_pair(name,format))) != m_attrMap.end()) {\r
-#else\r
- auto_ptr_char temp1(name);\r
- auto_ptr_char temp2(format);\r
- if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) {\r
-#endif\r
- if (!attributes || attributes->count(rule->second.second)) {\r
- resolved.push_back(\r
- rule->second.first->decode(rule->second.second.c_str(), *a, assertingParty.get(), relyingParty)\r
- );\r
- }\r
- }\r
- }\r
-\r
- const vector<saml2::EncryptedAttribute*>& encattrs = const_cast<const saml2::AttributeStatement*>(*s)->getEncryptedAttributes();\r
- if (!encattrs.empty()) {\r
- const XMLCh* recipient = ctx.getApplication().getXMLString("entityID").second;\r
- CredentialResolver* cr = ctx.getApplication().getCredentialResolver();\r
- if (!cr) {\r
- Category::getInstance(SHIBSP_LOGCAT".AttributeResolver").warn(\r
- "found encrypted attributes, but no CredentialResolver was available"\r
- );\r
- return;\r
- }\r
-\r
- // We look up credentials based on the peer who did the encrypting.\r
- CredentialCriteria cc;\r
- cc.setPeerName(assertingParty.get());\r
-\r
- Locker credlocker(cr);\r
- for (vector<saml2::EncryptedAttribute*>::const_iterator ea = encattrs.begin(); ea!=encattrs.end(); ++ea) {\r
- auto_ptr<XMLObject> decrypted((*ea)->decrypt(*cr, recipient, &cc));\r
- const saml2::Attribute* decattr = dynamic_cast<const saml2::Attribute*>(decrypted.get());\r
- name = decattr->getName();\r
- format = decattr->getNameFormat();\r
- if (!name || !*name)\r
- continue;\r
- if (!format || !*format)\r
- format = saml2::Attribute::UNSPECIFIED;\r
- else if (XMLString::equals(format, saml2::Attribute::URI_REFERENCE))\r
- format = &chNull;\r
-#ifdef HAVE_GOOD_STL\r
- if ((rule=m_attrMap.find(make_pair(name,format))) != m_attrMap.end()) {\r
-#else\r
- auto_ptr_char temp1(name);\r
- auto_ptr_char temp2(format);\r
- if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) {\r
-#endif\r
- if (!attributes || attributes->count(rule->second.second)) {\r
- resolved.push_back(\r
- rule->second.first->decode(rule->second.second.c_str(), decattr, assertingParty.get(), relyingParty)\r
- );\r
- }\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-void SimpleResolverImpl::query(ResolutionContext& ctx, const NameIdentifier& nameid, const set<string>* attributes) const\r
-{\r
-#ifdef _DEBUG\r
- xmltooling::NDC ndc("query");\r
-#endif\r
-\r
- const EntityDescriptor* entity = ctx.getEntityDescriptor();\r
- if (!entity) {\r
- m_log.debug("no issuer information available, skipping query");\r
- return;\r
- }\r
-\r
- int version = 1;\r
- const AttributeAuthorityDescriptor* AA = entity->getAttributeAuthorityDescriptor(samlconstants::SAML11_PROTOCOL_ENUM);\r
- if (!AA) {\r
- AA = entity->getAttributeAuthorityDescriptor(samlconstants::SAML10_PROTOCOL_ENUM);\r
- version = 0;\r
- }\r
- if (!AA) {\r
- m_log.info("no SAML 1.x AttributeAuthority role found in metadata");\r
- return;\r
- }\r
-\r
- shibsp::SecurityPolicy policy(ctx.getApplication());\r
- MetadataCredentialCriteria mcc(*AA);\r
- shibsp::SOAPClient soaper(policy);\r
- const PropertySet* policySettings = ctx.getApplication().getServiceProvider().getPolicySettings(ctx.getApplication().getString("policyId").second);\r
- pair<bool,bool> signedAssertions = policySettings->getBool("signedAssertions");\r
-\r
- auto_ptr_XMLCh binding(samlconstants::SAML1_BINDING_SOAP);\r
- saml1p::Response* response=NULL;\r
- const vector<AttributeService*>& endpoints=AA->getAttributeServices();\r
- for (vector<AttributeService*>::const_iterator ep=endpoints.begin(); !response && ep!=endpoints.end(); ++ep) {\r
- try {\r
- if (!XMLString::equals((*ep)->getBinding(),binding.get()))\r
- continue;\r
- auto_ptr_char loc((*ep)->getLocation());\r
- auto_ptr_XMLCh issuer(ctx.getApplication().getString("entityID").second);\r
- saml1::Subject* subject = saml1::SubjectBuilder::buildSubject();\r
- subject->setNameIdentifier(nameid.cloneNameIdentifier());\r
- saml1p::AttributeQuery* query = saml1p::AttributeQueryBuilder::buildAttributeQuery();\r
- query->setSubject(subject);\r
- Request* request = RequestBuilder::buildRequest();\r
- request->setAttributeQuery(query);\r
- query->setResource(issuer.get());\r
- request->setMinorVersion(version);\r
- if (attributes) {\r
- for (set<string>::const_iterator a = attributes->begin(); a!=attributes->end(); ++a)\r
- populateQuery(*query, *a);\r
- }\r
-\r
- SAML1SOAPClient client(soaper);\r
- client.sendSAML(request, mcc, loc.get());\r
- response = client.receiveSAML();\r
- }\r
- catch (exception& ex) {\r
- m_log.error("exception making SAML query: %s", ex.what());\r
- soaper.reset();\r
- }\r
- }\r
-\r
- if (!response) {\r
- m_log.error("unable to successfully query for attributes");\r
- return;\r
- }\r
-\r
- const vector<saml1::Assertion*>& assertions = const_cast<const saml1p::Response*>(response)->getAssertions();\r
- if (assertions.size()>1)\r
- m_log.warn("simple resolver only supports one assertion in the query response");\r
-\r
- auto_ptr<saml1p::Response> wrapper(response);\r
- saml1::Assertion* newtoken = assertions.front();\r
-\r
- if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) {\r
- m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");\r
- return;\r
- }\r
-\r
- try {\r
- policy.evaluate(*newtoken);\r
- if (!policy.isSecure())\r
- throw SecurityPolicyException("Security of SAML 1.x query result not established.");\r
- saml1::AssertionValidator tokval(ctx.getApplication().getAudiences(), time(NULL));\r
- tokval.validateAssertion(*newtoken);\r
- }\r
- catch (exception& ex) {\r
- m_log.error("assertion failed policy/validation: %s", ex.what());\r
- }\r
- newtoken->detach();\r
- wrapper.release();\r
- ctx.getResolvedAssertions().push_back(newtoken);\r
- resolve(ctx, newtoken, attributes);\r
-}\r
-\r
-void SimpleResolverImpl::populateQuery(saml1p::AttributeQuery& query, const string& id) const\r
-{\r
- for (attrmap_t::const_iterator i = m_attrMap.begin(); i!=m_attrMap.end(); ++i) {\r
- if (i->second.second == id) {\r
- AttributeDesignator* a = AttributeDesignatorBuilder::buildAttributeDesignator();\r
-#ifdef HAVE_GOOD_STL\r
- a->setAttributeName(i->first.first.c_str());\r
- a->setAttributeNamespace(i->first.second.empty() ? shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI : i->first.second.c_str());\r
-#else\r
- auto_ptr_XMLCh n(i->first.first.c_str());\r
- a->setAttributeName(n.get());\r
- if (i->first.second.empty())\r
- a->setAttributeNamespace(shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI);\r
- else {\r
- auto_ptr_XMLCh ns(i->first.second.c_str());\r
- a->setAttributeNamespace(ns.get());\r
- }\r
-#endif\r
- query.getAttributeDesignators().push_back(a);\r
- }\r
- }\r
-}\r
-\r
-void SimpleResolverImpl::query(ResolutionContext& ctx, const NameID& nameid, const set<string>* attributes) const\r
-{\r
-#ifdef _DEBUG\r
- xmltooling::NDC ndc("query");\r
-#endif\r
-\r
- const EntityDescriptor* entity = ctx.getEntityDescriptor();\r
- if (!entity) {\r
- m_log.debug("no issuer information available, skipping query");\r
- return;\r
- }\r
- const AttributeAuthorityDescriptor* AA = entity->getAttributeAuthorityDescriptor(samlconstants::SAML20P_NS);\r
- if (!AA) {\r
- m_log.info("no SAML 2 AttributeAuthority role found in metadata");\r
- return;\r
- }\r
-\r
- shibsp::SecurityPolicy policy(ctx.getApplication());\r
- MetadataCredentialCriteria mcc(*AA);\r
- shibsp::SOAPClient soaper(policy);\r
- const PropertySet* policySettings = ctx.getApplication().getServiceProvider().getPolicySettings(ctx.getApplication().getString("policyId").second);\r
- pair<bool,bool> signedAssertions = policySettings->getBool("signedAssertions");\r
-\r
- auto_ptr_XMLCh binding(samlconstants::SAML20_BINDING_SOAP);\r
- saml2p::StatusResponseType* srt=NULL;\r
- const vector<AttributeService*>& endpoints=AA->getAttributeServices();\r
- for (vector<AttributeService*>::const_iterator ep=endpoints.begin(); !srt && ep!=endpoints.end(); ++ep) {\r
- try {\r
- if (!XMLString::equals((*ep)->getBinding(),binding.get()))\r
- continue;\r
- auto_ptr_char loc((*ep)->getLocation());\r
- auto_ptr_XMLCh issuer(ctx.getApplication().getString("entityID").second);\r
- saml2::Subject* subject = saml2::SubjectBuilder::buildSubject();\r
- subject->setNameID(nameid.cloneNameID());\r
- saml2p::AttributeQuery* query = saml2p::AttributeQueryBuilder::buildAttributeQuery();\r
- query->setSubject(subject);\r
- Issuer* iss = IssuerBuilder::buildIssuer();\r
- query->setIssuer(iss);\r
- iss->setName(issuer.get());\r
- if (attributes) {\r
- for (set<string>::const_iterator a = attributes->begin(); a!=attributes->end(); ++a)\r
- populateQuery(*query, *a);\r
- }\r
-\r
- SAML2SOAPClient client(soaper);\r
- client.sendSAML(query, mcc, loc.get());\r
- srt = client.receiveSAML();\r
- }\r
- catch (exception& ex) {\r
- m_log.error("exception making SAML query: %s", ex.what());\r
- soaper.reset();\r
- }\r
- }\r
-\r
- if (!srt) {\r
- m_log.error("unable to successfully query for attributes");\r
- return;\r
- }\r
- saml2p::Response* response = dynamic_cast<saml2p::Response*>(srt);\r
- if (!response) {\r
- delete srt;\r
- m_log.error("message was not a samlp:Response");\r
- return;\r
- }\r
-\r
- const vector<saml2::Assertion*>& assertions = const_cast<const saml2p::Response*>(response)->getAssertions();\r
- if (assertions.size()>1)\r
- m_log.warn("simple resolver only supports one assertion in the query response");\r
-\r
- auto_ptr<saml2p::Response> wrapper(response);\r
- saml2::Assertion* newtoken = assertions.front();\r
-\r
- if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) {\r
- m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");\r
- return;\r
- }\r
-\r
- try {\r
- policy.evaluate(*newtoken);\r
- if (!policy.isSecure())\r
- throw SecurityPolicyException("Security of SAML 2.0 query result not established.");\r
- saml2::AssertionValidator tokval(ctx.getApplication().getAudiences(), time(NULL));\r
- tokval.validateAssertion(*newtoken);\r
- }\r
- catch (exception& ex) {\r
- m_log.error("assertion failed policy/validation: %s", ex.what());\r
- }\r
- newtoken->detach();\r
- wrapper.release();\r
- ctx.getResolvedAssertions().push_back(newtoken);\r
- resolve(ctx, newtoken, attributes);\r
-}\r
-\r
-void SimpleResolverImpl::populateQuery(saml2p::AttributeQuery& query, const string& id) const\r
-{\r
- for (attrmap_t::const_iterator i = m_attrMap.begin(); i!=m_attrMap.end(); ++i) {\r
- if (i->second.second == id) {\r
- saml2::Attribute* a = saml2::AttributeBuilder::buildAttribute();\r
-#ifdef HAVE_GOOD_STL\r
- a->setName(i->first.first.c_str());\r
- a->setNameFormat(i->first.second.empty() ? saml2::Attribute::URI_REFERENCE : i->first.second.c_str());\r
-#else\r
- auto_ptr_XMLCh n(i->first.first.c_str());\r
- a->setName(n.get());\r
- if (i->first.second.empty())\r
- a->setNameFormat(saml2::Attribute::URI_REFERENCE);\r
- else {\r
- auto_ptr_XMLCh ns(i->first.second.c_str());\r
- a->setNameFormat(ns.get());\r
- }\r
-#endif\r
- query.getAttributes().push_back(a);\r
- }\r
- }\r
-}\r
-\r
-void SimpleResolver::resolveAttributes(ResolutionContext& ctx, const set<string>* attributes) const\r
-{\r
-#ifdef _DEBUG\r
- xmltooling::NDC ndc("resolveAttributes");\r
-#endif\r
- \r
- m_log.debug("examining tokens to resolve");\r
-\r
- bool query = m_impl->m_allowQuery;\r
- const saml1::Assertion* token1;\r
- const saml2::Assertion* token2;\r
- if (ctx.getTokens()) {\r
- for (vector<const opensaml::Assertion*>::const_iterator t = ctx.getTokens()->begin(); t!=ctx.getTokens()->end(); ++t) {\r
- token2 = dynamic_cast<const saml2::Assertion*>(*t);\r
- if (token2 && !token2->getAttributeStatements().empty()) {\r
- m_log.debug("resolving SAML 2 token with an AttributeStatement");\r
- m_impl->resolve(ctx, token2, attributes);\r
- query = false;\r
- }\r
- else {\r
- token1 = dynamic_cast<const saml1::Assertion*>(*t);\r
- if (token1 && !token1->getAttributeStatements().empty()) {\r
- m_log.debug("resolving SAML 1 token with an AttributeStatement");\r
- m_impl->resolve(ctx, token1, attributes);\r
- query = false;\r
- }\r
- }\r
- }\r
- }\r
-\r
- if (query) {\r
- if (token1 && !token1->getAuthenticationStatements().empty()) {\r
- const AuthenticationStatement* statement = token1->getAuthenticationStatements().front();\r
- if (statement && statement->getSubject() && statement->getSubject()->getNameIdentifier()) {\r
- m_log.debug("attempting SAML 1.x attribute query");\r
- return m_impl->query(ctx, *(statement->getSubject()->getNameIdentifier()), attributes);\r
- }\r
- }\r
- else if (token2 && ctx.getNameID()) {\r
- m_log.debug("attempting SAML 2.0 attribute query");\r
- return m_impl->query(ctx, *ctx.getNameID(), attributes);\r
- }\r
- m_log.warn("can't attempt attribute query, no identifier in assertion subject");\r
- }\r
-}\r
-\r
-pair<bool,DOMElement*> SimpleResolver::load()\r
-{\r
- // Load from source using base class.\r
- pair<bool,DOMElement*> raw = ReloadableXMLFile::load();\r
- \r
- // If we own it, wrap it.\r
- XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL);\r
-\r
- SimpleResolverImpl* impl = new SimpleResolverImpl(raw.second, m_log);\r
- \r
- // If we held the document, transfer it to the impl. If we didn't, it's a no-op.\r
- impl->setDocument(docjanitor.release());\r
-\r
- delete m_impl;\r
- m_impl = impl;\r
-\r
- return make_pair(false,(DOMElement*)NULL);\r
-}\r
--- /dev/null
+/*\r
+ * Copyright 2001-2007 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
+ * XMLAttributeExtractor.cpp\r
+ * \r
+ * AttributeExtractor based on an XML mapping file.\r
+ */\r
+\r
+#include "internal.h"\r
+#include "Application.h"\r
+#include "ServiceProvider.h"\r
+#include "attribute/AttributeDecoder.h"\r
+#include "attribute/resolver/AttributeExtractor.h"\r
+#include "util/SPConstants.h"\r
+\r
+#include <saml/saml1/core/Assertions.h>\r
+#include <saml/saml2/core/Assertions.h>\r
+#include <saml/saml2/metadata/MetadataCredentialCriteria.h>\r
+#include <xmltooling/util/NDC.h>\r
+#include <xmltooling/util/ReloadableXMLFile.h>\r
+#include <xmltooling/util/XMLHelper.h>\r
+#include <xercesc/util/XMLUniDefs.hpp>\r
+\r
+using namespace shibsp;\r
+using namespace opensaml::saml2md;\r
+using namespace opensaml;\r
+using namespace xmltooling;\r
+using namespace log4cpp;\r
+using namespace std;\r
+using saml1::NameIdentifier;\r
+using saml2::NameID;\r
+using saml2::EncryptedAttribute;\r
+\r
+namespace shibsp {\r
+\r
+#if defined (_MSC_VER)\r
+ #pragma warning( push )\r
+ #pragma warning( disable : 4250 )\r
+#endif\r
+\r
+ class XMLExtractorImpl\r
+ {\r
+ public:\r
+ XMLExtractorImpl(const DOMElement* e, Category& log);\r
+ ~XMLExtractorImpl() {\r
+ for (attrmap_t::iterator i = m_attrMap.begin(); i!=m_attrMap.end(); ++i)\r
+ delete i->second.first;\r
+ if (m_document)\r
+ m_document->release();\r
+ }\r
+\r
+ void setDocument(DOMDocument* doc) {\r
+ m_document = doc;\r
+ }\r
+\r
+ void extractAttributes(\r
+ const Application& application, const char* assertingParty, const NameIdentifier& nameid, multimap<string,Attribute*>& attributes\r
+ ) const;\r
+ void extractAttributes(\r
+ const Application& application, const char* assertingParty, const NameID& nameid, multimap<string,Attribute*>& attributes\r
+ ) const;\r
+ void extractAttributes(\r
+ const Application& application, const char* assertingParty, const saml1::Attribute& attr, multimap<string,Attribute*>& attributes\r
+ ) const;\r
+ void extractAttributes(\r
+ const Application& application, const char* assertingParty, const saml2::Attribute& attr, multimap<string,Attribute*>& attributes\r
+ ) const;\r
+\r
+ private:\r
+ Category& m_log;\r
+ DOMDocument* m_document;\r
+#ifdef HAVE_GOOD_STL\r
+ typedef map< pair<xstring,xstring>,pair<AttributeDecoder*,string> > attrmap_t;\r
+#else\r
+ typedef map< pair<string,string>,pair<AttributeDecoder*,string> > attrmap_t;\r
+#endif\r
+ attrmap_t m_attrMap;\r
+ };\r
+ \r
+ class XMLExtractor : public AttributeExtractor, public ReloadableXMLFile\r
+ {\r
+ public:\r
+ XMLExtractor(const DOMElement* e) : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT".AttributeExtractor")), m_impl(NULL) {\r
+ load();\r
+ }\r
+ ~XMLExtractor() {\r
+ delete m_impl;\r
+ }\r
+ \r
+ void extractAttributes(\r
+ const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, multimap<string,Attribute*>& attributes\r
+ ) const;\r
+\r
+ protected:\r
+ pair<bool,DOMElement*> load();\r
+\r
+ private:\r
+ XMLExtractorImpl* m_impl;\r
+ };\r
+\r
+#if defined (_MSC_VER)\r
+ #pragma warning( pop )\r
+#endif\r
+\r
+ AttributeExtractor* SHIBSP_DLLLOCAL XMLAttributeExtractorFactory(const DOMElement* const & e)\r
+ {\r
+ return new XMLExtractor(e);\r
+ }\r
+ \r
+ static const XMLCh _AttributeDecoder[] = UNICODE_LITERAL_16(A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);\r
+ static const XMLCh Attributes[] = UNICODE_LITERAL_10(A,t,t,r,i,b,u,t,e,s);\r
+ static const XMLCh _id[] = UNICODE_LITERAL_2(i,d);\r
+ static const XMLCh _name[] = UNICODE_LITERAL_4(n,a,m,e);\r
+ static const XMLCh nameFormat[] = UNICODE_LITERAL_10(n,a,m,e,F,o,r,m,a,t);\r
+};\r
+\r
+void SHIBSP_API shibsp::registerAttributeExtractors()
+{
+ SPConfig::getConfig().AttributeExtractorManager.registerFactory(XML_ATTRIBUTE_EXTRACTOR, XMLAttributeExtractorFactory);
+}
+\r
+XMLExtractorImpl::XMLExtractorImpl(const DOMElement* e, Category& log) : m_log(log), m_document(NULL)\r
+{\r
+#ifdef _DEBUG\r
+ xmltooling::NDC ndc("XMLExtractorImpl");\r
+#endif\r
+ \r
+ if (!XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEMAP_NS, Attributes))\r
+ throw ConfigurationException("XML AttributeExtractor requires am:Attributes at root of configuration.");\r
+\r
+ DOMElement* child = XMLHelper::getFirstChildElement(e, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME);\r
+ while (child) {\r
+ // Check for missing name or id.\r
+ const XMLCh* name = child->getAttributeNS(NULL, _name);\r
+ if (!name || !*name) {\r
+ m_log.warn("skipping Attribute with no name");\r
+ child = XMLHelper::getNextSiblingElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME);\r
+ continue;\r
+ }\r
+\r
+ auto_ptr_char id(child->getAttributeNS(NULL, _id));\r
+ if (!id.get() || !*id.get()) {\r
+ m_log.warn("skipping Attribute with no id");\r
+ child = XMLHelper::getNextSiblingElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME);\r
+ continue;\r
+ }\r
+\r
+ AttributeDecoder* decoder=NULL;\r
+ try {\r
+ DOMElement* dchild = XMLHelper::getFirstChildElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, _AttributeDecoder);\r
+ if (child) {\r
+ auto_ptr<QName> q(XMLHelper::getXSIType(dchild));\r
+ if (q.get())\r
+ decoder = SPConfig::getConfig().AttributeDecoderManager.newPlugin(*q.get(), dchild);\r
+ }\r
+ if (!decoder)\r
+ decoder = SPConfig::getConfig().AttributeDecoderManager.newPlugin(StringAttributeDecoderType, NULL);\r
+ }\r
+ catch (exception& ex) {\r
+ m_log.error("skipping Attribute (%s), error building AttributeDecoder: %s", id.get(), ex.what());\r
+ }\r
+\r
+ if (!decoder) {\r
+ child = XMLHelper::getNextSiblingElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME);\r
+ continue;\r
+ }\r
+\r
+ // Empty NameFormat implies the usual Shib URI naming defaults.\r
+ const XMLCh* format = child->getAttributeNS(NULL, nameFormat);\r
+ if (!format || XMLString::equals(format, shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI) ||\r
+ XMLString::equals(format, saml2::Attribute::URI_REFERENCE))\r
+ format = &chNull; // ignore default Format/Namespace values\r
+\r
+ // Fetch/create the map entry and see if it's a duplicate rule.\r
+#ifdef HAVE_GOOD_STL\r
+ pair<AttributeDecoder*,string>& decl = m_attrMap[make_pair(name,format)];\r
+#else\r
+ auto_ptr_char n(name);\r
+ auto_ptr_char f(format);\r
+ pair<AttributeDecoder*,string>& decl = m_attrMap[make_pair(n.get(),f.get())];\r
+#endif\r
+ if (decl.first) {\r
+ m_log.warn("skipping duplicate Attribute declaration (same name and nameFormat)");\r
+ delete decoder;\r
+ child = XMLHelper::getNextSiblingElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME);\r
+ continue;\r
+ }\r
+\r
+ if (m_log.isInfoEnabled()) {\r
+#ifdef HAVE_GOOD_STL\r
+ auto_ptr_char n(name);\r
+ auto_ptr_char f(format);\r
+#endif\r
+ m_log.info("creating declaration for Attribute %s%s%s", n.get(), *f.get() ? ", Format/Namespace:" : "", f.get());\r
+ }\r
+ \r
+ decl.first = decoder;\r
+ decl.second = id.get();\r
+ \r
+ child = XMLHelper::getNextSiblingElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME);\r
+ }\r
+}\r
+\r
+void XMLExtractorImpl::extractAttributes(\r
+ const Application& application, const char* assertingParty, const NameIdentifier& nameid, multimap<string,Attribute*>& attributes\r
+ ) const\r
+{\r
+#ifdef HAVE_GOOD_STL\r
+ map< pair<xstring,xstring>,pair<AttributeDecoder*,string> >::const_iterator rule;\r
+#else\r
+ map< pair<string,string>,pair<AttributeDecoder*,string> >::const_iterator rule;\r
+#endif\r
+\r
+ const XMLCh* format = nameid.getFormat();\r
+ if (!format || !*format)\r
+ format = NameIdentifier::UNSPECIFIED;\r
+#ifdef HAVE_GOOD_STL\r
+ if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) {\r
+#else\r
+ auto_ptr_char temp(format);\r
+ if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {\r
+#endif\r
+ attributes.insert(\r
+ make_pair(\r
+ rule->second.second,\r
+ rule->second.first->decode(rule->second.second.c_str(), &nameid, assertingParty, application.getString("entityID").second)\r
+ )\r
+ );\r
+ }\r
+}\r
+\r
+void XMLExtractorImpl::extractAttributes(\r
+ const Application& application, const char* assertingParty, const NameID& nameid, multimap<string,Attribute*>& attributes\r
+ ) const\r
+{\r
+#ifdef HAVE_GOOD_STL\r
+ map< pair<xstring,xstring>,pair<AttributeDecoder*,string> >::const_iterator rule;\r
+#else\r
+ map< pair<string,string>,pair<AttributeDecoder*,string> >::const_iterator rule;\r
+#endif\r
+\r
+ const XMLCh* format = nameid.getFormat();\r
+ if (!format || !*format)\r
+ format = NameID::UNSPECIFIED;\r
+#ifdef HAVE_GOOD_STL\r
+ if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) {\r
+#else\r
+ auto_ptr_char temp(format);\r
+ if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {\r
+#endif\r
+ attributes.insert(\r
+ make_pair(\r
+ rule->second.second,\r
+ rule->second.first->decode(rule->second.second.c_str(), &nameid, assertingParty, application.getString("entityID").second)\r
+ )\r
+ );\r
+ }\r
+}\r
+\r
+void XMLExtractorImpl::extractAttributes(\r
+ const Application& application, const char* assertingParty, const saml1::Attribute& attr, multimap<string,Attribute*>& attributes\r
+ ) const\r
+{\r
+#ifdef HAVE_GOOD_STL\r
+ map< pair<xstring,xstring>,pair<AttributeDecoder*,string> >::const_iterator rule;\r
+#else\r
+ map< pair<string,string>,pair<AttributeDecoder*,string> >::const_iterator rule;\r
+#endif\r
+\r
+ const XMLCh* name = attr.getAttributeName();\r
+ const XMLCh* format = attr.getAttributeNamespace();\r
+ if (!name || !*name)\r
+ return;\r
+ if (!format || XMLString::equals(format, shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI))\r
+ format = &chNull;\r
+#ifdef HAVE_GOOD_STL\r
+ if ((rule=m_attrMap.find(make_pair(name,format))) != m_attrMap.end()) {\r
+#else\r
+ auto_ptr_char temp1(name);\r
+ auto_ptr_char temp2(format);\r
+ if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) {\r
+#endif\r
+ attributes.insert(\r
+ make_pair(\r
+ rule->second.second,\r
+ rule->second.first->decode(rule->second.second.c_str(), &attr, assertingParty, application.getString("entityID").second)\r
+ )\r
+ );\r
+ }\r
+}\r
+\r
+void XMLExtractorImpl::extractAttributes(\r
+ const Application& application, const char* assertingParty, const saml2::Attribute& attr, multimap<string,Attribute*>& attributes\r
+ ) const\r
+{\r
+#ifdef HAVE_GOOD_STL\r
+ map< pair<xstring,xstring>,pair<AttributeDecoder*,string> >::const_iterator rule;\r
+#else\r
+ map< pair<string,string>,pair<AttributeDecoder*,string> >::const_iterator rule;\r
+#endif\r
+\r
+ const XMLCh* name = attr.getName();\r
+ const XMLCh* format = attr.getNameFormat();\r
+ if (!name || !*name)\r
+ return;\r
+ if (!format || !*format)\r
+ format = saml2::Attribute::UNSPECIFIED;\r
+ else if (XMLString::equals(format, saml2::Attribute::URI_REFERENCE))\r
+ format = &chNull;\r
+#ifdef HAVE_GOOD_STL\r
+ if ((rule=m_attrMap.find(make_pair(name,format))) != m_attrMap.end()) {\r
+#else\r
+ auto_ptr_char temp1(name);\r
+ auto_ptr_char temp2(format);\r
+ if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) {\r
+#endif\r
+ attributes.insert(\r
+ make_pair(\r
+ rule->second.second,\r
+ rule->second.first->decode(rule->second.second.c_str(), &attr, assertingParty, application.getString("entityID").second)\r
+ )\r
+ );\r
+ }\r
+}\r
+\r
+void XMLExtractor::extractAttributes(\r
+ const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, multimap<string,Attribute*>& attributes\r
+ ) const\r
+{\r
+ // Check for assertions.\r
+ if (XMLString::equals(xmlObject.getElementQName().getLocalPart(), saml1::Assertion::LOCAL_NAME)) {\r
+ const saml2::Assertion* token2 = dynamic_cast<const saml2::Assertion*>(&xmlObject);\r
+ if (token2) {\r
+ auto_ptr_char assertingParty(issuer ? dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID() : NULL);\r
+ const vector<saml2::AttributeStatement*>& statements = token2->getAttributeStatements();\r
+ for (vector<saml2::AttributeStatement*>::const_iterator s = statements.begin(); s!=statements.end(); ++s) {\r
+ const vector<saml2::Attribute*>& attrs = const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();\r
+ for (vector<saml2::Attribute*>::const_iterator a = attrs.begin(); a!=attrs.end(); ++a)\r
+ m_impl->extractAttributes(application, assertingParty.get(), *(*a), attributes);\r
+\r
+ const vector<saml2::EncryptedAttribute*>& encattrs = const_cast<const saml2::AttributeStatement*>(*s)->getEncryptedAttributes();\r
+ for (vector<saml2::EncryptedAttribute*>::const_iterator ea = encattrs.begin(); ea!=encattrs.end(); ++ea)\r
+ extractAttributes(application, issuer, *(*ea), attributes);\r
+ }\r
+ }\r
+\r
+ const saml1::Assertion* token1 = dynamic_cast<const saml1::Assertion*>(&xmlObject);\r
+ if (token1) {\r
+ auto_ptr_char assertingParty(issuer ? dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID() : NULL);\r
+ const vector<saml1::AttributeStatement*>& statements = token1->getAttributeStatements();\r
+ for (vector<saml1::AttributeStatement*>::const_iterator s = statements.begin(); s!=statements.end(); ++s) {\r
+ const vector<saml1::Attribute*>& attrs = const_cast<const saml1::AttributeStatement*>(*s)->getAttributes();\r
+ for (vector<saml1::Attribute*>::const_iterator a = attrs.begin(); a!=attrs.end(); ++a)\r
+ m_impl->extractAttributes(application, assertingParty.get(), *(*a), attributes);\r
+ }\r
+ }\r
+\r
+ throw AttributeExtractionException("Unable to extract attributes, unknown object type.");\r
+ }\r
+\r
+ // Check for attributes.\r
+ if (XMLString::equals(xmlObject.getElementQName().getLocalPart(), saml1::Attribute::LOCAL_NAME)) {\r
+ auto_ptr_char assertingParty(issuer ? dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID() : NULL);\r
+\r
+ const saml2::Attribute* attr2 = dynamic_cast<const saml2::Attribute*>(&xmlObject);\r
+ if (attr2)\r
+ return m_impl->extractAttributes(application, assertingParty.get(), *attr2, attributes);\r
+\r
+ const saml1::Attribute* attr1 = dynamic_cast<const saml1::Attribute*>(&xmlObject);\r
+ if (attr1)\r
+ return m_impl->extractAttributes(application, assertingParty.get(), *attr1, attributes);\r
+\r
+ throw AttributeExtractionException("Unable to extract attributes, unknown object type.");\r
+ }\r
+\r
+ if (XMLString::equals(xmlObject.getElementQName().getLocalPart(), EncryptedAttribute::LOCAL_NAME)) {\r
+ const EncryptedAttribute* encattr = dynamic_cast<const EncryptedAttribute*>(&xmlObject);\r
+ if (encattr) {\r
+ const XMLCh* recipient = application.getXMLString("entityID").second;\r
+ CredentialResolver* cr = application.getCredentialResolver();\r
+ if (!cr) {\r
+ m_log.warn("found encrypted attribute, but no CredentialResolver was available");\r
+ return;\r
+ }\r
+\r
+ try {\r
+ Locker credlocker(cr);\r
+ if (issuer) {\r
+ MetadataCredentialCriteria mcc(*issuer);\r
+ auto_ptr<XMLObject> decrypted(encattr->decrypt(*cr, recipient, &mcc));\r
+ return extractAttributes(application, issuer, *(decrypted.get()), attributes);\r
+ }\r
+ else {\r
+ auto_ptr<XMLObject> decrypted(encattr->decrypt(*cr, recipient));\r
+ return extractAttributes(application, issuer, *(decrypted.get()), attributes);\r
+ }\r
+ }\r
+ catch (exception& ex) {\r
+ m_log.error("caught exception decrypting Attribute: %s", ex.what());\r
+ return;\r
+ }\r
+ }\r
+ }\r
+\r
+ // Check for NameIDs.\r
+ const NameID* name2 = dynamic_cast<const NameID*>(&xmlObject);\r
+ if (name2) {\r
+ auto_ptr_char assertingParty(issuer ? dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID() : NULL);\r
+ return m_impl->extractAttributes(application, assertingParty.get(), *name2, attributes);\r
+ }\r
+\r
+ const NameIdentifier* name1 = dynamic_cast<const NameIdentifier*>(&xmlObject);\r
+ if (name1) {\r
+ auto_ptr_char assertingParty(issuer ? dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID() : NULL);\r
+ return m_impl->extractAttributes(application, assertingParty.get(), *name1, attributes);\r
+ }\r
+\r
+ throw AttributeExtractionException("Unable to extract attributes, unknown object type.");\r
+}\r
+\r
+pair<bool,DOMElement*> XMLExtractor::load()\r
+{\r
+ // Load from source using base class.\r
+ pair<bool,DOMElement*> raw = ReloadableXMLFile::load();\r
+ \r
+ // If we own it, wrap it.\r
+ XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL);\r
+\r
+ XMLExtractorImpl* impl = new XMLExtractorImpl(raw.second, m_log);\r
+ \r
+ // If we held the document, transfer it to the impl. If we didn't, it's a no-op.\r
+ impl->setDocument(docjanitor.release());\r
+\r
+ delete m_impl;\r
+ m_impl = impl;\r
+\r
+ return make_pair(false,(DOMElement*)NULL);\r
+}\r
namespace shibsp {
DECL_XMLTOOLING_EXCEPTION(AttributeException,SHIBSP_EXCEPTIONAPI(SHIBSP_API),shibsp,xmltooling::XMLToolingException,Exceptions during attribute processing.);
+ DECL_XMLTOOLING_EXCEPTION(AttributeExtractionException,SHIBSP_EXCEPTIONAPI(SHIBSP_API),shibsp,shibsp::AttributeException,Exceptions during attribute extraction.);
+ DECL_XMLTOOLING_EXCEPTION(AttributeFilteringException,SHIBSP_EXCEPTIONAPI(SHIBSP_API),shibsp,shibsp::AttributeException,Exceptions during attribute filtering.);
DECL_XMLTOOLING_EXCEPTION(AttributeResolutionException,SHIBSP_EXCEPTIONAPI(SHIBSP_API),shibsp,shibsp::AttributeException,Exceptions during attribute resolution.);
DECL_XMLTOOLING_EXCEPTION(ConfigurationException,SHIBSP_EXCEPTIONAPI(SHIBSP_API),shibsp,xmltooling::XMLToolingException,Exceptions during configuration.);
DECL_XMLTOOLING_EXCEPTION(ListenerException,SHIBSP_EXCEPTIONAPI(SHIBSP_API),shibsp,xmltooling::XMLToolingException,Exceptions during inter-process communication.);
* <p>The caller must free the returned context handle.
*
* @param application reference to application receiving message
- * @param httpRequest client request that initiated session
* @param issuer source of SSO tokens
* @param nameid identifier of principal
- * @param tokens tokens to resolve, if any
+ * @param tokens available assertions, if any
+ * @param attributes attributes already extracted, if any
*/
ResolutionContext* resolveAttributes(
const Application& application,
- const opensaml::HTTPRequest& httpRequest,
const opensaml::saml2md::EntityDescriptor* issuer=NULL,
const opensaml::saml2::NameID* nameid=NULL,
- const std::vector<const opensaml::Assertion*>* tokens=NULL
+ const std::vector<const opensaml::Assertion*>* tokens=NULL,
+ const std::multimap<std::string,Attribute*>* attributes=NULL
) const;
private:
using namespace std;
namespace shibsp {
- SHIBSP_DLLLOCAL PluginManager<Handler,pair<const DOMElement*,const char*>>::Factory SAML1ConsumerFactory;
- SHIBSP_DLLLOCAL PluginManager<Handler,pair<const DOMElement*,const char*>>::Factory SAML2ConsumerFactory;
+ SHIBSP_DLLLOCAL PluginManager<Handler,string,pair<const DOMElement*,const char*>>::Factory SAML1ConsumerFactory;
+ SHIBSP_DLLLOCAL PluginManager<Handler,string,pair<const DOMElement*,const char*>>::Factory SAML2ConsumerFactory;
};
void SHIBSP_API shibsp::registerHandlers()
ResolutionContext* AssertionConsumerService::resolveAttributes(
const Application& application,
- const HTTPRequest& httpRequest,
const saml2md::EntityDescriptor* issuer,
const saml2::NameID* nameid,
- const vector<const Assertion*>* tokens
+ const vector<const Assertion*>* tokens,
+ const multimap<string,Attribute*>* attributes
) const
{
- AttributeResolver* resolver = application.getAttributeResolver();
- if (!resolver) {
- m_log.info("no AttributeResolver available, skipping resolution");
- return NULL;
- }
-
try {
+ AttributeResolver* resolver = application.getAttributeResolver();
+ if (!resolver) {
+ m_log.info("no AttributeResolver available, skipping resolution");
+ return NULL;
+ }
+
m_log.debug("resolving attributes...");
+
+ Locker locker(resolver);
auto_ptr<ResolutionContext> ctx(
- resolver->createResolutionContext(application, httpRequest.getRemoteAddr().c_str(), issuer, nameid, tokens)
+ resolver->createResolutionContext(application, issuer, nameid, tokens, attributes)
);
- resolver->resolveAttributes(*ctx.get(), application.getAttributeIds());
+ resolver->resolveAttributes(*ctx.get());
return ctx.release();
}
catch (exception& ex) {
#include "exceptions.h"
#include "ServiceProvider.h"
#include "SessionCache.h"
+#include "attribute/Attribute.h"
+#include "attribute/resolver/AttributeExtractor.h"
#include "attribute/resolver/ResolutionContext.h"
#include "handler/AssertionConsumerService.h"
m_log.debug("SSO profile processing completed successfully");
// We've successfully "accepted" at least one SSO token, along with any additional valid tokens.
- // To complete processing, we need to resolve attributes and then create the session.
+ // To complete processing, we need to extract and resolve attributes and then create the session.
+ multimap<string,Attribute*> resolvedAttributes;
+ AttributeExtractor* extractor = application.getAttributeExtractor();
+ if (extractor) {
+ Locker extlocker(extractor);
+ for (vector<const opensaml::Assertion*>::const_iterator t = tokens.begin(); t!=tokens.end(); ++t) {
+ try {
+ extractor->extractAttributes(application, policy.getIssuerMetadata(), *(*t), resolvedAttributes);
+ }
+ catch (exception& ex) {
+ m_log.error("caught exception extracting attributes: %s", ex.what());
+ }
+ }
+ }
// First, normalize the SAML 1.x NameIdentifier...
NameIdentifier* n = ssoStatement->getSubject()->getNameIdentifier();
nameid->setNameQualifier(n->getNameQualifier());
}
- const EntityDescriptor* issuerMetadata = dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent());
+ const EntityDescriptor* issuerMetadata =
+ policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL;
auto_ptr<ResolutionContext> ctx(
- resolveAttributes(application, httpRequest, issuerMetadata, nameid.get(), &tokens)
+ resolveAttributes(application, issuerMetadata, nameid.get(), &tokens, &resolvedAttributes)
);
- // Copy over any new tokens, but leave them in the context for cleanup.
- tokens.insert(tokens.end(), ctx->getResolvedAssertions().begin(), ctx->getResolvedAssertions().end());
+ if (ctx.get()) {
+ // Copy over any new tokens, but leave them in the context for cleanup.
+ tokens.insert(tokens.end(), ctx->getResolvedAssertions().begin(), ctx->getResolvedAssertions().end());
+
+ // Copy over new attributes, and transfer ownership.
+ resolvedAttributes.insert(ctx->getResolvedAttributes().begin(), ctx->getResolvedAttributes().end());
+ ctx->getResolvedAttributes().clear();
+ }
// Now merge in bad tokens for caching.
tokens.insert(tokens.end(), badtokens.begin(), badtokens.end());
);
auto_ptr_char authnMethod(ssoStatement->getAuthenticationMethod());
- vector<shibsp::Attribute*>& attrs = ctx->getResolvedAttributes();
- string key = application.getServiceProvider().getSessionCache()->insert(
- lifetime.second ? now + lifetime.second : 0,
- application,
- httpRequest.getRemoteAddr().c_str(),
- issuerMetadata,
- nameid.get(),
- authnInstant.get(),
- NULL,
- authnMethod.get(),
- NULL,
- &tokens,
- &attrs
- );
- attrs.clear(); // Attributes are owned by cache now.
- return key;
+ try {
+ string key = application.getServiceProvider().getSessionCache()->insert(
+ lifetime.second ? now + lifetime.second : 0,
+ application,
+ httpRequest.getRemoteAddr().c_str(),
+ issuerMetadata,
+ nameid.get(),
+ authnInstant.get(),
+ NULL,
+ authnMethod.get(),
+ NULL,
+ &tokens,
+ &resolvedAttributes
+ );
+ resolvedAttributes.clear(); // Attributes are owned by cache now.
+ return key;
+ }
+ catch (exception&) {
+ for_each(resolvedAttributes.begin(), resolvedAttributes.end(), cleanup_pair<string,Attribute>());
+ throw;
+ }
}
#include "exceptions.h"
#include "ServiceProvider.h"
#include "SessionCache.h"
+#include "attribute/Attribute.h"
+#include "attribute/resolver/AttributeExtractor.h"
#include "attribute/resolver/ResolutionContext.h"
#include "handler/AssertionConsumerService.h"
#include <saml/saml2/core/Protocols.h>
#include <saml/saml2/profile/BrowserSSOProfileValidator.h>
#include <saml/saml2/metadata/Metadata.h>
+#include <saml/saml2/metadata/MetadataCredentialCriteria.h>
using namespace shibsp;
using namespace opensaml::saml2;
using namespace opensaml::saml2p;
+using namespace opensaml::saml2md;
using namespace opensaml;
using namespace xmltooling;
using namespace log4cpp;
using namespace std;
-using saml2md::EntityDescriptor;
namespace shibsp {
}
}
- // We look up decryption credentials based on the peer who did the encrypting.
- CredentialCriteria cc;
- if (policy.getIssuerMetadata()) {
- auto_ptr_char assertingParty(dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent())->getEntityID());
- cc.setPeerName(assertingParty.get());
- }
+ // In case we need decryption...
CredentialResolver* cr=application.getCredentialResolver();
-
if (!cr && !encassertions.empty())
m_log.warn("found encrypted assertions, but no CredentialResolver was available");
saml2::Assertion* decrypted=NULL;
try {
Locker credlocker(cr);
- auto_ptr<XMLObject> wrapper((*ea)->decrypt(*cr, application.getXMLString("entityID").second, &cc));
+ auto_ptr<MetadataCredentialCriteria> mcc(
+ policy.getIssuerMetadata() ? new MetadataCredentialCriteria(*policy.getIssuerMetadata()) : NULL
+ );
+ auto_ptr<XMLObject> wrapper((*ea)->decrypt(*cr, application.getXMLString("entityID").second, mcc.get()));
decrypted = dynamic_cast<saml2::Assertion*>(wrapper.get());
if (decrypted) {
wrapper.release();
m_log.warn("found encrypted NameID, but no decryption credential was available");
else {
Locker credlocker(cr);
+ auto_ptr<MetadataCredentialCriteria> mcc(
+ policy.getIssuerMetadata() ? new MetadataCredentialCriteria(*policy.getIssuerMetadata()) : NULL
+ );
try {
- auto_ptr<XMLObject> decryptedID(encname->decrypt(*cr,application.getXMLString("entityID").second,&cc));
+ auto_ptr<XMLObject> decryptedID(encname->decrypt(*cr,application.getXMLString("entityID").second,mcc.get()));
ssoName = dynamic_cast<NameID*>(decryptedID.get());
if (ssoName) {
ownedName = true;
m_log.debug("SSO profile processing completed successfully");
// We've successfully "accepted" at least one SSO token, along with any additional valid tokens.
- // To complete processing, we need to resolve attributes and then create the session.
+ // To complete processing, we need to extract and resolve attributes and then create the session.
+
+ multimap<string,Attribute*> resolvedAttributes;
+ AttributeExtractor* extractor = application.getAttributeExtractor();
+ if (extractor) {
+ Locker extlocker(extractor);
+ for (vector<const opensaml::Assertion*>::const_iterator t = tokens.begin(); t!=tokens.end(); ++t) {
+ try {
+ extractor->extractAttributes(application, policy.getIssuerMetadata(), *(*t), resolvedAttributes);
+ }
+ catch (exception& ex) {
+ m_log.error("caught exception extracting attributes: %s", ex.what());
+ }
+ }
+ }
try {
- const EntityDescriptor* issuerMetadata = dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent());
+ const EntityDescriptor* issuerMetadata =
+ policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL;
auto_ptr<ResolutionContext> ctx(
- resolveAttributes(application, httpRequest, issuerMetadata, ssoName, &tokens)
+ resolveAttributes(application, issuerMetadata, ssoName, &tokens, &resolvedAttributes)
);
- // Copy over any new tokens, but leave them in the context for cleanup.
- tokens.insert(tokens.end(), ctx->getResolvedAssertions().begin(), ctx->getResolvedAssertions().end());
+ if (ctx.get()) {
+ // Copy over any new tokens, but leave them in the context for cleanup.
+ tokens.insert(tokens.end(), ctx->getResolvedAssertions().begin(), ctx->getResolvedAssertions().end());
+
+ // Copy over new attributes, and transfer ownership.
+ resolvedAttributes.insert(ctx->getResolvedAttributes().begin(), ctx->getResolvedAttributes().end());
+ ctx->getResolvedAttributes().clear();
+ }
// Now merge in bad tokens for caching.
tokens.insert(tokens.end(), badtokens.begin(), badtokens.end());
auto_ptr_char index(ssoStatement->getSessionIndex());
auto_ptr_char authnInstant(ssoStatement->getAuthnInstant() ? ssoStatement->getAuthnInstant()->getRawData() : NULL);
- vector<shibsp::Attribute*>& attrs = ctx->getResolvedAttributes();
string key = application.getServiceProvider().getSessionCache()->insert(
sessionExp,
application,
authnClass.get(),
authnDecl.get(),
&tokens,
- &attrs
+ &resolvedAttributes
);
- attrs.clear(); // Attributes are owned by cache now.
+ resolvedAttributes.clear(); // Attributes are owned by cache now.
if (ownedName)
delete ssoName;
if (ownedName)
delete ssoName;
for_each(ownedtokens.begin(), ownedtokens.end(), xmltooling::cleanup<saml2::Assertion>());
+ for_each(resolvedAttributes.begin(), resolvedAttributes.end(), cleanup_pair<string,Attribute>());
throw;
}
}
using namespace std;
namespace shibsp {
- SHIBSP_DLLLOCAL PluginManager<SessionInitiator,pair<const DOMElement*,const char*>>::Factory ChainingSessionInitiatorFactory;
- SHIBSP_DLLLOCAL PluginManager<SessionInitiator,pair<const DOMElement*,const char*>>::Factory Shib1SessionInitiatorFactory;
- SHIBSP_DLLLOCAL PluginManager<SessionInitiator,pair<const DOMElement*,const char*>>::Factory SAML2SessionInitiatorFactory;
- SHIBSP_DLLLOCAL PluginManager<SessionInitiator,pair<const DOMElement*,const char*>>::Factory WAYFSessionInitiatorFactory;
- SHIBSP_DLLLOCAL PluginManager<SessionInitiator,pair<const DOMElement*,const char*>>::Factory SAMLDSSessionInitiatorFactory;
+ SHIBSP_DLLLOCAL PluginManager<SessionInitiator,string,pair<const DOMElement*,const char*>>::Factory ChainingSessionInitiatorFactory;
+ SHIBSP_DLLLOCAL PluginManager<SessionInitiator,string,pair<const DOMElement*,const char*>>::Factory Shib1SessionInitiatorFactory;
+ SHIBSP_DLLLOCAL PluginManager<SessionInitiator,string,pair<const DOMElement*,const char*>>::Factory SAML2SessionInitiatorFactory;
+ SHIBSP_DLLLOCAL PluginManager<SessionInitiator,string,pair<const DOMElement*,const char*>>::Factory WAYFSessionInitiatorFactory;
+ SHIBSP_DLLLOCAL PluginManager<SessionInitiator,string,pair<const DOMElement*,const char*>>::Factory SAMLDSSessionInitiatorFactory;
};
void SHIBSP_API shibsp::registerSessionInitiators()
delete m_lock;\r
m_obj.destroy();\r
delete m_nameid;\r
- for_each(m_attributes.begin(), m_attributes.end(), cleanup_const_pair<string,Attribute>());\r
+ for_each(m_attributes.begin(), m_attributes.end(), cleanup_pair<string,Attribute>());\r
for_each(m_tokens.begin(), m_tokens.end(), cleanup_pair<string,Assertion>());\r
}\r
\r
const char* getAuthnContextDeclRef() const {\r
return m_obj["authncontext_decl"].string();\r
}\r
- const map<string,const Attribute*>& getAttributes() const {\r
+ const multimap<string,Attribute*>& getAttributes() const {\r
if (m_attributes.empty())\r
unmarshallAttributes();\r
return m_attributes;\r
int m_version;\r
mutable DDF m_obj;\r
saml2::NameID* m_nameid;\r
- mutable map<string,const Attribute*> m_attributes;\r
+ mutable multimap<string,Attribute*> m_attributes;\r
mutable vector<const char*> m_ids;\r
mutable map<string,Assertion*> m_tokens;\r
time_t m_expires,m_lastAccess;\r
const char* authncontext_class=NULL,\r
const char* authncontext_decl=NULL,\r
const vector<const Assertion*>* tokens=NULL,\r
- const vector<Attribute*>* attributes=NULL\r
+ const multimap<string,Attribute*>* attributes=NULL\r
);\r
Session* find(const char* key, const Application& application, const char* client_addr=NULL, time_t timeout=0);\r
void remove(const char* key, const Application& application, const char* client_addr);\r
while (!attr.isnull()) {\r
try {\r
attribute = Attribute::unmarshall(attr);\r
- m_attributes[attribute->getId()] = attribute;\r
+ m_attributes.insert(make_pair(attribute->getId(),attribute));\r
if (m_cache->m_log.isDebugEnabled())\r
m_cache->m_log.debug("unmarshalled attribute (ID: %s) with %d value%s",\r
attribute->getId(), attr.first().integer(), attr.first().integer()!=1 ? "s" : "");\r
const char* authncontext_class,\r
const char* authncontext_decl,\r
const vector<const Assertion*>* tokens,\r
- const vector<Attribute*>* attributes\r
+ const multimap<string,Attribute*>* attributes\r
)\r
{\r
DDF in("insert::"REMOTED_SESSION_CACHE"::SessionCache");\r
if (attributes) {\r
DDF attr;\r
DDF attrs = in.addmember("attributes").list();\r
- for (vector<Attribute*>::const_iterator a=attributes->begin(); a!=attributes->end(); ++a) {\r
- attr = (*a)->marshall();\r
+ for (multimap<string,Attribute*>::const_iterator a=attributes->begin(); a!=attributes->end(); ++a) {\r
+ attr = a->second->marshall();\r
attrs.add(attr);\r
}\r
}\r
") for (applicationId: " <<\r
application.getId() <<\r
") {";\r
- for (vector<Attribute*>::const_iterator a=attributes->begin(); a!=attributes->end(); ++a)\r
- xlog->log.infoStream() << "\t" << (*a)->getId() << " (" << (*a)->valueCount() << " values)";\r
+ for (multimap<string,Attribute*>::const_iterator a=attributes->begin(); a!=attributes->end(); ++a)\r
+ xlog->log.infoStream() << "\t" << a->second->getId() << " (" << a->second->valueCount() << " values)";\r
xlog->log.info("}");\r
- for_each(attributes->begin(), attributes->end(), xmltooling::cleanup<Attribute>());\r
+ for_each(attributes->begin(), attributes->end(), cleanup_pair<string,Attribute>());\r
}\r
\r
return out["key"].string();\r
const char* getAuthnContextDeclRef() const {\r
return m_obj["authncontext_decl"].string();\r
}\r
- const map<string,const Attribute*>& getAttributes() const {\r
+ const multimap<string,Attribute*>& getAttributes() const {\r
if (m_attributes.empty())\r
unmarshallAttributes();\r
return m_attributes;\r
\r
DDF m_obj;\r
saml2::NameID* m_nameid;\r
- mutable map<string,const Attribute*> m_attributes;\r
+ mutable multimap<string,Attribute*> m_attributes;\r
mutable vector<const char*> m_ids;\r
mutable map<string,Assertion*> m_tokens;\r
SSCache* m_cache;\r
const char* authncontext_class=NULL,\r
const char* authncontext_decl=NULL,\r
const vector<const Assertion*>* tokens=NULL,\r
- const vector<Attribute*>* attributes=NULL\r
+ const multimap<string,Attribute*>* attributes=NULL\r
);\r
Session* find(const char* key, const Application& application, const char* client_addr=NULL, time_t timeout=0);\r
void remove(const char* key, const Application& application, const char* client_addr);\r
{\r
m_obj.destroy();\r
delete m_nameid;\r
- for_each(m_attributes.begin(), m_attributes.end(), cleanup_const_pair<string,Attribute>());\r
+ for_each(m_attributes.begin(), m_attributes.end(), cleanup_pair<string,Attribute>());\r
for_each(m_tokens.begin(), m_tokens.end(), cleanup_pair<string,Assertion>());\r
}\r
\r
while (!attr.isnull()) {\r
try {\r
attribute = Attribute::unmarshall(attr);\r
- m_attributes[attribute->getId()] = attribute;\r
+ m_attributes.insert(make_pair(attribute->getId(), attribute));\r
if (m_cache->m_log.isDebugEnabled())\r
m_cache->m_log.debug("unmarshalled attribute (ID: %s) with %d value%s",\r
attribute->getId(), attr.first().integer(), attr.first().integer()!=1 ? "s" : "");\r
const char* authncontext_class,\r
const char* authncontext_decl,\r
const vector<const Assertion*>* tokens,\r
- const vector<Attribute*>* attributes\r
+ const multimap<string,Attribute*>* attributes\r
)\r
{\r
#ifdef _DEBUG\r
if (attributes) {\r
DDF attr;\r
DDF attrlist = obj.addmember("attributes").list();\r
- for (vector<Attribute*>::const_iterator a=attributes->begin(); a!=attributes->end(); ++a) {\r
- attr = (*a)->marshall();\r
+ for (multimap<string,Attribute*>::const_iterator a=attributes->begin(); a!=attributes->end(); ++a) {\r
+ attr = a->second->marshall();\r
attrlist.add(attr);\r
}\r
}\r
") for (applicationId: " <<\r
application.getId() <<\r
") {";\r
- for (vector<Attribute*>::const_iterator a=attributes->begin(); a!=attributes->end(); ++a)\r
- xlog->log.infoStream() << "\t" << (*a)->getId() << " (" << (*a)->valueCount() << " values)";\r
+ for (multimap<string,Attribute*>::const_iterator a=attributes->begin(); a!=attributes->end(); ++a)\r
+ xlog->log.infoStream() << "\t" << a->second->getId() << " (" << a->second->valueCount() << " values)";\r
xlog->log.info("}");\r
- for_each(attributes->begin(), attributes->end(), xmltooling::cleanup<Attribute>());\r
+ for_each(attributes->begin(), attributes->end(), cleanup_pair<string,Attribute>());\r
}\r
\r
return key.get();\r
return false;\r
}\r
\r
- // Find the attribute matching the require rule.\r
- map<string,const Attribute*>::const_iterator attr = session->getAttributes().find(m_alias);\r
- if (attr == session->getAttributes().end()) {\r
+ // Find the attribute(s) matching the require rule.\r
+ pair<multimap<string,Attribute*>::const_iterator, multimap<string,Attribute*>::const_iterator> attrs =\r
+ session->getAttributes().equal_range(m_alias);\r
+ if (attrs.first == attrs.second) {\r
request.log(SPRequest::SPWarn, string("rule requires attribute (") + m_alias + "), not found in session");\r
return false;\r
}\r
\r
- bool caseSensitive = attr->second->isCaseSensitive();\r
+ for (; attrs.first != attrs.second; ++attrs.first) {\r
+ bool caseSensitive = attrs.first->second->isCaseSensitive();\r
\r
- // Now we have to intersect the attribute's values against the rule's list.\r
- const vector<string>& vals = attr->second->getSerializedValues();\r
- for (vector<string>::const_iterator i=m_vals.begin(); i!=m_vals.end(); ++i) {\r
- for (vector<string>::const_iterator j=vals.begin(); j!=vals.end(); ++j) {\r
- if ((caseSensitive && *i == *j) || (!caseSensitive && !strcasecmp(i->c_str(),j->c_str()))) {\r
- request.log(SPRequest::SPDebug, string("AccessControl plugin expecting ") + *j + ", authz granted");\r
- return true;\r
+ // Now we have to intersect the attribute's values against the rule's list.\r
+ const vector<string>& vals = attrs.first->second->getSerializedValues();\r
+ for (vector<string>::const_iterator i=m_vals.begin(); i!=m_vals.end(); ++i) {\r
+ for (vector<string>::const_iterator j=vals.begin(); j!=vals.end(); ++j) {\r
+ if ((caseSensitive && *i == *j) || (!caseSensitive && !strcasecmp(i->c_str(),j->c_str()))) {\r
+ request.log(SPRequest::SPDebug, string("AccessControl plugin expecting ") + *j + ", authz granted");\r
+ return true;\r
+ }\r
}\r
}\r
}\r
#include "SPConfig.h"\r
#include "SPRequest.h"\r
#include "TransactionLog.h"\r
+#include "attribute/resolver/AttributeExtractor.h"\r
#include "attribute/resolver/AttributeResolver.h"\r
#include "handler/SessionInitiator.h"\r
#include "remoting/ListenerService.h"\r
TrustEngine* getTrustEngine() const {\r
return (!m_trust && m_base) ? m_base->getTrustEngine() : m_trust;\r
}\r
+ AttributeExtractor* getAttributeExtractor() const {\r
+ return (!m_attrExtractor && m_base) ? m_base->getAttributeExtractor() : m_attrExtractor;\r
+ }\r
AttributeResolver* getAttributeResolver() const {\r
return (!m_attrResolver && m_base) ? m_base->getAttributeResolver() : m_attrResolver;\r
}\r
- const set<string>* getAttributeIds() const {\r
- return (m_attributeIds.empty() && m_base) ? m_base->getAttributeIds() : (m_attributeIds.empty() ? NULL : &m_attributeIds);\r
- }\r
CredentialResolver* getCredentialResolver() const {\r
return (!m_credResolver && m_base) ? m_base->getCredentialResolver() : m_credResolver;\r
}\r
string m_hash;\r
MetadataProvider* m_metadata;\r
TrustEngine* m_trust;\r
+ AttributeExtractor* m_attrExtractor;\r
AttributeResolver* m_attrResolver;\r
CredentialResolver* m_credResolver;\r
vector<const XMLCh*> m_audiences;\r
- set<string> m_attributeIds;\r
\r
// manage handler objects\r
vector<Handler*> m_handlers;\r
static const XMLCh _Application[] = UNICODE_LITERAL_11(A,p,p,l,i,c,a,t,i,o,n);\r
static const XMLCh Applications[] = UNICODE_LITERAL_12(A,p,p,l,i,c,a,t,i,o,n,s);\r
static const XMLCh _ArtifactMap[] = UNICODE_LITERAL_11(A,r,t,i,f,a,c,t,M,a,p);\r
+ static const XMLCh _AttributeExtractor[] = UNICODE_LITERAL_18(A,t,t,r,i,b,u,t,e,E,x,t,r,a,c,t,o,r);\r
+ static const XMLCh _AttributeFilter[] = UNICODE_LITERAL_15(A,t,t,r,i,b,u,t,e,F,i,l,t,e,r);\r
static const XMLCh _AttributeResolver[] = UNICODE_LITERAL_17(A,t,t,r,i,b,u,t,e,R,e,s,o,l,v,e,r);\r
static const XMLCh _CredentialResolver[] = UNICODE_LITERAL_18(C,r,e,d,e,n,t,i,a,l,R,e,s,o,l,v,e,r);\r
static const XMLCh DefaultRelyingParty[] = UNICODE_LITERAL_19(D,e,f,a,u,l,t,R,e,l,y,i,n,g,P,a,r,t,y);\r
const ServiceProvider* sp,\r
const DOMElement* e,\r
const XMLApplication* base\r
- ) : m_sp(sp), m_base(base), m_metadata(NULL), m_trust(NULL), m_attrResolver(NULL), m_credResolver(NULL),\r
- m_partyDefault(NULL), m_sessionInitDefault(NULL), m_acsDefault(NULL)\r
+ ) : m_sp(sp), m_base(base), m_metadata(NULL), m_trust(NULL), m_attrExtractor(NULL), m_attrResolver(NULL),\r
+ m_credResolver(NULL), m_partyDefault(NULL), m_sessionInitDefault(NULL), m_acsDefault(NULL)\r
{\r
#ifdef _DEBUG\r
xmltooling::NDC ndc("XMLApplication");\r
m_hash+=getString("entityID").second;\r
m_hash=samlConf.hashSHA1(m_hash.c_str(), true);\r
\r
- pair<bool,const char*> attributes = getString("attributeIds");\r
- if (attributes.first) {\r
- char* dup = strdup(attributes.second);\r
- char* pos;\r
- char* start = dup;\r
- while (start && *start) {\r
- while (*start && isspace(*start))\r
- start++;\r
- if (!*start)\r
- break;\r
- pos = strchr(start,' ');\r
- if (pos)\r
- *pos=0;\r
- m_attributeIds.insert(start);\r
- start = pos ? pos+1 : NULL;\r
- }\r
- free(dup);\r
- }\r
-\r
const PropertySet* sessions = getPropertySet("Sessions");\r
\r
// Process handlers.\r
}\r
\r
if (conf.isEnabled(SPConfig::AttributeResolution)) {\r
+ child = XMLHelper::getFirstChildElement(e,_AttributeExtractor);\r
+ if (child) {\r
+ auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
+ log.info("building AttributeExtractor of type %s...",type.get());\r
+ try {\r
+ m_attrExtractor = conf.AttributeExtractorManager.newPlugin(type.get(),child);\r
+ }\r
+ catch (exception& ex) {\r
+ log.crit("error building AttributeExtractor: %s", ex.what());\r
+ }\r
+ }\r
+\r
child = XMLHelper::getFirstChildElement(e,_AttributeResolver);\r
if (child) {\r
auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
for_each(m_handlers.begin(),m_handlers.end(),xmltooling::cleanup<Handler>());\r
delete m_credResolver;\r
delete m_attrResolver;\r
+ delete m_attrExtractor;\r
delete m_trust;\r
delete m_metadata;\r
}\r
XMLString::equals(name,_MetadataProvider) ||\r
XMLString::equals(name,_TrustEngine) ||\r
XMLString::equals(name,_CredentialResolver) ||\r
+ XMLString::equals(name,_AttributeFilter) ||\r
+ XMLString::equals(name,_AttributeExtractor) ||\r
XMLString::equals(name,_AttributeResolver))\r
return FILTER_REJECT;\r
\r
namespace shibsp {
//SHIBSP_DLLLOCAL PluginManager<ListenerService,const DOMElement*>::Factory MemoryListenerServiceFactory;
- SHIBSP_DLLLOCAL PluginManager<ListenerService,const DOMElement*>::Factory TCPListenerServiceFactory;
+ SHIBSP_DLLLOCAL PluginManager<ListenerService,string,const DOMElement*>::Factory TCPListenerServiceFactory;
#ifndef WIN32
- SHIBSP_DLLLOCAL PluginManager<ListenerService,const DOMElement*>::Factory UnixListenerServiceFactory;
+ SHIBSP_DLLLOCAL PluginManager<ListenerService,string,const DOMElement*>::Factory UnixListenerServiceFactory;
#endif
};
mutable map<const ObservableMetadataProvider*,credmap_t> m_credentialMap;
};
- SHIBSP_DLLLOCAL PluginManager<TrustEngine,const DOMElement*>::Factory PKIXTrustEngineFactory;
+ SHIBSP_DLLLOCAL PluginManager<TrustEngine,string,const DOMElement*>::Factory PKIXTrustEngineFactory;
TrustEngine* SHIBSP_DLLLOCAL PKIXTrustEngineFactory(const DOMElement* const & e)
{
>\r
</File>\r
<File\r
- RelativePath=".\attribute\SimpleAttributeDecoder.cpp"\r
+ RelativePath=".\attribute\StringAttributeDecoder.cpp"\r
>\r
</File>\r
<Filter\r
Name="impl"\r
>\r
<File\r
- RelativePath=".\attribute\resolver\impl\AttributeResolver.cpp"\r
+ RelativePath=".\attribute\resolver\impl\QueryAttributeResolver.cpp"\r
>\r
</File>\r
<File\r
- RelativePath=".\attribute\resolver\impl\SimpleAttributeResolver.cpp"\r
+ RelativePath=".\attribute\resolver\impl\XMLAttributeExtractor.cpp"\r
>\r
</File>\r
</Filter>\r
Name="resolver"\r
>\r
<File\r
+ RelativePath=".\attribute\resolver\AttributeExtractor.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\attribute\resolver\AttributeResolver.h"\r
>\r
</File>\r
\r
const XMLCh shibspconstants::SHIBMD_PREFIX[] = UNICODE_LITERAL_6(s,h,i,b,m,d);\r
\r
-const XMLCh shibspconstants::SHIB2SPCONFIG_NS[] = // urn:mace:shibboleth:sp:config:2.0\r
+const XMLCh shibspconstants::SHIB2SPCONFIG_NS[] = // urn:mace:shibboleth:2.0:native:sp:config\r
{ chLatin_u, chLatin_r, chLatin_n, chColon, chLatin_m, chLatin_a, chLatin_c, chLatin_e, chColon,\r
chLatin_s, chLatin_h, chLatin_i, chLatin_b, chLatin_b, chLatin_o, chLatin_l, chLatin_e, chLatin_t, chLatin_h, chColon,\r
- chLatin_s, chLatin_p, chColon, chLatin_c, chLatin_o, chLatin_n, chLatin_f, chLatin_i, chLatin_g, chColon,\r
- chDigit_2, chPeriod, chDigit_0, chNull\r
+ chDigit_2, chPeriod, chDigit_0, chColon, chLatin_n, chLatin_a, chLatin_t, chLatin_i, chLatin_v, chLatin_e, chColon,\r
+ chLatin_s, chLatin_p, chColon, chLatin_c, chLatin_o, chLatin_n, chLatin_f, chLatin_i, chLatin_g, chNull\r
+};\r
+\r
+const XMLCh shibspconstants::SHIB2ATTRIBUTEMAP_NS[] = // urn:mace:shibboleth:2.0:attribute-map\r
+{ chLatin_u, chLatin_r, chLatin_n, chColon, chLatin_m, chLatin_a, chLatin_c, chLatin_e, chColon,\r
+ chLatin_s, chLatin_h, chLatin_i, chLatin_b, chLatin_b, chLatin_o, chLatin_l, chLatin_e, chLatin_t, chLatin_h, chColon,\r
+ chDigit_2, chPeriod, chDigit_0, chColon,\r
+ chLatin_a, chLatin_t, chLatin_t, chLatin_r, chLatin_i, chLatin_b, chLatin_u, chLatin_t, chLatin_e, chDash,\r
+ chLatin_m, chLatin_a, chLatin_p, chNull\r
};\r
\r
const XMLCh shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI[] = // urn:mace:shibboleth:1.0:attributeNamespace:uri\r
/** Shibboleth Metadata QName prefix ("shibmd") */
extern SHIBSP_API const XMLCh SHIBMD_PREFIX[];
- /** Shibboleth 2.0 SP configuration namespace ("urn:mace:shibboleth:sp:config:2.0") */
+ /** Shibboleth 2.0 SP configuration namespace ("urn:mace:shibboleth:2.0:native:sp:config") */
extern SHIBSP_API const XMLCh SHIB2SPCONFIG_NS[];
+ /** Shibboleth 2.0 attribute mapping namespace ("urn:mace:shibboleth:2.0:attribute-map") */
+ extern SHIBSP_API const XMLCh SHIB2ATTRIBUTEMAP_NS[];
+
/** Shibboleth 1.x Protocol Enumeration constant ("urn:mace:shibboleth:1.0") */
extern SHIBSP_API const XMLCh SHIB1_PROTOCOL_ENUM[];