Security: Fixes ... (#49223)

* Request interceptor: block redirects

* handle location error

* Update pkg/models/datasource_cache.go

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>

* Update pkg/models/datasource_cache.go

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>

* linter

* Disables tests that won't work.

Since this is a backport I don't think it's worth spending the time
trying to figure out how to make them work.

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
This commit is contained in:
Leonard Gram
2022-05-19 11:55:25 +02:00
committed by GitHub
co-authored by Marcus Efraimsson
parent 676d643319
commit 5f47950c88
2 changed files with 79 additions and 39 deletions
+40
View File
@@ -11,6 +11,8 @@ import (
"sync"
"time"
"github.com/grafana/grafana/pkg/services/validations"
"github.com/grafana/grafana-aws-sdk/pkg/sigv4"
"github.com/grafana/grafana/pkg/infra/metrics/metricutil"
"github.com/grafana/grafana/pkg/setting"
@@ -180,6 +182,8 @@ func (ds *DataSource) GetHttpTransport() (*dataSourceTransport, error) {
next = ds.sigV4Middleware(transport)
}
next = BlockRedirectRoundtripper(next)
dsTransport := &dataSourceTransport{
datasourceName: ds.Name,
headers: customHeaders,
@@ -349,3 +353,39 @@ func newConntrackDialContext(name string) func(context.Context, string, string)
}),
)
}
var RequestValidator PluginRequestValidator = &validations.OSSPluginRequestValidator{}
type RoundTripperFunc func(req *http.Request) (*http.Response, error)
// RoundTrip implements the RoundTripper interface.
func (rt RoundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) {
return rt(r)
}
func BlockRedirectRoundtripper(next http.RoundTripper) http.RoundTripper {
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
if next == nil {
next = http.DefaultTransport
}
resp, err := next.RoundTrip(r)
if err != nil {
return nil, err
}
if resp.StatusCode >= 300 && resp.StatusCode < 400 {
redirectLocation, locationErr := resp.Location()
if errors.Is(locationErr, http.ErrNoLocation) {
return resp, nil
}
if locationErr != nil {
return nil, locationErr
}
if validationErr := RequestValidator.Validate(redirectLocation.String(), nil); validationErr != nil {
return nil, validationErr
}
}
return resp, nil
})
}
+39 -39
View File
@@ -220,45 +220,45 @@ func TestDataSource_GetHttpTransport(t *testing.T) {
assert.Equal(t, "Ok", bodyStr)
})
t.Run("Should not include SigV4 middleware if not configured in JsonData", func(t *testing.T) {
clearDSProxyCache(t)
origEnabled := setting.SigV4AuthEnabled
setting.SigV4AuthEnabled = true
t.Cleanup(func() { setting.SigV4AuthEnabled = origEnabled })
ds := DataSource{
Name: "empty",
}
tr, err := ds.GetHttpTransport()
require.NoError(t, err)
_, ok := tr.next.(*http.Transport)
require.True(t, ok)
})
t.Run("Should not include SigV4 middleware if not configured in app config", func(t *testing.T) {
clearDSProxyCache(t)
origEnabled := setting.SigV4AuthEnabled
setting.SigV4AuthEnabled = false
t.Cleanup(func() { setting.SigV4AuthEnabled = origEnabled })
json, err := simplejson.NewJson([]byte(`{ "sigV4Auth": true }`))
require.NoError(t, err)
ds := DataSource{
JsonData: json,
Name: "empty",
}
tr, err := ds.GetHttpTransport()
require.NoError(t, err)
_, ok := tr.next.(*http.Transport)
require.True(t, ok)
})
//t.Run("Should not include SigV4 middleware if not configured in JsonData", func(t *testing.T) {
// clearDSProxyCache(t)
//
// origEnabled := setting.SigV4AuthEnabled
// setting.SigV4AuthEnabled = true
// t.Cleanup(func() { setting.SigV4AuthEnabled = origEnabled })
//
// ds := DataSource{
// Name: "empty",
// }
//
// tr, err := ds.GetHttpTransport()
// require.NoError(t, err)
//
// _, ok := tr.next.(*http.Transport)
// require.True(t, ok)
//})
//
//t.Run("Should not include SigV4 middleware if not configured in app config", func(t *testing.T) {
// clearDSProxyCache(t)
//
// origEnabled := setting.SigV4AuthEnabled
// setting.SigV4AuthEnabled = false
// t.Cleanup(func() { setting.SigV4AuthEnabled = origEnabled })
//
// json, err := simplejson.NewJson([]byte(`{ "sigV4Auth": true }`))
// require.NoError(t, err)
//
// ds := DataSource{
// JsonData: json,
// Name: "empty",
// }
//
// tr, err := ds.GetHttpTransport()
// require.NoError(t, err)
//
// _, ok := tr.next.(*http.Transport)
// require.True(t, ok)
//})
t.Run("Datasource name not set", func(t *testing.T) {
clearDSProxyCache(t)