Go to file
2024-07-18 02:40:47 +06:00
.vscode Some frontend side refactoring 2024-07-17 01:29:24 +06:00
etc Add systemd example 2020-11-13 19:45:00 +01:00
server Use pseudo-Bearer token auth instead of Basic auth 2024-07-18 00:06:51 +06:00
src Make the directory list extend fully, breaks schema popup 2024-07-18 02:40:47 +06:00
.dockerignore Minor fixes 2023-04-29 21:10:02 +02:00
.editorconfig Reformat everything Vue to 4 spaces like a jerk 2024-07-16 22:17:02 +06:00
.gitattributes Some frontend side refactoring 2024-07-17 01:29:24 +06:00
.gitignore Switch to Tailwind for CSS 2023-08-11 13:51:28 +02:00
docker-compose.yml Minor 2024-04-06 19:34:37 +02:00
Dockerfile Refactor python server into more manageable pieces 2024-07-17 01:26:33 +06:00
env.d.ts Use pseudo-Bearer token auth instead of Basic auth 2024-07-18 00:06:51 +06:00
env.demo Simplify demo setup, add .env support in standalone mode 2023-01-19 11:50:16 +01:00
env.example Simplify demo setup, add .env support in standalone mode 2023-01-19 11:50:16 +01:00
index.html Use pseudo-Bearer token auth instead of Basic auth 2024-07-18 00:06:51 +06:00
LICENSE.txt Simplify demo setup, add .env support in standalone mode 2023-01-19 11:50:16 +01:00
Makefile Dependabot #16 2024-01-16 23:35:22 +01:00
package-lock.json Use pseudo-Bearer token auth instead of Basic auth 2024-07-18 00:06:51 +06:00
package.json Use pseudo-Bearer token auth instead of Basic auth 2024-07-18 00:06:51 +06:00
postcss.config.cjs Migrate to TypeScript 2024-03-07 12:29:26 +01:00
README.md #57: Add deployment instructions 2024-04-14 21:29:55 +02:00
screenshot.png Switch to composition API 2023-09-11 18:57:57 +02:00
tailwind.config.cjs Make the directory list extend fully, breaks schema popup 2024-07-18 02:40:47 +06:00
tsconfig.app.json More refactoring 2024-07-17 02:18:32 +06:00
tsconfig.json Migrate to TypeScript 2024-03-07 12:29:26 +01:00
tsconfig.node.json Migrate to TypeScript 2024-03-07 12:29:26 +01:00
vite.config.ts Use pseudo-Bearer token auth instead of Basic auth 2024-07-18 00:06:51 +06:00

Simple LDAP editor

This is a minimal web interface for LDAP directories. Docker images for linux/amd64 and linux/arm64/v8 are available.

Screenshot

Features:

  • Directory tree view
  • Entry creation / modification / deletion
  • LDIF import / export
  • Image support for the jpegPhoto and thumbnailPhoto attributes
  • Schema aware
  • Simple search (configurable)
  • Asynchronous LDAP backend with decent scalability
  • Available as Docker image

The app always requires authentication, even if the directory permits anonymous access. User credentials are validated through a simple bind on the directory (SASL is not supported). What a particular user can see (and edit) is governed entirely by directory access rules. The app shows the directory contents, nothing less and nothing more.

Usage

Docker

For the impatient: Run it with

docker run -p 127.0.0.1:5000:5000 \
  -e LDAP_URL=ldap://your.ldap.server/ \
  -e BASE_DN=dc=example,dc=org dnknth/ldap-ui

For the even more impatient with X86_64 machines: Start a demo with

docker compose up -d

and go to http://localhost:5000/. You are automatically logged in as Fred Flintstone.

Environment variables

LDAP access is controlled by these environment variables, possibly from a .env file:

  • LDAP_URL (optional): Connection URL, defaults to ldap:///).

  • BASE_DN (required): Search base, e.g. dc=example,dc=org.

  • LOGIN_ATTR (optional): User name attribute, defaults to uid.

  • USE_TLS (optional): Enable TLS, defaults to true for ldaps connections. Set it to a non-empty string to force STARTTLS on ldap connections.

  • INSECURE_TLS (optional): Do not require a valid server TLS certificate, defaults to false, implies USE_TLS.

For finer-grained control, adjust settings.py.

Standalone

Copy env.example to .env, adjust it and run the app with

make run

then head over to http://localhost:5000/.

Manual installation and configuration

Prerequisites:

  • GNU make
  • node.js with NPM
  • Python3 ≥ 3.7
  • pip3
  • python-ldap; To compile the Python module:
    • Debian / Ubuntu: apt-get install libsasl2-dev python-dev libldap2-dev libssl-dev
    • RedHat / CentOS: yum install python-devel openldap-devel

ldap-ui consists of a Vue UI and a Python backend that roughly translates parts of the LDAP protocol as a stateless ReST API.

For the frontend, npm run build assembles everything in the dist directory. The result can then be served either via the backend (during development) or statically by any web server (remotely).

The backend runs locally, always as a separate process. There is an example systemd unit in etc/ldap-ui.service. Check the Makefile on how to set up a virtual Python environment for it.

Review the configuration in settings.py. It is very short and mostly self-explaining. Most settings can (and should) be overridden by environment variables or settings in a .env file; see env.demo or env.example.

The backend exposes port 5000 on localhost which is not reachable remotely. Therefore, for remote access, some web server configuration is needed. Let's assume that everything should show up under the HTP path /ldap:

  • The contents of dist should be statically served under /ldap by the web server.
  • The path /ldap/api should be proxied to http://localhost:5000/api

Notes

Authentication methods

The UI always uses a simple bind operation to authenticate with the LDAP directory. How the bind DN is obtained from a given user name depends on a combination of OS environment variables, possibly from a .env file:

  1. Search by some attribute. By default, this is the uid, which can be overridden by the environment variable LOGIN_ATTR, e.g. LOGIN_ATTR=cn.
  2. If the environment variable BIND_PATTERN is set, then no search is performed. Login with a full DN can be configured with BIND_PATTERN=%s, which for example allows to login as user cn=admin,dc=example,dc=org. If a partial DN like BIND_PATTERN=%s,dc=example,dc=org is configured, the corresponding login would be cn=admin. If a specific pattern like BIND_PATTERN=cn=%s,dc=example,dc=org is configured, the login name is just admin.
  3. If security is no concern, then a fixed BIND_DN and BIND_PASSWORD can be set in the environment. This is for demo purposes only, and probably a very bad idea if access to the UI is not restricted by any other means.

Searching

Search uses a (configurable) set of criteria (cn, gn, sn, and uid) if the query does not contain =. Wildcards are supported, e.g. f* will match all cn, gn, sn, and uid starting with f. Additionally, arbitrary attributes can be searched with an LDAP filter specification, for example sn=F*.

Caveats

  • The software works with OpenLdap using simple bind. Other directories have not been tested, and SASL authentication schemes are presently not supported.
  • Passwords are transmitted as plain text. The LDAP server is expected to hash them (OpenLdap 2.4 does). I strongly recommend to expose the app through a TLS-enabled web server.
  • HTTP Basic Authentication is triggered unless the AUTHORIZATION request variable is already set by some upstream HTTP server.

Q&A

  • Q: Why are some fields not editable?
    • A: The RDN of an entry is read-only. To change it, rename the entry with a different RDN, then change the old RDN and rename back. To change passwords, click on the question mark icon on the right side. Binary fields (as per schema) are read-only. You do not want to modify them accidentally.
  • Q: Why did you write this?
    • A: PHPLdapAdmin has not seen updates for ages. I needed a replacement, and wanted to try Vue.

Acknowledgements

The Python backend uses Quart which is an asynchronous Flask. The UI is built with Vue.js and Tailwind for CSS. Kudos for the authors of these elegant frameworks!