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

83 lines
2.4 KiB
Go

package receiver
import (
"context"
"errors"
"fmt"
"k8s.io/apiserver/pkg/authorization/authorizer"
"github.com/grafana/grafana/pkg/apimachinery/errutil"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/services/ngalert/accesscontrol"
)
// AccessControlService provides access control for receivers.
type AccessControlService interface {
AuthorizeReadSome(ctx context.Context, user identity.Requester) error
AuthorizeReadByUID(context.Context, identity.Requester, string) error
AuthorizeCreate(context.Context, identity.Requester) error
AuthorizeUpdateByUID(context.Context, identity.Requester, string) error
AuthorizeDeleteByUID(context.Context, identity.Requester, string) error
}
func Authorize(ctx context.Context, ac AccessControlService, attr authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
if attr.GetResource() != ResourceInfo.GroupResource().Resource {
return authorizer.DecisionNoOpinion, "", nil
}
user, err := identity.GetRequester(ctx)
if err != nil {
return authorizer.DecisionDeny, "valid user is required", err
}
uid := attr.GetName()
deny := func(err error) (authorizer.Decision, string, error) {
var utilErr errutil.Error
if errors.As(err, &utilErr) && utilErr.Reason.Status() == errutil.StatusForbidden {
if errors.Is(err, accesscontrol.ErrAuthorizationBase) {
return authorizer.DecisionDeny, fmt.Sprintf("required permissions: %s", utilErr.PublicPayload["permissions"]), nil
}
return authorizer.DecisionDeny, utilErr.PublicMessage, nil
}
return authorizer.DecisionDeny, "", err
}
switch attr.GetVerb() {
case "get":
if uid == "" {
return authorizer.DecisionDeny, "", nil
}
if err := ac.AuthorizeReadByUID(ctx, user, uid); err != nil {
return deny(err)
}
case "list":
return authorizer.DecisionAllow, "", nil // Always allow listing, receivers are filtered downstream.
case "create":
if err := ac.AuthorizeCreate(ctx, user); err != nil {
return deny(err)
}
case "patch":
fallthrough
case "update":
if uid == "" {
return deny(err)
}
if err := ac.AuthorizeUpdateByUID(ctx, user, uid); err != nil {
return deny(err)
}
case "delete":
if uid == "" {
return deny(err)
}
if err := ac.AuthorizeDeleteByUID(ctx, user, uid); err != nil {
return deny(err)
}
default:
return authorizer.DecisionNoOpinion, "", nil
}
return authorizer.DecisionAllow, "", nil
}