diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index 028ef7cccbe..c0d12237812 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -20,6 +20,7 @@ import ( "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/log" + ac "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/auth/identity" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/datasources" @@ -409,6 +410,11 @@ func validateLBACHeader(headervalue string) bool { return err == nil } +func evaluateTeamHTTPHeaderPermissions(hs *HTTPServer, c *contextmodel.ReqContext, scope string) (bool, error) { + ev := ac.EvalPermission(datasources.ActionPermissionsWrite, ac.Scope(scope)) + return hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, ev) +} + // swagger:route POST /datasources datasources addDataSource // // Create a data source. @@ -446,6 +452,7 @@ func (hs *HTTPServer) AddDataSource(c *contextmodel.ReqContext) response.Respons return resp } } + if err := validateJSONData(c.Req.Context(), cmd.JsonData, hs.Cfg, hs.Features); err != nil { return response.Error(http.StatusBadRequest, "Failed to add datasource", err) } @@ -514,7 +521,6 @@ func (hs *HTTPServer) UpdateDataSourceByID(c *contextmodel.ReqContext) response. if err := validateJSONData(c.Req.Context(), cmd.JsonData, hs.Cfg, hs.Features); err != nil { return response.Error(http.StatusBadRequest, "Failed to update datasource", err) } - ds, err := hs.getRawDataSourceById(c.Req.Context(), cmd.ID, cmd.OrgID) if err != nil { if errors.Is(err, datasources.ErrDataSourceNotFound) { @@ -522,6 +528,13 @@ func (hs *HTTPServer) UpdateDataSourceByID(c *contextmodel.ReqContext) response. } return response.Error(500, "Failed to update datasource", err) } + + // check if LBAC rules have been modified + hasAccess, errAccess := checkTeamHTTPHeaderPermissions(hs, c, ds, cmd) + if !hasAccess { + return response.Error(http.StatusForbidden, fmt.Sprintf("You'll need additional permissions to perform this action. Permissions needed: %s", datasources.ActionPermissionsWrite), errAccess) + } + return hs.updateDataSourceByID(c, ds, cmd) } @@ -563,9 +576,37 @@ func (hs *HTTPServer) UpdateDataSourceByUID(c *contextmodel.ReqContext) response return response.Error(http.StatusInternalServerError, "Failed to update datasource", err) } cmd.ID = ds.ID + + // check if LBAC rules have been modified + hasAccess, errAccess := checkTeamHTTPHeaderPermissions(hs, c, ds, cmd) + if !hasAccess { + return response.Error(http.StatusForbidden, fmt.Sprintf("You'll need additional permissions to perform this action. Permissions needed: %s", datasources.ActionPermissionsWrite), errAccess) + } + return hs.updateDataSourceByID(c, ds, cmd) } +func getEncodedString(jsonData *simplejson.Json, key string) string { + if jsonData == nil { + return "" + } + jsonValues, exists := jsonData.CheckGet(key) + if !exists { + return "" + } + val, _ := jsonValues.Encode() + return string(val) +} + +func checkTeamHTTPHeaderPermissions(hs *HTTPServer, c *contextmodel.ReqContext, ds *datasources.DataSource, cmd datasources.UpdateDataSourceCommand) (bool, error) { + currentTeamHTTPHeaders := getEncodedString(ds.JsonData, "teamHttpHeaders") + newTeamHTTPHeaders := getEncodedString(cmd.JsonData, "teamHttpHeaders") + if (currentTeamHTTPHeaders != "" || newTeamHTTPHeaders != "") && currentTeamHTTPHeaders != newTeamHTTPHeaders { + return evaluateTeamHTTPHeaderPermissions(hs, c, datasources.ScopePrefix+ds.UID) + } + return true, nil +} + func (hs *HTTPServer) updateDataSourceByID(c *contextmodel.ReqContext, ds *datasources.DataSource, cmd datasources.UpdateDataSourceCommand) response.Response { if ds.ReadOnly { return response.Error(403, "Cannot update read-only data source", nil) diff --git a/pkg/api/datasources_test.go b/pkg/api/datasources_test.go index 9599e33505c..2fc4f59d458 100644 --- a/pkg/api/datasources_test.go +++ b/pkg/api/datasources_test.go @@ -286,6 +286,10 @@ func TestUpdateDataSourceTeamHTTPHeaders_InvalidJSONData(t *testing.T) { Cfg: setting.NewCfg(), Features: featuremgmt.WithFeatures(featuremgmt.FlagTeamHttpHeaders), accesscontrolService: actest.FakeService{}, + AccessControl: actest.FakeAccessControl{ + ExpectedEvaluate: true, + ExpectedErr: nil, + }, } sc := setupScenarioContext(t, fmt.Sprintf("/api/datasources/%s", tenantID)) hs.Cfg.AuthProxyEnabled = true @@ -300,7 +304,9 @@ func TestUpdateDataSourceTeamHTTPHeaders_InvalidJSONData(t *testing.T) { Type: "test", JsonData: jsonData, }) - c.SignedInUser = authedUserWithPermissions(1, 1, []ac.Permission{}) + c.SignedInUser = authedUserWithPermissions(1, 1, []ac.Permission{ + {Action: datasources.ActionPermissionsWrite, Scope: datasources.ScopeAll}, + }) return hs.AddDataSource(c) }))