package common import ( "google.golang.org/protobuf/types/known/structpb" authzv1 "github.com/grafana/authlib/authz/proto/v1" dashboardV1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1" folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" iamv0alpha1 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/services/accesscontrol" authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" ) type typeInfo struct { Type string Relations []string } var typedResources = map[string]typeInfo{ FormatGroupResource( folders.FolderResourceInfo.GroupResource().Group, folders.FolderResourceInfo.GroupResource().Resource, "", ): {Type: "folder", Relations: RelationsTyped}, FormatGroupResource( iamv0alpha1.TeamResourceInfo.GroupResource().Group, iamv0alpha1.TeamResourceInfo.GroupResource().Resource, "", ): {Type: "team", Relations: RelationsTyped}, FormatGroupResource( iamv0alpha1.UserResourceInfo.GroupResource().Group, iamv0alpha1.UserResourceInfo.GroupResource().Resource, "", ): {Type: "user", Relations: RelationsTyped}, FormatGroupResource( iamv0alpha1.ServiceAccountResourceInfo.GroupResource().Group, iamv0alpha1.ServiceAccountResourceInfo.GroupResource().Resource, "", ): {Type: "service-account", Relations: RelationsTyped}, } func getTypeInfo(group, resource string) (typeInfo, bool) { info, ok := typedResources[FormatGroupResource(group, resource, "")] return info, ok } func NewResourceInfoFromCheck(r *authzv1.CheckRequest) ResourceInfo { typ, relations := getTypeAndRelations(r.GetGroup(), r.GetResource()) resource := newResource( typ, r.GetGroup(), r.GetResource(), r.GetName(), r.GetFolder(), r.GetSubresource(), relations, ) // Special case for creating folders and resources in the root folder if r.GetVerb() == utils.VerbCreate { if resource.IsFolderResource() && resource.name == "" { resource.name = accesscontrol.GeneralFolderUID } else if resource.HasFolderSupport() && resource.folder == "" { resource.folder = accesscontrol.GeneralFolderUID } return resource } return resource } func NewResourceInfoFromBatchItem(i *authzextv1.BatchCheckItem) ResourceInfo { typ, relations := getTypeAndRelations(i.GetGroup(), i.GetResource()) return newResource( typ, i.GetGroup(), i.GetResource(), i.GetName(), i.GetFolder(), i.GetSubresource(), relations, ) } func NewResourceInfoFromList(r *authzv1.ListRequest) ResourceInfo { typ, relations := getTypeAndRelations(r.GetGroup(), r.GetResource()) return newResource( typ, r.GetGroup(), r.GetResource(), "", "", r.GetSubresource(), relations, ) } func getTypeAndRelations(group, resource string) (string, []string) { if info, ok := getTypeInfo(group, resource); ok { return info.Type, info.Relations } return TypeResource, RelationsResource } func newResource( typ, group, resource, name, folder, subresource string, relations []string, ) ResourceInfo { return ResourceInfo{ typ: typ, group: group, resource: resource, name: name, folder: folder, subresource: subresource, relations: relations, } } type ResourceInfo struct { typ string group string resource string name string folder string subresource string relations []string } func (r ResourceInfo) GroupResource() string { return FormatGroupResource(r.group, r.resource, r.subresource) } func (r ResourceInfo) GroupResourceIdent() string { return NewGroupResourceIdent(r.group, r.resource, r.subresource) } func (r ResourceInfo) ResourceIdent() string { if r.name == "" { return "" } if r.IsGeneric() { return NewResourceIdent(r.group, r.resource, r.subresource, r.name) } return NewTypedIdent(r.typ, r.name) } func (r ResourceInfo) FolderIdent() string { if r.folder == "" { return "" } return NewFolderIdent(r.folder) } func (r ResourceInfo) IsGeneric() bool { return r.typ == TypeResource } func (r ResourceInfo) Type() string { return r.typ } func (r ResourceInfo) Context() *structpb.Struct { return &structpb.Struct{ Fields: map[string]*structpb.Value{ "requested_group": structpb.NewStringValue(r.GroupResource()), "subresource": structpb.NewStringValue(r.GroupResource()), }, } } func (r ResourceInfo) IsValidRelation(relation string) bool { return isValidRelation(relation, r.relations) } func (r ResourceInfo) HasSubresource() bool { return r.subresource != "" } var resourcesWithFolderSupport = map[string]bool{ dashboardV1.DashboardResourceInfo.GroupResource().Group: true, } func (r ResourceInfo) HasFolderSupport() bool { return resourcesWithFolderSupport[r.group] } func (r ResourceInfo) IsFolderResource() bool { return r.group == folders.FolderResourceInfo.GroupResource().Group }