Skip to content
Jennifer Programming Language

ldap API reference

An LDAP v3 client and a lightweight, read-only directory server (RFC 4511), over TCP with the wire messages built and parsed as ASN.1 BER (the asn1 library) on the net transport. The client binds (simple or SASL SCRAM), searches with RFC 4515 string filters, follows paged results, and unbinds; LDAPS and StartTLS reuse net's TLS. The server answers simple bind and search for an in-memory directory you build in a few lines - enough to back any LDAP client (an authentication portal such as Authelia, or an app that authenticates its users against LDAP): it validates userPassword on bind and evaluates search filters against the entries so a client can find users and read their groups.

The server is read-only over the LDAP protocol (it answers bind and search but rejects add / modify / delete on the wire), yet the in-memory directory is fully mutable from your own code: after building it you can addEntry / modifyEntry / deleteEntry / setAttribute at runtime, so a web interface or a database sync can update the directory a running server is serving. The Directory is shared mutable state (a kv-backed store shared across the serve loop's connection tasks), so a change is visible to the live server immediately. No schema enforcement, no ACLs.

Import with import "ldap.j" as ldap;. See the ldap guide for prose and examples.

Functions

ldap.add(conn as Conn, dn as string, attrs as map of string to list of string)

add creates an entry from a DN and an attribute map, returning the Result (check .code).

Parameters

  • conn {Conn} - an open, bound connection
  • dn {string} - the DN of the entry to create
  • attrs {map of string to list of string} - the entry's attributes (name -> values)

Returns {Result} - the operation result (check .code)

Throws

  • {Error} - on a transport or protocol error

ldap.addEntry(dir as Directory, e as Entry)

addEntry inserts an entry, replacing any existing entry with the same DN.

Parameters

  • dir {Directory} - the directory to modify
  • e {Entry} - the entry to insert (or replace a same-DN entry with)

ldap.allOf(filters as list of asn1.Value)

allOf builds a conjunction: (&(f1)(f2)...).

Parameters

  • filters {list of asn1.Value} - the sub-filters that must all match

Returns {asn1.Value} - the combined filter, for search

ldap.anyOf(filters as list of asn1.Value)

anyOf builds a disjunction: (|(f1)(f2)...).

Parameters

  • filters {list of asn1.Value} - the sub-filters, any of which may match

Returns {asn1.Value} - the combined filter, for search

ldap.approx(attr as string, value as string)

approx builds an approximate-match (attr~=value) filter; the server treats it as equality.

Parameters

  • attr {string} - the attribute name
  • value {string} - the value to match approximately

Returns {asn1.Value} - the encoded filter, for search

ldap.bind(conn as Conn, dn as string, password as string)

bind performs a simple bind and returns the Result (check .code against ldap.SUCCESS / ldap.INVALID_CREDENTIALS). An empty dn and password is an anonymous bind.

Parameters

  • conn {Conn} - an open connection
  • dn {string} - the bind DN ("" for anonymous)
  • password {string} - the password ("" for anonymous)

Returns {Result} - the bind result (check .code)

Throws

  • {Error} - on a transport or protocol error

ldap.bindSasl(conn as Conn, user as string, password as string, algo as string)

bindSasl performs a SASL SCRAM bind (algo "sha1" -> SCRAM-SHA-1, "sha256" -> SCRAM-SHA-256), verifying the server signature. Returns the Result on success or throws on a protocol / verification failure.

Parameters

  • conn {Conn} - an open connection
  • user {string} - the SCRAM authentication username
  • password {string} - the user's password
  • algo {string} - the SCRAM hash: "sha1" or "sha256"

Returns {Result} - the bind result on success

Throws

  • {Error} - on a protocol or server-signature-verification failure

ldap.change(operation as int, name as string, values as list of string)

change builds one modify change (operation is ldap.MOD_ADD / MOD_DELETE / MOD_REPLACE).

Parameters

  • operation {int} - ldap.MOD_ADD, MOD_DELETE, or MOD_REPLACE
  • name {string} - the attribute to change
  • values {list of string} - the values for the change (empty deletes the attribute)

Returns {Change} - the change, for modify

ldap.close(conn as Conn)

close closes the connection without sending an unbind.

Parameters

  • conn {Conn} - the connection to close

ldap.connect(address as string, security as transport.Security)

connect opens an LDAP connection. security selects the transport: transport.Security.None is plaintext (port defaults to 389), transport.Security.Tls is LDAPS / implicit TLS (port defaults to 636), and transport.Security.Starttls connects in plaintext then upgrades in-band via the StartTLS extended operation.

Parameters

  • address {string} - the server "host:port" (port defaults to 389, or 636 for Tls)
  • security {transport.Security} - the transport: None, Tls, or Starttls

Returns {Conn} - the open connection

Throws

  • {Error} - on a connection or StartTLS failure

ldap.delete(conn as Conn, dn as string)

delete removes an entry by DN, returning the Result.

Parameters

  • conn {Conn} - an open, bound connection
  • dn {string} - the DN of the entry to remove

Returns {Result} - the operation result (check .code)

Throws

  • {Error} - on a transport or protocol error

ldap.deleteEntry(dir as Directory, dn as string)

deleteEntry removes the entry with the given DN if present.

Parameters

  • dir {Directory} - the directory to modify
  • dn {string} - the DN of the entry to remove (matched case-insensitively)

ldap.directory(entries as list of Entry)

directory builds a mutable in-memory directory the server answers for - the lightweight, ephemeral default. Use openDirectory for one that persists.

Parameters

  • entries {list of Entry} - the initial entries to seed the directory with

Returns {Directory} - the in-memory directory

ldap.entry(dn as string, attrs as map of string to list of string)

entry builds a directory entry from a DN and an attribute map (name -> values).

Parameters

  • dn {string} - the entry's distinguished name
  • attrs {map of string to list of string} - the entry's attributes (name -> values)

Returns {Entry} - the constructed entry

ldap.equals(attr as string, value as string)

equals builds an equality filter: (attr=value).

Parameters

  • attr {string} - the attribute name
  • value {string} - the value to match exactly

Returns {asn1.Value} - the encoded filter, for search

ldap.firstValue(entry as Entry, name as string)

firstValue returns an entry's first value for an attribute, or "" if absent.

Parameters

  • entry {Entry} - the entry to read
  • name {string} - the attribute name, matched case-insensitively

Returns {string} - the first value, or "" if the attribute has none

ldap.getEntry(dir as Directory, dn as string)

getEntry returns the entry with the given DN, or an empty Entry (dn == "") if absent.

Parameters

  • dir {Directory} - the directory to read
  • dn {string} - the DN to look up (matched case-insensitively)

Returns {Entry} - the matching entry, or an empty Entry (dn == "") if absent

ldap.greaterOrEqual(attr as string, value as string)

greaterOrEqual builds an (attr>=value) filter.

Parameters

  • attr {string} - the attribute name
  • value {string} - the lower bound to compare against

Returns {asn1.Value} - the encoded filter, for search

ldap.group(dn as string, members as list of string)

group builds a groupOfNames entry (objectClass + cn from the DN's RDN + member) from members.

Parameters

  • dn {string} - the group's distinguished name (its RDN value becomes cn)
  • members {list of string} - the member DNs

Returns {Entry} - the constructed groupOfNames entry

ldap.hasEntry(dir as Directory, dn as string)

hasEntry reports whether an entry with the given DN exists.

Parameters

  • dir {Directory} - the directory to read
  • dn {string} - the DN to test (matched case-insensitively)

Returns {bool} - true if an entry with that DN exists

ldap.lessOrEqual(attr as string, value as string)

lessOrEqual builds an (attr<=value) filter.

Parameters

  • attr {string} - the attribute name
  • value {string} - the upper bound to compare against

Returns {asn1.Value} - the encoded filter, for search

ldap.listEntries(dir as Directory)

listEntries returns a snapshot of every entry currently in the directory.

Parameters

  • dir {Directory} - the directory to read

Returns {list of Entry} - a snapshot of all current entries

ldap.listen(address as string)

listen opens a listening socket for the server ("host:port"; port defaults to 389).

Parameters

  • address {string} - the listen address "host:port" (port defaults to 389)

Returns {net.Listener} - the open listener, for serveOn

Throws

  • {Error} - if the socket cannot be opened

ldap.modify(conn as Conn, dn as string, changes as list of Change)

modify applies a list of changes to an entry, returning the Result.

Parameters

  • conn {Conn} - an open, bound connection
  • dn {string} - the DN of the entry to modify
  • changes {list of Change} - the changes to apply, from change

Returns {Result} - the operation result (check .code)

Throws

  • {Error} - on a transport or protocol error

ldap.modifyDn(conn as Conn, dn as string, newRdn as string, deleteOldRdn as bool, newSuperior as string)

modifyDn renames or moves an entry: newRdn is the new relative DN, deleteOldRdn drops the old RDN attribute, and newSuperior ("" to keep the parent) moves the entry under a new parent DN.

Parameters

  • conn {Conn} - an open, bound connection
  • dn {string} - the DN of the entry to rename or move
  • newRdn {string} - the new relative DN (e.g. "cn=bob")
  • deleteOldRdn {bool} - whether to drop the old RDN attribute value
  • newSuperior {string} - the new parent DN, or "" to keep the current parent

Returns {Result} - the operation result (check .code)

Throws

  • {Error} - on a transport or protocol error

ldap.modifyEntry(dir as Directory, e as Entry)

modifyEntry replaces the entry with the same DN (an alias for addEntry).

Parameters

  • dir {Directory} - the directory to modify
  • e {Entry} - the replacement entry, keyed by its DN

ldap.negate(f as asn1.Value)

negate builds a negation: (!(f)).

Parameters

  • f {asn1.Value} - the sub-filter to invert

Returns {asn1.Value} - the negated filter, for search

ldap.openDirectory(path as string)

openDirectory opens a file-backed directory that persists across restarts (a kv.openFile store at path). A new file starts empty; an existing one restores its entries. Seed a fresh store on first run by checking listEntries and addEntry-ing when it is empty. Edits (addEntry / modifyEntry / ...) persist.

Parameters

  • path {string} - the backing file path for the kv store

Returns {Directory} - the file-backed directory

ldap.parseFilter(s as string)

parseFilter compiles an RFC 4515 filter string (e.g. "(&(a=1)(b=2))") into a filter value.

Parameters

  • s {string} - the RFC 4515 filter text

Returns {asn1.Value} - the compiled filter, for search

Throws

  • {Error} - on a malformed filter string

ldap.password(plain as string, scheme as string)

password hashes a plaintext password into an LDAP userPassword value. scheme is "plain", "sha", "sha256", "ssha", "ssha256" (salted variants use a random 8-byte salt), "pbkdf2" (PBKDF2-SHA256), or "pbkdf2-sha512". Store the result as an entry's userPassword.

Parameters

  • plain {string} - the plaintext password to hash
  • scheme {string} - one of plain / sha / sha256 / ssha / ssha256 / pbkdf2 / pbkdf2-sha512

Returns {string} - the encoded userPassword value (with its scheme prefix)

Throws

  • {Error} - on an unknown scheme

ldap.passwordModify(conn as Conn, userDn as string, oldPassword as string, newPassword as string)

passwordModify changes a password via the RFC 3062 extended operation. Pass userDn "" for the currently-bound user, oldPassword "" to skip the old-password check (an administrative reset), and newPassword "" to have the server generate one. Returns the Result.

Parameters

  • conn {Conn} - an open, bound connection
  • userDn {string} - the target user DN, or "" for the currently-bound user
  • oldPassword {string} - the current password, or "" to skip the check (admin reset)
  • newPassword {string} - the new password, or "" to let the server generate one

Returns {Result} - the operation result (check .code)

Throws

  • {Error} - on a transport or protocol error

ldap.present(attr as string)

present builds a presence filter: (attr=*).

Parameters

  • attr {string} - the attribute that must be present

Returns {asn1.Value} - the encoded filter, for search

ldap.search(conn as Conn, baseDn as string, scope as int, filter as asn1.Value, attributes as list of string)

search runs a search and returns the matching entries. scope is one of ldap.SCOPE_BASE / SCOPE_ONE / SCOPE_SUB; filter comes from parseFilter or the filter constructors; attributes is the list to return (empty = all user attributes).

Parameters

  • conn {Conn} - an open, bound connection
  • baseDn {string} - the search base DN
  • scope {int} - ldap.SCOPE_BASE, SCOPE_ONE, or SCOPE_SUB
  • filter {asn1.Value} - the filter, from parseFilter or a filter constructor
  • attributes {list of string} - the attributes to return (empty = all user attributes)

Returns {list of Entry} - the matching entries

Throws

  • {Error} - on a transport or protocol error

ldap.searchPaged(conn as Conn, baseDn as string, scope as int, filter as asn1.Value, attributes as list of string, pageSize as int)

searchPaged runs a search in pages of pageSize via the simple-paged-results control.

Parameters

  • conn {Conn} - an open, bound connection
  • baseDn {string} - the search base DN
  • scope {int} - ldap.SCOPE_BASE, SCOPE_ONE, or SCOPE_SUB
  • filter {asn1.Value} - the filter, from parseFilter or a filter constructor
  • attributes {list of string} - the attributes to return (empty = all user attributes)
  • pageSize {int} - the maximum entries per page

Returns {list of Entry} - all matching entries across every page

Throws

  • {Error} - on a transport or protocol error

ldap.serve(dir as Directory, address as string)

serve binds address and serves dir until the process ends (blocks).

Parameters

  • dir {Directory} - the directory to answer queries from
  • address {string} - the listen address "host:port" (port defaults to 389)

Throws

  • {Error} - if the socket cannot be opened

ldap.serveOn(dir as Directory, listener as net.Listener)

serveOn serves dir on an already-open listener, one spawn per connection, until the listener is closed (which ends the accept loop). Close the listener from another task for a graceful stop.

Parameters

  • dir {Directory} - the directory to answer queries from
  • listener {net.Listener} - an open listener from listen

ldap.setAttribute(dir as Directory, dn as string, name as string, vals as list of string)

setAttribute creates or replaces one attribute's values on an existing entry.

Parameters

  • dir {Directory} - the directory to modify
  • dn {string} - the DN of the entry to update
  • name {string} - the attribute to create or replace
  • vals {list of string} - the new values for the attribute

Throws

  • {Error} - if no entry with dn exists

ldap.startTls(conn as Conn)

startTls upgrades a plaintext connection to TLS via the StartTLS extended operation, then hands the same handle back (now encrypted).

Parameters

  • conn {Conn} - an open plaintext connection from connect

Returns {Conn} - the same connection, now encrypted

Throws

  • {Error} - if the server refuses StartTLS

ldap.substrings(attr as string, initial as string, anyParts as list of string, final as string)

substrings builds a substring filter, e.g. (cn=abc): initial "a", any ["b"], final "c". Pass "" for an absent initial or final and an empty list for no interior parts.

Parameters

  • attr {string} - the attribute name
  • initial {string} - the required leading substring, or "" for none
  • anyParts {list of string} - interior substrings in order, or empty for none
  • final {string} - the required trailing substring, or "" for none

Returns {asn1.Value} - the encoded filter, for search

ldap.unbind(conn as Conn)

unbind sends an unbind request and closes the connection.

Parameters

  • conn {Conn} - the connection to unbind and close

ldap.values(entry as Entry, name as string)

values returns an entry's values for an attribute (case-insensitive name), or an empty list.

Parameters

  • entry {Entry} - the entry to read
  • name {string} - the attribute name, matched case-insensitively

Returns {list of string} - the attribute's values, or an empty list if absent

Structs

ldap.Attribute

One attribute of a directory entry.

FieldTypeDescription
namestringthe attribute type (e.g. "mail", "objectClass")
valueslist of stringits values (LDAP attributes are multi-valued)

ldap.Change

One change in a modify request.

FieldTypeDescription
operationintldap.MOD_ADD / MOD_DELETE / MOD_REPLACE
namestringthe attribute to change
valueslist of stringthe values (empty deletes the whole attribute for MOD_DELETE)

ldap.Conn

An open LDAP connection.

FieldTypeDescription
handlenet.Connthe underlying TCP (or TLS) connection
timeoutMsintthe per-read timeout in ms (0 blocks with no deadline)

ldap.Directory

A mutable in-memory directory the server answers for. It is backed by a shared kv store, so edits made with addEntry / modifyEntry / deleteEntry / setAttribute are visible to a running server across its connection tasks.

FieldTypeDescription
storekv.Storethe shared backing store holding every entry

ldap.Entry

A directory entry.

FieldTypeDescription
dnstringthe distinguished name
attributeslist of ldap.Attributethe entry's attributes

ldap.Result

The outcome of a bind (or any LDAPResult).

FieldTypeDescription
codeintthe result code (ldap.SUCCESS, or ldap.INVALID_CREDENTIALS on a bad bind)
matchedDnstringthe matched DN the server reports, if any
messagestringthe server's diagnostic message

Constants

ConstantTypeDescription
ldap.INVALID_CREDENTIALSintLDAP result code: invalid credentials (a failed bind).
ldap.MOD_ADDintmodify() change type: add the given values to the attribute.
ldap.MOD_DELETEintmodify() change type: delete the given values (or the whole attribute if none).
ldap.MOD_REPLACEintmodify() change type: replace the attribute with the given values.
ldap.SCOPE_BASEintSearch scope: the base entry only.
ldap.SCOPE_ONEintSearch scope: the base's immediate children.
ldap.SCOPE_SUBintSearch scope: the base and its whole subtree.
ldap.SUCCESSintLDAP result code: success.