fix: Tenant-Isolation in handleSearch + requireMailAccess

- handleSearch: Ergebnisse nach tenant_id filtern (via email_refs)
- requireMailAccess: domain_admin darf Mails lesen, Tenant-Prüfung
  erfolgt bereits in handleGetMail via GetTenantForMail

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sysops
2026-03-17 22:03:22 +01:00
parent d8a8204e36
commit 143db65755
+27 -3
View File
@@ -542,6 +542,26 @@ func (s *Server) handleSearch(w http.ResponseWriter, r *http.Request) {
return return
} }
// Tenant isolation: filter results to only this tenant's emails.
tenantID := tenantFromCtx(r.Context())
if tenantID != nil && len(result.Hits) > 0 {
allowedIDs, idErr := s.store.GetAllIDsByTenant(r.Context(), tenantID)
if idErr == nil {
allowed := make(map[string]struct{}, len(allowedIDs))
for _, id := range allowedIDs {
allowed[id] = struct{}{}
}
filtered := result.Hits[:0]
for _, h := range result.Hits {
if _, ok := allowed[h.ID]; ok {
filtered = append(filtered, h)
}
}
result.Hits = filtered
result.Total = len(filtered)
}
}
sess := sessionFromCtx(r.Context()) sess := sessionFromCtx(r.Context())
s.audlog.Log(audit.Entry{ s.audlog.Log(audit.Entry{
EventType: audit.EventSearch, EventType: audit.EventSearch,
@@ -768,12 +788,16 @@ func remoteIP(r *http.Request) string {
// ── Mail access middleware ──────────────────────────────────────────────── // ── Mail access middleware ────────────────────────────────────────────────
// requireMailAccess blocks admin role (no mail access) and passes user/auditor through. // requireMailAccess checks that the caller may read mail content.
// superadmin and domain_admin have read access (tenant-scoped via handleGetMail).
// Auditor and user have access to their own mails.
// The old "admin" role (now domain_admin) previously had no mail access — that
// restriction is removed; domain_admin now needs to be able to read archived mails.
func (s *Server) requireMailAccess(next http.HandlerFunc) http.HandlerFunc { func (s *Server) requireMailAccess(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
sess := sessionFromCtx(r.Context()) sess := sessionFromCtx(r.Context())
if sess.Role == userstore.RoleAdmin { if sess == nil {
writeError(w, http.StatusForbidden, "admins have no access to mail content") writeError(w, http.StatusUnauthorized, "not authenticated")
return return
} }
next(w, r) next(w, r)