mirror of https://github.com/grafana/grafana.git
				
				
				
			Team LBAC: Add permission check for Update datasource (#77709)
* add permission check for updating the LBAC Rules * permission scoped for id in the updating datasource * fixed test to cover for permissions * fix proper check for permissions and empty teamHTTPHeader requests * check for jsondata * check nil for jsondata inside the getEncodedString
This commit is contained in:
		
							parent
							
								
									a39242890e
								
							
						
					
					
						commit
						c13fd62b16
					
				|  | @ -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) | ||||
|  |  | |||
|  | @ -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) | ||||
| 			})) | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue