mirror of
https://github.com/grafana/grafana.git
synced 2025-07-30 02:22:43 +08:00
Access Control: Allow signed in users access to GET data sources endpoints (#43338)
* remove scopes from endpoints and add datasources:read without scope to the compatibility role
This commit is contained in:
@ -266,15 +266,15 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
|
|
||||||
// Data sources
|
// Data sources
|
||||||
apiRoute.Group("/datasources", func(datasourceRoute routing.RouteRegister) {
|
apiRoute.Group("/datasources", func(datasourceRoute routing.RouteRegister) {
|
||||||
datasourceRoute.Get("/", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead, ScopeDatasourcesAll)), routing.Wrap(hs.GetDataSources))
|
datasourceRoute.Get("/", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead)), routing.Wrap(hs.GetDataSources))
|
||||||
datasourceRoute.Post("/", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesCreate)), quota("data_source"), routing.Wrap(AddDataSource))
|
datasourceRoute.Post("/", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesCreate)), quota("data_source"), routing.Wrap(AddDataSource))
|
||||||
datasourceRoute.Put("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesWrite, ScopeDatasourceID)), routing.Wrap(hs.UpdateDataSource))
|
datasourceRoute.Put("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesWrite, ScopeDatasourceID)), routing.Wrap(hs.UpdateDataSource))
|
||||||
datasourceRoute.Delete("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesDelete, ScopeDatasourceID)), routing.Wrap(hs.DeleteDataSourceById))
|
datasourceRoute.Delete("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesDelete, ScopeDatasourceID)), routing.Wrap(hs.DeleteDataSourceById))
|
||||||
datasourceRoute.Delete("/uid/:uid", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesDelete, ScopeDatasourceUID)), routing.Wrap(hs.DeleteDataSourceByUID))
|
datasourceRoute.Delete("/uid/:uid", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesDelete, ScopeDatasourceUID)), routing.Wrap(hs.DeleteDataSourceByUID))
|
||||||
datasourceRoute.Delete("/name/:name", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesDelete, ScopeDatasourceName)), routing.Wrap(hs.DeleteDataSourceByName))
|
datasourceRoute.Delete("/name/:name", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesDelete, ScopeDatasourceName)), routing.Wrap(hs.DeleteDataSourceByName))
|
||||||
datasourceRoute.Get("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead, ScopeDatasourceID)), routing.Wrap(hs.GetDataSourceById))
|
datasourceRoute.Get("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead)), routing.Wrap(hs.GetDataSourceById))
|
||||||
datasourceRoute.Get("/uid/:uid", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead, ScopeDatasourceUID)), routing.Wrap(hs.GetDataSourceByUID))
|
datasourceRoute.Get("/uid/:uid", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead)), routing.Wrap(hs.GetDataSourceByUID))
|
||||||
datasourceRoute.Get("/name/:name", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead, ScopeDatasourceName)), routing.Wrap(GetDataSourceByName))
|
datasourceRoute.Get("/name/:name", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead)), routing.Wrap(GetDataSourceByName))
|
||||||
})
|
})
|
||||||
|
|
||||||
apiRoute.Get("/datasources/id/:name", authorize(reqSignedIn, ac.EvalPermission(ActionDatasourcesIDRead, ScopeDatasourceName)), routing.Wrap(GetDataSourceIdByName))
|
apiRoute.Get("/datasources/id/:name", authorize(reqSignedIn, ac.EvalPermission(ActionDatasourcesIDRead, ScopeDatasourceName)), routing.Wrap(GetDataSourceIdByName))
|
||||||
|
@ -31,8 +31,13 @@ func (hs *HTTPServer) GetDataSources(c *models.ReqContext) response.Response {
|
|||||||
return response.Error(500, "Failed to query datasources", err)
|
return response.Error(500, "Failed to query datasources", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filtered, err := filterDatasourcesByQueryPermission(c.Req.Context(), c.SignedInUser, query.Result)
|
||||||
|
if err != nil {
|
||||||
|
return response.Error(500, "Failed to query datasources", err)
|
||||||
|
}
|
||||||
|
|
||||||
result := make(dtos.DataSourceList, 0)
|
result := make(dtos.DataSourceList, 0)
|
||||||
for _, ds := range query.Result {
|
for _, ds := range filtered {
|
||||||
dsItem := dtos.DataSourceListItemDTO{
|
dsItem := dtos.DataSourceListItemDTO{
|
||||||
OrgId: ds.OrgId,
|
OrgId: ds.OrgId,
|
||||||
Id: ds.Id,
|
Id: ds.Id,
|
||||||
@ -102,17 +107,20 @@ func (hs *HTTPServer) GetDataSourceById(c *models.ReqContext) response.Response
|
|||||||
return response.Error(500, "Failed to query datasources", err)
|
return response.Error(500, "Failed to query datasources", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ds := query.Result
|
filtered, err := filterDatasourcesByQueryPermission(c.Req.Context(), c.SignedInUser, []*models.DataSource{query.Result})
|
||||||
dtos := convertModelToDtos(ds)
|
if err != nil || len(filtered) != 1 {
|
||||||
|
return response.Error(404, "Data source not found", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dto := convertModelToDtos(filtered[0])
|
||||||
// Add accesscontrol metadata
|
// Add accesscontrol metadata
|
||||||
metadata, err := hs.getDataSourceAccessControlMetadata(c, ds.Id)
|
metadata, err := hs.getDataSourceAccessControlMetadata(c, dto.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.Error(http.StatusInternalServerError, "Failed to query metadata", err)
|
return response.Error(http.StatusInternalServerError, "Failed to query metadata", err)
|
||||||
}
|
}
|
||||||
dtos.AccessControl = metadata
|
dto.AccessControl = metadata
|
||||||
|
|
||||||
return response.JSON(200, &dtos)
|
return response.JSON(200, &dto)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hs *HTTPServer) DeleteDataSourceById(c *models.ReqContext) response.Response {
|
func (hs *HTTPServer) DeleteDataSourceById(c *models.ReqContext) response.Response {
|
||||||
@ -160,16 +168,21 @@ func (hs *HTTPServer) GetDataSourceByUID(c *models.ReqContext) response.Response
|
|||||||
return response.Error(http.StatusInternalServerError, "Failed to query datasource", err)
|
return response.Error(http.StatusInternalServerError, "Failed to query datasource", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dtos := convertModelToDtos(ds)
|
filtered, err := filterDatasourcesByQueryPermission(c.Req.Context(), c.SignedInUser, []*models.DataSource{ds})
|
||||||
|
if err != nil || len(filtered) != 1 {
|
||||||
|
return response.Error(404, "Data source not found", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dto := convertModelToDtos(filtered[0])
|
||||||
|
|
||||||
// Add accesscontrol metadata
|
// Add accesscontrol metadata
|
||||||
metadata, err := hs.getDataSourceAccessControlMetadata(c, ds.Id)
|
metadata, err := hs.getDataSourceAccessControlMetadata(c, dto.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.Error(http.StatusInternalServerError, "Failed to query metadata", err)
|
return response.Error(http.StatusInternalServerError, "Failed to query metadata", err)
|
||||||
}
|
}
|
||||||
dtos.AccessControl = metadata
|
dto.AccessControl = metadata
|
||||||
|
|
||||||
return response.JSON(200, &dtos)
|
return response.JSON(200, &dto)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE /api/datasources/uid/:uid
|
// DELETE /api/datasources/uid/:uid
|
||||||
@ -397,8 +410,13 @@ func GetDataSourceByName(c *models.ReqContext) response.Response {
|
|||||||
return response.Error(500, "Failed to query datasources", err)
|
return response.Error(500, "Failed to query datasources", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dtos := convertModelToDtos(query.Result)
|
filtered, err := filterDatasourcesByQueryPermission(c.Req.Context(), c.SignedInUser, []*models.DataSource{query.Result})
|
||||||
return response.JSON(200, &dtos)
|
if err != nil || len(filtered) != 1 {
|
||||||
|
return response.Error(404, "Data source not found", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dto := convertModelToDtos(filtered[0])
|
||||||
|
return response.JSON(200, &dto)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get /api/datasources/id/:name
|
// Get /api/datasources/id/:name
|
||||||
@ -549,3 +567,19 @@ func (hs *HTTPServer) decryptSecureJsonDataFn() func(map[string][]byte) map[stri
|
|||||||
return decryptedJsonData
|
return decryptedJsonData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func filterDatasourcesByQueryPermission(ctx context.Context, user *models.SignedInUser, datasources []*models.DataSource) ([]*models.DataSource, error) {
|
||||||
|
query := models.DatasourcesPermissionFilterQuery{
|
||||||
|
User: user,
|
||||||
|
Datasources: datasources,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := bus.Dispatch(ctx, &query); err != nil {
|
||||||
|
if !errors.Is(err, bus.ErrHandlerNotFound) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return datasources, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return query.Datasources, nil
|
||||||
|
}
|
||||||
|
@ -2,7 +2,6 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
@ -25,20 +24,12 @@ func (hs *HTTPServer) getFSDataSources(c *models.ReqContext, enabledPlugins Enab
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dsFilterQuery := models.DatasourcesPermissionFilterQuery{
|
filtered, err := filterDatasourcesByQueryPermission(c.Req.Context(), c.SignedInUser, query.Result)
|
||||||
User: c.SignedInUser,
|
if err != nil {
|
||||||
Datasources: query.Result,
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := bus.Dispatch(c.Req.Context(), &dsFilterQuery); err != nil {
|
orgDataSources = filtered
|
||||||
if !errors.Is(err, bus.ErrHandlerNotFound) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
orgDataSources = query.Result
|
|
||||||
} else {
|
|
||||||
orgDataSources = dsFilterQuery.Result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dataSources := make(map[string]plugins.DataSourceDTO)
|
dataSources := make(map[string]plugins.DataSourceDTO)
|
||||||
|
@ -134,6 +134,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
Group: "Infrequently used",
|
Group: "Infrequently used",
|
||||||
Permissions: []accesscontrol.Permission{
|
Permissions: []accesscontrol.Permission{
|
||||||
{Action: ActionDatasourcesQuery},
|
{Action: ActionDatasourcesQuery},
|
||||||
|
{Action: ActionDatasourcesRead},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Grants: []string{string(models.ROLE_VIEWER)},
|
Grants: []string{string(models.ROLE_VIEWER)},
|
||||||
|
Reference in New Issue
Block a user