Skip to content
simpleworkjsPublic

About

Shared ldapts client + read queries + RFC 4515/4514 escaping for theta42 apps.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

7 Commits

Folders and files

Repository files navigation

@simpleworkjs/ldap

Shared ldapts client + read queries + RFC 4515/4514 escaping for the theta42 apps (sso-manager-node, proxy, jump-host). The connection and read surface that all three copy-paste; write-side and posix logic stay app-local (sso owns those).

What it provides

  • escapeFilter(value) — RFC 4515. Escapes * \ ( ) NUL in a value interpolated into a search filter. This is the fix for the proxy's latent filter-injection bug (User.get interpolated data.username raw).
  • escapeDN(value) — RFC 4514. Escapes the reserved DN chars (sso had this as escapeLDAPDNValue; jump-host never built a DN by interpolation so didn't).
  • makeClient(conf, {Client?}) — new Client({ url, tlsOptions }). tlsOptions is forwarded as-is (no default): sso omits it and relies on ldapts' cert validation, so the shared client must not silently weaken it. Jump-host applies its own { rejectUnauthorized: false } default in its app-local wrapper.
  • withClient(conf, fn, {Client?}) — admin-bind, fn(client), always unbind() in finally.
  • createLdapClient(conf, {Client?, Change?, Attribute?}) — factory returning the jump-host API shape bound to a conf.ldap block:
{
  makeClient, withClient,
  getUser(uid),        // -> { dn, uid, sshPublicKeys: [] } | null
  getGroups(dn),       // -> [cn, ...]   (groupOfNames membership)
  checkPassword(dn, pw),   // -> bool   (simple bind as the user)
  addSshKey(dn, keyLine),  // -> void   (idempotent multi-value add)
  escapeFilter, escapeDN,
}

conf is injected, not read from @simpleworkjs/conf here — so the package is unit-testable with a plain object and a fake Client. Apps pass their conf.ldap block.

conf.ldap reconciliation

The three apps name things slightly differently; the factory normalizes:

field sso jump-host proxy default
user base userBase userBase searchBase userBase || searchBase
user filter userFilter (posixAccount) (hardcoded) userFilter (inetOrgPerson) (objectClass=posixAccount)
user attr userNameAttribute userNameAttribute userNameAttribute uid
group base groupBase groupBase (none — uses memberOf overlay) —

So jump-host's hardcoded (objectClass=posixAccount) becomes the default, and the proxy's inetOrgPerson is expressed via conf.userFilter rather than code.

Install

npm install @simpleworkjs/ldap

Usage (jump-host)

const { createLdapClient } = require('@simpleworkjs/ldap');
const conf = require('@simpleworkjs/conf');

const ldap = createLdapClient(conf.ldap);
const user = await ldap.getUser('alice');     // { dn, uid, sshPublicKeys }
const groups = await ldap.getGroups(user.dn); // ['host_web01_access', ...]

Why

Two things this exists to fix:

  1. Security — the proxy built (&${conf.userFilter}(${attr}=${data.username})) with the username interpolated raw. escapeFilter closes that.
  2. Duplication — sso's user_ldap.js and group_ldap.js already byte-duplicate makeClient/withClient/escapeLDAPDNValue; jump-host reimplements the same pattern. One package, one source of truth.

License

MIT © William Mantly

About

Shared ldapts client + read queries + RFC 4515/4514 escaping for theta42 apps.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages