mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Zanzana: Evaluate access with Check request (server-side) (#96213)
* Zanzana: Evaluate access with Check request (server-side) * Pass parent folder for checking access * Review suggestions * remove fixme comment
This commit is contained in:
parent
27a0491f30
commit
b1fb581ab1
@ -8,6 +8,8 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"go.opentelemetry.io/otel"
|
||||
|
||||
"github.com/grafana/authlib/claims"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||
@ -116,9 +118,36 @@ func (a *AccessControl) evaluateZanzana(ctx context.Context, user identity.Reque
|
||||
eval = evaluator
|
||||
}
|
||||
|
||||
return eval.EvaluateCustom(func(action, scope string) (bool, error) {
|
||||
// FIXME: Implement using new schema / apis
|
||||
return false, nil
|
||||
return eval.EvaluateCustom(func(action string, scopes ...string) (bool, error) {
|
||||
// FIXME: handle action with no scopes
|
||||
if len(scopes) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
resourceScope := scopes[0]
|
||||
kind, _, identifier := accesscontrol.SplitScope(resourceScope)
|
||||
|
||||
// Parent folder always returned by scope resolver as a second value
|
||||
var parentFolder string
|
||||
if len(scopes) > 1 {
|
||||
_, _, parentFolder = accesscontrol.SplitScope(scopes[1])
|
||||
}
|
||||
|
||||
namespace := claims.OrgNamespaceFormatter(user.GetOrgID())
|
||||
req, ok := zanzana.TranslateToCheckRequest(namespace, action, kind, parentFolder, identifier)
|
||||
if !ok {
|
||||
// unsupported translation
|
||||
return false, errAccessNotImplemented
|
||||
}
|
||||
|
||||
a.log.Debug("evaluating zanzana", "user", user.GetUID(), "namespace", req.Namespace, "verb", req.Verb, "resource", req.Resource, "name", req.Name)
|
||||
res, err := a.zclient.Check(ctx, user, *req)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return res.Allowed, nil
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
|
||||
var logger = log.New("accesscontrol.evaluator")
|
||||
|
||||
type CheckerFn func(action string, scope string) (bool, error)
|
||||
type CheckerFn func(action string, scopes ...string) (bool, error)
|
||||
|
||||
type Evaluator interface {
|
||||
// Evaluate permissions that are grouped by action
|
||||
@ -89,18 +89,12 @@ func (p permissionEvaluator) EvaluateCustom(fn CheckerFn) (bool, error) {
|
||||
return fn(p.Action, "")
|
||||
}
|
||||
|
||||
for _, target := range p.Scopes {
|
||||
matches, err := fn(p.Action, target)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if matches {
|
||||
return true, nil
|
||||
}
|
||||
matches, err := fn(p.Action, p.Scopes...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return false, nil
|
||||
return matches, nil
|
||||
}
|
||||
|
||||
func (p permissionEvaluator) MutateScopes(ctx context.Context, mutate ScopeAttributeMutator) (Evaluator, error) {
|
||||
|
@ -23,12 +23,19 @@ func GetTypeInfo(group, resource string) (TypeInfo, bool) {
|
||||
}
|
||||
|
||||
var VerbMapping = map[string]string{
|
||||
utils.VerbGet: "read",
|
||||
utils.VerbList: "read",
|
||||
utils.VerbWatch: "read",
|
||||
utils.VerbCreate: "create",
|
||||
utils.VerbUpdate: "write",
|
||||
utils.VerbPatch: "write",
|
||||
utils.VerbDelete: "delete",
|
||||
utils.VerbDeleteCollection: "delete",
|
||||
utils.VerbGet: RelationRead,
|
||||
utils.VerbList: RelationRead,
|
||||
utils.VerbWatch: RelationRead,
|
||||
utils.VerbCreate: RelationCreate,
|
||||
utils.VerbUpdate: RelationWrite,
|
||||
utils.VerbPatch: RelationWrite,
|
||||
utils.VerbDelete: RelationDelete,
|
||||
utils.VerbDeleteCollection: RelationDelete,
|
||||
}
|
||||
|
||||
var RelationToVerbMapping = map[string]string{
|
||||
RelationRead: utils.VerbGet,
|
||||
RelationCreate: utils.VerbCreate,
|
||||
RelationWrite: utils.VerbUpdate,
|
||||
RelationDelete: utils.VerbDelete,
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
|
||||
openfgav1 "github.com/openfga/api/proto/openfga/v1"
|
||||
|
||||
"github.com/grafana/authlib/authz"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana/common"
|
||||
)
|
||||
|
||||
@ -143,3 +145,32 @@ func MergeFolderResourceTuples(a, b *openfgav1.TupleKey) {
|
||||
vb := b.Condition.Context.Fields["group_resources"]
|
||||
va.GetListValue().Values = append(va.GetListValue().Values, vb.GetListValue().Values...)
|
||||
}
|
||||
|
||||
func TranslateToCheckRequest(namespace, action, kind, folder, name string) (*authz.CheckRequest, bool) {
|
||||
translation, ok := resourceTranslations[kind]
|
||||
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
m, ok := translation.mapping[action]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
verb, ok := common.RelationToVerbMapping[m.relation]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
req := &authz.CheckRequest{
|
||||
Namespace: namespace,
|
||||
Verb: verb,
|
||||
Group: translation.group,
|
||||
Resource: translation.resource,
|
||||
Name: name,
|
||||
Folder: folder,
|
||||
}
|
||||
|
||||
return req, true
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user