mirror of
https://github.com/grafana/grafana.git
synced 2026-08-13 06:34:55 -05:00
Access control: SQL filtering for annotation listing (#47467)
* pass in user to attribute scope resolver * add SQL filter to annotation listing * check annotation FGAC permissions before exposing them for commenting * remove the requirement to be able to list all annotations from annotation listing endpoint * adding tests for annotation listing * remove changes that got moved to a different PR * unused var * Update pkg/services/sqlstore/annotation.go Co-authored-by: Ezequiel Victorero <evictorero@gmail.com> * remove unneeded check * remove unneeded check * undo accidental change * undo accidental change * doc update * move tests * redo the approach for passing the user in for scope resolution * accidental change * cleanup * error handling Co-authored-by: Ezequiel Victorero <evictorero@gmail.com>
This commit is contained in:
co-authored by
Ezequiel Victorero
parent
4bc582570e
commit
ef4c2672b3
+37
-19
@@ -20,17 +20,18 @@ import (
|
||||
|
||||
func (hs *HTTPServer) GetAnnotations(c *models.ReqContext) response.Response {
|
||||
query := &annotations.ItemQuery{
|
||||
From: c.QueryInt64("from"),
|
||||
To: c.QueryInt64("to"),
|
||||
OrgId: c.OrgId,
|
||||
UserId: c.QueryInt64("userId"),
|
||||
AlertId: c.QueryInt64("alertId"),
|
||||
DashboardId: c.QueryInt64("dashboardId"),
|
||||
PanelId: c.QueryInt64("panelId"),
|
||||
Limit: c.QueryInt64("limit"),
|
||||
Tags: c.QueryStrings("tags"),
|
||||
Type: c.Query("type"),
|
||||
MatchAny: c.QueryBool("matchAny"),
|
||||
From: c.QueryInt64("from"),
|
||||
To: c.QueryInt64("to"),
|
||||
OrgId: c.OrgId,
|
||||
UserId: c.QueryInt64("userId"),
|
||||
AlertId: c.QueryInt64("alertId"),
|
||||
DashboardId: c.QueryInt64("dashboardId"),
|
||||
PanelId: c.QueryInt64("panelId"),
|
||||
Limit: c.QueryInt64("limit"),
|
||||
Tags: c.QueryStrings("tags"),
|
||||
Type: c.Query("type"),
|
||||
MatchAny: c.QueryBool("matchAny"),
|
||||
SignedInUser: c.SignedInUser,
|
||||
}
|
||||
|
||||
repo := annotations.GetRepository()
|
||||
@@ -192,7 +193,7 @@ func (hs *HTTPServer) UpdateAnnotation(c *models.ReqContext) response.Response {
|
||||
|
||||
repo := annotations.GetRepository()
|
||||
|
||||
annotation, resp := findAnnotationByID(c.Req.Context(), repo, annotationID, c.OrgId)
|
||||
annotation, resp := findAnnotationByID(c.Req.Context(), repo, annotationID, c.SignedInUser)
|
||||
if resp != nil {
|
||||
return resp
|
||||
}
|
||||
@@ -239,7 +240,7 @@ func (hs *HTTPServer) PatchAnnotation(c *models.ReqContext) response.Response {
|
||||
|
||||
repo := annotations.GetRepository()
|
||||
|
||||
annotation, resp := findAnnotationByID(c.Req.Context(), repo, annotationID, c.OrgId)
|
||||
annotation, resp := findAnnotationByID(c.Req.Context(), repo, annotationID, c.SignedInUser)
|
||||
if resp != nil {
|
||||
return resp
|
||||
}
|
||||
@@ -310,7 +311,7 @@ func (hs *HTTPServer) MassDeleteAnnotations(c *models.ReqContext) response.Respo
|
||||
var dashboardId int64
|
||||
|
||||
if cmd.AnnotationId != 0 {
|
||||
annotation, respErr := findAnnotationByID(c.Req.Context(), repo, cmd.AnnotationId, c.OrgId)
|
||||
annotation, respErr := findAnnotationByID(c.Req.Context(), repo, cmd.AnnotationId, c.SignedInUser)
|
||||
if respErr != nil {
|
||||
return respErr
|
||||
}
|
||||
@@ -358,7 +359,7 @@ func (hs *HTTPServer) DeleteAnnotationByID(c *models.ReqContext) response.Respon
|
||||
|
||||
repo := annotations.GetRepository()
|
||||
|
||||
annotation, resp := findAnnotationByID(c.Req.Context(), repo, annotationID, c.OrgId)
|
||||
annotation, resp := findAnnotationByID(c.Req.Context(), repo, annotationID, c.SignedInUser)
|
||||
if resp != nil {
|
||||
return resp
|
||||
}
|
||||
@@ -400,8 +401,13 @@ func canSaveOrganizationAnnotation(c *models.ReqContext) bool {
|
||||
return c.SignedInUser.HasRole(models.ROLE_EDITOR)
|
||||
}
|
||||
|
||||
func findAnnotationByID(ctx context.Context, repo annotations.Repository, annotationID int64, orgID int64) (*annotations.ItemDTO, response.Response) {
|
||||
items, err := repo.Find(ctx, &annotations.ItemQuery{AnnotationId: annotationID, OrgId: orgID})
|
||||
func findAnnotationByID(ctx context.Context, repo annotations.Repository, annotationID int64, user *models.SignedInUser) (*annotations.ItemDTO, response.Response) {
|
||||
query := &annotations.ItemQuery{
|
||||
AnnotationId: annotationID,
|
||||
OrgId: user.OrgId,
|
||||
SignedInUser: user,
|
||||
}
|
||||
items, err := repo.Find(ctx, query)
|
||||
|
||||
if err != nil {
|
||||
return nil, response.Error(500, "Failed to find annotation", err)
|
||||
@@ -446,9 +452,21 @@ func AnnotationTypeScopeResolver() (string, accesscontrol.AttributeScopeResolveF
|
||||
return "", accesscontrol.ErrInvalidScope
|
||||
}
|
||||
|
||||
annotation, resp := findAnnotationByID(ctx, annotations.GetRepository(), int64(annotationId), orgID)
|
||||
// tempUser is used to resolve annotation type.
|
||||
// The annotation doesn't get returned to the real user, so real user's permissions don't matter here.
|
||||
tempUser := &models.SignedInUser{
|
||||
OrgId: orgID,
|
||||
Permissions: map[int64]map[string][]string{
|
||||
orgID: {
|
||||
accesscontrol.ActionDashboardsRead: {accesscontrol.ScopeDashboardsAll},
|
||||
accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsAll},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
annotation, resp := findAnnotationByID(ctx, annotations.GetRepository(), int64(annotationId), tempUser)
|
||||
if resp != nil {
|
||||
return "", err
|
||||
return "", errors.New("could not resolve annotation type")
|
||||
}
|
||||
|
||||
if annotation.GetType() == annotations.Organization {
|
||||
|
||||
Reference in New Issue
Block a user