datasources: querier: single-tenant: explicit permission-check (#102189)
This commit is contained in:
@@ -2,7 +2,6 @@ package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
@@ -13,9 +12,11 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
query "github.com/grafana/grafana/pkg/apis/query/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/query/clientapi"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||
@@ -26,6 +27,7 @@ import (
|
||||
type pluginClient struct {
|
||||
pluginClient plugins.Client
|
||||
pCtxProvider *plugincontext.Provider
|
||||
ac accesscontrol.AccessControl
|
||||
}
|
||||
|
||||
type pluginRegistry struct {
|
||||
@@ -43,10 +45,11 @@ var _ clientapi.QueryDataClient = (*pluginClient)(nil)
|
||||
var _ query.DataSourceApiServerRegistry = (*pluginRegistry)(nil)
|
||||
|
||||
// NewQueryClientForPluginClient creates a client that delegates to the internal plugins.Client stack
|
||||
func NewQueryClientForPluginClient(p plugins.Client, ctx *plugincontext.Provider) clientapi.QueryDataClient {
|
||||
func NewQueryClientForPluginClient(p plugins.Client, ctx *plugincontext.Provider, accessControl accesscontrol.AccessControl) clientapi.QueryDataClient {
|
||||
return &pluginClient{
|
||||
pluginClient: p,
|
||||
pCtxProvider: ctx,
|
||||
ac: accessControl,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +62,17 @@ func NewDataSourceRegistryFromStore(pluginStore pluginstore.Store,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *pluginClient) CanQueryDataSource(ctx context.Context, uid string) (bool, error) {
|
||||
user, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
requiredScope := "datasources:uid:" + uid
|
||||
evaluate := accesscontrol.EvalPermission(datasources.ActionQuery, requiredScope)
|
||||
return d.ac.Evaluate(ctx, user, evaluate)
|
||||
}
|
||||
|
||||
// ExecuteQueryData implements QueryHelper.
|
||||
func (d *pluginClient) QueryData(ctx context.Context, req data.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
||||
queries, dsRef, err := data.ToDataSourceQueries(req)
|
||||
@@ -69,17 +83,23 @@ func (d *pluginClient) QueryData(ctx context.Context, req data.QueryDataRequest)
|
||||
return nil, fmt.Errorf("expected single datasource request")
|
||||
}
|
||||
|
||||
canQuery, err := d.CanQueryDataSource(ctx, dsRef.UID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !canQuery {
|
||||
status := metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusForbidden,
|
||||
Message: "Access denied to the data source",
|
||||
}
|
||||
return nil, &apierrors.StatusError{ErrStatus: status}
|
||||
}
|
||||
|
||||
// NOTE: this depends on uid unique across datasources
|
||||
settings, err := d.pCtxProvider.GetDataSourceInstanceSettings(ctx, dsRef.UID)
|
||||
if err != nil {
|
||||
if errors.Is(err, datasources.ErrDataSourceNotFound) {
|
||||
status := metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusNotFound,
|
||||
Message: "datasource not found",
|
||||
}
|
||||
return nil, &apierrors.StatusError{ErrStatus: status}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ func RegisterAPIService(features featuremgmt.FeatureToggles,
|
||||
builder, err := NewQueryAPIBuilder(
|
||||
features,
|
||||
&CommonDataSourceClientSupplier{
|
||||
Client: client.NewQueryClientForPluginClient(pluginClient, pCtxProvider),
|
||||
Client: client.NewQueryClientForPluginClient(pluginClient, pCtxProvider, accessControl),
|
||||
},
|
||||
ar,
|
||||
client.NewDataSourceRegistryFromStore(pluginStore, dataSourcesService),
|
||||
|
||||
Reference in New Issue
Block a user