enhancement
major
minor
defect
critical
major
minor
minor
#30269
ModelAccessRights.isAllowed(Person, ...): Prüfung für eine andere Person übernimmt Bypass bzw. Admin-Status des aktuellen Kontexts
Hintergrund
Eine Anwendung legt im Commit (ModificationListener) Benachrichtigungen für andere Personen an. Jede Benachrichtigung soll nur entstehen, wenn der Empfänger das betroffene Objekt lesen darf. Dafür bietet die Engine ModelAccessRights.isReadAllowed(Person person, TLObject instance) bzw. isAllowed(Person, TLObject, BoundCommandGroup): „Checks whether the given person can perform the given command group on the given instance.“
Problem
SecurityConfigurationService.isAllowed(Person, TLObject, BoundCommandGroup) fragt vor der Rollenprüfung BoundChecker.isAllowedBypass(person, commandGroup). Das antwortet true, wenn
- der aktuelle Kontext die Sicherheitsprüfung umgeht (ThreadContext.isSecurityBypassed(), z. B. Systemkontext, Hintergrundtask), oder
- der Nutzer des aktuellen Kontexts Administrator ist (ThreadContext.isAdmin()).
Beides sind Eigenschaften des aktuellen Kontexts, nicht der geprüften Person. Ändert also ein Administrator oder ein Systemprozess ein Objekt, gilt jede beliebige Person als leseberechtigt. Die Javadoc von ThreadContext.isAdmin() sagt selbst: „Whether some given user is an administrator is a property of that user, not of the current context.“
Version: 8.0.0-alpha12 (com.top_logic.model.security.SecurityConfigurationService, com.top_logic.tool.boundsec.BoundChecker).
Reproduktion
- Person p ohne Rolle auf Objekt o.
- Im Systemkontext (oder angemeldet als root) auswerten: ModelAccessRights.getInstance().isReadAllowed(p, o).
- Ergebnis: true. Erwartet: false.
Erwartetes Verhalten
Die Variante mit Person-Parameter entscheidet nach der übergebenen Person: Bypass und Admin-Status des aktuellen Kontexts gelten nur für die Varianten ohne Person (aktueller Nutzer). Ist die übergebene Person Administrator, darf sie natürlich alles.
Umgehung
Prime (com.top_logic.prime.notify.Responsibles#canRead) setzt für die Prüfung die geprüfte Person als Nutzer des Kontexts (TLContext.captureIdentity()/setPerson) und schaltet die Sicherheitsprüfung ein (ThreadContext.withSecurityChecks(true, ...)); danach wird die Identität wiederhergestellt.
Lösung
- Neue Prüfung TLContext.hasAdministrativeRights(Person): Eine Person hat administrative Rechte, wenn sie Administrator ist (Person.isAdmin(Person)) oder wenn sie die Person des aktuellen Kontexts ist und die Sicherheitsprüfung umgangen wird (ThreadContext.isSecurityBypassed()).
- BoundChecker.isAllowedBypass(Person, BoundCommandGroup) und SimpleBoundCommandGroup.isAllowedCommandGroup(Person, BoundCommandGroup) entscheiden über diese Prüfung statt über den Zustand des aktuellen Kontexts. Damit gilt die Korrektur für alle Prüfungen des SecurityConfigurationService (ModelAccessRights), für BoundChecker.allow(...) und für die Zugriffsprüfung der React-Views (ModelAccessPolicy).
- Die Varianten ohne Person (aktueller Nutzer, auch im Systemkontext) verhalten sich unverändert. Eine Prüfung für eine andere Person entscheidet nach deren Rollen, Administrator-Kennzeichen und Einschränkung (restricted user).
- Die Zugriffserklärung (EffectiveAccess) braucht den Wechsel in den Kontext der erklärten Person nicht mehr; er entfällt.
- Die Umgehung in Anwendungen (Wechsel der Identität vor der Prüfung) ist nicht mehr nötig.