2022-09-05 18:15:47 +02:00
|
|
|
package acimpl
|
2022-08-24 13:29:17 +02:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2022-08-25 12:50:27 +02:00
|
|
|
"errors"
|
2022-08-24 13:29:17 +02:00
|
|
|
|
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
|
|
|
"github.com/grafana/grafana/pkg/infra/metrics"
|
|
|
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
2023-08-09 09:35:50 +02:00
|
|
|
"github.com/grafana/grafana/pkg/services/auth/identity"
|
2022-08-24 13:29:17 +02:00
|
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var _ accesscontrol.AccessControl = new(AccessControl)
|
|
|
|
|
|
2022-09-09 09:07:45 +02:00
|
|
|
func ProvideAccessControl(cfg *setting.Cfg) *AccessControl {
|
2022-08-24 13:29:17 +02:00
|
|
|
logger := log.New("accesscontrol")
|
|
|
|
|
return &AccessControl{
|
2022-09-09 09:07:45 +02:00
|
|
|
cfg, logger, accesscontrol.NewResolvers(logger),
|
2022-08-24 13:29:17 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type AccessControl struct {
|
|
|
|
|
cfg *setting.Cfg
|
|
|
|
|
log log.Logger
|
|
|
|
|
resolvers accesscontrol.Resolvers
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-09 09:35:50 +02:00
|
|
|
func (a *AccessControl) Evaluate(ctx context.Context, user identity.Requester, evaluator accesscontrol.Evaluator) (bool, error) {
|
2022-08-24 13:29:17 +02:00
|
|
|
timer := prometheus.NewTimer(metrics.MAccessEvaluationsSummary)
|
|
|
|
|
defer timer.ObserveDuration()
|
|
|
|
|
metrics.MAccessEvaluationCount.Inc()
|
|
|
|
|
|
2023-08-09 09:35:50 +02:00
|
|
|
if user == nil || user.IsNil() {
|
2023-09-04 18:49:47 +02:00
|
|
|
a.log.Warn("No entity set for access control evaluation")
|
2022-09-09 09:07:45 +02:00
|
|
|
return false, nil
|
2022-08-24 13:29:17 +02:00
|
|
|
}
|
2023-08-09 09:35:50 +02:00
|
|
|
|
2024-02-01 12:37:01 +01:00
|
|
|
// If the user is in no organization, then the evaluation must happen based on the user's global permissions
|
|
|
|
|
permissions := user.GetPermissions()
|
|
|
|
|
if user.GetOrgID() == accesscontrol.NoOrgID {
|
|
|
|
|
permissions = user.GetGlobalPermissions()
|
|
|
|
|
}
|
|
|
|
|
if len(permissions) == 0 {
|
2024-03-05 08:50:19 +01:00
|
|
|
a.debug(ctx, user, "No permissions set", evaluator)
|
2023-08-09 09:35:50 +02:00
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-05 08:50:19 +01:00
|
|
|
a.debug(ctx, user, "Evaluating permissions", evaluator)
|
2022-08-25 12:50:27 +02:00
|
|
|
// Test evaluation without scope resolver first, this will prevent 403 for wildcard scopes when resource does not exist
|
2024-02-01 12:37:01 +01:00
|
|
|
if evaluator.Evaluate(permissions) {
|
2022-08-25 12:50:27 +02:00
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-09 09:35:50 +02:00
|
|
|
resolvedEvaluator, err := evaluator.MutateScopes(ctx, a.resolvers.GetScopeAttributeMutator(user.GetOrgID()))
|
2022-08-24 13:29:17 +02:00
|
|
|
if err != nil {
|
2022-08-25 12:50:27 +02:00
|
|
|
if errors.Is(err, accesscontrol.ErrResolverNotFound) {
|
|
|
|
|
return false, nil
|
|
|
|
|
}
|
2022-08-24 13:29:17 +02:00
|
|
|
return false, err
|
|
|
|
|
}
|
2022-08-25 12:50:27 +02:00
|
|
|
|
2024-03-05 08:50:19 +01:00
|
|
|
a.debug(ctx, user, "Evaluating resolved permissions", resolvedEvaluator)
|
2024-02-01 12:37:01 +01:00
|
|
|
return resolvedEvaluator.Evaluate(permissions), nil
|
2022-08-24 13:29:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (a *AccessControl) RegisterScopeAttributeResolver(prefix string, resolver accesscontrol.ScopeAttributeResolver) {
|
|
|
|
|
a.resolvers.AddScopeAttributeResolver(prefix, resolver)
|
|
|
|
|
}
|
2024-03-05 08:50:19 +01:00
|
|
|
|
|
|
|
|
func (a *AccessControl) debug(ctx context.Context, ident identity.Requester, msg string, eval accesscontrol.Evaluator) {
|
|
|
|
|
namespace, id := ident.GetNamespacedID()
|
2024-03-07 16:34:22 -05:00
|
|
|
a.log.FromContext(ctx).Debug(msg, "namespace", namespace, "id", id, "orgID", ident.GetOrgID(), "permissions", eval.GoString())
|
2024-03-05 08:50:19 +01:00
|
|
|
}
|