diff --git a/pkg/api/app_routes.go b/pkg/api/app_routes.go index 74f76787af5..60a82f40626 100644 --- a/pkg/api/app_routes.go +++ b/pkg/api/app_routes.go @@ -63,7 +63,7 @@ func AppPluginRoute(route *plugins.Route, appID string, hs *HTTPServer) web.Hand return func(c *models.ReqContext) { path := web.Params(c.Req)["*"] - proxy := pluginproxy.NewApiPluginProxy(c, path, route, appID, hs.Cfg, hs.SecretsService) + proxy := pluginproxy.NewApiPluginProxy(c, path, route, appID, hs.Cfg, hs.SQLStore, hs.SecretsService) proxy.Transport = pluginProxyTransport proxy.ServeHTTP(c.Resp, c.Req) } diff --git a/pkg/api/pluginproxy/pluginproxy.go b/pkg/api/pluginproxy/pluginproxy.go index d2f88ff0a31..cfbaffc832b 100644 --- a/pkg/api/pluginproxy/pluginproxy.go +++ b/pkg/api/pluginproxy/pluginproxy.go @@ -6,10 +6,10 @@ import ( "net/http/httputil" "net/url" - "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/services/secrets" + "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util/proxyutil" @@ -22,10 +22,10 @@ type templateData struct { // NewApiPluginProxy create a plugin proxy func NewApiPluginProxy(ctx *models.ReqContext, proxyPath string, route *plugins.Route, - appID string, cfg *setting.Cfg, secretsService secrets.Service) *httputil.ReverseProxy { + appID string, cfg *setting.Cfg, store sqlstore.Store, secretsService secrets.Service) *httputil.ReverseProxy { director := func(req *http.Request) { query := models.GetPluginSettingByIdQuery{OrgId: ctx.OrgId, PluginId: appID} - if err := bus.Dispatch(ctx.Req.Context(), &query); err != nil { + if err := store.GetPluginSettingById(ctx.Req.Context(), &query); err != nil { ctx.JsonApiErr(500, "Failed to fetch plugin settings", err) return } diff --git a/pkg/api/pluginproxy/pluginproxy_test.go b/pkg/api/pluginproxy/pluginproxy_test.go index 4be064e5ffb..ff862606566 100644 --- a/pkg/api/pluginproxy/pluginproxy_test.go +++ b/pkg/api/pluginproxy/pluginproxy_test.go @@ -6,12 +6,13 @@ import ( "net/http" "testing" - "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/services/secrets/fakes" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" + "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" "github.com/stretchr/testify/assert" @@ -28,20 +29,13 @@ func TestPluginProxy(t *testing.T) { {Name: "x-header", Content: "my secret {{.SecureJsonData.key}}"}, }, } - - bus.AddHandler("test", func(ctx context.Context, query *models.GetPluginSettingByIdQuery) error { - key, err := secretsService.Encrypt(ctx, []byte("123"), secrets.WithoutScope()) - if err != nil { - return err - } - - query.Result = &models.PluginSetting{ - SecureJsonData: map[string][]byte{ - "key": key, - }, - } - return nil - }) + store := mockstore.NewSQLStoreMock() + key, _ := secretsService.Encrypt(context.Background(), []byte("123"), secrets.WithoutScope()) + store.ExpectedPluginSetting = &models.PluginSetting{ + SecureJsonData: map[string][]byte{ + "key": key, + }, + } httpReq, err := http.NewRequest(http.MethodGet, "", nil) require.NoError(t, err) @@ -59,6 +53,7 @@ func TestPluginProxy(t *testing.T) { }, &setting.Cfg{SendUserHeader: true}, route, + store, ) assert.Equal(t, "my secret 123", req.Header.Get("x-header")) @@ -67,6 +62,8 @@ func TestPluginProxy(t *testing.T) { t.Run("When SendUserHeader config is enabled", func(t *testing.T) { httpReq, err := http.NewRequest(http.MethodGet, "", nil) require.NoError(t, err) + store := mockstore.NewSQLStoreMock() + store.ExpectedPluginSetting = &models.PluginSetting{} req := getPluginProxiedRequest( t, @@ -81,6 +78,7 @@ func TestPluginProxy(t *testing.T) { }, &setting.Cfg{SendUserHeader: true}, nil, + store, ) // Get will return empty string even if header is not set @@ -90,6 +88,8 @@ func TestPluginProxy(t *testing.T) { t.Run("When SendUserHeader config is disabled", func(t *testing.T) { httpReq, err := http.NewRequest(http.MethodGet, "", nil) require.NoError(t, err) + store := mockstore.NewSQLStoreMock() + store.ExpectedPluginSetting = &models.PluginSetting{} req := getPluginProxiedRequest( t, @@ -104,6 +104,7 @@ func TestPluginProxy(t *testing.T) { }, &setting.Cfg{SendUserHeader: false}, nil, + store, ) // Get will return empty string even if header is not set assert.Equal(t, "", req.Header.Get("X-Grafana-User")) @@ -112,6 +113,8 @@ func TestPluginProxy(t *testing.T) { t.Run("When SendUserHeader config is enabled but user is anonymous", func(t *testing.T) { httpReq, err := http.NewRequest(http.MethodGet, "", nil) require.NoError(t, err) + store := mockstore.NewSQLStoreMock() + store.ExpectedPluginSetting = &models.PluginSetting{} req := getPluginProxiedRequest( t, @@ -124,6 +127,7 @@ func TestPluginProxy(t *testing.T) { }, &setting.Cfg{SendUserHeader: true}, nil, + store, ) // Get will return empty string even if header is not set @@ -135,15 +139,12 @@ func TestPluginProxy(t *testing.T) { URL: "{{.JsonData.dynamicUrl}}", Method: "GET", } - - bus.AddHandler("test", func(_ context.Context, query *models.GetPluginSettingByIdQuery) error { - query.Result = &models.PluginSetting{ - JsonData: map[string]interface{}{ - "dynamicUrl": "https://dynamic.grafana.com", - }, - } - return nil - }) + store := mockstore.NewSQLStoreMock() + store.ExpectedPluginSetting = &models.PluginSetting{ + JsonData: map[string]interface{}{ + "dynamicUrl": "https://dynamic.grafana.com", + }, + } httpReq, err := http.NewRequest(http.MethodGet, "", nil) require.NoError(t, err) @@ -161,6 +162,7 @@ func TestPluginProxy(t *testing.T) { }, &setting.Cfg{SendUserHeader: true}, route, + store, ) assert.Equal(t, "https://dynamic.grafana.com", req.URL.String()) assert.Equal(t, "{{.JsonData.dynamicUrl}}", route.URL) @@ -171,11 +173,8 @@ func TestPluginProxy(t *testing.T) { URL: "{{if .JsonData.apiHost}}{{.JsonData.apiHost}}{{else}}https://example.com{{end}}", Method: "GET", } - - bus.AddHandler("test", func(_ context.Context, query *models.GetPluginSettingByIdQuery) error { - query.Result = &models.PluginSetting{} - return nil - }) + store := mockstore.NewSQLStoreMock() + store.ExpectedPluginSetting = &models.PluginSetting{} httpReq, err := http.NewRequest(http.MethodGet, "", nil) require.NoError(t, err) @@ -193,6 +192,7 @@ func TestPluginProxy(t *testing.T) { }, &setting.Cfg{SendUserHeader: true}, route, + store, ) assert.Equal(t, "https://example.com", req.URL.String()) }) @@ -204,25 +204,17 @@ func TestPluginProxy(t *testing.T) { Body: []byte(`{ "url": "{{.JsonData.dynamicUrl}}", "secret": "{{.SecureJsonData.key}}" }`), } - bus.AddHandler("test", func(ctx context.Context, query *models.GetPluginSettingByIdQuery) error { - encryptedJsonData, err := secretsService.EncryptJsonData( - ctx, - map[string]string{"key": "123"}, - secrets.WithoutScope(), - ) - - if err != nil { - return err - } + store := mockstore.NewSQLStoreMock() - query.Result = &models.PluginSetting{ - JsonData: map[string]interface{}{ - "dynamicUrl": "https://dynamic.grafana.com", - }, - SecureJsonData: encryptedJsonData, - } - return nil - }) + encryptedJsonData, _ := secretsService.EncryptJsonData( + context.Background(), + map[string]string{"key": "123"}, + secrets.WithoutScope(), + ) + store.ExpectedPluginSetting = &models.PluginSetting{ + JsonData: map[string]interface{}{"dynamicUrl": "https://dynamic.grafana.com"}, + SecureJsonData: encryptedJsonData, + } httpReq, err := http.NewRequest(http.MethodGet, "", nil) require.NoError(t, err) @@ -240,6 +232,7 @@ func TestPluginProxy(t *testing.T) { }, &setting.Cfg{SendUserHeader: true}, route, + store, ) content, err := ioutil.ReadAll(req.Body) require.NoError(t, err) @@ -248,7 +241,7 @@ func TestPluginProxy(t *testing.T) { } // getPluginProxiedRequest is a helper for easier setup of tests based on global config and ReqContext. -func getPluginProxiedRequest(t *testing.T, secretsService secrets.Service, ctx *models.ReqContext, cfg *setting.Cfg, route *plugins.Route) *http.Request { +func getPluginProxiedRequest(t *testing.T, secretsService secrets.Service, ctx *models.ReqContext, cfg *setting.Cfg, route *plugins.Route, store sqlstore.Store) *http.Request { // insert dummy route if none is specified if route == nil { route = &plugins.Route{ @@ -257,7 +250,7 @@ func getPluginProxiedRequest(t *testing.T, secretsService secrets.Service, ctx * ReqRole: models.ROLE_EDITOR, } } - proxy := NewApiPluginProxy(ctx, "", route, "", cfg, secretsService) + proxy := NewApiPluginProxy(ctx, "", route, "", cfg, store, secretsService) req, err := http.NewRequest(http.MethodGet, "/api/plugin-proxy/grafana-simple-app/api/v4/alerts", nil) require.NoError(t, err) diff --git a/pkg/services/sqlstore/mockstore/mockstore.go b/pkg/services/sqlstore/mockstore/mockstore.go index 78f41bdf6c3..429131d2067 100644 --- a/pkg/services/sqlstore/mockstore/mockstore.go +++ b/pkg/services/sqlstore/mockstore/mockstore.go @@ -11,10 +11,12 @@ import ( type SQLStoreMock struct { LastGetAlertsQuery *models.GetAlertsQuery - ExpectedUser *models.User - ExpectedDatasource *models.DataSource - ExpectedAlert *models.Alert - ExpectedError error + ExpectedUser *models.User + ExpectedDatasource *models.DataSource + ExpectedAlert *models.Alert + ExpectedPluginSetting *models.PluginSetting + + ExpectedError error } func NewSQLStoreMock() *SQLStoreMock { @@ -239,6 +241,7 @@ func (m *SQLStoreMock) GetPluginSettings(ctx context.Context, orgID int64) ([]*m } func (m *SQLStoreMock) GetPluginSettingById(ctx context.Context, query *models.GetPluginSettingByIdQuery) error { + query.Result = m.ExpectedPluginSetting return m.ExpectedError }