DevTools Hub

Search tools

Search for a developer tool

LDAP Filter Parser & Validator

Parse an LDAP search filter into a plain-English breakdown — AND/OR/NOT, substrings, and extensible matches.

Part of the Active Directory Toolkit
Plain-English breakdown
ANDALL of 4 conditions
equalityobjectCategory equals "person"
equalityobjectClass equals "user"
equalitymemberOf equals "cn=Sales,dc=example,dc=com"
NOTNOT the following condition
extensible matchuserAccountControl using matching rule "1.2.840.113556.1.4.803" equals "2"

What this does

Parses an LDAP search filter — the parenthesized, prefix-notation syntax used by Active Directory, OpenLDAP, and every other LDAP-compatible directory — into a plain-English breakdown of what it actually matches, entirely in your browser. It implements the real grammar (RFC 4515), not a simplified approximation: nested AND/OR/NOT, presence tests, substring wildcards, comparison operators, and extensible matches with matching rule OIDs.

Why the grammar matters more than it looks

LDAP filters are prefix notation — the operator comes before its operands, and every group is explicitly parenthesized, which avoids any ambiguity about precedence but reads unnaturally to anyone used to infix boolean expressions. A filter like (&(objectCategory=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2))) is genuinely doing several distinct things at once — an AND, a NOT, and a bitwise extensible match against a specific matching rule OID — and getting any one part wrong (an unescaped special character, a NOT wrapping more than one filter) produces either a syntax error or, worse, a filter that's syntactically valid but silently matches the wrong set of entries.

FAQ

Why does a literal asterisk need to be escaped as \2a instead of just \*?

LDAP filter escaping (RFC 4515) only defines one form: a backslash followed by exactly two hex digits representing the byte's value — \2a is the hex code for *. There's no shorthand backslash-asterisk escape the way many programming languages allow; any bare * in a value is always interpreted as a substring wildcard, never a literal character.

What's the difference between (attr=*) and a substring filter?

(attr=*) is a presence test — it matches any entry that has the attribute set at all, regardless of its value. A substring filter like (cn=al*) matches entries whose value starts, contains, or ends with specific text. The parser distinguishes them by whether the value is exactly a single asterisk (presence) or contains one alongside other characters (substring).

Why does an extensible match filter look so different from the others?

Extensible matches (attr:dn:matchingRule:=value) exist specifically for cases the basic operators can't express — matching against a specific matching rule OID (like a domain's LDAP_MATCHING_RULE_BIT_AND) or searching through DN-valued attributes. Either the attribute or the matching rule can be omitted, but not both, since the filter needs at least one to know what it's actually testing.

Does this tool verify that an attribute actually exists in a schema?

No — it validates that a token is syntactically a legal attribute name or numeric OID, not that it corresponds to a real attribute in any particular directory's schema. A filter using a nonexistent attribute name parses successfully here; the actual LDAP server would simply never match anything against it.

Why does ! (NOT) only accept exactly one filter?

It's how the LDAP filter grammar itself defines it (RFC 4515) — NOT negates a single condition, unlike & and | which take one or more. Wanting to negate multiple conditions at once means wrapping them in their own AND or OR first: (!(&(a=1)(b=2))) negates the combined condition, not (!(a=1)(b=2)), which isn't valid syntax.

Try it yourself

For the full syntax reference and common real-world filter examples, see LDAP Filter Syntax Explained.

Related tools