mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Plugins: Support set body content in plugin routes (#32551)
Adds support for overriding the body and length in plugin routes.
This commit is contained in:
committed by
GitHub
parent
027e886997
commit
aad43869c3
@@ -50,6 +50,10 @@ func ApplyRoute(ctx context.Context, req *http.Request, proxyPath string, route
|
||||
logger.Error("Failed to render plugin headers", "error", err)
|
||||
}
|
||||
|
||||
if err := setBodyContent(req, route, data); err != nil {
|
||||
logger.Error("Failed to set plugin route body content", "error", err)
|
||||
}
|
||||
|
||||
tokenProvider := newAccessTokenProvider(ds, route)
|
||||
|
||||
if route.TokenAuth != nil {
|
||||
|
||||
@@ -69,6 +69,11 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
Path: "api/restricted",
|
||||
ReqRole: models.ROLE_ADMIN,
|
||||
},
|
||||
{
|
||||
Path: "api/body",
|
||||
URL: "http://www.test.com",
|
||||
Body: []byte(`{ "url": "{{.JsonData.dynamicUrl}}", "secret": "{{.SecureJsonData.key}}" }`),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -136,6 +141,18 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
assert.Equal(t, "http://localhost/asd", req.URL.String())
|
||||
})
|
||||
|
||||
t.Run("When matching route path and has dynamic body", func(t *testing.T) {
|
||||
ctx, req := setUp()
|
||||
proxy, err := NewDataSourceProxy(ds, plugin, ctx, "api/body", &setting.Cfg{})
|
||||
require.NoError(t, err)
|
||||
proxy.route = plugin.Routes[5]
|
||||
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, proxy.route, proxy.ds)
|
||||
|
||||
content, err := ioutil.ReadAll(req.Body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, `{ "url": "https://dynamic.grafana.com", "secret": "123" }`, string(content))
|
||||
})
|
||||
|
||||
t.Run("Validating request", func(t *testing.T) {
|
||||
t.Run("plugin route with valid role", func(t *testing.T) {
|
||||
ctx, _ := setUp()
|
||||
|
||||
@@ -70,6 +70,10 @@ func NewApiPluginProxy(ctx *models.ReqContext, proxyPath string, route *plugins.
|
||||
ctx.JsonApiErr(500, "Failed to render plugin headers", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := setBodyContent(req, route, data); err != nil {
|
||||
logger.Error("Failed to set plugin route body content", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &httputil.ReverseProxy{Director: director}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package pluginproxy
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/securejsondata"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -148,6 +150,38 @@ func TestPluginProxy(t *testing.T) {
|
||||
)
|
||||
assert.Equal(t, "https://example.com", req.URL.String())
|
||||
})
|
||||
|
||||
t.Run("When getting templated body", func(t *testing.T) {
|
||||
route := &plugins.AppPluginRoute{
|
||||
Path: "api/body",
|
||||
URL: "http://www.test.com",
|
||||
Body: []byte(`{ "url": "{{.JsonData.dynamicUrl}}", "secret": "{{.SecureJsonData.key}}" }`),
|
||||
}
|
||||
|
||||
bus.AddHandler("test", func(query *models.GetPluginSettingByIdQuery) error {
|
||||
query.Result = &models.PluginSetting{
|
||||
JsonData: map[string]interface{}{
|
||||
"dynamicUrl": "https://dynamic.grafana.com",
|
||||
},
|
||||
SecureJsonData: securejsondata.GetEncryptedJsonData(map[string]string{"key": "123"}),
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
req := getPluginProxiedRequest(
|
||||
t,
|
||||
&models.ReqContext{
|
||||
SignedInUser: &models.SignedInUser{
|
||||
Login: "test_user",
|
||||
},
|
||||
},
|
||||
&setting.Cfg{SendUserHeader: true},
|
||||
route,
|
||||
)
|
||||
content, err := ioutil.ReadAll(req.Body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, `{ "url": "https://dynamic.grafana.com", "secret": "123" }`, string(content))
|
||||
})
|
||||
}
|
||||
|
||||
// getPluginProxiedRequest is a helper for easier setup of tests based on global config and ReqContext.
|
||||
|
||||
@@ -3,7 +3,9 @@ package pluginproxy
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
@@ -60,6 +62,20 @@ func addQueryString(req *http.Request, route *plugins.AppPluginRoute, data templ
|
||||
return nil
|
||||
}
|
||||
|
||||
func setBodyContent(req *http.Request, route *plugins.AppPluginRoute, data templateData) error {
|
||||
if route.Body != nil {
|
||||
interpolatedBody, err := interpolateString(string(route.Body), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Body = ioutil.NopCloser(strings.NewReader(interpolatedBody))
|
||||
req.ContentLength = int64(len(interpolatedBody))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set the X-Grafana-User header if needed (and remove if not)
|
||||
func applyUserHeader(sendUserHeader bool, req *http.Request, user *models.SignedInUser) {
|
||||
req.Header.Del("X-Grafana-User")
|
||||
|
||||
Reference in New Issue
Block a user