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
}
You do NOT need to know LDAP syntax to use this DSL.

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"
}
Inside { }, 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 wantWrite this
Exact matchcn: "John"
Not equalcn: not "John"
Attribute existsmail: any
Attribute missingmail: not any
Contains textcn: "*John*"
Does NOT containcn: not "*Admin*"
Starts withcn: "Jo*"
Does NOT start withcn: not "Test*"
Ends withcn: "*son"
Matches every listed valuememberOf: all of "A","B","C"
Matches at least one listed valuedepartment: any of "IT","HR","Finance"
Does NOT match every listed valuememberOf: not all of "A","B","C"
Does NOT match any listed valuedepartment: not any of "IT","HR","Finance"
Approximately matches (fuzzy)cn: similar to "Jon"
Does NOT approximately matchcn: not similar to "Jon"
Greater than or equalage: >= "18"
Less than or equalage: <= "65"
Less thanage: < "18"
Greater thanage: > "65"
Use : 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.

PatternMeaning
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"
}
LDAP has native >= 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