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 // 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)},

Loading…
Cancel
Save