CLI ldapsearch tool with json and table output
Go to file
2023-05-12 11:16:45 +02:00
src/ldaptool fix table outputs (join multiple values with separator again), use separate method for (simple) json 2023-05-12 11:16:45 +02:00
.gitignore Initial 2023-04-28 14:14:03 +02:00
.pycodestyle Initial 2023-04-28 14:14:03 +02:00
fmt.sh Initial 2023-04-28 14:14:03 +02:00
LICENSE Initial 2023-04-28 14:14:03 +02:00
lints.sh Initial 2023-04-28 14:14:03 +02:00
pyproject.toml :Fix version requirement for python3.10 2023-05-02 17:47:11 +02:00
README.md move --json to --full_json; remove --human JSON output, replace with --json, but don't merge multiple values - use list instead 2023-05-11 17:29:00 +02:00

ldaptool

CLI tool to query LDAP/AD servers

  • Configuration file to configure "realms"
    • DNS domain (mapping to ldap search base as DC labels)
    • LDAP servers in that domain
    • Bind account
    • Integration with password managers
  • Various output formats
    • Classic LDIF
    • JSON stream (with simplified or detailed attribute values)
    • CSV
    • Markdown table with stretched columns (for viewing in CLI/for monospaces fonts); requires csvlook from csvkit
    • HTML
  • Decodes certain well-known attributes (UUIDs, Timestamps, SID, userAccountControl)
  • Requires server to support RFC 2696: Simple Paged Results for proper pagination
    • By default the first 1000 entries are shown, and it errors if there are more results
    • Use --all to show all results

Virtual attributes

ldaptool supports constructing new values from existing attributes by adding a :<postprocess> suffix (which can be chained apart from the length limit).

  • Some suffixes support an argument as :<postprocess>[<arg>].
  • A single integer as postprocess suffix limits the length of the value; it replaces the last character of the output with if it cut something off.
  • Multi-valued attributes generate multiple virtual attrites; each value is processed individually. (The values are joined afterwards for table output if needed.)

DN handling

DNs are decoded into lists of lists of (name, value) pairs (the inner list usually contains exactly one entry). Attributes with a DC name are considered part of the "domain", everything else belongs to the "path". (Usually a DN will start with path segments and end with domain segments.) The path is read from back to front.

The following postprocess hooks are available:

  • domain: extracts the domain as DNS FQDN (CN=Someone,OU=Dep1,DC=example,DC=com becomes example.com)
  • path: extracts the non-domain parts without names and separates them by / (CN=Someone,OU=Dep1,DC=example,DC=com becomes Dep1/Someone)
  • fullpath: uses the domain as first segment in a path (CN=Someone,OU=Dep1,DC=example,DC=com becomes example.com/Dep1/Someone)
  • dnslice: extracts a "slice" from a DN (outer list only); the result is still in DN format.

path, fullpath and dnslice take an optional index/slice as argument, written in python syntax. For path and fullpath this extracts only the given index/slice from the path (fullpath always includes the full FQDN as first segment), dnslice operates on the outer list of decoded (lists of) pairs:

  • dn:dnslice[1:] on dn: CN=Someone,OU=Dep1,DC=example,DC=com returns OU=Dep1,DC=example,DC=com
  • dn:fullpath[:-1] on dn: CN=Someone,OU=Dep1,DC=example,DC=com returns example.com/Dep1
  • dn:path[-1] on dn: CN=Someone,OU=Dep1,DC=example,DC=com returns Someone

Authentication, Protocol, Ports

ldaptool always uses TLS for password based authentication, and SASL GSS-API over non-TLS for Kerberos ones.

Config file

Location: ~/.config/ldaptool.yaml

Realms

realms:
  EXAMPLE:
    domain: "example.com"
    servers: server1 server2
    account: "bind@example.com"
    password_folder: mainaccounts
  EXAMPLE.admin:
    domain: "example.com"
    servers: server1 server2
    account: "CN=admin,OU=Admins,DC=example,DC=com"
    password_folder: adminaccounts
  EXAMPLE.admin2:
    domain: "example.com"
    servers: server1 server2
    account: "CN=admin,OU=Admins,DC=example,DC=com"
    password_file: localadmin2
    password_folder: adminaccounts
  SUB:
    domain: "sub.example.com"
    servers: subserver1 subserver2
    forest_root_domain: "example.com"

The servers field is a whitespace separates list of hostnames in the domain.

If a password manager is used, the password_file (defaults to names derived from account) and password_folder fields determine the name of the file ("secret") queried from the password manager. Here the following file names would be used:

  • EXAMPLE: mainaccounts/bind
  • EXAMPLE.admin: adminaccounts/example.com/Admins/admin
  • EXAMPLE.admin2: adminaccounts/localadmin2

If the account field isn't present ldaptool always uses kerberos; if --krb is used, account is ignored.

Windows AD has a concept of a "global catalog" across all domains in a AD Forest; it uses separate ports (3268 without TLS and 3269 with TLS). The forest_root_domain field can be used to set a search base for global catalog (--gc) queries (usually the forest root should be parent domain).

Unless specified with --base the search base is derived from domain (or forest_root_domain with --gc) as DC=... for each DNS label.

Script as password manager

password-script: keyring local decrypt

This configures a script as password manager.

Either takes a string (split by shlex.split) or a list of strings. The password name is appended as last argument.

keyringer

keyringer:
  keyring: yourkeyringname
  folder: ldapquery

This configures keyringer (based on GPG) as password manager.

keyringer need a "keyring" to search in, and you can (optionally) specify a folder to be prefixed to the password names created from the realm.

keepass

keepass: /home/me/mypasswords.kdbx

This configures KeePass as password manager; it will prompt for your master password every time.