fix(PROJ-63): Defense-in-Depth Tenant-Scope-Härtung der Admin-Endpunkte
tenantAccessAllowed()-Check in allen {id}-Handlern von tenant_handlers.go,
tenant_domain_handlers.go und tenant_logo_handlers.go ergänzt — No-op für
globale Admins, zweite Verteidigungslinie für hypothetische tenant-gebundene
Admin-Sessions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
c1338f6721
commit
dcb88317ac
@@ -18,6 +18,11 @@ func (s *Server) handleListTenantDomains(w http.ResponseWriter, r *http.Request)
|
||||
writeError(w, http.StatusBadRequest, "invalid tenant id")
|
||||
return
|
||||
}
|
||||
// Defense-in-depth tenant scope check (PROJ-63): no-op for global admins.
|
||||
if !tenantAccessAllowed(sessionFromCtx(r.Context()), &id) {
|
||||
writeError(w, http.StatusForbidden, "access denied")
|
||||
return
|
||||
}
|
||||
domains, err := s.tenantStore.ListDomains(r.Context(), id)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "failed to list domains")
|
||||
@@ -37,6 +42,12 @@ func (s *Server) handleAddTenantDomain(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Defense-in-depth tenant scope check (PROJ-63): no-op for global admins.
|
||||
if !tenantAccessAllowed(sessionFromCtx(r.Context()), &id) {
|
||||
writeError(w, http.StatusForbidden, "access denied")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
@@ -63,6 +74,11 @@ func (s *Server) handleRemoveTenantDomain(w http.ResponseWriter, r *http.Request
|
||||
writeError(w, http.StatusBadRequest, "invalid tenant id")
|
||||
return
|
||||
}
|
||||
// Defense-in-depth tenant scope check (PROJ-63): no-op for global admins.
|
||||
if !tenantAccessAllowed(sessionFromCtx(r.Context()), &tenantID) {
|
||||
writeError(w, http.StatusForbidden, "access denied")
|
||||
return
|
||||
}
|
||||
didStr := r.PathValue("did")
|
||||
domainID, err := strconv.ParseInt(didStr, 10, 64)
|
||||
if err != nil {
|
||||
|
||||
@@ -117,6 +117,11 @@ func (s *Server) handleGetTenant(w http.ResponseWriter, r *http.Request) {
|
||||
writeError(w, http.StatusBadRequest, "invalid tenant id")
|
||||
return
|
||||
}
|
||||
// Defense-in-depth tenant scope check (PROJ-63): no-op for global admins.
|
||||
if !tenantAccessAllowed(sessionFromCtx(r.Context()), &id) {
|
||||
writeError(w, http.StatusForbidden, "access denied")
|
||||
return
|
||||
}
|
||||
tenant, err := s.tenantStore.Get(r.Context(), id)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusNotFound, "tenant not found")
|
||||
@@ -136,6 +141,12 @@ func (s *Server) handleUpdateTenant(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Defense-in-depth tenant scope check (PROJ-63): no-op for global admins.
|
||||
if !tenantAccessAllowed(sessionFromCtx(r.Context()), &id) {
|
||||
writeError(w, http.StatusForbidden, "access denied")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Name string `json:"name"`
|
||||
Active *bool `json:"active"`
|
||||
@@ -181,6 +192,11 @@ func (s *Server) handleDeleteTenant(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
sess := sessionFromCtx(r.Context())
|
||||
// Defense-in-depth tenant scope check (PROJ-63): no-op for global admins.
|
||||
if !tenantAccessAllowed(sess, &id) {
|
||||
writeError(w, http.StatusForbidden, "access denied")
|
||||
return
|
||||
}
|
||||
if err := s.tenantStore.Delete(r.Context(), id); err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "failed to delete tenant")
|
||||
return
|
||||
@@ -204,6 +220,11 @@ func (s *Server) handleListTenantUsers(w http.ResponseWriter, r *http.Request) {
|
||||
writeError(w, http.StatusBadRequest, "invalid tenant id")
|
||||
return
|
||||
}
|
||||
// Defense-in-depth tenant scope check (PROJ-63): no-op for global admins.
|
||||
if !tenantAccessAllowed(sessionFromCtx(r.Context()), &tenantID) {
|
||||
writeError(w, http.StatusForbidden, "access denied")
|
||||
return
|
||||
}
|
||||
users, err := s.users.ListByTenant(r.Context(), tenantID)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "failed to list tenant users")
|
||||
|
||||
@@ -57,6 +57,11 @@ func (s *Server) handleUploadTenantLogo(w http.ResponseWriter, r *http.Request)
|
||||
writeError(w, http.StatusBadRequest, "invalid tenant id")
|
||||
return
|
||||
}
|
||||
// Defense-in-depth tenant scope check (PROJ-63): no-op for global admins.
|
||||
if !tenantAccessAllowed(sessionFromCtx(r.Context()), &id) {
|
||||
writeError(w, http.StatusForbidden, "access denied")
|
||||
return
|
||||
}
|
||||
s.saveTenantLogo(w, r, id)
|
||||
}
|
||||
|
||||
@@ -70,6 +75,11 @@ func (s *Server) handleDeleteTenantLogo(w http.ResponseWriter, r *http.Request)
|
||||
writeError(w, http.StatusBadRequest, "invalid tenant id")
|
||||
return
|
||||
}
|
||||
// Defense-in-depth tenant scope check (PROJ-63): no-op for global admins.
|
||||
if !tenantAccessAllowed(sessionFromCtx(r.Context()), &id) {
|
||||
writeError(w, http.StatusForbidden, "access denied")
|
||||
return
|
||||
}
|
||||
if err := s.tenantStore.DeleteLogo(r.Context(), id); err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "failed to delete logo")
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user