Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ RUN apk add --no-cache py3-pip py3-pyldap \
&& pip3 install --break-system-packages ldap-ui \
&& apk del py3-pip

HEALTHCHECK --interval=30s --timeout=2s --start-period=5s --retries=2 CMD [ "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:5000" ]
EXPOSE 5000
CMD ["ldap-ui", "--host", "0.0.0.0"]
25 changes: 8 additions & 17 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

SITE = backend/ldap_ui/statics
VERSION = $(shell fgrep __version__ backend/ldap_ui/__init__.py | cut -d'"' -f2)
ARCH = $(shell docker run --rm alpine uname -m)
TAG = $(VERSION)-$(subst aarch64,arm64,$(ARCH))
IMAGE = dnknth/ldap-ui

debug: $(SITE) .env
Expand All @@ -16,7 +14,7 @@ dist: clean $(SITE)
uv build

pypi: dist
- uv publish dist/*
uv publish --token `pass token/pypi.org` dist/*

deploy: clean $(SITE)
rsync -a --delete $(SITE)/ mx:/opt/ldap-ui/venv/lib/python3.12/site-packages/ldap_ui/statics/
Expand All @@ -31,21 +29,14 @@ node_modules: package.json

clean:
rm -rf build dist $(SITE) backend/ldap_ui.egg-info
find backend -name __pycache__ -exec rm -rf {} \;
-find backend -name __pycache__ -exec rm -rf {} \;

tidy: clean
rm -rf .venv node_modules

image:
docker build --no-cache -t $(IMAGE):$(TAG) .

push: image
docker push $(IMAGE):$(TAG)
- docker pushrm $(IMAGE)

manifest:
docker manifest create $(IMAGE) \
--amend $(IMAGE):$(VERSION)-x86_64 \
--amend $(IMAGE):$(VERSION)-arm64
docker manifest push --purge $(IMAGE)
docker compose pull
# See: https://docs.docker.com/build/building/multi-platform/#multiple-native-nodes
push:
docker buildx build --push \
--platform linux/amd64,linux/arm64 \
-t $(IMAGE):$(VERSION) -t $(IMAGE):latest .
docker pushrm $(IMAGE)
34 changes: 27 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,20 @@ Options:

Prerequisites:

* [GNU make](https://www.gnu.org/software/make/)
* [node.js](https://nodejs.dev) LTS version with NPM
* [Python3](https://www.python.org) ≥ 3.7
* [pip3](https://packaging.python.org/tutorials/installing-packages/)
* [pnpm](https://pnpm.io)
* [Python](https://www.python.org) ≥ 3.12
* [uv](https://docs.astral.sh/uv/)
* [python-ldap](https://pypi.org/project/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`
* [GNU make](https://www.gnu.org/software/make/)

`ldap-ui` consists of a Vue frontend and a Python backend that roughly translates a subset of the LDAP protocol to a stateless ReST API.

For the frontend, `npm run build` assembles everything in `backend/ldap_ui/statics`.
`pnpm build` assembles the frontend in `backend/ldap_ui/statics`.

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

The backend can be run locally with `make`, which will also install dependencies and build the frontend if needed.
Expand All @@ -122,10 +123,29 @@ The UI always uses a simple `bind` operation to authenticate with the LDAP direc

### Searching

Search uses a (configurable) set of criteria (`cn`, `gn`, `sn`, and `uid`) if the query does not contain `=`.
Search uses a (configurable) set of criteria#
(default: `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*`.

Apart from the search field in the navigation bar,
searches are also performed in the entry editor for any DN-valued input field.

### Keyboard navigation

The editor and modal dialogs focus the first input when opening, so you can the ⇥ key to navigate the form.
Save or dismiss with the ↩ key.

The following [access keys](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/accesskey#try_it) are defined:

| Access Key | UI Element |
|------------|---------------------------|
| K | Global search at page top |
| A | Add an atrribute |
| O | Add an object class |
| R | Reset entry modifications |
| S | Save an entry (same as ↩) |

### Caveats

* The software works with [OpenLdap](http://www.openldap.org) using simple bind. Other directories have not been tested much, although [389 DS](https://www.port389.org) works to some extent.
Expand All @@ -138,7 +158,7 @@ Additionally, arbitrary attributes can be searched with an LDAP filter specifica
* 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](http://phpldapadmin.sf.net/) has not seen updates for ages. I needed a replacement, and wanted to try Vue.
* A: [PHPLdapAdmin](http://phpldapadmin.sf.net/) is no longer actively maintained. I needed a replacement, and wanted to try Vue.

## Acknowledgements

Expand Down
2 changes: 1 addition & 1 deletion backend/ldap_ui/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.11.1"
__version__ = "0.12.6"
7 changes: 3 additions & 4 deletions backend/ldap_ui/ldap_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
File,
Header,
HTTPException,
Request,
Response,
UploadFile,
)
Expand Down Expand Up @@ -445,12 +446,10 @@ def handle(self, dn: str, entry: Attributes):
operation_id="post_ldif",
status_code=HTTPStatus.NO_CONTENT,
)
async def upload_ldif(
ldif: Annotated[str, Body()], connection: AuthenticatedConnection
) -> None:
async def upload_ldif(request: Request, connection: AuthenticatedConnection) -> None:
"Import LDIF"

reader = LDIFReader(ldif.encode(), connection)
reader = LDIFReader(await request.body(), connection)
try:
reader.parse()
except ValueError as e:
Expand Down
10 changes: 10 additions & 0 deletions demo-ldap/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM alpine

RUN apk add --no-cache openldap openldap-clients openldap-back-mdb
COPY slapd.conf /etc/openldap/slapd.conf
COPY flintstones.ldif /var/restore/flintstones-data.ldif
COPY start.sh /start.sh

HEALTHCHECK --interval=30s --timeout=2s --start-period=5s --retries=2 CMD [ "ldapsearch", "-LLLx", "-b", "o=Flintstones", "cn=admin", "dn" ]
EXPOSE 389
CMD [ "/start.sh" ]
6 changes: 6 additions & 0 deletions demo-ldap/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.PHONY: push

push:
docker buildx build --push \
--platform linux/amd64,linux/arm64 \
-t dnknth/ldap-demo .
18 changes: 18 additions & 0 deletions demo-ldap/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Flintstones LDAP demo

This is an [OpenLDAP](https://www.openldap.org) Docker [image](https://hub.docker.com/r/dnknth/ldap-demo)
populated with demo data of [Flintstones](https://en.wikipedia.org/wiki/The_Flintstones) characters,
courtesy of the [PHPLdapAdmin](https://phpldapadmin.sourceforge.net/) project.

To bind to the directory, use one of the following accounts:

| DN | Password | Role |
| ---- | -------- | ---- |
| cn=admin,o=Flintstones | bedrock | Admin |
| cn=Bamm Bamm Rubble,ou=People,o=Flintstones | bammbamm | User |
| cn=Fred Flintstone,ou=People,o=Flintstones | yabbadabbado | User |
| cn=Wilma Flintstone,ou=People,o=Flintstones | pebble | User |

Regular users can read and modify their password.
The admin modify everything.
Anonymous users can read everything except passwords.
Loading