Team LBAC: Refactor to use only the teamHeader json part (#76756)

* refactor: to check for feature toggle and for checking for jsonData field

* fix tests

* whitelisting of X-Prom-Label-Policy Header
This commit is contained in:
Eric Leijonmarck
2023-10-18 16:09:22 +01:00
committed by GitHub
parent 756df61a88
commit 17fe1d3fc7
4 changed files with 30 additions and 55 deletions

View File

@@ -18,9 +18,9 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/contexthandler"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
@@ -334,7 +334,7 @@ func validateURL(cmdType string, url string) response.Response {
// validateJSONData prevents the user from adding a custom header with name that matches the auth proxy header name.
// This is done to prevent data source proxy from being used to circumvent auth proxy.
// For more context take a look at CVE-2022-35957
func validateJSONData(ctx context.Context, jsonData *simplejson.Json, cfg *setting.Cfg) error {
func validateJSONData(ctx context.Context, jsonData *simplejson.Json, cfg *setting.Cfg, features *featuremgmt.FeatureManager) error {
if jsonData == nil || !cfg.AuthProxyEnabled {
return nil
}
@@ -350,25 +350,19 @@ func validateJSONData(ctx context.Context, jsonData *simplejson.Json, cfg *setti
}
// Prevent adding a data source team header with a name that matches the auth proxy header name
list := contexthandler.AuthHTTPHeaderListFromContext(ctx)
if list == nil {
return nil
}
teamHTTPHeadersJSON := datasources.TeamHTTPHeadersJSONData{}
if jsonData != nil {
jsonData, err := jsonData.MarshalJSON()
if features.IsEnabled(featuremgmt.FlagTeamHttpHeaders) {
teamHTTPHeadersJSON, err := datasources.GetTeamHTTPHeaders(jsonData)
if err != nil {
return err
datasourcesLogger.Error("Unable to marshal TeamHTTPHeaders")
return errors.New("validation error, invalid format of TeamHTTPHeaders")
}
err = json.Unmarshal(jsonData, &teamHTTPHeadersJSON)
if err != nil {
return err
}
for _, headers := range teamHTTPHeadersJSON.TeamHTTPHeaders {
// whitelisting X-Prom-Label-Policy
for _, headers := range teamHTTPHeadersJSON {
for _, header := range headers {
for _, name := range list.Items {
if http.CanonicalHeaderKey(header.Header) == http.CanonicalHeaderKey(name) {
datasourcesLogger.Error("Cannot add a data source team header with a used by our proxy header", "headerName", header.Header)
// TODO: currently we only allow for X-Prom-Label-Policy header to be used by our proxy
for _, name := range []string{"X-Prom-Label-Policy"} {
if http.CanonicalHeaderKey(header.Header) != http.CanonicalHeaderKey(name) {
datasourcesLogger.Error("Cannot add a data source team header that is different than", "headerName", name)
return errors.New("validation error, invalid header name specified")
}
}
@@ -416,7 +410,7 @@ func (hs *HTTPServer) AddDataSource(c *contextmodel.ReqContext) response.Respons
return resp
}
}
if err := validateJSONData(c.Req.Context(), cmd.JsonData, hs.Cfg); err != nil {
if err := validateJSONData(c.Req.Context(), cmd.JsonData, hs.Cfg, hs.Features); err != nil {
return response.Error(http.StatusBadRequest, "Failed to add datasource", err)
}
@@ -481,7 +475,7 @@ func (hs *HTTPServer) UpdateDataSourceByID(c *contextmodel.ReqContext) response.
if resp := validateURL(cmd.Type, cmd.URL); resp != nil {
return resp
}
if err := validateJSONData(c.Req.Context(), cmd.JsonData, hs.Cfg); err != nil {
if err := validateJSONData(c.Req.Context(), cmd.JsonData, hs.Cfg, hs.Features); err != nil {
return response.Error(http.StatusBadRequest, "Failed to update datasource", err)
}
@@ -521,7 +515,7 @@ func (hs *HTTPServer) UpdateDataSourceByUID(c *contextmodel.ReqContext) response
if resp := validateURL(cmd.Type, cmd.URL); resp != nil {
return resp
}
if err := validateJSONData(c.Req.Context(), cmd.JsonData, hs.Cfg); err != nil {
if err := validateJSONData(c.Req.Context(), cmd.JsonData, hs.Cfg, hs.Features); err != nil {
return response.Error(http.StatusBadRequest, "Failed to update datasource", err)
}

View File

@@ -21,6 +21,7 @@ import (
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/datasources/guardian"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web"
@@ -226,6 +227,7 @@ func TestUpdateDataSourceTeamHTTPHeaders_InvalidJSONData(t *testing.T) {
hs := &HTTPServer{
DataSourcesService: &dataSourcesServiceMock{},
Cfg: setting.NewCfg(),
Features: featuremgmt.WithFeatures(featuremgmt.FlagTeamHttpHeaders),
}
sc := setupScenarioContext(t, "/api/datasources/1234")
@@ -243,7 +245,7 @@ func TestUpdateDataSourceTeamHTTPHeaders_InvalidJSONData(t *testing.T) {
hs.Cfg.AuthProxyEnabled = true
jsonData := simplejson.New()
jsonData.Set("teamHTTPHeaders", data)
jsonData.Set("teamHttpHeaders", data)
sc.m.Put(sc.url, routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
c.Req.Body = mockRequestBody(datasources.AddDataSourceCommand{