<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
        xmlns:afp="urn:mace:shibboleth:2.0:afp"
        xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
        targetNamespace="urn:mace:shibboleth:2.0:afp"
        version="3.1.0"
        elementFormDefault="qualified">

    <import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd"/>

    <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:IdentityType">
                <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:PermitValueRule" minOccurs="0" maxOccurs="unbounded">
                        <annotation>
                            <documentation>
                                Defines a permit value rule that may be reused across multiple attribute rules.
                            </documentation>
                        </annotation>
                    </element>
                    <element ref="afp:DenyValueRule" minOccurs="0" maxOccurs="unbounded">
                        <annotation>
                            <documentation>
                                Defines a deny value rule that may be reused across multiple attribute rules.
                            </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: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>
                </sequence>
            </extension>
        </complexContent>
    </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:IdentityType">
                <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>
                                    Reference 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>
                                    Reference to a AttributeRule defined within this policy group or another.
                                </documentation>
                            </annotation>
                        </element>
                    </choice>
                </sequence>
            </extension>
        </complexContent>
    </complexType>

    <element name="AttributeRule" type="afp:AttributeRuleType">
        <annotation>
            <documentation>A rule that describes how values of an attribute will be filtered.</documentation>
        </annotation>
    </element>
    <complexType name="AttributeRuleType">
        <complexContent>
            <extension base="afp:IdentityType">
                <choice>
                    <choice minOccurs="0">
                        <element ref="afp:PermitValueRule" />
                        <element name="PermitValueRuleReference" type="afp:ReferenceType">
                            <annotation>
                                <documentation>
                                    Reference to a PermitValueRule defined within this policy group or another.
                                </documentation>
                            </annotation>
                        </element>
                    </choice>
                    <choice minOccurs="0">
                        <element ref="afp:DenyValueRule" />
                        <element name="DenyValueRuleReference" type="afp:ReferenceType">
                            <annotation>
                                <documentation>
                                    Reference to a DenyValueRule defined within this policy group or another.
                                </documentation>
                            </annotation>
                        </element>
                    </choice>
                </choice>
                <attribute name="attributeID" type="afp:string" use="required">
                    <annotation>
                        <documentation>The ID of the attribute to which this rule applies.</documentation>
                    </annotation>
                </attribute>
                <attribute name="permitAny" type="boolean">
                    <annotation>
                        <documentation>If present, and true injects an implicit permit value rule of type ANY</documentation>
                    </annotation>
                </attribute>
            </extension>
        </complexContent>
    </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 attribute values. If the filter evaluates to true the value is permitted to be released.
            </documentation>
        </annotation>
    </element>
    <element name="DenyValueRule" type="afp:MatchFunctorType">
        <annotation>
            <documentation>
                A filter for attribute values. If the filter evaluates to true the value is denied and may not be released.
            </documentation>
        </annotation>
    </element>
    <complexType name="MatchFunctorType" abstract="true">
        <complexContent>
            <extension base="afp:IdentityType" />
        </complexContent>
    </complexType>

    <complexType name="IdentityType">
        <attribute name="id" type="afp:string">
            <annotation>
                <documentation>An ID, unique within the policy and component type.</documentation>
            </annotation>
        </attribute>
    </complexType>

    <complexType name="ReferenceType">
        <attribute name="ref" type="afp:string">
            <annotation>
                <documentation>Used to reference a globally defined policy component.</documentation>
            </annotation>
        </attribute>
    </complexType>

    <!-- 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 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 maxOccurs="unbounded">
                    <element name="Rule" type="afp:MatchFunctorType">
                        <annotation>
                            <documentation>
                                The set of match function rules to be ORed.
                            </documentation>
                        </annotation>
                    </element>
                    <element name="RuleReference" type="afp:ReferenceType">
                        <annotation>
                            <documentation>
                                The set of match function rules to be ORed.
                            </documentation>
                        </annotation>
                    </element>
                </choice>
            </extension>
        </complexContent>
    </complexType>

    <complexType name="NOT">
        <annotation>
            <documentation>
                A match function that performs a logical NOT on the result of 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 negated.
                            </documentation>
                        </annotation>
                    </element>
                    <element name="RuleReference" type="afp:ReferenceType">
                        <annotation>
                            <documentation>
                                The set of match function rules to be negated.
                            </documentation>
                        </annotation>
                    </element>
                </choice>
            </extension>
        </complexContent>
    </complexType>

    <!--  Literal String Match Functions -->
    <complexType name="Requester">
        <annotation>
            <documentation>
                A match function that matches the attribute requester against the specified value.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:StringMatchType"/>
        </complexContent>
    </complexType>

    <complexType name="Issuer">
        <annotation>
            <documentation>
                A match function that matches the attribute issuer against the specified value.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:StringMatchType"/>
        </complexContent>
    </complexType>

    <complexType name="AuthenticationMethod">
        <annotation>
            <documentation>
                A match function that matches the authentication method against the specified value.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:StringMatchType" />
        </complexContent>
    </complexType>

    <complexType name="Value">
        <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="afp:TargetedStringMatchType"/>
        </complexContent>
    </complexType>

    <complexType name="Scope">
        <annotation>
            <documentation>
                A match function that matches the attribute scope against the specified value.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:TargetedStringMatchType"/>
        </complexContent>
    </complexType>

    <complexType name="TargetedStringMatchType" abstract="true">
        <complexContent>
            <extension base="afp:StringMatchType">
                <attribute name="attributeID" type="afp: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="afp:string" use="required">
                    <annotation>
                        <documentation>The string value to match.</documentation>
                    </annotation>
                </attribute>
                <attribute name="caseSensitive" type="boolean">
                    <annotation>
                        <documentation>
                            A boolean flag indicating whether the match evaluation should be case sensitive.
                        </documentation>
                    </annotation>
                </attribute>
            </extension>
        </complexContent>
    </complexType>

    <!--  Regular Expression Match Functions -->
    <complexType name="RequesterRegex">
        <annotation>
            <documentation>
                A match function that matches the attribute requester against the specified regular expression.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:RegexMatchType"/>
        </complexContent>
    </complexType>

    <complexType name="IssuerRegex">
        <annotation>
            <documentation>
                A match function that matches the attribute issuer against the specified regular expression.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp: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="afp:RegexMatchType" />
        </complexContent>
    </complexType>

    <complexType name="ValueRegex">
        <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="afp:TargetedRegexMatchType"/>
        </complexContent>
    </complexType>

    <complexType name="ScopeRegex">
        <annotation>
            <documentation>
                A match function that matches the attribute scope against the specified regular expression.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:TargetedRegexMatchType"/>
        </complexContent>
    </complexType>

    <complexType name="TargetedRegexMatchType" abstract="true">
        <complexContent>
            <extension base="afp:RegexMatchType">
                <attribute name="attributeID" type="afp: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="afp:string" use="required">
                    <annotation>
                        <documentation>The regular expression values are matched against.</documentation>
                    </annotation>
                </attribute>
                <attribute name="caseSensitive" type="boolean">
                    <annotation>
                        <documentation>Whether the comparison is case sensitive, default TRUE</documentation>
                    </annotation>
                </attribute>     
                <attribute name="options" type="afp:string">
                    <annotation>
                        <documentation>The regular expression options to apply.</documentation>
                    </annotation>
                </attribute>
            </extension>
        </complexContent>
    </complexType>

    <!-- Misc. Functions -->

    <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="afp:string" use="required">
                    <annotation>
                        <documentation>The ID of the attribute whose value should be matched.</documentation>
                    </annotation>
                </attribute>
                <attribute name="minimum" type="nonNegativeInteger">
                    <annotation>
                        <documentation>Minimum number of values an attribute may have.</documentation>
                    </annotation>
                </attribute>
                <attribute name="maximum" type="positiveInteger">
                    <annotation>
                        <documentation>Maximum number of values an attribute may have.</documentation>
                    </annotation>
                </attribute>
            </extension>
        </complexContent>
    </complexType>

    <!-- SAML-specific. -->

    <complexType name="EntityAttributeExactMatch">
        <annotation>
            <documentation>
                A match function that checks if the attribute requester's metadata
                contains an entity attribute with the specified value.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:EntityAttributeExactMatchType"/>
        </complexContent>
    </complexType>

    <complexType name="IssuerEntityAttributeExactMatch">
        <annotation>
            <documentation>
                A match function that checks if the attribute issuer's metadata
                contains an entity attribute with the specified value.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:EntityAttributeExactMatchType"/>
        </complexContent>
    </complexType>

    <complexType name="EntityAttributeExactMatchType" abstract="true">
        <complexContent>
            <extension base="afp:MatchFunctorType">
                <attribute name="attributeName" type="afp:string" use="required">
                    <annotation>
                        <documentation>The name of the entity attribute to match.</documentation>
                    </annotation>
                </attribute>
                <attribute name="attributeValue" type="afp:string" use="required">
                    <annotation>
                        <documentation>The value of the entity attribute to match.</documentation>
                    </annotation>
                </attribute>
                <attribute name="attributeNameFormat" type="afp:string">
                    <annotation>
                        <documentation>The NameFormat of the entity attribute to match.</documentation>
                    </annotation>
                </attribute>
            </extension>
        </complexContent>
    </complexType>

    <complexType name="EntityAttributeRegexMatch">
        <annotation>
            <documentation>
                A match function that checks if the attribute requester's metadata
                contains an entity attribute with a value that matches the given regular expression.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:EntityAttributeRegexMatchType"/>
        </complexContent>
    </complexType>

    <complexType name="IssuerEntityAttributeRegexMatch">
        <annotation>
            <documentation>
                A match function that checks if the attribute issuer's metadata
                contains an entity attribute with a value that matches the given regular expression.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:EntityAttributeRegexMatchType"/>
        </complexContent>
    </complexType>

    <complexType name="EntityAttributeRegexMatchType" abstract="true">
        <complexContent>
            <extension base="afp:MatchFunctorType">
                <attribute name="attributeName" type="afp:string" use="required">
                    <annotation>
                        <documentation>The name of the entity attribute to match.</documentation>
                    </annotation>
                </attribute>
                <attribute name="attributeValueRegex" type="afp:string" use="required">
                    <annotation>
                        <documentation>The regular expression that must match the value of the entity attribute to
                            match.</documentation>
                    </annotation>
                </attribute>
                <attribute name="attributeNameFormat" type="afp:string">
                    <annotation>
                        <documentation>The name format of the entity attribute to match.</documentation>
                    </annotation>
                </attribute>
            </extension>
        </complexContent>
    </complexType>

    <!-- TODO: implement NameID functions or remove -->

    <complexType name="NameIDFormatExactMatch">
        <annotation>
            <documentation>
                A match function that evaluates to true if the attribute requester supports a specified
                NameID format.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:NameIDFormatExactMatchType"/>
        </complexContent>
    </complexType>

    <complexType name="IssuerNameIDFormatExactMatch">
        <annotation>
            <documentation>
                A match function that evaluates to true if the attribute issuer supports a specified
                NameID format.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:NameIDFormatExactMatchType"/>
        </complexContent>
    </complexType>

    <complexType name="NameIDFormatExactMatchType" abstract="true">
        <complexContent>
            <extension base="afp:MatchFunctorType">
                <attribute name="nameIdFormat" type="afp:string" use="required">
                    <annotation>
                        <documentation>The NameID format that needs to be supported by the entity.</documentation>
                    </annotation>
                </attribute>
            </extension>
        </complexContent>
    </complexType>

    <complexType name="InEntityGroup">
        <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="afp:EntityGroupMatchType"/>
        </complexContent>
    </complexType>

    <complexType name="IssuerInEntityGroup">
        <annotation>
            <documentation>
                A match function that evaluates to true if the attribute issuer is found in metadata and
                is a member of the given entity group.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:EntityGroupMatchType"/>
        </complexContent>
    </complexType>

    <complexType name="EntityGroupMatchType" abstract="true">
        <complexContent>
            <extension base="afp:MatchFunctorType">
                <attribute name="groupID" type="afp:string" use="required">
                    <annotation>
                        <documentation>The entity group ID that an entity must be in.</documentation>
                    </annotation>
                </attribute>
                <attribute name="checkAffiliations" type="boolean">
                    <annotation>
                        <documentation>
                            Whether to check for membership in metadata-based AffiliationDescriptors.
                            
                            Defaults to false.
                        </documentation>
                    </annotation>
                </attribute>
            </extension>
        </complexContent>
    </complexType>

    <complexType name="RegistrationAuthority">
        <annotation>
            <documentation>
                A match function that matches the SP (requester) MDRPI against a list of potential values.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:RegistrationAuthorityMatchType" />
        </complexContent>
    </complexType>
        
    <complexType name="IssuerRegistrationAuthority">
        <annotation>
            <documentation>
                A match function that matches the attribute issuer's MDRPI content against a list of potential values.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:RegistrationAuthorityMatchType" />
        </complexContent>
    </complexType>

    <complexType name="RegistrationAuthorityMatchType" abstract="true">
        <complexContent>
            <extension base="afp:MatchFunctorType">
                <attribute name="registrars" type="afp:anyURIListType" use="required">
                    <annotation>
                        <documentation>The string values to match.</documentation>
                    </annotation>
                </attribute>
                <attribute name="matchIfMetadataSilent" type="boolean">
                    <annotation>
                        <documentation>
                            A boolean flag indicating whether a match should occur if the metadata does
                            not contain an MDRPI statement (coded) default is false.
                        </documentation>
                    </annotation>
                </attribute>
            </extension>
        </complexContent>
    </complexType>

    <complexType name="ScopeMatchesShibMDScope">
        <annotation>
            <documentation>
                A match function that ensures that an attribute value's scope matches a scope given in
                metadata for the entity or role of the attribute issuer.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:MatchFunctorType"/>
        </complexContent>
    </complexType>

    <complexType name="ValueMatchesShibMDScope">
        <annotation>
            <documentation>
                A match function that ensures that an attribute value's scope matches a scope given in
                metadata for the entity or role of the attribute issuer.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:MatchFunctorType"/>
        </complexContent>
    </complexType>

    <!-- SP-only matchers -->

    <complexType name="NameIDQualifierString">
        <annotation>
            <documentation>
                A match function that ensures that a NameID-valued attribute's qualifier(s), if set, match particular values.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:MatchFunctorType">
                <attribute name="attributeID" type="afp:string">
                    <annotation>
                        <documentation>
                            The ID of the attribute whose qualifiers should be matched. If no attribute ID is specified the
                            ID of the containing attribute rule is assumed.
                        </documentation>
                    </annotation>
                </attribute>
                <attribute name="NameQualifier" type="afp:string">
                    <annotation>
                        <documentation>
                            A value to require in the NameQualifier field, or if omitted, require that it match the issuing IdP's entityID.
                        </documentation>
                    </annotation>
                </attribute>
                <attribute name="SPNameQualifier" type="afp:string">
                    <annotation>
                        <documentation>
                            A value to require in the SPNameQualifier field, or if omitted, require that it match the SP's entityID.
                        </documentation>
                    </annotation>
                </attribute>
            </extension>
        </complexContent>
    </complexType>

    <complexType name="AttributeIssuerEntityMatcher">
        <annotation>
            <documentation>
                A match function that checks if the attribute issuer matches pluggable criteria.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:EntityMatcherType"/>
        </complexContent>
    </complexType>

    <complexType name="AttributeRequesterEntityMatcher">
        <annotation>
            <documentation>
                A match function that checks if the attribute requester matches pluggable criteria.
            </documentation>
        </annotation>
        <complexContent>
            <extension base="afp:EntityMatcherType"/>
        </complexContent>
    </complexType>
    
    <complexType name="EntityMatcherType" abstract="true">
        <complexContent>
            <extension base="afp:MatchFunctorType">
                <sequence>
                    <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
                </sequence>
                <attribute name="matcher" type="afp:string" use="required">
                    <annotation>
                        <documentation>
                            The type of plugin to apply as a matching mechanism.
                        </documentation>
                    </annotation>
                </attribute>
                <anyAttribute namespace="##any" processContents="lax"/>
            </extension>
        </complexContent>
    </complexType>

    <!-- Utility types -->

    <simpleType name="anyURIListType">
        <list itemType="string"/>
    </simpleType>

    <simpleType name="string">
        <restriction base="string">
            <minLength value="1"/>
        </restriction>
    </simpleType>

</schema>
