Supply-Chain-Scan (Go) / govulncheck (push) Failing after 41s
Haertet die Control-Plane-Registry als eigene Schutzzone: - Dedizierte Postgres-Rolle nexarch_registry (ohne CREATEDB) fuer NEXARCH_REGISTRY_DSN, getrennt von der Provisioning-Rolle nexarch_core (deploy/install.sh). Neu angelegte Tenant-Datenbanken entziehen PUBLIC explizit das CONNECT-Recht (internal/tenant/provisioner.go), damit die Registry-Rolle unter keinen Umstaenden Zugriff auf eine Tenant-Datenbank erhaelt (Akzeptanzkriterium 1). - Auditierte Zugriffsmethoden (*AsActor) fuer Superadmin-Konten (internal/user.SuperadminStore) und Verbindungsinformationen (internal/tenant.Registry) — jeder lesende/schreibende Zugriff erzeugt einen Audit-Event mit Akteur und Zeitstempel, verdrahtet in internal/tenantadmin (TEN-05-Konsole) und cmd/core (Akzeptanzkriterium 2). - Betriebsanleitung docs/TEN-09-REGISTRY-BETRIEB.md dokumentiert Rollentrennung und den auf den Core-Dienst beschraenkten Netzwerkzugriff (pg_hba.conf, listen_addresses, Firewall-Default-Policy), abgesichert durch internal/opsdocs/registry_hardening_test.go (Akzeptanzkriterium 3). Automatisierte Tests je Akzeptanzkriterium: internal/tenant/isolation_test.go (negativer Zugriffstest), internal/audit/wiring_test.go (TestWiring_SuperadminReadIsAudited, TestWiring_RegistryConnectionInfoReadIsAudited), internal/opsdocs/registry_hardening_test.go. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QPsyieCYwvbUBsnN598SbP
73 lines
2.3 KiB
Go
73 lines
2.3 KiB
Go
package user
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
)
|
|
|
|
// Handler stellt die CRUD-API fuer Benutzerkonten bereit (IAM-01-Auftrag).
|
|
// Auth/Sessions (IAM-02) und Rollen (RBAC-01) sind ausdruecklich nicht Teil
|
|
// dieser Kachel und daher hier noch nicht angebunden.
|
|
type Handler struct {
|
|
users *TenantUserStore
|
|
superadmins *SuperadminStore
|
|
}
|
|
|
|
func NewHandler(users *TenantUserStore, superadmins *SuperadminStore) *Handler {
|
|
return &Handler{users: users, superadmins: superadmins}
|
|
}
|
|
|
|
type createUserRequest struct {
|
|
Email string `json:"email"`
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
func (h *Handler) CreateUser(w http.ResponseWriter, r *http.Request) {
|
|
var req createUserRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "ungueltige Anfrage", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
u, err := h.users.Create(r.Context(), req.Email, req.Name)
|
|
writeUserResult(w, u, err)
|
|
}
|
|
|
|
// CreateSuperadmin legt ein mandantenuebergreifendes Superadmin-Konto an —
|
|
// bewusst ein eigener Endpunkt statt eines Tenant-Parameters mit Null-Wert.
|
|
func (h *Handler) CreateSuperadmin(w http.ResponseWriter, r *http.Request) {
|
|
var req createUserRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "ungueltige Anfrage", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// TEN-09 Akzeptanzkriterium 2: Anlage eines Superadmin-Kontos ist ein
|
|
// schreibender Zugriff auf ein Superadmin-Konto und wird auditiert.
|
|
// Echte Aufrufer-Identitaet (IAM-02-Session) ist an diesem vorlaeufigen,
|
|
// noch unauthentifizierten Bootstrap-Endpunkt nicht verfuegbar (siehe
|
|
// Paketkommentar) — "system" folgt derselben Konvention wie
|
|
// tenant.Registry.transition fuer Vorgaenge ohne bekannten Akteur.
|
|
u, err := h.superadmins.CreateAsActor(r.Context(), "system", req.Email, req.Name)
|
|
writeUserResult(w, u, err)
|
|
}
|
|
|
|
func writeUserResult(w http.ResponseWriter, u User, err error) {
|
|
if err != nil {
|
|
switch {
|
|
case errors.Is(err, ErrInvalidEmail), errors.Is(err, ErrEmailTaken):
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
case errors.Is(err, ErrNotFound):
|
|
http.Error(w, err.Error(), http.StatusNotFound)
|
|
default:
|
|
http.Error(w, "benutzer konnte nicht verarbeitet werden", http.StatusInternalServerError)
|
|
}
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusCreated)
|
|
_ = json.NewEncoder(w).Encode(u)
|
|
}
|