Source code for ldaptor.ldapfilter

#!/usr/bin/python

from ldaptor.protocols import pureldap

"""

RFC2254:

        filter     = "(" filtercomp ")"
        filtercomp = and / or / not / item
        and        = "&" filterlist
        or         = "|" filterlist
        not        = "!" filter
        filterlist = 1*filter
        item       = simple / present / substring / extensible
        simple     = attr filtertype value
        filtertype = equal / approx / greater / less
        equal      = "="
        approx     = "~="
        greater    = ">="
        less       = "<="
        extensible = attr [":dn"] [":" matchingrule] ":=" value
                     / [":dn"] ":" matchingrule ":=" value
        present    = attr "=*"
        substring  = attr "=" [initial] any [final]
        initial    = value
        any        = "*" *(value "*")
        final      = value
        attr       = AttributeDescription from Section 4.1.5 of [1]
        matchingrule = MatchingRuleId from Section 4.1.9 of [1]
        value      = AttributeValue from Section 4.1.6 of [1]
"""

[docs]class InvalidLDAPFilter(Exception): def __init__(self, msg, loc, text): Exception.__init__(self) self.msg=msg self.loc=loc self.text=text def __str__(self): return "Invalid LDAP filter: %s at point %d in %r" \ % (self.msg, self.loc, self.text)
[docs]def parseExtensible(attr, s): raise NotImplementedError
from pyparsing import Word, Literal, Optional, ZeroOrMore, Suppress, \ Group, Forward, OneOrMore, ParseException, \ CharsNotIn, Combine, StringStart, \ StringEnd, delimitedList import string filter_ = Forward() attr = Word(string.ascii_letters, string.ascii_letters + string.digits + ';-',) attr.leaveWhitespace() attr.setName('attr') hexdigits = Word(string.hexdigits, exact=2) hexdigits.setName('hexdigits') escaped = Suppress(Literal('\\'))+hexdigits escaped.setName('escaped') def _p_escaped(s,l,t): text=t[0] return chr(int(text, 16)) escaped.setParseAction(_p_escaped) value = Combine(OneOrMore(CharsNotIn('*()\\\0') | escaped)) value.setName('value') equal = Literal("=") equal.setParseAction(lambda s,l,t: pureldap.LDAPFilter_equalityMatch) approx = Literal("~=") approx.setParseAction(lambda s,l,t: pureldap.LDAPFilter_approxMatch) greater = Literal(">=") greater.setParseAction(lambda s,l,t: pureldap.LDAPFilter_greaterOrEqual) less = Literal("<=") less.setParseAction(lambda s,l,t: pureldap.LDAPFilter_lessOrEqual) filtertype = equal | approx | greater | less filtertype.setName('filtertype') simple = attr + filtertype + value simple.leaveWhitespace() simple.setName('simple') def _p_simple(s,l,t): attr, filtertype, value = t return filtertype(attributeDesc=pureldap.LDAPAttributeDescription(attr), assertionValue=pureldap.LDAPAssertionValue(value)) simple.setParseAction(_p_simple) present = attr + "=*" present.setParseAction(lambda s,l,t: pureldap.LDAPFilter_present(t[0])) initial = value.copy() initial.setParseAction(lambda s,l,t: pureldap.LDAPFilter_substrings_initial(t[0])) initial.setName('initial') any_value = value + Suppress(Literal("*")) any_value.setParseAction(lambda s,l,t: pureldap.LDAPFilter_substrings_any(t[0])) any = Suppress(Literal("*")) + ZeroOrMore(any_value) any.setName('any') final = value.copy() final.setName('final') final.setParseAction(lambda s,l,t: pureldap.LDAPFilter_substrings_final(t[0])) substring = attr + Suppress(Literal("=")) + Group(Optional(initial) + any + Optional(final)) substring.setName('substring') def _p_substring(s,l,t): attrtype, substrings = t return pureldap.LDAPFilter_substrings( type=attrtype, substrings=substrings) substring.setParseAction(_p_substring) keystring = Word(string.ascii_letters, string.ascii_letters + string.digits + ';-') keystring.setName('keystring') numericoid = delimitedList(Word(string.digits), delim='.', combine=True) numericoid.setName('numericoid') oid = numericoid | keystring oid.setName('oid') matchingrule = oid.copy() matchingrule.setName('matchingrule') extensible_dn = Optional(":dn") def _p_extensible_dn(s,l,t): return bool(t) extensible_dn.setParseAction(_p_extensible_dn) matchingrule_or_none = Optional(Suppress(":") + matchingrule) def _p_matchingrule_or_none(s,l,t): if not t: return [None] else: return t[0] matchingrule_or_none.setParseAction(_p_matchingrule_or_none) extensible_attr = attr + extensible_dn + matchingrule_or_none + Suppress(":=") + value extensible_attr.setName('extensible_attr') def _p_extensible_attr(s,l,t): return list(t) extensible_attr.setParseAction(_p_extensible_attr) extensible_noattr = extensible_dn + Suppress(":") + matchingrule + Suppress(":=") + value extensible_noattr.setName('extensible_noattr') def _p_extensible_noattr(s,l,t): return [None]+list(t) extensible_noattr.setParseAction(_p_extensible_noattr) extensible = extensible_attr | extensible_noattr extensible.setName('extensible') def _p_extensible(s,l,t): attr, dn, matchingRule, value = t return pureldap.LDAPFilter_extensibleMatch( matchingRule=matchingRule, type=attr, matchValue=value, dnAttributes=dn) extensible.setParseAction(_p_extensible) item = simple ^ present ^ substring ^ extensible item.setName('item') item.leaveWhitespace() not_ = Suppress(Literal('!')) + filter_ not_.setParseAction(lambda s,l,t: pureldap.LDAPFilter_not(t[0])) not_.setName('not') filterlist = OneOrMore(filter_) or_ = Suppress(Literal('|')) + filterlist or_.setParseAction(lambda s,l,t: pureldap.LDAPFilter_or(t)) or_.setName('or') and_ = Suppress(Literal('&')) + filterlist and_.setParseAction(lambda s,l,t: pureldap.LDAPFilter_and(t)) and_.setName('and') filtercomp = and_ | or_ | not_ | item filtercomp.setName('filtercomp') filter_ << (Suppress(Literal('(').leaveWhitespace()) + filtercomp + Suppress(Literal(')').leaveWhitespace())) filter_.setName('filter') filtercomp.leaveWhitespace() filter_.leaveWhitespace() toplevel = (StringStart().leaveWhitespace() + filter_ + StringEnd().leaveWhitespace()) toplevel.leaveWhitespace() toplevel.setName('toplevel')
[docs]def parseFilter(s): try: x=toplevel.parseString(s) except ParseException, e: raise InvalidLDAPFilter, (e.msg, e.loc, e.line) assert len(x)==1 return x[0]
maybeSubString_value = Combine(OneOrMore(CharsNotIn('*\\\0') | escaped)) maybeSubString_simple = maybeSubString_value.copy() def _p_maybeSubString_simple(s,l,t): return (lambda attr: pureldap.LDAPFilter_equalityMatch( attributeDesc=pureldap.LDAPAttributeDescription(attr), assertionValue=pureldap.LDAPAssertionValue(t[0]))) maybeSubString_simple.setParseAction(_p_maybeSubString_simple) maybeSubString_present = Literal("*") def _p_maybeSubString_present(s,l,t): return (lambda attr: pureldap.LDAPFilter_present(attr)) maybeSubString_present.setParseAction(_p_maybeSubString_present) maybeSubString_substring = Optional(initial) + any + Optional(final) def _p_maybeSubString_substring(s,l,t): return (lambda attr: pureldap.LDAPFilter_substrings( type=attr, substrings=t)) maybeSubString_substring.setParseAction(_p_maybeSubString_substring) maybeSubString = (maybeSubString_simple ^ maybeSubString_present ^ maybeSubString_substring )
[docs]def parseMaybeSubstring(attrType, s): try: x=maybeSubString.parseString(s) except ParseException, e: raise InvalidLDAPFilter, (e.msg, e.loc, e.line) assert len(x)==1 fn = x[0] return fn(attrType)
if __name__=='__main__': import sys for filt in sys.argv[1:]: print repr(parseFilter(filt)) print