Release govoplan-access v0.1.25: harden authentication and repair identity mappings
Module Package Release / publish-packages (push) Successful in 15s
Module Package Release / publish-packages (push) Successful in 15s
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
# Authentication cache boundary hardening
|
||||
|
||||
The authentication cache is an optimization, never an additional authentication
|
||||
method or permission source. The September 2026 review found and reproduced
|
||||
three violations of that boundary in isolated SQLite tests.
|
||||
|
||||
| Finding | Consequence | Resolution |
|
||||
| --- | --- | --- |
|
||||
| Service-account credentials passed through ordinary principal-summary refresh | A narrowed service-account ceiling could be replaced by backing membership roles; the service-account identifier and authentication method were lost. | Dedicated service-account resolution retains its provenance and checks the current ceiling/lifecycle on every request. It does not enter the interactive principal-summary cache. |
|
||||
| A warmed API-key summary accepted the same secret through a session cookie | The warm path accepted a cookie-authenticated mutation without the CSRF rule applied to real browser sessions; the cold path rejected the credential. | API keys require an explicit Bearer or X-API-Key header on both paths. Session cookies still require matching CSRF cookie/header/hash for mutations. |
|
||||
| Tenant-key intersection excluded only the historical `system:` spelling | Module-native system permissions and retained module wildcards could survive the tenant-only intersection. | Resolve wildcard grants to concrete registered tenant permissions and exclude system permissions by catalogue and compatibility aliases. |
|
||||
|
||||
No existing secrets, sessions, assignments, or database schema are changed.
|
||||
Normal header-authenticated API keys and concrete tenant aliases remain
|
||||
compatible. Clients relying on API keys in browser cookies, implicit unknown
|
||||
wildcards, or accidental instance-level rights must correct their authentication
|
||||
method or permission configuration; these are not preserved as compatibility
|
||||
exceptions. Stored grants are not rewritten. Service-account access continues
|
||||
to narrow immediately when its ceiling is reduced or its lifecycle blocks use.
|
||||
|
||||
Regression coverage is in `tests/test_auth_cache_security.py` and
|
||||
`tests/test_permission_catalog_contract.py`; the tests exercise the full
|
||||
credential resolver with principal caching enabled, not only the lower-level
|
||||
API-key lookup. They also verify that valid session CSRF and concrete legacy
|
||||
tenant aliases still work.
|
||||
|
||||
## Remaining coordinated password-change workflow
|
||||
|
||||
`Account.password_reset_required` is currently advisory metadata, not an
|
||||
enforced sign-in restriction. The administrator UI states this limitation,
|
||||
but the authentication-fields documentation previously claimed mandatory
|
||||
replacement; its English and German text now reflects the implementation.
|
||||
A generated password is disclosed once but is not a single-use login secret.
|
||||
|
||||
A follow-up must deliver the password-change endpoint, current-password
|
||||
verification and replacement policy, CSRF and attempt limits, session
|
||||
revocation/rotation and cache invalidation, a restricted reset-required
|
||||
principal, and the corresponding accessible UI/recovery path together.
|
||||
Enabling only a rejection gate would lock affected accounts out without any
|
||||
supported way to finish the change. This review does not enable such a gate or
|
||||
change existing passwords.
|
||||
|
||||
## Betriebshinweise
|
||||
|
||||
API-Schlüssel werden ausschließlich über `Authorization: Bearer` oder
|
||||
`X-API-Key` gesendet, nicht über das Sitzungscookie. Ändernde Cookie-Anfragen
|
||||
benötigen weiterhin einen passenden CSRF-Header samt Cookie und serverseitigem
|
||||
Prüfwert. Dienstkonten behalten ihre eigene Herkunft und werden bei jeder
|
||||
Anfrage gegen den aktuellen Berechtigungsrahmen und Lebenszyklus geprüft.
|
||||
Mitgliedschaftsrollen oder zwischengespeicherte interaktive Rechte dürfen diesen
|
||||
Rahmen nicht ersetzen.
|
||||
|
||||
Mandantenschlüssel erhalten keine instanzweiten Rechte, auch nicht unter
|
||||
modulbezogenen Berechtigungsnamen. Platzhalter werden in konkrete registrierte
|
||||
Mandantenrechte aufgelöst. Bestehende konkrete Mandantenrechte und ihre
|
||||
Kompatibilitätsnamen bleiben erhalten; gespeicherte Geheimnisse und
|
||||
Rollenzuweisungen werden nicht geändert.
|
||||
|
||||
Das Kennzeichen `password_reset_required` erzwingt derzeit keinen
|
||||
Passwortwechsel. Ein einmal angezeigtes Anfangspasswort bleibt zur Anmeldung
|
||||
verwendbar. Die Nachfolgeumsetzung muss Passwortänderung, eng begrenzten
|
||||
Zwischenzugriff, Sitzungswechsel beziehungsweise Widerruf und eine bedienbare
|
||||
Wiederherstellung gemeinsam liefern; eine alleinige Zugriffssperre würde
|
||||
betroffene Konten ohne durchführbaren Passwortwechsel aussperren.
|
||||
Reference in New Issue
Block a user