datasources: ClearAuthHeadersMiddleware: refactor (#113707)

* refactor: extract logic

* directly use the setting.cfg in the middleware

* more granular config handling, per section

* fixed unit test

* refactor code to avoid lint error
This commit is contained in:
Gábor Farkas
2025-11-21 14:18:32 +01:00
committed by GitHub
parent 203549ce3c
commit 669382c212
4 changed files with 230 additions and 390 deletions
+28 -20
View File
@@ -207,6 +207,33 @@ type AuthHTTPHeaderList struct {
Items []string
}
func GetAuthHTTPHeaders(jwtAuth *setting.AuthJWTSettings, authProxy *setting.AuthProxySettings) []string {
var items []string
// used by basic auth, api keys and potentially jwt auth
items = append(items, "Authorization")
// remove X-Grafana-Device-Id as it is only used for auth in authn clients.
items = append(items, "X-Grafana-Device-Id")
// if jwt is enabled we add it to the list. We can ignore in case it is set to Authorization
if jwtAuth.Enabled && jwtAuth.HeaderName != "" && jwtAuth.HeaderName != "Authorization" {
items = append(items, jwtAuth.HeaderName)
}
// if auth proxy is enabled add the main proxy header and all configured headers
if authProxy.Enabled {
items = append(items, authProxy.HeaderName)
for _, header := range authProxy.Headers {
if header != "" {
items = append(items, header)
}
}
}
return items
}
// WithAuthHTTPHeaders returns a new context in which all possible configured auth header will be included
// and later retrievable by AuthHTTPHeaderListFromContext.
func WithAuthHTTPHeaders(ctx context.Context, cfg *setting.Cfg) context.Context {
@@ -217,26 +244,7 @@ func WithAuthHTTPHeaders(ctx context.Context, cfg *setting.Cfg) context.Context
}
}
// used by basic auth, api keys and potentially jwt auth
list.Items = append(list.Items, "Authorization")
// remove X-Grafana-Device-Id as it is only used for auth in authn clients.
list.Items = append(list.Items, "X-Grafana-Device-Id")
// if jwt is enabled we add it to the list. We can ignore in case it is set to Authorization
if cfg.JWTAuth.Enabled && cfg.JWTAuth.HeaderName != "" && cfg.JWTAuth.HeaderName != "Authorization" {
list.Items = append(list.Items, cfg.JWTAuth.HeaderName)
}
// if auth proxy is enabled add the main proxy header and all configured headers
if cfg.AuthProxy.Enabled {
list.Items = append(list.Items, cfg.AuthProxy.HeaderName)
for _, header := range cfg.AuthProxy.Headers {
if header != "" {
list.Items = append(list.Items, header)
}
}
}
list.Items = append(list.Items, GetAuthHTTPHeaders(&cfg.JWTAuth, &cfg.AuthProxy)...)
return context.WithValue(ctx, authHTTPHeaderListKey, list)
}
@@ -6,21 +6,26 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/services/contexthandler"
"github.com/grafana/grafana/pkg/setting"
)
// NewClearAuthHeadersMiddleware creates a new backend.HandlerMiddleware
// that will clear any outgoing HTTP headers that was part of the incoming
// HTTP request and used when authenticating to Grafana.
func NewClearAuthHeadersMiddleware() backend.HandlerMiddleware {
func NewClearAuthHeadersMiddleware(cfgJWTAuth *setting.AuthJWTSettings, cfgAuthProxy *setting.AuthProxySettings) backend.HandlerMiddleware {
return backend.HandlerMiddlewareFunc(func(next backend.Handler) backend.Handler {
return &ClearAuthHeadersMiddleware{
BaseHandler: backend.NewBaseHandler(next),
BaseHandler: backend.NewBaseHandler(next),
cfgJWTAuth: cfgJWTAuth,
cfgAuthProxy: cfgAuthProxy,
}
})
}
type ClearAuthHeadersMiddleware struct {
backend.BaseHandler
cfgJWTAuth *setting.AuthJWTSettings
cfgAuthProxy *setting.AuthProxySettings
}
func (m *ClearAuthHeadersMiddleware) clearHeaders(ctx context.Context, h backend.ForwardHTTPHeaders) {
@@ -30,11 +35,9 @@ func (m *ClearAuthHeadersMiddleware) clearHeaders(ctx context.Context, h backend
return
}
list := contexthandler.AuthHTTPHeaderListFromContext(ctx)
if list != nil {
for _, k := range list.Items {
h.DeleteHTTPHeader(k)
}
items := contexthandler.GetAuthHTTPHeaders(m.cfgJWTAuth, m.cfgAuthProxy)
for _, k := range items {
h.DeleteHTTPHeader(k)
}
}
@@ -8,7 +8,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/handlertest"
"github.com/grafana/grafana/pkg/services/contexthandler"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
)
@@ -16,397 +15,227 @@ import (
func TestClearAuthHeadersMiddleware(t *testing.T) {
const otherHeader = "test"
t.Run("When no auth headers in reqContext", func(t *testing.T) {
req, err := http.NewRequest(http.MethodGet, "/some/thing", nil)
require.NoError(t, err)
req, err := http.NewRequest(http.MethodGet, "/some/thing", nil)
require.NoError(t, err)
req.Header.Set(otherHeader, "test")
t.Run("When requests are for a datasource", func(t *testing.T) {
cfg := setting.NewCfg()
cdt := handlertest.NewHandlerMiddlewareTest(t,
WithReqContext(req, &user.SignedInUser{}),
handlertest.WithMiddlewares(NewClearAuthHeadersMiddleware(&cfg.JWTAuth, &cfg.AuthProxy)),
)
t.Run("And requests are for a datasource", func(t *testing.T) {
cdt := handlertest.NewHandlerMiddlewareTest(t,
WithReqContext(req, &user.SignedInUser{}),
handlertest.WithMiddlewares(NewClearAuthHeadersMiddleware()),
)
pluginCtx := backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
}
pluginCtx := backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
}
t.Run("No auth headers to clear when calling QueryData", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.QueryData(req.Context(), &backend.QueryDataRequest{
PluginContext: pluginCtx,
Headers: map[string]string{otherHeader: "test"},
})
require.NoError(t, err)
require.NotNil(t, cdt.QueryDataReq)
require.Len(t, cdt.QueryDataReq.Headers, 1)
require.Empty(t, cdt.QueryDataReq.GetHTTPHeaders())
})
t.Run("No auth headers to clear when calling CallResource", func(t *testing.T) {
err = cdt.MiddlewareHandler.CallResource(req.Context(), &backend.CallResourceRequest{
PluginContext: pluginCtx,
Headers: map[string][]string{otherHeader: {"test"}},
}, nopCallResourceSender)
require.NoError(t, err)
require.NotNil(t, cdt.CallResourceReq)
require.Len(t, cdt.CallResourceReq.Headers, 1)
require.Equal(t, http.Header{http.CanonicalHeaderKey(otherHeader): {"test"}}, cdt.CallResourceReq.GetHTTPHeaders())
})
t.Run("No auth headers to clear when calling CheckHealth", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.CheckHealth(req.Context(), &backend.CheckHealthRequest{
PluginContext: pluginCtx,
Headers: map[string]string{otherHeader: "test"},
})
require.NoError(t, err)
require.NotNil(t, cdt.CheckHealthReq)
require.Len(t, cdt.CheckHealthReq.Headers, 1)
require.Empty(t, cdt.CheckHealthReq.GetHTTPHeaders())
})
t.Run("No auth headers to clear when calling SubscribeStream", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.SubscribeStream(req.Context(), &backend.SubscribeStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{otherHeader: "test"},
})
require.NoError(t, err)
require.NotNil(t, cdt.SubscribeStreamReq)
require.Len(t, cdt.SubscribeStreamReq.Headers, 1)
require.Empty(t, cdt.SubscribeStreamReq.GetHTTPHeaders())
})
t.Run("No auth headers to clear when calling PublishStream", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.PublishStream(req.Context(), &backend.PublishStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{otherHeader: "test"},
})
require.NoError(t, err)
require.NotNil(t, cdt.PublishStreamReq)
require.Len(t, cdt.PublishStreamReq.Headers, 1)
require.Empty(t, cdt.PublishStreamReq.GetHTTPHeaders())
})
t.Run("No auth headers to clear when calling RunStream", func(t *testing.T) {
err = cdt.MiddlewareHandler.RunStream(req.Context(), &backend.RunStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{otherHeader: "test"},
}, &backend.StreamSender{})
require.NoError(t, err)
require.NotNil(t, cdt.RunStreamReq)
require.Len(t, cdt.RunStreamReq.Headers, 1)
require.Empty(t, cdt.RunStreamReq.GetHTTPHeaders())
t.Run("Should clear auth headers when calling QueryData", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.QueryData(req.Context(), &backend.QueryDataRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.QueryDataReq)
require.Len(t, cdt.QueryDataReq.Headers, 1)
require.Equal(t, "test", cdt.QueryDataReq.Headers[otherHeader])
require.Empty(t, cdt.QueryDataReq.GetHTTPHeaders())
})
t.Run("And requests are for an app", func(t *testing.T) {
cdt := handlertest.NewHandlerMiddlewareTest(t,
WithReqContext(req, &user.SignedInUser{}),
handlertest.WithMiddlewares(NewClearAuthHeadersMiddleware()),
)
t.Run("Should clear auth headers when calling CallResource", func(t *testing.T) {
err = cdt.MiddlewareHandler.CallResource(req.Context(), &backend.CallResourceRequest{
PluginContext: pluginCtx,
Headers: map[string][]string{
otherHeader: {"test"},
"Authorization": {"secret"},
"X-Grafana-Device-Id": {"secret"},
},
}, nopCallResourceSender)
require.NoError(t, err)
require.NotNil(t, cdt.CallResourceReq)
require.Len(t, cdt.CallResourceReq.Headers, 1)
require.Equal(t, []string{"test"}, cdt.CallResourceReq.Headers[otherHeader])
require.Equal(t, "test", cdt.CallResourceReq.GetHTTPHeader(otherHeader))
})
pluginCtx := backend.PluginContext{
AppInstanceSettings: &backend.AppInstanceSettings{},
}
t.Run("No auth headers to clear when calling QueryData", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.QueryData(req.Context(), &backend.QueryDataRequest{
PluginContext: pluginCtx,
Headers: map[string]string{otherHeader: "test"},
})
require.NoError(t, err)
require.NotNil(t, cdt.QueryDataReq)
require.Len(t, cdt.QueryDataReq.Headers, 1)
require.Equal(t, "test", cdt.QueryDataReq.Headers[otherHeader])
require.Empty(t, cdt.QueryDataReq.GetHTTPHeaders())
t.Run("Should clear auth headers when calling CheckHealth", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.CheckHealth(req.Context(), &backend.CheckHealthRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.CheckHealthReq)
require.Len(t, cdt.CheckHealthReq.Headers, 1)
require.Equal(t, "test", cdt.CheckHealthReq.Headers[otherHeader])
require.Empty(t, cdt.CheckHealthReq.GetHTTPHeaders())
})
t.Run("No auth headers to clear when calling CallResource", func(t *testing.T) {
err = cdt.MiddlewareHandler.CallResource(req.Context(), &backend.CallResourceRequest{
PluginContext: pluginCtx,
Headers: map[string][]string{otherHeader: {"test"}},
}, nopCallResourceSender)
require.NoError(t, err)
require.NotNil(t, cdt.CallResourceReq)
require.Len(t, cdt.CallResourceReq.Headers, 1)
require.Equal(t, []string{"test"}, cdt.CallResourceReq.Headers[otherHeader])
require.Equal(t, http.Header{http.CanonicalHeaderKey(otherHeader): {"test"}}, cdt.CallResourceReq.GetHTTPHeaders())
t.Run("Should clear auth headers when calling SubscribeStream", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.SubscribeStream(req.Context(), &backend.SubscribeStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.SubscribeStreamReq)
require.Len(t, cdt.SubscribeStreamReq.Headers, 1)
require.Equal(t, "test", cdt.SubscribeStreamReq.Headers[otherHeader])
require.Empty(t, cdt.SubscribeStreamReq.GetHTTPHeaders())
})
t.Run("No auth headers to clear when calling CheckHealth", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.CheckHealth(req.Context(), &backend.CheckHealthRequest{
PluginContext: pluginCtx,
Headers: map[string]string{otherHeader: "test"},
})
require.NoError(t, err)
require.NotNil(t, cdt.CheckHealthReq)
require.Len(t, cdt.CheckHealthReq.Headers, 1)
require.Equal(t, "test", cdt.CheckHealthReq.Headers[otherHeader])
require.Empty(t, cdt.CheckHealthReq.GetHTTPHeaders())
t.Run("Should clear auth headers when calling PublishStream", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.PublishStream(req.Context(), &backend.PublishStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.PublishStreamReq)
require.Len(t, cdt.PublishStreamReq.Headers, 1)
require.Equal(t, "test", cdt.PublishStreamReq.Headers[otherHeader])
require.Empty(t, cdt.PublishStreamReq.GetHTTPHeaders())
})
t.Run("No auth headers to clear when calling SubscribeStream", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.SubscribeStream(req.Context(), &backend.SubscribeStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{otherHeader: "test"},
})
require.NoError(t, err)
require.NotNil(t, cdt.SubscribeStreamReq)
require.Len(t, cdt.SubscribeStreamReq.Headers, 1)
require.Equal(t, "test", cdt.SubscribeStreamReq.Headers[otherHeader])
require.Empty(t, cdt.SubscribeStreamReq.GetHTTPHeaders())
})
t.Run("No auth headers to clear when calling PublishStream", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.PublishStream(req.Context(), &backend.PublishStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{otherHeader: "test"},
})
require.NoError(t, err)
require.NotNil(t, cdt.PublishStreamReq)
require.Len(t, cdt.PublishStreamReq.Headers, 1)
require.Equal(t, "test", cdt.PublishStreamReq.Headers[otherHeader])
require.Empty(t, cdt.PublishStreamReq.GetHTTPHeaders())
})
t.Run("No auth headers to clear when calling RunStream", func(t *testing.T) {
err = cdt.MiddlewareHandler.RunStream(req.Context(), &backend.RunStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{otherHeader: "test"},
}, &backend.StreamSender{})
require.NoError(t, err)
require.NotNil(t, cdt.RunStreamReq)
require.Len(t, cdt.RunStreamReq.Headers, 1)
require.Equal(t, "test", cdt.RunStreamReq.Headers[otherHeader])
require.Empty(t, cdt.RunStreamReq.GetHTTPHeaders())
})
t.Run("Should clear auth headers when calling RunStream", func(t *testing.T) {
err = cdt.MiddlewareHandler.RunStream(req.Context(), &backend.RunStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
}, &backend.StreamSender{})
require.NoError(t, err)
require.NotNil(t, cdt.RunStreamReq)
require.Len(t, cdt.RunStreamReq.Headers, 1)
require.Equal(t, "test", cdt.RunStreamReq.Headers[otherHeader])
require.Empty(t, cdt.RunStreamReq.GetHTTPHeaders())
})
})
t.Run("When auth headers in reqContext", func(t *testing.T) {
req, err := http.NewRequest(http.MethodGet, "/some/thing", nil)
require.NoError(t, err)
t.Run("When requests are for an app", func(t *testing.T) {
cfg := setting.NewCfg()
cdt := handlertest.NewHandlerMiddlewareTest(t,
WithReqContext(req, &user.SignedInUser{}),
handlertest.WithMiddlewares(NewClearAuthHeadersMiddleware(&cfg.JWTAuth, &cfg.AuthProxy)),
)
t.Run("And requests are for a datasource", func(t *testing.T) {
cdt := handlertest.NewHandlerMiddlewareTest(t,
WithReqContext(req, &user.SignedInUser{}),
handlertest.WithMiddlewares(NewClearAuthHeadersMiddleware()),
)
req.Header.Set("Authorization", "val")
req := req.WithContext(contexthandler.WithAuthHTTPHeaders(req.Context(), setting.NewCfg()))
const otherHeader = "x-Other"
req.Header.Set(otherHeader, "test")
pluginCtx := backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
}
pluginCtx := backend.PluginContext{
AppInstanceSettings: &backend.AppInstanceSettings{},
}
t.Run("Should clear auth headers when calling QueryData", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.QueryData(req.Context(), &backend.QueryDataRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.QueryDataReq)
require.Len(t, cdt.QueryDataReq.Headers, 1)
require.Equal(t, "test", cdt.QueryDataReq.Headers[otherHeader])
require.Empty(t, cdt.QueryDataReq.GetHTTPHeaders())
})
t.Run("Should clear auth headers when calling CallResource", func(t *testing.T) {
err = cdt.MiddlewareHandler.CallResource(req.Context(), &backend.CallResourceRequest{
PluginContext: pluginCtx,
Headers: map[string][]string{
otherHeader: {"test"},
"Authorization": {"secret"},
"X-Grafana-Device-Id": {"secret"},
},
}, nopCallResourceSender)
require.NoError(t, err)
require.NotNil(t, cdt.CallResourceReq)
require.Len(t, cdt.CallResourceReq.Headers, 1)
require.Equal(t, []string{"test"}, cdt.CallResourceReq.Headers[otherHeader])
require.Equal(t, "test", cdt.CallResourceReq.GetHTTPHeader(otherHeader))
})
t.Run("Should clear auth headers when calling CheckHealth", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.CheckHealth(req.Context(), &backend.CheckHealthRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.CheckHealthReq)
require.Len(t, cdt.CheckHealthReq.Headers, 1)
require.Equal(t, "test", cdt.CheckHealthReq.Headers[otherHeader])
require.Empty(t, cdt.CheckHealthReq.GetHTTPHeaders())
})
t.Run("Should clear auth headers when calling SubscribeStream", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.SubscribeStream(req.Context(), &backend.SubscribeStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.SubscribeStreamReq)
require.Len(t, cdt.SubscribeStreamReq.Headers, 1)
require.Equal(t, "test", cdt.SubscribeStreamReq.Headers[otherHeader])
require.Empty(t, cdt.SubscribeStreamReq.GetHTTPHeaders())
})
t.Run("Should clear auth headers when calling PublishStream", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.PublishStream(req.Context(), &backend.PublishStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.PublishStreamReq)
require.Len(t, cdt.PublishStreamReq.Headers, 1)
require.Equal(t, "test", cdt.PublishStreamReq.Headers[otherHeader])
require.Empty(t, cdt.PublishStreamReq.GetHTTPHeaders())
})
t.Run("Should clear auth headers when calling RunStream", func(t *testing.T) {
err = cdt.MiddlewareHandler.RunStream(req.Context(), &backend.RunStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
}, &backend.StreamSender{})
require.NoError(t, err)
require.NotNil(t, cdt.RunStreamReq)
require.Len(t, cdt.RunStreamReq.Headers, 1)
require.Equal(t, "test", cdt.RunStreamReq.Headers[otherHeader])
require.Empty(t, cdt.RunStreamReq.GetHTTPHeaders())
t.Run("Should clear auth headers when calling QueryData", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.QueryData(req.Context(), &backend.QueryDataRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.QueryDataReq)
require.Len(t, cdt.QueryDataReq.Headers, 1)
require.Equal(t, "test", cdt.QueryDataReq.Headers[otherHeader])
require.Empty(t, cdt.QueryDataReq.GetHTTPHeaders())
})
t.Run("And requests are for an app", func(t *testing.T) {
cdt := handlertest.NewHandlerMiddlewareTest(t,
WithReqContext(req, &user.SignedInUser{}),
handlertest.WithMiddlewares(NewClearAuthHeadersMiddleware()),
)
t.Run("Should clear auth headers when calling CallResource", func(t *testing.T) {
err = cdt.MiddlewareHandler.CallResource(req.Context(), &backend.CallResourceRequest{
PluginContext: pluginCtx,
Headers: map[string][]string{
otherHeader: {"test"},
"Authorization": {"secret"},
"X-Grafana-Device-Id": {"secret"},
},
}, nopCallResourceSender)
require.NoError(t, err)
require.NotNil(t, cdt.CallResourceReq)
require.Len(t, cdt.CallResourceReq.Headers, 1)
require.Equal(t, []string{"test"}, cdt.CallResourceReq.Headers[otherHeader])
require.Equal(t, "test", cdt.CallResourceReq.GetHTTPHeader(otherHeader))
})
req := req.WithContext(contexthandler.WithAuthHTTPHeaders(req.Context(), setting.NewCfg()))
req.Header.Set("Authorization", "val")
const otherHeader = "x-Other"
req.Header.Set(otherHeader, "test")
pluginCtx := backend.PluginContext{
AppInstanceSettings: &backend.AppInstanceSettings{},
}
t.Run("Should clear auth headers when calling QueryData", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.QueryData(req.Context(), &backend.QueryDataRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.QueryDataReq)
require.Len(t, cdt.QueryDataReq.Headers, 1)
require.Equal(t, "test", cdt.QueryDataReq.Headers[otherHeader])
require.Empty(t, cdt.QueryDataReq.GetHTTPHeaders())
t.Run("Should clear auth headers when calling CheckHealth", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.CheckHealth(req.Context(), &backend.CheckHealthRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.CheckHealthReq)
require.Len(t, cdt.CheckHealthReq.Headers, 1)
require.Equal(t, "test", cdt.CheckHealthReq.Headers[otherHeader])
require.Empty(t, cdt.CheckHealthReq.GetHTTPHeaders())
})
t.Run("Should clear auth headers when calling CallResource", func(t *testing.T) {
err = cdt.MiddlewareHandler.CallResource(req.Context(), &backend.CallResourceRequest{
PluginContext: pluginCtx,
Headers: map[string][]string{
otherHeader: {"test"},
"Authorization": {"secret"},
"X-Grafana-Device-Id": {"secret"},
},
}, nopCallResourceSender)
require.NoError(t, err)
require.NotNil(t, cdt.CallResourceReq)
require.Len(t, cdt.CallResourceReq.Headers, 1)
require.Equal(t, []string{"test"}, cdt.CallResourceReq.Headers[otherHeader])
require.Equal(t, "test", cdt.CallResourceReq.GetHTTPHeader(otherHeader))
t.Run("Should clear auth headers when calling SubscribeStream", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.SubscribeStream(req.Context(), &backend.SubscribeStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.SubscribeStreamReq)
require.Len(t, cdt.SubscribeStreamReq.Headers, 1)
require.Equal(t, "test", cdt.SubscribeStreamReq.Headers[otherHeader])
require.Empty(t, cdt.SubscribeStreamReq.GetHTTPHeaders())
})
t.Run("Should clear auth headers when calling CheckHealth", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.CheckHealth(req.Context(), &backend.CheckHealthRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.CheckHealthReq)
require.Len(t, cdt.CheckHealthReq.Headers, 1)
require.Equal(t, "test", cdt.CheckHealthReq.Headers[otherHeader])
require.Empty(t, cdt.CheckHealthReq.GetHTTPHeaders())
t.Run("Should clear auth headers when calling PublishStream", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.PublishStream(req.Context(), &backend.PublishStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.PublishStreamReq)
require.Len(t, cdt.PublishStreamReq.Headers, 1)
require.Equal(t, "test", cdt.PublishStreamReq.Headers[otherHeader])
require.Empty(t, cdt.PublishStreamReq.GetHTTPHeaders())
})
t.Run("Should clear auth headers when calling SubscribeStream", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.SubscribeStream(req.Context(), &backend.SubscribeStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.SubscribeStreamReq)
require.Len(t, cdt.SubscribeStreamReq.Headers, 1)
require.Equal(t, "test", cdt.SubscribeStreamReq.Headers[otherHeader])
require.Empty(t, cdt.SubscribeStreamReq.GetHTTPHeaders())
})
t.Run("Should clear auth headers when calling PublishStream", func(t *testing.T) {
_, err = cdt.MiddlewareHandler.PublishStream(req.Context(), &backend.PublishStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
})
require.NoError(t, err)
require.NotNil(t, cdt.PublishStreamReq)
require.Len(t, cdt.PublishStreamReq.Headers, 1)
require.Equal(t, "test", cdt.PublishStreamReq.Headers[otherHeader])
require.Empty(t, cdt.PublishStreamReq.GetHTTPHeaders())
})
t.Run("Should clear auth headers when calling RunStream", func(t *testing.T) {
err = cdt.MiddlewareHandler.RunStream(req.Context(), &backend.RunStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
}, &backend.StreamSender{})
require.NoError(t, err)
require.NotNil(t, cdt.RunStreamReq)
require.Len(t, cdt.RunStreamReq.Headers, 1)
require.Equal(t, "test", cdt.RunStreamReq.Headers[otherHeader])
require.Empty(t, cdt.RunStreamReq.GetHTTPHeaders())
})
t.Run("Should clear auth headers when calling RunStream", func(t *testing.T) {
err = cdt.MiddlewareHandler.RunStream(req.Context(), &backend.RunStreamRequest{
PluginContext: pluginCtx,
Headers: map[string]string{
otherHeader: "test",
"Authorization": "secret",
"X-Grafana-Device-Id": "secret",
},
}, &backend.StreamSender{})
require.NoError(t, err)
require.NotNil(t, cdt.RunStreamReq)
require.Len(t, cdt.RunStreamReq.Headers, 1)
require.Equal(t, "test", cdt.RunStreamReq.Headers[otherHeader])
require.Empty(t, cdt.RunStreamReq.GetHTTPHeaders())
})
})
}
@@ -200,7 +200,7 @@ func CreateMiddlewares(cfg *setting.Cfg, oAuthTokenService oauthtoken.OAuthToken
middlewares = append(middlewares,
clientmiddleware.NewTracingHeaderMiddleware(),
clientmiddleware.NewClearAuthHeadersMiddleware(),
clientmiddleware.NewClearAuthHeadersMiddleware(&cfg.JWTAuth, &cfg.AuthProxy),
clientmiddleware.NewOAuthTokenMiddleware(oAuthTokenService),
clientmiddleware.NewCookiesMiddleware(skipCookiesNames),
clientmiddleware.NewCachingMiddleware(cachingServiceClient),