Zanzana: reconcile basic roles and bindings (#96473)

* Add reconciler for basic roles

* Add reconciler for basic role bindings
This commit is contained in:
Karl Persson
2024-11-15 12:10:22 +01:00
committed by GitHub
parent 0f4517df98
commit 1f34096fdf
4 changed files with 135 additions and 19 deletions
@@ -17,7 +17,7 @@ func teamMembershipCollector(store db.DB) legacyTupleCollector {
FROM team_member tm
INNER JOIN team t ON tm.team_id = t.id
INNER JOIN ` + store.GetDialect().Quote("user") + ` u ON tm.user_id = u.id
WHERE org_id = ?
WHERE t.org_id = ?
`
type membership struct {
@@ -109,7 +109,7 @@ func folderTreeCollector(store db.DB) legacyTupleCollector {
}
}
// managedPermissionsCollector collects managed permissions into provided tuple map.
// managedPermissionsCollector collects managed permissions.
// It will only store actions that are supported by our schema. Managed permissions can
// be directly mapped to user/team/role without having to write an intermediate role.
func managedPermissionsCollector(store db.DB, kind string) legacyTupleCollector {
@@ -195,6 +195,99 @@ func tupleStringWithoutCondition(tuple *openfgav1.TupleKey) string {
return s
}
// basicRolePermissionsCollector collects permissions for basic roles
func basicRolePermissionsCollector(store db.DB) legacyTupleCollector {
return func(ctx context.Context, _ int64) (map[string]map[string]*openfgav1.TupleKey, error) {
const query = `
SELECT r.uid as role_uid, p.action, p.kind, p.identifier
FROM permission p
INNER JOIN role r ON p.role_id = r.id
LEFT JOIN builtin_role br ON r.id = br.role_id
WHERE r.name LIKE 'basic:%'
`
type Permission struct {
Action string `xorm:"action"`
Kind string
Identifier string
RoleUID string `xorm:"role_uid"`
}
var permissions []Permission
err := store.WithDbSession(ctx, func(sess *db.Session) error {
return sess.SQL(query).Find(&permissions)
})
if err != nil {
return nil, err
}
tuples := make(map[string]map[string]*openfgav1.TupleKey)
for _, p := range permissions {
subject := zanzana.NewTupleEntry(zanzana.TypeRole, p.RoleUID, "assignee")
tuple, ok := zanzana.TranslateToResourceTuple(subject, p.Action, p.Kind, p.Identifier)
if !ok {
continue
}
if tuples[tuple.Object] == nil {
tuples[tuple.Object] = make(map[string]*openfgav1.TupleKey)
}
tuples[tuple.Object][tuple.String()] = tuple
}
return tuples, nil
}
}
// basicRoleBindingsCollects collects role bindings for basic roles
func basicRoleBindingsCollector(store db.DB) legacyTupleCollector {
return func(ctx context.Context, orgID int64) (map[string]map[string]*openfgav1.TupleKey, error) {
query := `
SELECT ou.org_id, u.uid as user_uid, ou.role as org_role
FROM org_user ou
LEFT JOIN ` + store.GetDialect().Quote("user") + ` u ON u.id = ou.user_id
WHERE ou.org_id = ?
AND NOT u.is_service_account
`
// FIXME: handle service admin role
type Binding struct {
UserUID string `xorm:"user_uid"`
OrgRole string `xorm:"org_role"`
}
var bindings []Binding
err := store.WithDbSession(ctx, func(sess *db.Session) error {
return sess.SQL(query, orgID).Find(&bindings)
})
if err != nil {
return nil, err
}
tuples := make(map[string]map[string]*openfgav1.TupleKey)
for _, b := range bindings {
subject := zanzana.NewTupleEntry(zanzana.TypeUser, b.UserUID, "")
tuple := &openfgav1.TupleKey{
User: subject,
Relation: zanzana.RelationAssignee,
Object: zanzana.NewTupleEntry(zanzana.TypeRole, zanzana.TranslateBasicRole(b.OrgRole), ""),
}
if tuples[tuple.Object] == nil {
tuples[tuple.Object] = make(map[string]*openfgav1.TupleKey)
}
tuples[tuple.Object][tuple.String()] = tuple
}
return tuples, nil
}
}
func zanzanaCollector(relations []string) zanzanaTupleCollector {
return func(ctx context.Context, client zanzana.Client, object string, namespace string) (map[string]*openfgav1.TupleKey, error) {
// list will use continuation token to collect all tuples for object and relation
@@ -64,6 +64,18 @@ func NewZanzanaReconciler(cfg *setting.Cfg, client zanzana.Client, store db.DB,
zanzanaCollector(zanzana.ResourceRelations),
client,
),
newResourceReconciler(
"basic role permissions",
basicRolePermissionsCollector(store),
zanzanaCollector(zanzana.FolderRelations),
client,
),
newResourceReconciler(
"basic role bindings",
basicRoleBindingsCollector(store),
zanzanaCollector([]string{zanzana.RelationAssignee}),
client,
),
},
}
}