diff --git a/pkg/services/pluginsintegration/pluginconfig/fakes.go b/pkg/services/pluginsintegration/pluginconfig/fakes.go index c58a8443801..daedad1488e 100644 --- a/pkg/services/pluginsintegration/pluginconfig/fakes.go +++ b/pkg/services/pluginsintegration/pluginconfig/fakes.go @@ -1,6 +1,10 @@ package pluginconfig -import "context" +import ( + "context" + + "github.com/grafana/grafana/pkg/plugins/auth" +) 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. -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{} } diff --git a/pkg/services/pluginsintegration/pluginconfig/request.go b/pkg/services/pluginsintegration/pluginconfig/request.go index c70725b59c9..af2de223bda 100644 --- a/pkg/services/pluginsintegration/pluginconfig/request.go +++ b/pkg/services/pluginsintegration/pluginconfig/request.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana-aws-sdk/pkg/awsds" "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/proxy" @@ -18,7 +19,7 @@ import ( var _ PluginRequestConfigProvider = (*RequestConfigProvider)(nil) 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 { @@ -33,7 +34,7 @@ func NewRequestConfigProvider(cfg *PluginInstanceCfg) *RequestConfigProvider { // PluginRequestConfig returns a map of configuration that should be passed in a plugin request. // 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) if s.cfg.GrafanaAppURL != "" { @@ -160,5 +161,9 @@ func (s *RequestConfigProvider) PluginRequestConfig(ctx context.Context, pluginI m[awsds.SigV4VerboseLoggingEnvVarKeyName] = strconv.FormatBool(s.cfg.SigV4VerboseLogging) } + if externalService != nil { + m[backend.AppClientSecret] = externalService.ClientSecret + } + return m } diff --git a/pkg/services/pluginsintegration/pluginconfig/request_test.go b/pkg/services/pluginsintegration/pluginconfig/request_test.go index f21d2c0de19..cec19e4a252 100644 --- a/pkg/services/pluginsintegration/pluginconfig/request_test.go +++ b/pkg/services/pluginsintegration/pluginconfig/request_test.go @@ -7,7 +7,9 @@ import ( "github.com/stretchr/testify/require" "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/setting" ) @@ -22,7 +24,7 @@ func TestRequestConfigProvider_PluginRequestConfig_Defaults(t *testing.T) { "GF_SQL_MAX_OPEN_CONNS_DEFAULT": "0", "GF_SQL_MAX_IDLE_CONNS_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) { @@ -132,7 +134,7 @@ func TestRequestConfigProvider_PluginRequestConfig(t *testing.T) { for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { 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) 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) 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) 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_MAX_OPEN_CONNS_DEFAULT": "24", "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_IDLE_CONNS_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) 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) { @@ -241,7 +243,7 @@ func TestRequestConfigProvider_PluginRequestConfig_concurrentQueryCount(t *testi require.NoError(t, err) 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) { @@ -252,7 +254,7 @@ func TestRequestConfigProvider_PluginRequestConfig_concurrentQueryCount(t *testi require.NoError(t, err) 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) - 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) { @@ -273,7 +275,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azureAuthEnabled(t *testing.T } 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) { @@ -283,7 +285,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azureAuthEnabled(t *testing.T } 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) 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_MANAGED_IDENTITY_CLIENT_ID": "mock_managed_identity_client_id", "GFAZPL_WORKLOAD_IDENTITY_ENABLED": "true", @@ -341,7 +343,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azure(t *testing.T) { require.NoError(t, err) 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_MANAGED_IDENTITY_ENABLED") require.NotContains(t, m, "GFAZPL_MANAGED_IDENTITY_CLIENT_ID") @@ -366,7 +368,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azure(t *testing.T) { require.NoError(t, err) 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_MANAGED_IDENTITY_CLIENT_ID": "mock_managed_identity_client_id", "GFAZPL_WORKLOAD_IDENTITY_ENABLED": "true", @@ -398,7 +400,7 @@ func TestRequestConfigProvider_PluginRequestConfig_aws(t *testing.T) { p := NewRequestConfigProvider(cfg) 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_AllowedAuthProviders": "grafana_assume_role,keys", "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) { - m := p.PluginRequestConfig(context.Background(), "") + m := p.PluginRequestConfig(context.Background(), "", nil) require.NotContains(t, m, "AWS_AUTH_AssumeRoleEnabled") require.NotContains(t, m, "AWS_AUTH_AllowedAuthProviders") 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") 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_AllowedAuthProviders": "grafana_assume_role,keys", "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"}) + }) +} diff --git a/pkg/services/pluginsintegration/plugincontext/plugincontext.go b/pkg/services/pluginsintegration/plugincontext/plugincontext.go index 4d601b7b34f..de042f74878 100644 --- a/pkg/services/pluginsintegration/plugincontext/plugincontext.go +++ b/pkg/services/pluginsintegration/plugincontext/plugincontext.go @@ -82,7 +82,7 @@ func (p *Provider) Get(ctx context.Context, pluginID string, user identity.Reque pCtx.AppInstanceSettings = appSettings } - settings := p.pluginRequestConfigProvider.PluginRequestConfig(ctx, pluginID) + settings := p.pluginRequestConfigProvider.PluginRequestConfig(ctx, pluginID, plugin.ExternalService) pCtx.GrafanaConfig = backend.NewGrafanaCfg(settings) 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 - settings := p.pluginRequestConfigProvider.PluginRequestConfig(ctx, pluginID) + settings := p.pluginRequestConfigProvider.PluginRequestConfig(ctx, pluginID, plugin.ExternalService) pCtx.GrafanaConfig = backend.NewGrafanaCfg(settings) 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 - settings := p.pluginRequestConfigProvider.PluginRequestConfig(ctx, pluginID) + settings := p.pluginRequestConfigProvider.PluginRequestConfig(ctx, pluginID, plugin.ExternalService) pCtx.GrafanaConfig = backend.NewGrafanaCfg(settings) ua, err := useragent.New(p.cfg.BuildVersion, runtime.GOOS, runtime.GOARCH)