LibraryPanels: Add RBAC support (#73475)

This commit is contained in:
kay delaney
2023-10-12 00:30:50 +01:00
committed by GitHub
parent d003ffe439
commit a12cb8cbf3
16 changed files with 370 additions and 28 deletions

View File

@ -6,23 +6,38 @@ import (
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/middleware"
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/libraryelements/model"
"github.com/grafana/grafana/pkg/web"
)
func (l *LibraryElementService) registerAPIEndpoints() {
authorize := ac.Middleware(l.AccessControl)
l.RouteRegister.Group("/api/library-elements", func(entities routing.RouteRegister) {
entities.Post("/", middleware.ReqSignedIn, routing.Wrap(l.createHandler))
entities.Delete("/:uid", middleware.ReqSignedIn, routing.Wrap(l.deleteHandler))
entities.Get("/", middleware.ReqSignedIn, routing.Wrap(l.getAllHandler))
entities.Get("/:uid", middleware.ReqSignedIn, routing.Wrap(l.getHandler))
entities.Get("/:uid/connections/", middleware.ReqSignedIn, routing.Wrap(l.getConnectionsHandler))
entities.Get("/name/:name", middleware.ReqSignedIn, routing.Wrap(l.getByNameHandler))
entities.Patch("/:uid", middleware.ReqSignedIn, routing.Wrap(l.patchHandler))
uidScope := ScopeLibraryPanelsProvider.GetResourceScopeUID(ac.Parameter(":uid"))
if l.features.IsEnabled(featuremgmt.FlagLibraryPanelRBAC) {
entities.Post("/", authorize(ac.EvalPermission(ActionLibraryPanelsCreate)), routing.Wrap(l.createHandler))
entities.Delete("/:uid", authorize(ac.EvalPermission(ActionLibraryPanelsDelete, uidScope)), routing.Wrap(l.deleteHandler))
entities.Get("/", authorize(ac.EvalPermission(ActionLibraryPanelsRead)), routing.Wrap(l.getAllHandler))
entities.Get("/:uid", authorize(ac.EvalPermission(ActionLibraryPanelsRead, uidScope)), routing.Wrap(l.getHandler))
entities.Get("/:uid/connections/", authorize(ac.EvalPermission(ActionLibraryPanelsRead, uidScope)), routing.Wrap(l.getConnectionsHandler))
entities.Get("/name/:name", routing.Wrap(l.getByNameHandler))
entities.Patch("/:uid", authorize(ac.EvalPermission(ActionLibraryPanelsWrite, uidScope)), routing.Wrap(l.patchHandler))
} else {
entities.Post("/", routing.Wrap(l.createHandler))
entities.Delete("/:uid", routing.Wrap(l.deleteHandler))
entities.Get("/", routing.Wrap(l.getAllHandler))
entities.Get("/:uid", routing.Wrap(l.getHandler))
entities.Get("/:uid/connections/", routing.Wrap(l.getConnectionsHandler))
entities.Get("/name/:name", routing.Wrap(l.getByNameHandler))
entities.Patch("/:uid", routing.Wrap(l.patchHandler))
}
})
}
@ -56,7 +71,8 @@ func (l *LibraryElementService) createHandler(c *contextmodel.ReqContext) respon
cmd.FolderID = folder.ID
}
}
element, err := l.CreateElement(c.Req.Context(), c.SignedInUser, cmd)
element, err := l.createLibraryElement(c.Req.Context(), c.SignedInUser, cmd)
if err != nil {
return toLibraryElementError(err, "Failed to create library element")
}
@ -109,6 +125,7 @@ func (l *LibraryElementService) deleteHandler(c *contextmodel.ReqContext) respon
// Responses:
// 200: getLibraryElementResponse
// 401: unauthorisedError
// 403: forbiddenError
// 404: notFoundError
// 500: internalServerError
func (l *LibraryElementService) getHandler(c *contextmodel.ReqContext) response.Response {
@ -154,6 +171,14 @@ func (l *LibraryElementService) getAllHandler(c *contextmodel.ReqContext) respon
return toLibraryElementError(err, "Failed to get library elements")
}
if l.features.IsEnabled(featuremgmt.FlagLibraryPanelRBAC) {
filteredPanels, err := l.filterLibraryPanelsByPermission(c, elementsResult.Elements)
if err != nil {
return toLibraryElementError(err, "Failed to evaluate permissions")
}
elementsResult.Elements = filteredPanels
}
return response.JSON(http.StatusOK, model.LibraryElementSearchResponse{Result: elementsResult})
}
@ -216,6 +241,7 @@ func (l *LibraryElementService) patchHandler(c *contextmodel.ReqContext) respons
// Responses:
// 200: getLibraryElementConnectionsResponse
// 401: unauthorisedError
// 403: forbiddenError
// 404: notFoundError
// 500: internalServerError
func (l *LibraryElementService) getConnectionsHandler(c *contextmodel.ReqContext) response.Response {
@ -244,7 +270,31 @@ func (l *LibraryElementService) getByNameHandler(c *contextmodel.ReqContext) res
return toLibraryElementError(err, "Failed to get library element")
}
return response.JSON(http.StatusOK, model.LibraryElementArrayResponse{Result: elements})
if l.features.IsEnabled(featuremgmt.FlagLibraryPanelRBAC) {
filteredElements, err := l.filterLibraryPanelsByPermission(c, elements)
if err != nil {
return toLibraryElementError(err, err.Error())
}
return response.JSON(http.StatusOK, model.LibraryElementArrayResponse{Result: filteredElements})
} else {
return response.JSON(http.StatusOK, model.LibraryElementArrayResponse{Result: elements})
}
}
func (l *LibraryElementService) filterLibraryPanelsByPermission(c *contextmodel.ReqContext, elements []model.LibraryElementDTO) ([]model.LibraryElementDTO, error) {
filteredPanels := make([]model.LibraryElementDTO, 0)
for _, p := range elements {
allowed, err := l.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, ac.EvalPermission(ActionLibraryPanelsRead, ScopeLibraryPanelsProvider.GetResourceScopeUID(p.UID)))
if err != nil {
return nil, err
}
if allowed {
filteredPanels = append(filteredPanels, p)
}
}
return filteredPanels, nil
}
func toLibraryElementError(err error, message string) response.Response {