LDAP Filter DSL Guide
This page explains a simple way to write LDAP filters with readable blocks and attribute expressions in LDAP filters domain specific language.
1. What is this?
LDAP filters are normally hard to read, like this:
(&(objectClass=user)(mail=*))
With this DSL, you can write the same logic like this:
{
objectClass: "user"
mail: any
}
2. Filter structure
A filter is made from one or more AND blocks. Each block uses curly braces, and each attribute expression inside a block must be on its own line.
{
objectClass: "user"
mail: any
accountStatus: not "disabled"
}
Use or between blocks when any block may match:
{
department: "IT"
title: "*Engineer*"
}
or
{
department: "Security"
title: "*Analyst*"
}
Use or not when the next block must not match:
{
objectClass: "user"
}
or not
{
accountStatus: "disabled"
}
{ }, expressions are combined with AND. Separate sibling expressions with newlines, not spaces.
3. Comments
Comments start with // and continue until the end of the line. They can be on their own line or after an expression.
// Active users with an email address
{
objectClass: "user"
mail: any // attribute exists
accountStatus: not "disabled"
}
Inside quoted values, // is treated as normal text:
{
url: "https://example.test/path"
note: "literal // text"
}
4. Attribute expressions
Most conditions use this shape:
attribute: operator-or-value
Examples:
cn: "John"
mail: any
age: >= "18"
5. Most common operations
| What you want | Write this |
|---|---|
| Exact match | cn: "John" |
| Not equal | cn: not "John" |
| Attribute exists | mail: any |
| Attribute missing | mail: not any |
| Contains text | cn: "*John*" |
| Does NOT contain | cn: not "*Admin*" |
| Starts with | cn: "Jo*" |
| Does NOT start with | cn: not "Test*" |
| Ends with | cn: "*son" |
| Matches every listed value | memberOf: all of "A","B","C" |
| Matches at least one listed value | department: any of "IT","HR","Finance" |
| Does NOT match every listed value | memberOf: not all of "A","B","C" |
| Does NOT match any listed value | department: not any of "IT","HR","Finance" |
| Approximately matches (fuzzy) | cn: similar to "Jon" |
| Does NOT approximately match | cn: not similar to "Jon" |
| Greater than or equal | age: >= "18" |
| Less than or equal | age: <= "65" |
| Less than | age: < "18" |
| Greater than | age: > "65" |
: for equality values, presence, set equality, fuzzy matching, and ordering.
6. Combining conditions
AND (all must match)
{
objectClass: "user"
department: "IT"
}
OR (any can match)
{
cn: "Admin*"
}
or
{
cn: "Service*"
}
NOT (invert logic)
not {
accountStatus: "disabled"
accountStatus: "locked"
}
7. Wildcards in equality
The * character is treated as an LDAP wildcard inside : equality values.
| Pattern | Meaning |
|---|---|
cn: "John" | Exact value |
cn: "John*" | Starts with John |
cn: "*John" | Ends with John |
cn: "*John*" | Contains John |
8. Set equality shortcuts
Use set equality when the same attribute must be compared with several values.
memberOf: all of "Admins","VPN Users","Developers"
This is equivalent to:
{
memberOf: "Admins"
memberOf: "VPN Users"
memberOf: "Developers"
}
department: any of "IT","Security","Operations"
This matches when the attribute has at least one of the listed values.
You can also negate set equality:
memberOf: not all of "Admins","VPN Users"
department: not any of "HR","Finance"
9. Ordering comparisons
Use ordering comparisons when your LDAP attribute values can be ordered by the server.
{
age: >= "18"
age: <= "65"
}
Strict comparisons are available too:
{
age: < "18"
}
or
{
age: > "65"
}
>= and <= filters. This DSL implements < as NOT >=, and > as NOT <=.
10. Approximate (fuzzy) matching
Use this when you want a "close enough" match (depends on LDAP server rules):
cn: similar to "Jon"
To invert it, write:
cn: not similar to "Jon"
This is useful for small spelling differences like John vs Jon.
11. Full example
// Find user Ali G
{
objectClass: "user"
sn: any of "A*","B*","C*","D*","E*","F*"
sn: "G*"
givenName: "Ali*"
loginDisabled: not "TRUE"
lockedByIntruder: not "TRUE"
passwordExpiration: > "202601010000Z"
}
12. Tips
- Always use quotes for values:
"text" - Use
//for comments that run to the end of the line - Use
{ }for AND blocks - Use
orbetween blocks for OR - Use
or notbefore a block to invert that OR branch - Use
:for exact values and wildcard value patterns - Use
: anyinstead of remembering=* - Use
: similar tofor approximate (fuzzy) matching