Minimalistic web frontend for OpenLDAP
This is a minimal web interface for LDAP directories. Docker images for linux/amd64
and linux/arm64/v8
are available.
Features:
jpegPhoto
and thumbnailPhoto
attributesThe 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.
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
.
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.
Copy env.example to .env
, adjust it and run the app with
make run
then head over to http://localhost:5000/.
Prerequisites:
apt-get install libsasl2-dev python-dev libldap2-dev libssl-dev
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
:
dist
should be statically served under /ldap
by the web server./ldap/api
should be proxied to http://localhost:5000/api
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:
uid
, which can be overridden by the environment variable LOGIN_ATTR
, e.g. LOGIN_ATTR=cn
.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
.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.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*
.
AUTHORIZATION
request variable is already set by some upstream HTTP server.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!