fix(auth): restricted User können nur zugewiesene Screens aufrufen
requireScreenAccess prüft jetzt für Rolle 'restricted' zusätzlich ob ein Eintrag in user_screen_permissions existiert. Tenant-Match allein reichte bisher nicht — restricted User konnten alle Screens des Tenants aufrufen.
This commit is contained in:
parent
3ebeaa70e1
commit
3a0ac13faa
3 changed files with 20 additions and 20 deletions
|
|
@ -112,7 +112,7 @@ func HandleSetScreenOverride(screens *store.ScreenStore, schedules *store.Screen
|
|||
http.Error(w, "screen not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if !requireScreenAccess(w, r, screen) {
|
||||
if !requireScreenAccess(w, r, screen, screens) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ func HandleUpdateSchedule(screens *store.ScreenStore, schedules *store.ScreenSch
|
|||
http.Error(w, "screen not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if !requireScreenAccess(w, r, screen) {
|
||||
if !requireScreenAccess(w, r, screen, screens) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,9 +43,10 @@ func renderTemplate(w http.ResponseWriter, t *template.Template, data any) {
|
|||
}
|
||||
|
||||
// requireScreenAccess prüft, ob der eingeloggte User Zugriff auf den Screen hat.
|
||||
// Admins dürfen alles. Tenant-User dürfen nur Screens ihres eigenen Tenants bearbeiten.
|
||||
// Admins dürfen alles. screen_user dürfen Screens ihres Tenants. restricted User
|
||||
// benötigen zusätzlich einen Eintrag in user_screen_permissions.
|
||||
// Gibt true zurück wenn Zugriff erlaubt ist; schreibt 403 und gibt false zurück wenn nicht.
|
||||
func requireScreenAccess(w http.ResponseWriter, r *http.Request, screen *store.Screen) bool {
|
||||
func requireScreenAccess(w http.ResponseWriter, r *http.Request, screen *store.Screen, sc *store.ScreenStore) bool {
|
||||
u := reqcontext.UserFromContext(r.Context())
|
||||
if u == nil {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
|
@ -54,19 +55,18 @@ func requireScreenAccess(w http.ResponseWriter, r *http.Request, screen *store.S
|
|||
if u.Role == "admin" {
|
||||
return true
|
||||
}
|
||||
// Tenant-User: Screen muss zum eigenen Tenant gehören.
|
||||
// Wir vergleichen über TenantSlug→TenantID, aber der Screen hat TenantID.
|
||||
// Da uns der Tenant-Slug des Users bekannt ist und wir keinen TenantStore
|
||||
// hier haben, vergleichen wir TenantID des Screens mit dem user.TenantID-Feld.
|
||||
// store.User hat TenantSlug aber nicht TenantID — deswegen muss der
|
||||
// aufrufende Handler nach GetBySlug bereits die TenantID des Screens bekannt haben.
|
||||
// Wir nutzen u.TenantSlug und vertrauen darauf dass der Screen bereits geladen ist.
|
||||
// Den eigentlichen Vergleich machen wir via TenantID des Screens vs.
|
||||
// dem TenantID-Feld im User (das über reqcontext gespeichert ist).
|
||||
if u.TenantID != "" && u.TenantID != screen.TenantID {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return false
|
||||
}
|
||||
// Restricted User: zusätzlich explizite Screen-Berechtigung prüfen.
|
||||
if u.Role == "restricted" {
|
||||
ok, err := sc.HasUserScreenAccess(r.Context(), u.ID, screen.ID)
|
||||
if err != nil || !ok {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -370,7 +370,7 @@ func HandleManageUI(
|
|||
notifier.RequestScreenshot(screen.Slug)
|
||||
|
||||
// K2: Tenant-Isolation — nur eigener Tenant oder Admin.
|
||||
if !requireScreenAccess(w, r, screen) {
|
||||
if !requireScreenAccess(w, r, screen, screens) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -607,7 +607,7 @@ func HandleUploadMediaUI(media *store.MediaStore, screens *store.ScreenStore, up
|
|||
}
|
||||
|
||||
// K2: Tenant-Isolation.
|
||||
if !requireScreenAccess(w, r, screen) {
|
||||
if !requireScreenAccess(w, r, screen, screens) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -694,7 +694,7 @@ func HandleAddItemUI(playlists *store.PlaylistStore, media *store.MediaStore, sc
|
|||
}
|
||||
|
||||
// K2: Tenant-Isolation.
|
||||
if !requireScreenAccess(w, r, screen) {
|
||||
if !requireScreenAccess(w, r, screen, screens) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -760,7 +760,7 @@ func HandleDeleteItemUI(playlists *store.PlaylistStore, screens *store.ScreenSto
|
|||
http.Error(w, "screen nicht gefunden", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if !requireScreenAccess(w, r, screen) {
|
||||
if !requireScreenAccess(w, r, screen, screens) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -783,7 +783,7 @@ func HandleReorderUI(playlists *store.PlaylistStore, screens *store.ScreenStore,
|
|||
return
|
||||
}
|
||||
// K2: Tenant-Isolation.
|
||||
if !requireScreenAccess(w, r, screen) {
|
||||
if !requireScreenAccess(w, r, screen, screens) {
|
||||
return
|
||||
}
|
||||
playlist, err := playlists.GetByScreen(r.Context(), screen.ID)
|
||||
|
|
@ -822,7 +822,7 @@ func HandleUpdateItemUI(playlists *store.PlaylistStore, screens *store.ScreenSto
|
|||
http.Error(w, "screen nicht gefunden", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if !requireScreenAccess(w, r, screen) {
|
||||
if !requireScreenAccess(w, r, screen, screens) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -864,7 +864,7 @@ func HandleDeleteMediaUI(media *store.MediaStore, screens *store.ScreenStore, up
|
|||
http.Error(w, "screen nicht gefunden", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if !requireScreenAccess(w, r, screen) {
|
||||
if !requireScreenAccess(w, r, screen, screens) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue