Plugins: Expose ExternalService in request config (#85187)

This commit is contained in:
Andres Martinez Gotor 2024-04-03 09:22:34 +02:00 committed by GitHub
parent 1522499c4a
commit 9c7237891c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 50 additions and 25 deletions

View File

@ -1,6 +1,10 @@
package pluginconfig package pluginconfig
import "context" import (
"context"
"github.com/grafana/grafana/pkg/plugins/auth"
)
var _ PluginRequestConfigProvider = (*FakePluginRequestConfigProvider)(nil) var _ PluginRequestConfigProvider = (*FakePluginRequestConfigProvider)(nil)
@ -11,6 +15,6 @@ func NewFakePluginRequestConfigProvider() *FakePluginRequestConfigProvider {
} }
// PluginRequestConfig returns a map of configuration that should be passed in a plugin request. // PluginRequestConfig returns a map of configuration that should be passed in a plugin request.
func (s *FakePluginRequestConfigProvider) PluginRequestConfig(ctx context.Context, pluginID string) map[string]string { func (s *FakePluginRequestConfigProvider) PluginRequestConfig(ctx context.Context, pluginID string, externalService *auth.ExternalService) map[string]string {
return map[string]string{} return map[string]string{}
} }

View File

@ -9,6 +9,7 @@ import (
"github.com/grafana/grafana-aws-sdk/pkg/awsds" "github.com/grafana/grafana-aws-sdk/pkg/awsds"
"github.com/grafana/grafana-azure-sdk-go/v2/azsettings" "github.com/grafana/grafana-azure-sdk-go/v2/azsettings"
"github.com/grafana/grafana/pkg/plugins/auth"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/proxy" "github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
@ -18,7 +19,7 @@ import (
var _ PluginRequestConfigProvider = (*RequestConfigProvider)(nil) var _ PluginRequestConfigProvider = (*RequestConfigProvider)(nil)
type PluginRequestConfigProvider interface { type PluginRequestConfigProvider interface {
PluginRequestConfig(ctx context.Context, pluginID string) map[string]string PluginRequestConfig(ctx context.Context, pluginID string, externalService *auth.ExternalService) map[string]string
} }
type RequestConfigProvider struct { type RequestConfigProvider struct {
@ -33,7 +34,7 @@ func NewRequestConfigProvider(cfg *PluginInstanceCfg) *RequestConfigProvider {
// PluginRequestConfig returns a map of configuration that should be passed in a plugin request. // PluginRequestConfig returns a map of configuration that should be passed in a plugin request.
// nolint:gocyclo // nolint:gocyclo
func (s *RequestConfigProvider) PluginRequestConfig(ctx context.Context, pluginID string) map[string]string { func (s *RequestConfigProvider) PluginRequestConfig(ctx context.Context, pluginID string, externalService *auth.ExternalService) map[string]string {
m := make(map[string]string) m := make(map[string]string)
if s.cfg.GrafanaAppURL != "" { if s.cfg.GrafanaAppURL != "" {
@ -160,5 +161,9 @@ func (s *RequestConfigProvider) PluginRequestConfig(ctx context.Context, pluginI
m[awsds.SigV4VerboseLoggingEnvVarKeyName] = strconv.FormatBool(s.cfg.SigV4VerboseLogging) m[awsds.SigV4VerboseLoggingEnvVarKeyName] = strconv.FormatBool(s.cfg.SigV4VerboseLogging)
} }
if externalService != nil {
m[backend.AppClientSecret] = externalService.ClientSecret
}
return m return m
} }

View File

@ -7,7 +7,9 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana-azure-sdk-go/v2/azsettings" "github.com/grafana/grafana-azure-sdk-go/v2/azsettings"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/plugins/auth"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@ -22,7 +24,7 @@ func TestRequestConfigProvider_PluginRequestConfig_Defaults(t *testing.T) {
"GF_SQL_MAX_OPEN_CONNS_DEFAULT": "0", "GF_SQL_MAX_OPEN_CONNS_DEFAULT": "0",
"GF_SQL_MAX_IDLE_CONNS_DEFAULT": "0", "GF_SQL_MAX_IDLE_CONNS_DEFAULT": "0",
"GF_SQL_MAX_CONN_LIFETIME_SECONDS_DEFAULT": "0", "GF_SQL_MAX_CONN_LIFETIME_SECONDS_DEFAULT": "0",
}, p.PluginRequestConfig(context.Background(), "")) }, p.PluginRequestConfig(context.Background(), "", nil))
} }
func TestRequestConfigProvider_PluginRequestConfig(t *testing.T) { func TestRequestConfigProvider_PluginRequestConfig(t *testing.T) {
@ -132,7 +134,7 @@ func TestRequestConfigProvider_PluginRequestConfig(t *testing.T) {
for _, tc := range tcs { for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
p := NewRequestConfigProvider(tc.cfg) p := NewRequestConfigProvider(tc.cfg)
require.Subset(t, p.PluginRequestConfig(context.Background(), ""), tc.expected) require.Subset(t, p.PluginRequestConfig(context.Background(), "", nil), tc.expected)
}) })
} }
} }
@ -167,7 +169,7 @@ func TestRequestConfigProvider_PluginRequestConfig_featureToggles(t *testing.T)
require.NoError(t, err) require.NoError(t, err)
p := NewRequestConfigProvider(pCfg) p := NewRequestConfigProvider(pCfg)
require.Subset(t, p.PluginRequestConfig(context.Background(), ""), tc.expectedConfig) require.Subset(t, p.PluginRequestConfig(context.Background(), "", nil), tc.expectedConfig)
} }
}) })
} }
@ -181,7 +183,7 @@ func TestRequestConfigProvider_PluginRequestConfig_appURL(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
p := NewRequestConfigProvider(pCfg) p := NewRequestConfigProvider(pCfg)
require.Subset(t, p.PluginRequestConfig(context.Background(), ""), map[string]string{"GF_APP_URL": "https://myorg.com/"}) require.Subset(t, p.PluginRequestConfig(context.Background(), "", nil), map[string]string{"GF_APP_URL": "https://myorg.com/"})
}) })
} }
@ -197,7 +199,7 @@ func TestRequestConfigProvider_PluginRequestConfig_SQL(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
p := NewRequestConfigProvider(pCfg) p := NewRequestConfigProvider(pCfg)
require.Subset(t, p.PluginRequestConfig(context.Background(), ""), map[string]string{ require.Subset(t, p.PluginRequestConfig(context.Background(), "", nil), map[string]string{
"GF_SQL_ROW_LIMIT": "23", "GF_SQL_ROW_LIMIT": "23",
"GF_SQL_MAX_OPEN_CONNS_DEFAULT": "24", "GF_SQL_MAX_OPEN_CONNS_DEFAULT": "24",
"GF_SQL_MAX_IDLE_CONNS_DEFAULT": "25", "GF_SQL_MAX_IDLE_CONNS_DEFAULT": "25",
@ -219,7 +221,7 @@ func TestRequestConfigProvider_PluginRequestConfig_SQL(t *testing.T) {
"GF_SQL_MAX_OPEN_CONNS_DEFAULT": "0", "GF_SQL_MAX_OPEN_CONNS_DEFAULT": "0",
"GF_SQL_MAX_IDLE_CONNS_DEFAULT": "0", "GF_SQL_MAX_IDLE_CONNS_DEFAULT": "0",
"GF_SQL_MAX_CONN_LIFETIME_SECONDS_DEFAULT": "0", "GF_SQL_MAX_CONN_LIFETIME_SECONDS_DEFAULT": "0",
}, p.PluginRequestConfig(context.Background(), "")) }, p.PluginRequestConfig(context.Background(), "", nil))
}) })
} }
@ -232,7 +234,7 @@ func TestRequestConfigProvider_PluginRequestConfig_concurrentQueryCount(t *testi
require.NoError(t, err) require.NoError(t, err)
p := NewRequestConfigProvider(pCfg) p := NewRequestConfigProvider(pCfg)
require.Subset(t, p.PluginRequestConfig(context.Background(), ""), map[string]string{"GF_CONCURRENT_QUERY_COUNT": "42"}) require.Subset(t, p.PluginRequestConfig(context.Background(), "", nil), map[string]string{"GF_CONCURRENT_QUERY_COUNT": "42"})
}) })
t.Run("Doesn't set the concurrent query count if it is not in the config", func(t *testing.T) { t.Run("Doesn't set the concurrent query count if it is not in the config", func(t *testing.T) {
@ -241,7 +243,7 @@ func TestRequestConfigProvider_PluginRequestConfig_concurrentQueryCount(t *testi
require.NoError(t, err) require.NoError(t, err)
p := NewRequestConfigProvider(pCfg) p := NewRequestConfigProvider(pCfg)
require.NotContains(t, p.PluginRequestConfig(context.Background(), ""), "GF_CONCURRENT_QUERY_COUNT") require.NotContains(t, p.PluginRequestConfig(context.Background(), "", nil), "GF_CONCURRENT_QUERY_COUNT")
}) })
t.Run("Doesn't set the concurrent query count if it is zero", func(t *testing.T) { t.Run("Doesn't set the concurrent query count if it is zero", func(t *testing.T) {
@ -252,7 +254,7 @@ func TestRequestConfigProvider_PluginRequestConfig_concurrentQueryCount(t *testi
require.NoError(t, err) require.NoError(t, err)
p := NewRequestConfigProvider(pCfg) p := NewRequestConfigProvider(pCfg)
require.NotContains(t, p.PluginRequestConfig(context.Background(), ""), "GF_CONCURRENT_QUERY_COUNT") require.NotContains(t, p.PluginRequestConfig(context.Background(), "", nil), "GF_CONCURRENT_QUERY_COUNT")
}) })
} }
@ -264,7 +266,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azureAuthEnabled(t *testing.T
} }
p := NewRequestConfigProvider(cfg) p := NewRequestConfigProvider(cfg)
require.Subset(t, p.PluginRequestConfig(context.Background(), ""), map[string]string{"GFAZPL_AZURE_AUTH_ENABLED": "true"}) require.Subset(t, p.PluginRequestConfig(context.Background(), "", nil), map[string]string{"GFAZPL_AZURE_AUTH_ENABLED": "true"})
}) })
t.Run("Doesn't set the azureAuthEnabled if it is not in the config", func(t *testing.T) { t.Run("Doesn't set the azureAuthEnabled if it is not in the config", func(t *testing.T) {
@ -273,7 +275,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azureAuthEnabled(t *testing.T
} }
p := NewRequestConfigProvider(cfg) p := NewRequestConfigProvider(cfg)
require.NotContains(t, p.PluginRequestConfig(context.Background(), ""), "GFAZPL_AZURE_AUTH_ENABLED") require.NotContains(t, p.PluginRequestConfig(context.Background(), "", nil), "GFAZPL_AZURE_AUTH_ENABLED")
}) })
t.Run("Doesn't set the azureAuthEnabled if it is false", func(t *testing.T) { t.Run("Doesn't set the azureAuthEnabled if it is false", func(t *testing.T) {
@ -283,7 +285,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azureAuthEnabled(t *testing.T
} }
p := NewRequestConfigProvider(cfg) p := NewRequestConfigProvider(cfg)
require.NotContains(t, p.PluginRequestConfig(context.Background(), ""), "GFAZPL_AZURE_AUTH_ENABLED") require.NotContains(t, p.PluginRequestConfig(context.Background(), "", nil), "GFAZPL_AZURE_AUTH_ENABLED")
}) })
} }
@ -317,7 +319,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azure(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
p := NewRequestConfigProvider(pCfg) p := NewRequestConfigProvider(pCfg)
require.Subset(t, p.PluginRequestConfig(context.Background(), "grafana-azure-monitor-datasource"), map[string]string{ require.Subset(t, p.PluginRequestConfig(context.Background(), "grafana-azure-monitor-datasource", nil), map[string]string{
"GFAZPL_AZURE_CLOUD": "AzureCloud", "GFAZPL_MANAGED_IDENTITY_ENABLED": "true", "GFAZPL_AZURE_CLOUD": "AzureCloud", "GFAZPL_MANAGED_IDENTITY_ENABLED": "true",
"GFAZPL_MANAGED_IDENTITY_CLIENT_ID": "mock_managed_identity_client_id", "GFAZPL_MANAGED_IDENTITY_CLIENT_ID": "mock_managed_identity_client_id",
"GFAZPL_WORKLOAD_IDENTITY_ENABLED": "true", "GFAZPL_WORKLOAD_IDENTITY_ENABLED": "true",
@ -341,7 +343,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azure(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
p := NewRequestConfigProvider(pCfg) p := NewRequestConfigProvider(pCfg)
m := p.PluginRequestConfig(context.Background(), "") m := p.PluginRequestConfig(context.Background(), "", nil)
require.NotContains(t, m, "GFAZPL_AZURE_CLOUD") require.NotContains(t, m, "GFAZPL_AZURE_CLOUD")
require.NotContains(t, m, "GFAZPL_MANAGED_IDENTITY_ENABLED") require.NotContains(t, m, "GFAZPL_MANAGED_IDENTITY_ENABLED")
require.NotContains(t, m, "GFAZPL_MANAGED_IDENTITY_CLIENT_ID") require.NotContains(t, m, "GFAZPL_MANAGED_IDENTITY_CLIENT_ID")
@ -366,7 +368,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azure(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
p := NewRequestConfigProvider(pCfg) p := NewRequestConfigProvider(pCfg)
require.Subset(t, p.PluginRequestConfig(context.Background(), "test-datasource"), map[string]string{ require.Subset(t, p.PluginRequestConfig(context.Background(), "test-datasource", nil), map[string]string{
"GFAZPL_AZURE_CLOUD": "AzureCloud", "GFAZPL_MANAGED_IDENTITY_ENABLED": "true", "GFAZPL_AZURE_CLOUD": "AzureCloud", "GFAZPL_MANAGED_IDENTITY_ENABLED": "true",
"GFAZPL_MANAGED_IDENTITY_CLIENT_ID": "mock_managed_identity_client_id", "GFAZPL_MANAGED_IDENTITY_CLIENT_ID": "mock_managed_identity_client_id",
"GFAZPL_WORKLOAD_IDENTITY_ENABLED": "true", "GFAZPL_WORKLOAD_IDENTITY_ENABLED": "true",
@ -398,7 +400,7 @@ func TestRequestConfigProvider_PluginRequestConfig_aws(t *testing.T) {
p := NewRequestConfigProvider(cfg) p := NewRequestConfigProvider(cfg)
t.Run("uses the aws settings for an AWS plugin", func(t *testing.T) { t.Run("uses the aws settings for an AWS plugin", func(t *testing.T) {
require.Subset(t, p.PluginRequestConfig(context.Background(), "cloudwatch"), map[string]string{ require.Subset(t, p.PluginRequestConfig(context.Background(), "cloudwatch", nil), map[string]string{
"AWS_AUTH_AssumeRoleEnabled": "false", "AWS_AUTH_AssumeRoleEnabled": "false",
"AWS_AUTH_AllowedAuthProviders": "grafana_assume_role,keys", "AWS_AUTH_AllowedAuthProviders": "grafana_assume_role,keys",
"AWS_AUTH_EXTERNAL_ID": "mock_external_id", "AWS_AUTH_EXTERNAL_ID": "mock_external_id",
@ -408,7 +410,7 @@ func TestRequestConfigProvider_PluginRequestConfig_aws(t *testing.T) {
}) })
t.Run("does not use the aws settings for a non-aws plugin", func(t *testing.T) { t.Run("does not use the aws settings for a non-aws plugin", func(t *testing.T) {
m := p.PluginRequestConfig(context.Background(), "") m := p.PluginRequestConfig(context.Background(), "", nil)
require.NotContains(t, m, "AWS_AUTH_AssumeRoleEnabled") require.NotContains(t, m, "AWS_AUTH_AssumeRoleEnabled")
require.NotContains(t, m, "AWS_AUTH_AllowedAuthProviders") require.NotContains(t, m, "AWS_AUTH_AllowedAuthProviders")
require.NotContains(t, m, "AWS_AUTH_EXTERNAL_ID") require.NotContains(t, m, "AWS_AUTH_EXTERNAL_ID")
@ -420,7 +422,7 @@ func TestRequestConfigProvider_PluginRequestConfig_aws(t *testing.T) {
cfg.AWSForwardSettingsPlugins = append(cfg.AWSForwardSettingsPlugins, "test-datasource") cfg.AWSForwardSettingsPlugins = append(cfg.AWSForwardSettingsPlugins, "test-datasource")
p = NewRequestConfigProvider(cfg) p = NewRequestConfigProvider(cfg)
require.Subset(t, p.PluginRequestConfig(context.Background(), "test-datasource"), map[string]string{ require.Subset(t, p.PluginRequestConfig(context.Background(), "test-datasource", nil), map[string]string{
"AWS_AUTH_AssumeRoleEnabled": "false", "AWS_AUTH_AssumeRoleEnabled": "false",
"AWS_AUTH_AllowedAuthProviders": "grafana_assume_role,keys", "AWS_AUTH_AllowedAuthProviders": "grafana_assume_role,keys",
"AWS_AUTH_EXTERNAL_ID": "mock_external_id", "AWS_AUTH_EXTERNAL_ID": "mock_external_id",
@ -429,3 +431,17 @@ func TestRequestConfigProvider_PluginRequestConfig_aws(t *testing.T) {
}) })
}) })
} }
func TestRequestConfigProvider_PluginRequestConfig_appClientSecret(t *testing.T) {
t.Run("Uses the configured app URL", func(t *testing.T) {
cfg := setting.NewCfg()
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg)
require.Subset(t, p.PluginRequestConfig(context.Background(), "", &auth.ExternalService{
ClientSecret: "mysecret",
}), map[string]string{backend.AppClientSecret: "mysecret"})
})
}

View File

@ -82,7 +82,7 @@ func (p *Provider) Get(ctx context.Context, pluginID string, user identity.Reque
pCtx.AppInstanceSettings = appSettings pCtx.AppInstanceSettings = appSettings
} }
settings := p.pluginRequestConfigProvider.PluginRequestConfig(ctx, pluginID) settings := p.pluginRequestConfigProvider.PluginRequestConfig(ctx, pluginID, plugin.ExternalService)
pCtx.GrafanaConfig = backend.NewGrafanaCfg(settings) pCtx.GrafanaConfig = backend.NewGrafanaCfg(settings)
ua, err := useragent.New(p.cfg.BuildVersion, runtime.GOOS, runtime.GOARCH) ua, err := useragent.New(p.cfg.BuildVersion, runtime.GOOS, runtime.GOARCH)
@ -119,7 +119,7 @@ func (p *Provider) GetWithDataSource(ctx context.Context, pluginID string, user
} }
pCtx.DataSourceInstanceSettings = datasourceSettings pCtx.DataSourceInstanceSettings = datasourceSettings
settings := p.pluginRequestConfigProvider.PluginRequestConfig(ctx, pluginID) settings := p.pluginRequestConfigProvider.PluginRequestConfig(ctx, pluginID, plugin.ExternalService)
pCtx.GrafanaConfig = backend.NewGrafanaCfg(settings) pCtx.GrafanaConfig = backend.NewGrafanaCfg(settings)
ua, err := useragent.New(p.cfg.BuildVersion, runtime.GOOS, runtime.GOARCH) ua, err := useragent.New(p.cfg.BuildVersion, runtime.GOOS, runtime.GOARCH)
@ -167,7 +167,7 @@ func (p *Provider) PluginContextForDataSource(ctx context.Context, datasourceSet
pCtx.DataSourceInstanceSettings = datasourceSettings pCtx.DataSourceInstanceSettings = datasourceSettings
settings := p.pluginRequestConfigProvider.PluginRequestConfig(ctx, pluginID) settings := p.pluginRequestConfigProvider.PluginRequestConfig(ctx, pluginID, plugin.ExternalService)
pCtx.GrafanaConfig = backend.NewGrafanaCfg(settings) pCtx.GrafanaConfig = backend.NewGrafanaCfg(settings)
ua, err := useragent.New(p.cfg.BuildVersion, runtime.GOOS, runtime.GOARCH) ua, err := useragent.New(p.cfg.BuildVersion, runtime.GOOS, runtime.GOARCH)