mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			107 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			107 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
package folders
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"errors"
 | 
						|
	"slices"
 | 
						|
 | 
						|
	"k8s.io/apiserver/pkg/authorization/authorizer"
 | 
						|
 | 
						|
	"github.com/grafana/authlib/types"
 | 
						|
	"github.com/grafana/grafana/pkg/apimachinery/identity"
 | 
						|
	"github.com/grafana/grafana/pkg/apimachinery/utils"
 | 
						|
	"github.com/grafana/grafana/pkg/services/accesscontrol"
 | 
						|
	"github.com/grafana/grafana/pkg/services/dashboards"
 | 
						|
)
 | 
						|
 | 
						|
// newLegacyAuthorizer creates an authorizer using legacy access control, this is only usable for single tenant api.
 | 
						|
func newLegacyAuthorizer(ac accesscontrol.AccessControl) authorizer.Authorizer {
 | 
						|
	return authorizer.AuthorizerFunc(func(ctx context.Context, attr authorizer.Attributes) (authorizer.Decision, string, error) {
 | 
						|
		in, err := authorizerFunc(ctx, attr)
 | 
						|
		if err != nil {
 | 
						|
			if errors.Is(err, errNoUser) {
 | 
						|
				return authorizer.DecisionDeny, "", nil
 | 
						|
			}
 | 
						|
			return authorizer.DecisionNoOpinion, "", nil
 | 
						|
		}
 | 
						|
 | 
						|
		ok, err := ac.Evaluate(ctx, in.user, in.evaluator)
 | 
						|
		if ok {
 | 
						|
			return authorizer.DecisionAllow, "", nil
 | 
						|
		}
 | 
						|
		return authorizer.DecisionDeny, "folder", err
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func authorizerFunc(ctx context.Context, attr authorizer.Attributes) (*authorizerParams, error) {
 | 
						|
	allowedVerbs := []string{utils.VerbCreate, utils.VerbDelete, utils.VerbList}
 | 
						|
	verb := attr.GetVerb()
 | 
						|
	name := attr.GetName()
 | 
						|
	if (!attr.IsResourceRequest()) || (name == "" && verb != utils.VerbCreate && slices.Contains(allowedVerbs, verb)) {
 | 
						|
		return nil, errNoResource
 | 
						|
	}
 | 
						|
 | 
						|
	// require a user
 | 
						|
	user, err := identity.GetRequester(ctx)
 | 
						|
	if err != nil {
 | 
						|
		return nil, errNoUser
 | 
						|
	}
 | 
						|
 | 
						|
	scope := dashboards.ScopeFoldersProvider.GetResourceScopeUID(name)
 | 
						|
	var eval accesscontrol.Evaluator
 | 
						|
 | 
						|
	// "get" is used for sub-resources with GET http (parents, access, count)
 | 
						|
	switch verb {
 | 
						|
	case utils.VerbCreate:
 | 
						|
		eval = accesscontrol.EvalPermission(dashboards.ActionFoldersCreate)
 | 
						|
	case utils.VerbPatch:
 | 
						|
		fallthrough
 | 
						|
	case utils.VerbUpdate:
 | 
						|
		eval = accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, scope)
 | 
						|
	case utils.VerbDeleteCollection:
 | 
						|
		fallthrough
 | 
						|
	case utils.VerbDelete:
 | 
						|
		eval = accesscontrol.EvalPermission(dashboards.ActionFoldersDelete, scope)
 | 
						|
	case utils.VerbList:
 | 
						|
		eval = accesscontrol.EvalPermission(dashboards.ActionFoldersRead)
 | 
						|
	default:
 | 
						|
		eval = accesscontrol.EvalPermission(dashboards.ActionFoldersRead, scope)
 | 
						|
	}
 | 
						|
	return &authorizerParams{evaluator: eval, user: user}, nil
 | 
						|
}
 | 
						|
 | 
						|
// newMultiTenantAuthorizer creates an authorizer sutiable to multi-tenant setup.
 | 
						|
// For now it only allow authorization of access tokens.
 | 
						|
func newMultiTenantAuthorizer(ac types.AccessClient) authorizer.Authorizer {
 | 
						|
	return authorizer.AuthorizerFunc(func(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) {
 | 
						|
		info, ok := types.AuthInfoFrom(ctx)
 | 
						|
		if !ok {
 | 
						|
			return authorizer.DecisionDeny, "missing auth info", nil
 | 
						|
		}
 | 
						|
 | 
						|
		// For now we only allow access policy to authorize with multi-tenant setup
 | 
						|
		if !types.IsIdentityType(info.GetIdentityType(), types.TypeAccessPolicy) {
 | 
						|
			return authorizer.DecisionDeny, "permission denied", nil
 | 
						|
		}
 | 
						|
 | 
						|
		res, err := ac.Check(ctx, info, types.CheckRequest{
 | 
						|
			Verb:        a.GetVerb(),
 | 
						|
			Group:       a.GetAPIGroup(),
 | 
						|
			Resource:    a.GetResource(),
 | 
						|
			Name:        a.GetName(),
 | 
						|
			Namespace:   a.GetNamespace(),
 | 
						|
			Subresource: a.GetSubresource(),
 | 
						|
		})
 | 
						|
 | 
						|
		if err != nil {
 | 
						|
			return authorizer.DecisionDeny, "faild to perform authorization", err
 | 
						|
		}
 | 
						|
 | 
						|
		if !res.Allowed {
 | 
						|
			return authorizer.DecisionDeny, "permission denied", nil
 | 
						|
		}
 | 
						|
 | 
						|
		return authorizer.DecisionAllow, "", nil
 | 
						|
	})
 | 
						|
}
 |