check that the user has RBAC permissions to save dashboard annotation (#47882)

This commit is contained in:
Ieva 2022-04-20 08:43:42 +01:00 committed by GitHub
parent 39d3c8afd7
commit 1588cd393a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 54 deletions

View File

@ -64,22 +64,7 @@ func (hs *HTTPServer) PostAnnotation(c *models.ReqContext) response.Response {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
var canSave bool
var err error
if cmd.DashboardId != 0 {
canSave, err = canSaveDashboardAnnotation(c, cmd.DashboardId)
} else { // organization annotations
if !hs.Features.IsEnabled(featuremgmt.FlagAccesscontrol) {
canSave = canSaveOrganizationAnnotation(c)
} else {
// This is an additional validation needed only for FGAC Organization Annotations.
// It is not possible to do it in the middleware because we need to look
// into the request to determine if this is a Organization annotation or not
canSave, err = hs.canCreateOrganizationAnnotation(c)
}
}
if err != nil || !canSave {
if canSave, err := hs.canCreateAnnotation(c, cmd.DashboardId); err != nil || !canSave {
return dashboardGuardianResponse(err)
}
@ -198,16 +183,7 @@ func (hs *HTTPServer) UpdateAnnotation(c *models.ReqContext) response.Response {
return resp
}
canSave := true
if annotation.GetType() == annotations.Dashboard {
canSave, err = canSaveDashboardAnnotation(c, annotation.DashboardId)
} else {
if !hs.Features.IsEnabled(featuremgmt.FlagAccesscontrol) {
canSave = canSaveOrganizationAnnotation(c)
}
}
if err != nil || !canSave {
if canSave, err := hs.canSaveAnnotation(c, annotation); err != nil || !canSave {
return dashboardGuardianResponse(err)
}
@ -245,15 +221,7 @@ func (hs *HTTPServer) PatchAnnotation(c *models.ReqContext) response.Response {
return resp
}
canSave := true
if annotation.GetType() == annotations.Dashboard {
canSave, err = canSaveDashboardAnnotation(c, annotation.DashboardId)
} else {
if !hs.Features.IsEnabled(featuremgmt.FlagAccesscontrol) {
canSave = canSaveOrganizationAnnotation(c)
}
}
if err != nil || !canSave {
if canSave, err := hs.canSaveAnnotation(c, annotation); err != nil || !canSave {
return dashboardGuardianResponse(err)
}
@ -364,16 +332,7 @@ func (hs *HTTPServer) DeleteAnnotationByID(c *models.ReqContext) response.Respon
return resp
}
canSave := true
if annotation.GetType() == annotations.Dashboard {
canSave, err = canSaveDashboardAnnotation(c, annotation.DashboardId)
} else {
if !hs.Features.IsEnabled(featuremgmt.FlagAccesscontrol) {
canSave = canSaveOrganizationAnnotation(c)
}
}
if err != nil || !canSave {
if canSave, err := hs.canSaveAnnotation(c, annotation); err != nil || !canSave {
return dashboardGuardianResponse(err)
}
@ -388,7 +347,18 @@ func (hs *HTTPServer) DeleteAnnotationByID(c *models.ReqContext) response.Respon
return response.Success("Annotation deleted")
}
func canSaveDashboardAnnotation(c *models.ReqContext, dashboardID int64) (bool, error) {
func (hs *HTTPServer) canSaveAnnotation(c *models.ReqContext, annotation *annotations.ItemDTO) (bool, error) {
if annotation.GetType() == annotations.Dashboard {
return canEditDashboard(c, annotation.DashboardId)
} else {
if !hs.Features.IsEnabled(featuremgmt.FlagAccesscontrol) {
return c.SignedInUser.HasRole(models.ROLE_EDITOR), nil
}
return true, nil
}
}
func canEditDashboard(c *models.ReqContext, dashboardID int64) (bool, error) {
guard := guardian.New(c.Req.Context(), dashboardID, c.OrgId, c.SignedInUser)
if canEdit, err := guard.CanEdit(); err != nil || !canEdit {
return false, err
@ -397,10 +367,6 @@ func canSaveDashboardAnnotation(c *models.ReqContext, dashboardID int64) (bool,
return true, nil
}
func canSaveOrganizationAnnotation(c *models.ReqContext) bool {
return c.SignedInUser.HasRole(models.ROLE_EDITOR)
}
func findAnnotationByID(ctx context.Context, repo annotations.Repository, annotationID int64, user *models.SignedInUser) (*annotations.ItemDTO, response.Response) {
query := &annotations.ItemQuery{
AnnotationId: annotationID,
@ -478,9 +444,23 @@ func AnnotationTypeScopeResolver() (string, accesscontrol.AttributeScopeResolveF
return accesscontrol.ScopeAnnotationsProvider.GetResourceScope(""), annotationTypeResolver
}
func (hs *HTTPServer) canCreateOrganizationAnnotation(c *models.ReqContext) (bool, error) {
evaluator := accesscontrol.EvalPermission(accesscontrol.ActionAnnotationsCreate, accesscontrol.ScopeAnnotationsTypeOrganization)
return hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, evaluator)
func (hs *HTTPServer) canCreateAnnotation(c *models.ReqContext, dashboardId int64) (bool, error) {
if dashboardId != 0 {
if hs.Features.IsEnabled(featuremgmt.FlagAccesscontrol) {
evaluator := accesscontrol.EvalPermission(accesscontrol.ActionAnnotationsCreate, accesscontrol.ScopeAnnotationsTypeDashboard)
if canSave, err := hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, evaluator); err != nil || !canSave {
return canSave, err
}
}
return canEditDashboard(c, dashboardId)
} else { // organization annotations
if hs.Features.IsEnabled(featuremgmt.FlagAccesscontrol) {
evaluator := accesscontrol.EvalPermission(accesscontrol.ActionAnnotationsCreate, accesscontrol.ScopeAnnotationsTypeOrganization)
return hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, evaluator)
} else {
return c.SignedInUser.HasRole(models.ROLE_EDITOR), nil
}
}
}
func (hs *HTTPServer) canMassDeleteAnnotations(c *models.ReqContext, dashboardID int64) (bool, error) {
@ -494,7 +474,7 @@ func (hs *HTTPServer) canMassDeleteAnnotations(c *models.ReqContext, dashboardID
return false, err
}
canSave, err = canSaveDashboardAnnotation(c, dashboardID)
canSave, err = canEditDashboard(c, dashboardID)
if err != nil || !canSave {
return false, err
}

View File

@ -615,6 +615,18 @@ func TestAPI_Annotations_AccessControl(t *testing.T) {
},
want: http.StatusForbidden,
},
{
name: "AccessControl create dashboard annotation with incorrect permissions is forbidden",
args: args{
permissions: []*accesscontrol.Permission{{
Action: accesscontrol.ActionAnnotationsCreate, Scope: accesscontrol.ScopeAnnotationsTypeOrganization,
}},
url: "/api/annotations",
method: http.MethodPost,
body: mockRequestBody(postDashboardCmd),
},
want: http.StatusForbidden,
},
{
name: "AccessControl create organization annotation with permissions is allowed",
args: args{