[v11.2.x] Zanzana: Evaluate dashboard and folder permissions (#92253)
Zanzana: Evaluate dashboard and folder permissions (#91539)
* Zanzana: basic folder permissions checks
* Fix managed permissions for teams
* fix sync batch size
* add dashboards actions translations
* migrate folder tree
* migrate dashboard folders
* remove action sets from schema
* Adding more dashboard and folder-related permissions
* refactor
* Correctly translate dashboard permissions in folders
* fix dashboard parent permissions
(cherry picked from commit 1cc438a56c)
Co-authored-by: Alexander Zobnin <alexanderzobnin@gmail.com>
This commit is contained in:
committed by
GitHub
parent
25c9b9d58e
commit
4115a67a42
@@ -114,6 +114,7 @@ func (a *AccessControl) evaluateZanzana(ctx context.Context, user identity.Reque
|
||||
return false, errAccessNotImplemented
|
||||
}
|
||||
|
||||
a.log.Debug("evaluating zanzana", "user", key.User, "relation", key.Relation, "object", key.Object)
|
||||
res, err := a.zclient.Check(ctx, &openfgav1.CheckRequest{
|
||||
TupleKey: &openfgav1.CheckRequestTupleKey{
|
||||
User: key.User,
|
||||
|
||||
@@ -3,6 +3,7 @@ package migrator
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
openfgav1 "github.com/openfga/api/proto/openfga/v1"
|
||||
@@ -33,6 +34,8 @@ func NewZanzanaSynchroniser(client zanzana.Client, store db.DB, collectors ...Tu
|
||||
collectors,
|
||||
teamMembershipCollector(store),
|
||||
managedPermissionsCollector(store),
|
||||
folderTreeCollector(store),
|
||||
dashboardFolderCollector(store),
|
||||
)
|
||||
|
||||
return &ZanzanaSynchroniser{
|
||||
@@ -111,9 +114,9 @@ func managedPermissionsCollector(store db.DB) TupleCollector {
|
||||
for _, p := range permissions {
|
||||
var subject string
|
||||
if len(p.UserUID) > 0 {
|
||||
subject = zanzana.NewObject(zanzana.TypeUser, p.UserUID)
|
||||
subject = zanzana.NewTupleEntry(zanzana.TypeUser, p.UserUID, "")
|
||||
} else if len(p.TeamUID) > 0 {
|
||||
subject = zanzana.NewObject(zanzana.TypeTeam, p.TeamUID)
|
||||
subject = zanzana.NewTupleEntry(zanzana.TypeTeam, p.TeamUID, "member")
|
||||
} else {
|
||||
// FIXME(kalleep): Unsuported role binding (org role). We need to have basic roles in place
|
||||
continue
|
||||
@@ -161,8 +164,8 @@ func teamMembershipCollector(store db.DB) TupleCollector {
|
||||
|
||||
for _, m := range memberships {
|
||||
tuple := &openfgav1.TupleKey{
|
||||
User: zanzana.NewObject(zanzana.TypeUser, m.UserUID),
|
||||
Object: zanzana.NewObject(zanzana.TypeTeam, m.TeamUID),
|
||||
User: zanzana.NewTupleEntry(zanzana.TypeUser, m.UserUID, ""),
|
||||
Object: zanzana.NewTupleEntry(zanzana.TypeTeam, m.TeamUID, ""),
|
||||
}
|
||||
|
||||
// Admin permission is 4 and member 0
|
||||
@@ -178,3 +181,75 @@ func teamMembershipCollector(store db.DB) TupleCollector {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// folderTreeCollector collects folder tree structure and writes it as relation tuples
|
||||
func folderTreeCollector(store db.DB) TupleCollector {
|
||||
return func(ctx context.Context, tuples map[string][]*openfgav1.TupleKey) error {
|
||||
const collectorID = "folder"
|
||||
const query = `
|
||||
SELECT uid, parent_uid, org_id FROM folder WHERE parent_uid IS NOT NULL
|
||||
`
|
||||
type folder struct {
|
||||
OrgID int64 `xorm:"org_id"`
|
||||
FolderUID string `xorm:"uid"`
|
||||
ParentUID string `xorm:"parent_uid"`
|
||||
}
|
||||
|
||||
var folders []folder
|
||||
err := store.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
return sess.SQL(query).Find(&folders)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, f := range folders {
|
||||
tuple := &openfgav1.TupleKey{
|
||||
User: zanzana.NewScopedTupleEntry(zanzana.TypeFolder, f.ParentUID, "", strconv.FormatInt(f.OrgID, 10)),
|
||||
Object: zanzana.NewScopedTupleEntry(zanzana.TypeFolder, f.FolderUID, "", strconv.FormatInt(f.OrgID, 10)),
|
||||
Relation: zanzana.RelationParent,
|
||||
}
|
||||
|
||||
tuples[collectorID] = append(tuples[collectorID], tuple)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// dashboardFolderCollector collects information about dashboards parent folders
|
||||
func dashboardFolderCollector(store db.DB) TupleCollector {
|
||||
return func(ctx context.Context, tuples map[string][]*openfgav1.TupleKey) error {
|
||||
const collectorID = "folder"
|
||||
const query = `
|
||||
SELECT org_id, uid, folder_uid, is_folder FROM dashboard WHERE is_folder = 0 AND folder_uid IS NOT NULL
|
||||
`
|
||||
type dashboard struct {
|
||||
OrgID int64 `xorm:"org_id"`
|
||||
UID string `xorm:"uid"`
|
||||
ParentUID string `xorm:"folder_uid"`
|
||||
}
|
||||
|
||||
var dashboards []dashboard
|
||||
err := store.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
return sess.SQL(query).Find(&dashboards)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, d := range dashboards {
|
||||
tuple := &openfgav1.TupleKey{
|
||||
User: zanzana.NewScopedTupleEntry(zanzana.TypeFolder, d.ParentUID, "", strconv.FormatInt(d.OrgID, 10)),
|
||||
Object: zanzana.NewScopedTupleEntry(zanzana.TypeDashboard, d.UID, "", strconv.FormatInt(d.OrgID, 10)),
|
||||
Relation: zanzana.RelationParent,
|
||||
}
|
||||
|
||||
tuples[collectorID] = append(tuples[collectorID], tuple)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user