Source code for ldaptor.ldapfilter

#!/usr/bin/env python3


from ldaptor.protocols import pureldap
from ldaptor._encoder import to_unicode


"""

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): """ Converting source string to pureldap.LDAPFilter Source string is converted to unicode as pyparsing cannot parse bytes objects with the rules declared in this module. """ s = to_unicode(s) try: x = toplevel.parseString(s) except ParseException as 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 as 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()