Files

30 lines
4.0 KiB
Markdown

---
status: complete
---
# Quick Task 260707-csw: LDAP AD Anbindung — Zugangsdaten aus XWiki vorbefuellen und Import-Filter fuer Benutzer/Gruppen
## What shipped
1. **AD connection prefill** — `admin/ldap` page now defaults a brand-new config form to the CTL Active Directory values extracted from `user-files/xwiki.cfg` (server `balios.ctl.local:3268`, base DN `dc=ctl,dc=local`, AD person search filter, down-level bind-DN hint). Password stays blank. Editing an existing config still shows its real saved values (unchanged behavior).
2. **Selective group/OU import filter** — new `groupFilterDns String[]` column on `LdapConfig` (additive migration, empty array = current "import everyone" behavior). `GET /ldap/groups` discovers AD groups/OUs under the base DN; admin can select from the discovered list or add DNs manually; selection persists via `PATCH /ldap/config` and is editable any time post-setup. `syncUsersForTenant` now restricts its directory search to members of selected groups (via escaped `memberOf` clauses) or users under selected OUs (extra search bases), for both manual sync and the scheduled cron sync.
3. **Bugfix caught during manual testing (not in original plan):** `CreateLdapConfigDto`'s optional fields (`searchFilter`, `syncIntervalMin`, `isActive`, `groupFilterDns`) had TS class-field default initializers. NestJS's `ValidationPipe` applies those defaults via `plainToInstance` even when the field is absent from the request body, so any partial PATCH silently reset the other fields to hardcoded defaults. Caught live: saving the group filter alone reset `searchFilter` back to `(objectClass=person)`, clobbering the AD-specific filter. Fixed by removing the initializers — the service layer's own `?? default` fallback already covers create-time defaults.
4. **Pre-existing i18n gap fixed (user-approved scope addition):** the `admin.ldap` message block referenced by the page (`t('title')`, `t('connectionTitle')`, `t('serverUrl')`, etc.) did not exist in `de.json`/`en.json` at all, so the whole page rendered raw translation keys instead of text. Backfilled the full set of keys the page actually uses, in addition to the new group-filter keys.
## Verification performed
- `prisma validate`, `prisma generate`, API `type-check`, API `build` — all green.
- Web `type-check` green; both message JSON files parse.
- Migration applied live via container restart (`Applying migration 20260707090000_add_ldap_group_filter`), confirmed idempotent entrypoint (`prisma migrate deploy`).
- End-to-end manual test via Playwright against the running dev stack:
- Fresh `/admin/ldap` page load shows AD-prefilled connection form, password blank.
- Created a config (test bind DN/password — dev environment, no live AD reachable from this sandbox), confirmed default field mappings (`displayName`, `mail`, `sAMAccountName`) are AD-correct.
- Added a group DN manually, saved the filter, reloaded the page — filter persisted.
- Verified via direct DB query (`SELECT ... FROM "LdapConfig"`) that `groupFilterDns` persisted correctly and, after the DTO fix, that `searchFilter`/`syncIntervalMin`/`isActive` are no longer clobbered by a groupFilterDns-only PATCH.
## Known limitations / follow-ups for the user
- **Not tested against a live AD server** — `balios.ctl.local` is not reachable from this environment. `GET /ldap/groups` discovery and the `memberOf`-filtered sync are implemented per the plan's design and pass all static checks, but have not been exercised against real Active Directory data. Recommend testing `testConnection`, `Gruppen/OUs suchen`, and a real sync once this is deployed somewhere with network access to the CTL AD.
- The dev database now has one `LdapConfig` test row (server/base DN are the real CTL AD values; bind DN/password are placeholders `ctl\testservice` / `testpassword`) with one filter DN saved. Replace the bind credentials with the real service-account before relying on this in a real environment.
- The i18n backfill only covers keys this page actually calls — it does not audit the rest of the app for similar gaps.