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
pull/44092/head
Karl Persson 3 years ago committed by GitHub
parent f763be8f0f
commit f75e4d1a4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      pkg/api/api.go
  2. 58
      pkg/api/datasources.go
  3. 17
      pkg/api/frontendsettings.go
  4. 1
      pkg/api/roles.go

@ -266,15 +266,15 @@ func (hs *HTTPServer) registerRoutes() {
// Data sources
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.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("/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.Get("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead, ScopeDatasourceID)), routing.Wrap(hs.GetDataSourceById))
datasourceRoute.Get("/uid/:uid", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead, ScopeDatasourceUID)), routing.Wrap(hs.GetDataSourceByUID))
datasourceRoute.Get("/name/:name", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead, ScopeDatasourceName)), routing.Wrap(GetDataSourceByName))
datasourceRoute.Get("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead)), routing.Wrap(hs.GetDataSourceById))
datasourceRoute.Get("/uid/:uid", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead)), routing.Wrap(hs.GetDataSourceByUID))
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))

@ -31,8 +31,13 @@ func (hs *HTTPServer) GetDataSources(c *models.ReqContext) response.Response {
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)
for _, ds := range query.Result {
for _, ds := range filtered {
dsItem := dtos.DataSourceListItemDTO{
OrgId: ds.OrgId,
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)
}
ds := query.Result
dtos := convertModelToDtos(ds)
filtered, err := filterDatasourcesByQueryPermission(c.Req.Context(), c.SignedInUser, []*models.DataSource{query.Result})
if err != nil || len(filtered) != 1 {
return response.Error(404, "Data source not found", err)
}
dto := convertModelToDtos(filtered[0])
// Add accesscontrol metadata
metadata, err := hs.getDataSourceAccessControlMetadata(c, ds.Id)
metadata, err := hs.getDataSourceAccessControlMetadata(c, dto.Id)
if err != nil {
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 {
@ -160,16 +168,21 @@ func (hs *HTTPServer) GetDataSourceByUID(c *models.ReqContext) response.Response
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
metadata, err := hs.getDataSourceAccessControlMetadata(c, ds.Id)
metadata, err := hs.getDataSourceAccessControlMetadata(c, dto.Id)
if err != nil {
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
@ -397,8 +410,13 @@ func GetDataSourceByName(c *models.ReqContext) response.Response {
return response.Error(500, "Failed to query datasources", err)
}
dtos := convertModelToDtos(query.Result)
return response.JSON(200, &dtos)
filtered, err := filterDatasourcesByQueryPermission(c.Req.Context(), c.SignedInUser, []*models.DataSource{query.Result})
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
@ -549,3 +567,19 @@ func (hs *HTTPServer) decryptSecureJsonDataFn() func(map[string][]byte) map[stri
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 (
"context"
"errors"
"strconv"
"github.com/grafana/grafana/pkg/bus"
@ -25,20 +24,12 @@ func (hs *HTTPServer) getFSDataSources(c *models.ReqContext, enabledPlugins Enab
return nil, err
}
dsFilterQuery := models.DatasourcesPermissionFilterQuery{
User: c.SignedInUser,
Datasources: query.Result,
filtered, err := filterDatasourcesByQueryPermission(c.Req.Context(), c.SignedInUser, query.Result)
if err != nil {
return nil, err
}
if err := bus.Dispatch(c.Req.Context(), &dsFilterQuery); err != nil {
if !errors.Is(err, bus.ErrHandlerNotFound) {
return nil, err
}
orgDataSources = query.Result
} else {
orgDataSources = dsFilterQuery.Result
}
orgDataSources = filtered
}
dataSources := make(map[string]plugins.DataSourceDTO)

@ -134,6 +134,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
Group: "Infrequently used",
Permissions: []accesscontrol.Permission{
{Action: ActionDatasourcesQuery},
{Action: ActionDatasourcesRead},
},
},
Grants: []string{string(models.ROLE_VIEWER)},

Loading…
Cancel
Save