2025-04-01 10:38:02 +09:00

361 lines
10 KiB
Go

package common
import (
"strings"
openfgav1 "github.com/openfga/api/proto/openfga/v1"
"google.golang.org/protobuf/types/known/structpb"
"github.com/grafana/grafana/pkg/apimachinery/utils"
dashboardalpha1 "github.com/grafana/grafana/pkg/apis/dashboard/v0alpha1"
authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1"
)
const (
TypeUser string = "user"
TypeServiceAccount string = "service-account"
TypeRenderService string = "render"
TypeAnonymous string = "anonymous"
TypeTeam string = "team"
TypeRole string = "role"
)
const (
TypeFolder string = "folder"
TypeResource string = "resource"
TypeGroupResouce string = "group_resource"
)
const (
TypeFolderPrefix string = TypeFolder + ":"
TypeResourcePrefix string = TypeResource + ":"
TypeGroupResoucePrefix string = TypeGroupResouce + ":"
)
const (
RelationTeamMember string = "member"
RelationTeamAdmin string = "admin"
RelationParent string = "parent"
RelationAssignee string = "assignee"
RelationSetView string = "view"
RelationSetEdit string = "edit"
RelationSetAdmin string = "admin"
RelationGet string = "get"
RelationUpdate string = "update"
RelationCreate string = "create"
RelationDelete string = "delete"
RelationGetPermissions string = "get_permissions"
RelationSetPermissions string = "set_permissions"
RelationFolderResourceSetView string = "resource_" + RelationSetView
RelationFolderResourceSetEdit string = "resource_" + RelationSetEdit
RelationFolderResourceSetAdmin string = "resource_" + RelationSetAdmin
RelationFolderResourceGet string = "resource_" + RelationGet
RelationFolderResourceUpdate string = "resource_" + RelationUpdate
RelationFolderResourceCreate string = "resource_" + RelationCreate
RelationFolderResourceDelete string = "resource_" + RelationDelete
RelationFolderResourceGetPermissions string = "resource_" + RelationGetPermissions
RelationFolderResourceSetPermissions string = "resource_" + RelationSetPermissions
)
// RelationsGroupResource are relations that can be added on type "group_resource".
var RelationsGroupResource = []string{
RelationGet,
RelationUpdate,
RelationCreate,
RelationDelete,
RelationGetPermissions,
RelationSetPermissions,
}
// RelationsResource are relations that can be added on type "resource".
var RelationsResource = []string{
RelationGet,
RelationUpdate,
RelationDelete,
RelationGetPermissions,
RelationSetPermissions,
}
// RelationsFolderResource are relations that can be added on type "folder" for child resources.
var RelationsFolderResource = []string{
RelationFolderResourceGet,
RelationFolderResourceUpdate,
RelationFolderResourceCreate,
RelationFolderResourceDelete,
RelationFolderResourceGetPermissions,
RelationFolderResourceSetPermissions,
}
// RelationsFolder are relations that can be added on type "folder".
var RelationsFolder = append(
RelationsFolderResource,
RelationGet,
RelationUpdate,
RelationCreate,
RelationDelete,
RelationGetPermissions,
RelationSetPermissions,
)
// VerbMapping is mapping a k8s verb to a zanzana relation.
var VerbMapping = map[string]string{
utils.VerbGet: RelationGet,
utils.VerbList: RelationGet,
utils.VerbWatch: RelationGet,
utils.VerbCreate: RelationCreate,
utils.VerbUpdate: RelationUpdate,
utils.VerbPatch: RelationUpdate,
utils.VerbDelete: RelationDelete,
utils.VerbDeleteCollection: RelationDelete,
utils.VerbGetPermissions: RelationGetPermissions,
utils.VerbSetPermissions: RelationSetPermissions,
}
// RelationToVerbMapping is mapping a zanzana relation to k8s verb.
var RelationToVerbMapping = map[string]string{
RelationGet: utils.VerbGet,
RelationCreate: utils.VerbCreate,
RelationUpdate: utils.VerbUpdate,
RelationDelete: utils.VerbDelete,
RelationGetPermissions: utils.VerbGetPermissions,
RelationSetPermissions: utils.VerbSetPermissions,
}
func IsGroupResourceRelation(relation string) bool {
return isValidRelation(relation, RelationsGroupResource)
}
func IsFolderResourceRelation(relation string) bool {
return isValidRelation(relation, RelationsFolderResource)
}
func isValidRelation(relation string, valid []string) bool {
for _, r := range valid {
if r == relation {
return true
}
}
return false
}
func FolderResourceRelation(relation string) string {
return TypeResource + "_" + relation
}
func NewTypedIdent(typ string, name string) string {
return typ + ":" + name
}
func NewResourceIdent(group, resource, subresource, name string) string {
return TypeResourcePrefix + FormatGroupResource(group, resource, subresource) + "/" + name
}
func NewFolderIdent(name string) string {
return TypeFolderPrefix + name
}
func NewGroupResourceIdent(group, resource, subresource string) string {
return TypeGroupResoucePrefix + FormatGroupResource(group, resource, subresource)
}
func FormatGroupResource(group, resource, subresource string) string {
b := strings.Builder{}
b.WriteString(group)
b.WriteRune('/')
b.WriteString(resource)
if subresource != "" {
b.WriteRune('/')
b.WriteString(subresource)
}
return b.String()
}
func NewResourceTuple(subject, relation, group, resource, subresource, name string) *openfgav1.TupleKey {
return &openfgav1.TupleKey{
User: subject,
Relation: relation,
Object: NewResourceIdent(group, resource, subresource, name),
Condition: &openfgav1.RelationshipCondition{
Name: "group_filter",
Context: &structpb.Struct{
Fields: map[string]*structpb.Value{
"group_resource": structpb.NewStringValue(FormatGroupResource(group, resource, subresource)),
},
},
},
}
}
func isFolderResourceRelationSet(relation string) bool {
return relation == RelationFolderResourceSetView ||
relation == RelationFolderResourceSetEdit ||
relation == RelationFolderResourceSetAdmin
}
func NewFolderResourceTuple(subject, relation, group, resource, subresource, folder string) *openfgav1.TupleKey {
relation = FolderResourceRelation(relation)
var condition *openfgav1.RelationshipCondition
if !isFolderResourceRelationSet(relation) {
condition = &openfgav1.RelationshipCondition{
Name: "folder_group_filter",
Context: &structpb.Struct{
Fields: map[string]*structpb.Value{
"group_resources": structpb.NewListValue(&structpb.ListValue{
Values: []*structpb.Value{structpb.NewStringValue(FormatGroupResource(group, resource, subresource))},
}),
},
},
}
}
return &openfgav1.TupleKey{
User: subject,
Relation: relation,
Object: NewFolderIdent(folder),
Condition: condition,
}
}
func NewGroupResourceTuple(subject, relation, group, resource, subresource string) *openfgav1.TupleKey {
return &openfgav1.TupleKey{
User: subject,
Relation: relation,
Object: NewGroupResourceIdent(group, resource, subresource),
}
}
func NewFolderParentTuple(folder, parent string) *openfgav1.TupleKey {
return &openfgav1.TupleKey{
Object: NewFolderIdent(folder),
Relation: RelationParent,
User: NewFolderIdent(parent),
}
}
func NewFolderTuple(subject, relation, name string) *openfgav1.TupleKey {
return NewTypedTuple(TypeFolder, subject, relation, name)
}
func NewTypedTuple(typ, subject, relation, name string) *openfgav1.TupleKey {
return &openfgav1.TupleKey{
User: subject,
Relation: relation,
Object: NewTypedIdent(typ, name),
}
}
func ToAuthzExtTupleKey(t *openfgav1.TupleKey) *authzextv1.TupleKey {
tupleKey := &authzextv1.TupleKey{
User: t.GetUser(),
Relation: t.GetRelation(),
Object: t.GetObject(),
}
if t.GetCondition() != nil {
tupleKey.Condition = &authzextv1.RelationshipCondition{
Name: t.GetCondition().GetName(),
Context: t.GetCondition().GetContext(),
}
}
return tupleKey
}
func ToAuthzExtTupleKeys(tuples []*openfgav1.TupleKey) []*authzextv1.TupleKey {
result := make([]*authzextv1.TupleKey, 0, len(tuples))
for _, t := range tuples {
result = append(result, ToAuthzExtTupleKey(t))
}
return result
}
func ToAuthzExtTupleKeyWithoutCondition(t *openfgav1.TupleKeyWithoutCondition) *authzextv1.TupleKeyWithoutCondition {
return &authzextv1.TupleKeyWithoutCondition{
User: t.GetUser(),
Relation: t.GetRelation(),
Object: t.GetObject(),
}
}
func ToAuthzExtTupleKeysWithoutCondition(tuples []*openfgav1.TupleKeyWithoutCondition) []*authzextv1.TupleKeyWithoutCondition {
result := make([]*authzextv1.TupleKeyWithoutCondition, 0, len(tuples))
for _, t := range tuples {
result = append(result, ToAuthzExtTupleKeyWithoutCondition(t))
}
return result
}
func ToOpenFGATupleKey(t *authzextv1.TupleKey) *openfgav1.TupleKey {
tupleKey := &openfgav1.TupleKey{
User: t.GetUser(),
Relation: t.GetRelation(),
Object: t.GetObject(),
}
if t.GetCondition() != nil {
tupleKey.Condition = &openfgav1.RelationshipCondition{
Name: t.GetCondition().GetName(),
Context: t.GetCondition().GetContext(),
}
}
return tupleKey
}
func ToOpenFGATupleKeys(tuples []*authzextv1.TupleKey) []*openfgav1.TupleKey {
result := make([]*openfgav1.TupleKey, 0, len(tuples))
for _, t := range tuples {
result = append(result, ToOpenFGATupleKey(t))
}
return result
}
func ToOpenFGATupleKeyWithoutCondition(t *authzextv1.TupleKeyWithoutCondition) *openfgav1.TupleKeyWithoutCondition {
return &openfgav1.TupleKeyWithoutCondition{
User: t.GetUser(),
Relation: t.GetRelation(),
Object: t.GetObject(),
}
}
func ToOpenFGATuple(t *authzextv1.Tuple) *openfgav1.Tuple {
return &openfgav1.Tuple{
Key: ToOpenFGATupleKey(t.GetKey()),
Timestamp: t.GetTimestamp(),
}
}
func ToOpenFGATuples(tuples []*authzextv1.Tuple) []*openfgav1.Tuple {
result := make([]*openfgav1.Tuple, 0, len(tuples))
for _, t := range tuples {
result = append(result, ToOpenFGATuple(t))
}
return result
}
func AddRenderContext(req *openfgav1.CheckRequest) {
if req.ContextualTuples == nil {
req.ContextualTuples = &openfgav1.ContextualTupleKeys{}
}
if req.ContextualTuples.TupleKeys == nil {
req.ContextualTuples.TupleKeys = make([]*openfgav1.TupleKey, 0)
}
req.ContextualTuples.TupleKeys = append(req.ContextualTuples.TupleKeys, &openfgav1.TupleKey{
User: req.TupleKey.User,
Relation: RelationSetView,
Object: NewGroupResourceIdent(
dashboardalpha1.DashboardResourceInfo.GroupResource().Group,
dashboardalpha1.DashboardResourceInfo.GroupResource().Resource,
"",
),
})
}