fix: use multi client for provisioning API builder (#111144)
This commit is contained in:
@@ -28,6 +28,7 @@ import (
|
||||
|
||||
authlib "github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
|
||||
dashboard "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
|
||||
folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
|
||||
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
||||
@@ -132,8 +133,14 @@ func NewAPIBuilder(
|
||||
extraWorkers []jobs.Worker,
|
||||
jobHistoryConfig *JobHistoryConfig,
|
||||
allowedTargets []provisioning.SyncTargetType,
|
||||
newStandaloneClientFactoryFunc func(loopbackConfigProvider apiserver.RestConfigProvider) resources.ClientFactory, // optional, only used for standalone apiserver
|
||||
) *APIBuilder {
|
||||
clients := resources.NewClientFactory(configProvider)
|
||||
var clients resources.ClientFactory
|
||||
if newStandaloneClientFactoryFunc != nil {
|
||||
clients = newStandaloneClientFactoryFunc(configProvider)
|
||||
} else {
|
||||
clients = resources.NewClientFactory(configProvider)
|
||||
}
|
||||
parsers := resources.NewParserFactory(clients)
|
||||
resourceLister := resources.NewResourceListerForMigrations(unified, legacyMigrator, storageStatus)
|
||||
|
||||
@@ -237,6 +244,7 @@ func RegisterAPIService(
|
||||
extraWorkers,
|
||||
createJobHistoryConfigFromSettings(cfg),
|
||||
allowedTargets,
|
||||
nil,
|
||||
)
|
||||
apiregistration.RegisterAPI(builder)
|
||||
return builder, nil
|
||||
|
||||
@@ -18,7 +18,14 @@ import (
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
)
|
||||
|
||||
// DualReadWriter is a wrapper around a repository that can read and write resources
|
||||
// DualReadWriter is a wrapper around a repository that can read from and write resources
|
||||
// into both the Git repository as well as in Grafana. It isn't a dual writer in the sense of what unistore handling calls dual writing.
|
||||
|
||||
// Standard provisioning Authorizer has already run by the time DualReadWriter is called
|
||||
// for incoming requests from actors, external or internal. However, since it is the files
|
||||
// connector that redirects here, the external resources such as dashboards
|
||||
// end up requiring additional authorization checks which the DualReadWriter performs here.
|
||||
|
||||
// TODO: it does not support folders yet
|
||||
type DualReadWriter struct {
|
||||
repo repository.ReaderWriter
|
||||
@@ -496,24 +503,32 @@ func (r *DualReadWriter) authorize(ctx context.Context, parsed *ParsedResource,
|
||||
return apierrors.NewUnauthorized(err.Error())
|
||||
}
|
||||
|
||||
// Use configured permissions for get+delete
|
||||
if parsed.Existing != nil && (verb == utils.VerbGet || verb == utils.VerbDelete) {
|
||||
rsp, err := r.access.Check(ctx, id, authlib.CheckRequest{
|
||||
Group: parsed.GVR.Group,
|
||||
Resource: parsed.GVR.Resource,
|
||||
Namespace: parsed.Existing.GetNamespace(),
|
||||
Name: parsed.Existing.GetName(),
|
||||
Folder: parsed.Meta.GetFolder(),
|
||||
Verb: utils.VerbGet,
|
||||
})
|
||||
if err != nil || !rsp.Allowed {
|
||||
return apierrors.NewForbidden(parsed.GVR.GroupResource(), parsed.Obj.GetName(),
|
||||
fmt.Errorf("no access to read the embedded file"))
|
||||
}
|
||||
var name string
|
||||
if parsed.Existing != nil {
|
||||
name = parsed.Existing.GetName()
|
||||
} else {
|
||||
name = parsed.Obj.GetName()
|
||||
}
|
||||
|
||||
// Simple role based access for now
|
||||
if id.GetOrgRole().Includes(identity.RoleEditor) {
|
||||
rsp, err := r.access.Check(ctx, id, authlib.CheckRequest{
|
||||
Group: parsed.GVR.Group,
|
||||
Resource: parsed.GVR.Resource,
|
||||
Namespace: id.GetNamespace(),
|
||||
Name: name,
|
||||
Folder: parsed.Meta.GetFolder(),
|
||||
Verb: verb,
|
||||
})
|
||||
if err != nil || !rsp.Allowed {
|
||||
return apierrors.NewForbidden(parsed.GVR.GroupResource(), parsed.Obj.GetName(),
|
||||
fmt.Errorf("no access to read the embedded file"))
|
||||
}
|
||||
|
||||
idType, _, err := authlib.ParseTypeID(id.GetID())
|
||||
if err != nil {
|
||||
return apierrors.NewForbidden(parsed.GVR.GroupResource(), parsed.Obj.GetName(), fmt.Errorf("could not determine identity type to check access"))
|
||||
}
|
||||
// only apply role based access if identity is not of type access policy
|
||||
if idType == authlib.TypeAccessPolicy || id.GetOrgRole().Includes(identity.RoleEditor) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user