361 lines
10 KiB
Go
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,
|
|
"",
|
|
),
|
|
})
|
|
}
|