Skip to main content
Version: Next

Backend LDAP

Lua scripts can submit searches and modifications to the configured LDAP worker pool when the LDAP backend is enabled.

local nauthilus_ldap = require("nauthilus_ldap")

Security Model

LDAP operations are bounded by default. An untrusted operation must declare allowed_base_dn; the search base or modify DN must be equal to that DN or a descendant of it.

For searches, prefer filter_attr and filter_value. Nauthilus validates the attribute description and escapes the value before constructing an LDAP equality filter. A raw filter is accepted only together with trusted = true.

warning

Do not set trusted = true for data derived from requests, users, headers, tokens, or other external input. Trusted mode removes the mandatory subtree boundary when allowed_base_dn is omitted and permits a raw LDAP filter.

The safe and trusted search forms are mutually exclusive in practice:

-- Safe equality filter: filter_value is escaped by Nauthilus.
filter_attr = "uid"
filter_value = user

-- Raw filter: use only for a static, application-controlled expression.
filter = "(&(objectClass=person)(accountStatus=active))"
trusted = true

nauthilus_ldap.ldap_endpoint

Resolves the LDAP endpoint for a worker pool. The helper reads the first configured server_uri. If the URI does not contain a port, it returns 636 for ldaps and 389 for other TCP schemes. The selected pool must have active workers.

Syntax

local server, port, err = nauthilus_ldap.ldap_endpoint(pool_name)

Parameters

  • pool_name (string, optional): configured pool name. Omit it for the default pool.

Returns

  • server (string or nil): endpoint hostname on success.
  • port (number or nil): endpoint port on success.
  • err (string or nil): error message on failure.

For an ldapi URI, the helper returns the socket path as server and 0 as port.

Possible Errors

  • ldap pool not active: <name>
  • ldap pool config not found: <name>
  • no LDAP server_uri configured for pool: <name>
  • invalid LDAP server_uri: <uri>

Example

local nauthilus_ldap = require("nauthilus_ldap")

local host, port, err = nauthilus_ldap.ldap_endpoint()
if err ~= nil then
error("ldap_endpoint failed: " .. err)
end

print("LDAP host:", host, "port:", port)

local eu_host, eu_port, eu_err = nauthilus_ldap.ldap_endpoint("directory_eu")
if eu_err == nil then
print("EU LDAP host:", eu_host, "port:", eu_port)
end

Performs an LDAP search through the selected worker pool.

Syntax

local result, err = nauthilus_ldap.ldap_search(search_params)

Parameters

search_params is a table with these fields:

FieldTypeRequiredMeaning
pool_namestringyesConfigured pool name. Use "default" for the default pool.
sessionstringyesRequest/session identifier used for correlation.
basednstringyesSearch base DN.
allowed_base_dnstringunless trustedMaximum subtree available to the operation.
filter_attrstringfor safe formLDAP attribute description for an equality filter.
filter_valuestringfor safe formEquality value; Nauthilus escapes it with LDAP filter escaping.
filterstringtrusted form onlyComplete raw LDAP filter. Requires trusted = true.
trustedbooleannoEnables the raw-filter form and permits omitting allowed_base_dn. Defaults to false.
attributestableyesArray of attribute names to retrieve.
scopestringyesbase, one, or sub.
raw_resultbooleannoReturn entries with their DNs instead of the merged attribute map.

Only conservative LDAP attribute descriptions are accepted for filter_attr. The base DN and allowed DN must both be valid LDAP DNs, and the base must stay inside the allowed subtree.

Returns

With raw_result omitted or false, result is a table whose keys are LDAP attribute names and whose values are arrays containing all values for that attribute.

With raw_result = true, result is an array of entries:

{
{
dn = "uid=bob,ou=people,dc=example,dc=com",
attributes = {
uid = { "bob" },
mail = { "bob@example.com" }
}
}
}

On a worker or LDAP error, the function returns nil, err.

Safe Search Example

local nauthilus_ldap = require("nauthilus_ldap")

local user = request.username
local result, err = nauthilus_ldap.ldap_search({
pool_name = "default",
session = request.session,
basedn = "ou=people,dc=example,dc=com",
allowed_base_dn = "ou=people,dc=example,dc=com",
filter_attr = "uid",
filter_value = user,
attributes = {
"uid",
"mail",
"displayName",
},
scope = "sub"
})

if err ~= nil then
error("LDAP search failed: " .. err)
end

local first_mail = result.mail and result.mail[1]

Even if user contains LDAP filter metacharacters, Nauthilus treats it as a value rather than filter syntax.

Raw Result Example

local result, err = nauthilus_ldap.ldap_search({
pool_name = "default",
session = request.session,
basedn = "ou=people,dc=example,dc=com",
allowed_base_dn = "ou=people,dc=example,dc=com",
filter_attr = "uid",
filter_value = request.username,
attributes = { "uid", "mail" },
scope = "sub",
raw_result = true
})

if err ~= nil then
error("LDAP search failed: " .. err)
end

for _, entry in ipairs(result) do
print("DN: " .. entry.dn)
for name, values in pairs(entry.attributes) do
for _, value in ipairs(values) do
print(name .. ": " .. value)
end
end
end
warning

LDAP search requests are blocking operations. Keep searches narrow and use request timeouts appropriate for the calling Lua extension point.

nauthilus_ldap.ldap_modify

Performs one LDAP modify operation through the selected worker pool.

Syntax

local result, err = nauthilus_ldap.ldap_modify(modify_params)

Parameters

modify_params is a table with these fields:

FieldTypeRequiredMeaning
pool_namestringyesConfigured pool name. Use "default" for the default pool.
sessionstringyesRequest/session identifier used for correlation.
dnstringyesExact entry DN to modify.
allowed_base_dnstringunless trustedMaximum subtree available to the operation.
trustedbooleannoPermits omitting allowed_base_dn. Defaults to false.
operationstringyesadd, delete, or replace.
attributestableyesMap of attribute name to a single string value for this operation.

The entry DN must be equal to or below allowed_base_dn. Prefer a narrow subtree such as an organizational unit rather than the directory root.

Returns

  • "OK" on success.
  • nil, err when the LDAP worker reports an error.

Example

local nauthilus_ldap = require("nauthilus_ldap")

local result, err = nauthilus_ldap.ldap_modify({
pool_name = "default",
session = request.session,
dn = "uid=bob,ou=people,dc=example,dc=com",
allowed_base_dn = "ou=people,dc=example,dc=com",
operation = "replace",
attributes = {
telephoneNumber = "+1 555 123 4567"
}
})

if err ~= nil then
error("LDAP modify failed: " .. err)
end

Use separate calls for separate modify operations or values.

warning

LDAP modify requests are blocking and mutate directory state. Keep allowed_base_dn narrow and never enable trusted mode for user-controlled DNs.