Skip to content

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.username is the personal CN (e.g. nasarek_u_0fc67079), NOT {slug}_edit.
  • qgis_connection.user_id / qgis_connection.cert_cn match the web user / Cert-CN.
  • PgBouncer auth_type=cert requires libpq user == cert CN. Shared org certs no longer auth via proxy.
  • API base URL for team: https://linetra-web.nasarek.dev (legacy hosts linetra.nasarek.dev / linetra-app.nasarek.dev return 301/308 — do not follow for POST).

Goal UX

  1. Dock shows only API URL, username, password initially (no cert field on first paint).
  2. On Anmelden:
  3. POST /api/v1/auth/login (or token endpoint if used) with credentials.
  4. GET /api/v1/auth/me → read qgis_connection (host, port, database, username=CN, sslmode, user_id, cert_cn, password if present).
  5. If sslmode is not verify-full / no qgis_connection → current local/dev behaviour (no cert UI).
  6. Else look up cert store for an entry whose cert CN == qgis_connection.username (also accept Subject UID == user_id as secondary check; both must not contradict).
  7. If found → configure QgsAuth / Postgres provider with that crt/key/ca and connect.
  8. 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.
  9. 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.
  10. 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.
  11. 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 cn and user_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