No description
Find a file
2026-08-21 11:28:39 +02:00
cmd/server Initial commit 2026-08-20 13:26:16 +02:00
deploy/systemd systemd Service hinzugefügt 2026-08-20 13:52:01 +02:00
internal Initial commit 2026-08-20 13:26:16 +02:00
.env.example Initial commit 2026-08-20 13:26:16 +02:00
.gitignore Initial commit 2026-08-20 13:26:16 +02:00
go.mod Initial commit 2026-08-20 13:26:16 +02:00
go.sum Initial commit 2026-08-20 13:26:16 +02:00
README.md systemd Service hinzugefügt 2026-08-20 13:52:01 +02:00
settings.yaml o (Organisation) und ou (Organisationseinheit/Abteilung) im Result darstellen 2026-08-21 11:28:39 +02:00

teldap-ws-proxy

LDAP-zu-WebSocket-Proxy für das TELDAP-Telefonbuch. Ein Service-Account (ldap.bind_dn) mit Read-Only-Rechten und authzTo sucht via LDAP Proxy Authorization Control (RFC 4370) im Namen des jeweils per JWT authentifizierten Benutzers, sodass jeder Client nur seine eigene Sicht auf das Adressbuch sieht.

Konfiguration

  • settings.yaml — alle nicht-geheimen Einstellungen (Server, LDAP, Pool, Auth, Logging).
  • .env — Secrets: LDAP_BIND_PASSWORD, JWT_SECRET (siehe .env.example, .env ist gitignored).

Starten

go run ./cmd/server -settings settings.yaml -env .env

WebSocket-Protokoll

Endpoint: server.ws_path (Standard /ws). JSON-Frames in beide Richtungen.

Erste Nachricht des Clients muss auth sein:

{"cmd": "auth", "token": "<jwt>"}

Antwort:

{"cmd": "auth", "status": "ok"}

Danach kann der Client beliebig viele Suchanfragen parallel/asynchron stellen, jede mit eigener id:

{"cmd": "search", "id": "req-1", "query": "0851"}

Die Antwort trägt dieselbe id, damit der Client sie seiner Anfrage zuordnen kann (Antworten können in beliebiger Reihenfolge eintreffen):

{
  "cmd": "search",
  "id": "req-1",
  "status": "ok",
  "results": [
    {"dn": "...", "cn": ["..."], "telephoneNumber": ["..."], "rsmSource": ["..."], "rsmOwnerDN": ["..."]}
  ]
}

Fehlerfall:

{"cmd": "search", "id": "req-1", "status": "error", "error": "search failed"}

LDAP Connection Pool

Konfigurierbar über pool.* in settings.yaml (min, max, min_spare, max_idle_time, health_check_interval). Solange freie Verbindungen verfügbar sind, blockiert eine Suche nie unnötig; ist max erreicht, wartet die Anfrage (wird "gequeued"), bis eine Verbindung frei wird. Der Pool hält mindestens min_spare Leerlaufverbindungen warm und skaliert bedarfsgesteuert bis max.

GET /healthz liefert den aktuellen Pool-Status (pool_total, pool_idle, pool_in_use).

Deployment als systemd-Service

# Binary bauen und installieren
go build -o /tmp/teldap-ws-proxy ./cmd/server
sudo install -m 755 /tmp/teldap-ws-proxy /usr/local/bin/teldap-ws-proxy

# Konfiguration ablegen
sudo mkdir -p /etc/teldap-ws-proxy
sudo install -m 644 settings.yaml /etc/teldap-ws-proxy/settings.yaml
sudo install -m 600 .env /etc/teldap-ws-proxy/teldap-ws-proxy.env

# Unit installieren und starten
sudo install -m 644 deploy/systemd/teldap-ws-proxy.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now teldap-ws-proxy

# Status / Logs
systemctl status teldap-ws-proxy
journalctl -u teldap-ws-proxy -f

Die Unit nutzt DynamicUser=yes — es muss also kein Service-User manuell angelegt werden, systemd vergibt einen unprivilegierten Laufzeit-UID/GID. settings.yaml (unkritisch) liegt mit 644, die Secrets-Datei teldap-ws-proxy.env mit 600 root:root — sie wird per EnvironmentFile= von systemd selbst (als root) eingelesen und als Prozessumgebung weitergereicht, bevor auf den unprivilegierten User gewechselt wird. Der Proxy-Prozess selbst braucht also nie Leserechte auf die Secrets-Datei.

Nach Änderungen an settings.yaml oder der .env-Datei:

sudo systemctl restart teldap-ws-proxy