Pyroscope: Add authentication when calling backendType resource API (#67667)

pull/68319/head
Andrej Ocenas 2 years ago committed by GitHub
parent c9ce1a28c3
commit 8da90f624d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      pkg/plugins/manager/manager_integration_test.go
  2. 39
      pkg/tsdb/phlare/instance.go
  3. 9
      pkg/tsdb/phlare/service.go

@ -10,6 +10,7 @@ import (
"github.com/grafana/grafana-azure-sdk-go/azsettings" "github.com/grafana/grafana-azure-sdk-go/azsettings"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
@ -107,7 +108,7 @@ func TestIntegrationPluginManager(t *testing.T) {
ms := mssql.ProvideService(cfg) ms := mssql.ProvideService(cfg)
sv2 := searchV2.ProvideService(cfg, db.InitTestDB(t), nil, nil, tracer, features, nil, nil, nil) sv2 := searchV2.ProvideService(cfg, db.InitTestDB(t), nil, nil, tracer, features, nil, nil, nil)
graf := grafanads.ProvideService(sv2, nil) graf := grafanads.ProvideService(sv2, nil)
phlare := phlare.ProvideService(hcp) phlare := phlare.ProvideService(hcp, acimpl.ProvideAccessControl(cfg))
parca := parca.ProvideService(hcp) parca := parca.ProvideService(hcp)
coreRegistry := coreplugin.ProvideCoreRegistry(am, cw, cm, es, grap, idb, lk, otsdb, pr, tmpo, td, pg, my, ms, graf, phlare, parca) coreRegistry := coreplugin.ProvideCoreRegistry(am, cw, cm, es, grap, idb, lk, otsdb, pr, tmpo, td, pg, my, ms, graf, phlare, parca)

@ -13,6 +13,9 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/infra/httpclient" "github.com/grafana/grafana/pkg/infra/httpclient"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/contexthandler"
"github.com/grafana/grafana/pkg/services/datasources"
) )
var ( var (
@ -27,6 +30,7 @@ type PhlareDatasource struct {
httpClient *http.Client httpClient *http.Client
client ProfilingClient client ProfilingClient
settings backend.DataSourceInstanceSettings settings backend.DataSourceInstanceSettings
ac accesscontrol.AccessControl
} }
type JsonData struct { type JsonData struct {
@ -34,7 +38,7 @@ type JsonData struct {
} }
// NewPhlareDatasource creates a new datasource instance. // NewPhlareDatasource creates a new datasource instance.
func NewPhlareDatasource(httpClientProvider httpclient.Provider, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { func NewPhlareDatasource(httpClientProvider httpclient.Provider, settings backend.DataSourceInstanceSettings, ac accesscontrol.AccessControl) (instancemgmt.Instance, error) {
opt, err := settings.HTTPClientOptions() opt, err := settings.HTTPClientOptions()
if err != nil { if err != nil {
return nil, err return nil, err
@ -54,6 +58,7 @@ func NewPhlareDatasource(httpClientProvider httpclient.Provider, settings backen
httpClient: httpClient, httpClient: httpClient,
client: getClient(jsonData.BackendType, httpClient, settings.URL), client: getClient(jsonData.BackendType, httpClient, settings.URL),
settings: settings, settings: settings,
ac: ac,
}, nil }, nil
} }
@ -165,6 +170,17 @@ type BackendTypeRespBody struct {
// backendType is a simplistic test to figure out if we are speaking to phlare or pyroscope backend // backendType is a simplistic test to figure out if we are speaking to phlare or pyroscope backend
func (d *PhlareDatasource) backendType(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { func (d *PhlareDatasource) backendType(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
// To prevent any user sending arbitrary URL for us to test with we allow this only for users who can edit the datasource
// as config page is where this is meant to be used.
ok, err := d.isUserAllowedToEditDatasource(ctx)
if err != nil {
return err
}
if !ok {
return sender.Send(&backend.CallResourceResponse{Headers: req.Headers, Status: 401})
}
u, err := url.Parse(req.URL) u, err := url.Parse(req.URL)
if err != nil { if err != nil {
return err return err
@ -194,11 +210,26 @@ func (d *PhlareDatasource) backendType(ctx context.Context, req *backend.CallRes
return err return err
} }
err = sender.Send(&backend.CallResourceResponse{Body: data, Headers: req.Headers, Status: 200}) return sender.Send(&backend.CallResourceResponse{Body: data, Headers: req.Headers, Status: 200})
}
func (d *PhlareDatasource) isUserAllowedToEditDatasource(ctx context.Context) (bool, error) {
reqCtx := contexthandler.FromContext(ctx)
uidScope := datasources.ScopeProvider.GetResourceScopeUID(accesscontrol.Parameter(":uid"))
if reqCtx == nil || reqCtx.SignedInUser == nil {
return false, nil
}
ok, err := d.ac.Evaluate(ctx, reqCtx.SignedInUser, accesscontrol.EvalPermission(datasources.ActionWrite, uidScope))
if err != nil { if err != nil {
return err return false, err
} }
return nil if !ok {
return false, nil
}
return true, nil
} }
// QueryData handles multiple queries and returns multiple responses. // QueryData handles multiple queries and returns multiple responses.

@ -8,6 +8,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana/pkg/infra/httpclient" "github.com/grafana/grafana/pkg/infra/httpclient"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/accesscontrol"
) )
// Make sure PhlareDatasource implements required interfaces. This is important to do // Make sure PhlareDatasource implements required interfaces. This is important to do
@ -41,15 +42,15 @@ func (s *Service) getInstance(pluginCtx backend.PluginContext) (*PhlareDatasourc
return in, nil return in, nil
} }
func ProvideService(httpClientProvider httpclient.Provider) *Service { func ProvideService(httpClientProvider httpclient.Provider, ac accesscontrol.AccessControl) *Service {
return &Service{ return &Service{
im: datasource.NewInstanceManager(newInstanceSettings(httpClientProvider)), im: datasource.NewInstanceManager(newInstanceSettings(httpClientProvider, ac)),
} }
} }
func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc { func newInstanceSettings(httpClientProvider httpclient.Provider, ac accesscontrol.AccessControl) datasource.InstanceFactoryFunc {
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return NewPhlareDatasource(httpClientProvider, settings) return NewPhlareDatasource(httpClientProvider, settings, ac)
} }
} }

Loading…
Cancel
Save