docs(PROJ-72): Feature-Spec nachtragen + Audit-Log-Härtung für abgelehnte Privilege-Checks
Feature-Spec, INDEX.md und features.ts für PROJ-72 (Superadmin-Peer-Patch-Fix) ergänzt inkl. QA-Ergebnisse. Zusätzlich: abgelehnte Privilege-Escalation-/ Tenant-Isolation-Versuche (403) werden jetzt als Success:false im Audit-Log protokolliert (vorher nur erfolgreiche Updates) - Härtungspunkt aus QA-Runde.
This commit is contained in:
@@ -66,6 +66,14 @@ func (s *Server) handleCreateUser(w http.ResponseWriter, r *http.Request) {
|
||||
// at or above their own level.
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if roleLevel(req.Role) >= roleLevel(sess.Role) {
|
||||
s.audlog.Log(audit.Entry{
|
||||
EventType: audit.EventUserMgmt,
|
||||
Username: sess.Username,
|
||||
TenantID: sess.TenantID,
|
||||
IPAddress: s.remoteIP(r),
|
||||
Detail: fmt.Sprintf("denied: insufficient privileges to assign role %q on create", req.Role),
|
||||
Success: false,
|
||||
})
|
||||
writeError(w, http.StatusForbidden, "insufficient privileges to assign this role")
|
||||
return
|
||||
}
|
||||
@@ -148,6 +156,14 @@ func (s *Server) handleUpdateUser(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
if sess.TenantID != nil {
|
||||
if target.TenantID == nil || *target.TenantID != *sess.TenantID {
|
||||
s.audlog.Log(audit.Entry{
|
||||
EventType: audit.EventUserMgmt,
|
||||
Username: sess.Username,
|
||||
TenantID: sess.TenantID,
|
||||
IPAddress: s.remoteIP(r),
|
||||
Detail: fmt.Sprintf("denied: cross-tenant access to user %d", id),
|
||||
Success: false,
|
||||
})
|
||||
writeError(w, http.StatusForbidden, "access denied")
|
||||
return
|
||||
}
|
||||
@@ -159,10 +175,26 @@ func (s *Server) handleUpdateUser(w http.ResponseWriter, r *http.Request) {
|
||||
// checks would otherwise block superadmin-vs-superadmin management.
|
||||
if sess.Role != userstore.RoleSuperAdmin {
|
||||
if roleLevel(target.Role) >= roleLevel(sess.Role) {
|
||||
s.audlog.Log(audit.Entry{
|
||||
EventType: audit.EventUserMgmt,
|
||||
Username: sess.Username,
|
||||
TenantID: sess.TenantID,
|
||||
IPAddress: s.remoteIP(r),
|
||||
Detail: fmt.Sprintf("denied: insufficient privileges to modify user %d", id),
|
||||
Success: false,
|
||||
})
|
||||
writeError(w, http.StatusForbidden, "insufficient privileges to modify this user")
|
||||
return
|
||||
}
|
||||
if req.Role != nil && roleLevel(*req.Role) >= roleLevel(sess.Role) {
|
||||
s.audlog.Log(audit.Entry{
|
||||
EventType: audit.EventUserMgmt,
|
||||
Username: sess.Username,
|
||||
TenantID: sess.TenantID,
|
||||
IPAddress: s.remoteIP(r),
|
||||
Detail: fmt.Sprintf("denied: insufficient privileges to assign role %q to user %d", *req.Role, id),
|
||||
Success: false,
|
||||
})
|
||||
writeError(w, http.StatusForbidden, "insufficient privileges to assign this role")
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user