Plugin-Briefing: Per-user QGIS client certs (ADR-0055)
Copy-paste for an agent working in the sibling repo linetra-plugin. Backend contract lives in this web repo.
Context
Linetra Web API issues one Postgres LOGIN role + client cert CN per app user.
- After login,
GET /api/v1/auth/me→qgis_connection.usernameis the personal CN (e.g.nasarek_u_0fc67079), NOT{slug}_edit. qgis_connection.user_id/qgis_connection.cert_cnmatch the web user / Cert-CN.- PgBouncer
auth_type=certrequires libpq user == cert CN. Shared org certs no longer auth via proxy. - API base URL for team:
https://linetra-web.nasarek.dev(legacy hostslinetra.nasarek.dev/linetra-app.nasarek.devreturn 301/308 — do not follow for POST).
Goal UX
- Dock shows only API URL, username, password initially (no cert field on first paint).
- On Anmelden:
POST /api/v1/auth/login(or token endpoint if used) with credentials.GET /api/v1/auth/me→ readqgis_connection(host, port, database, username=CN, sslmode, user_id, cert_cn, password if present).- If
sslmodeis notverify-full/ noqgis_connection→ current local/dev behaviour (no cert UI). - Else look up cert store for an entry whose cert CN ==
qgis_connection.username(also accept Subject UID ==user_idas secondary check; both must not contradict). - If found → configure QgsAuth / Postgres provider with that crt/key/ca and connect.
- If not found → modal: “Kein passendes Zertifikat für Benutzer X. Ordner wählen…” → user picks unzipped QGIS-Cert-ZIP folder → import crt/key/ca → validate CN/UID → on mismatch reject (“Zertifikat gehört zu anderem Benutzer”) → on match save into store and continue.
- User switch (logout / other username login): never reuse previous user’s cert. Resolve again via store keyed by personal CN / user_id; prompt if missing.
- Multi-cert store: keep many imported identities (several users on one workstation). Importing a new folder adds/replaces the entry for that CN; does not wipe others.
- Never allow manual override of DB username independent of cert CN (no backdoor in UI).
Cert store (suggested)
- Location: QGIS profile dir, e.g.
…/Linetra/certs/<cn>/or encrypted QgsAuthConfig with metadata JSON:{ "user_id", "username_web", "cn", "imported_at", "paths": {crt,key,ca} }. - Index by
cnanduser_id. - On import: parse X.509 CN (+ UID if present); refuse if CN empty or not matching expected after login.
Non-goals
- Do not invent per-person DB roles in the plugin; trust API
qgis_connection. - Do not use legacy API hosts
linetra.nasarek.dev/linetra-app.nasarek.dev. - Web CMS login has no cert upload — only the plugin.
Acceptance
- Login as A with only B’s cert in store → prompt; importing B’s folder while logged in as A → error.
- Import A’s + B’s certs → switch users without re-download; each uses own CN.
- Wrong API URL (301) → actionable error, not silent redirect success.
- Local Docker without mTLS → cert UI stays hidden.
Backend reference
- ADR: 0055-per-user-qgis-cert-roles.md
- User docs: QGIS-Verbindung