Alerting: Change getEvaluatorForAlertRule to checkDatasourcePermissionsForRule (#46887)

update method getEvaluatorForAlertRule to accept permissions evaluator and exit on the first negative result, which is more effective than returning an evaluator that in fact is a bunch of slices.
This commit is contained in:
Yuriy Tseretyan
2022-03-23 13:11:30 -04:00
committed by GitHub
parent 78c23d8dab
commit acd7be1cb4
2 changed files with 51 additions and 29 deletions

View File

@@ -172,16 +172,17 @@ func (api *API) authorize(method, path string) web.Handler {
panic(fmt.Sprintf("no authorization handler for method [%s] of endpoint [%s]", method, path))
}
// GetDatasourceScopesFromAlertRule extracts data source scopes from an alert rule
func getEvaluatorForAlertRule(rule *ngmodels.AlertRule) ac.Evaluator {
scopes := make([]ac.Evaluator, 0, len(rule.Data))
// authorizeDatasourceAccessForRule checks that user has access to all data sources declared by the rule
func authorizeDatasourceAccessForRule(rule *ngmodels.AlertRule, evaluator func(evaluator ac.Evaluator) bool) bool {
for _, query := range rule.Data {
if query.QueryType == expr.DatasourceType || query.DatasourceUID == expr.OldDatasourceUID {
continue
}
scopes = append(scopes, ac.EvalPermission(datasources.ActionQuery, dashboards.ScopeFoldersProvider.GetResourceScopeUID(query.DatasourceUID)))
if !evaluator(ac.EvalPermission(datasources.ActionQuery, dashboards.ScopeFoldersProvider.GetResourceScopeUID(query.DatasourceUID))) {
return false
}
}
return ac.EvalAll(scopes...)
return true
}
// authorizeRuleChanges analyzes changes in the rule group, determines what actions the user is trying to perform and check whether those actions are authorized.
@@ -203,7 +204,7 @@ func authorizeRuleChanges(namespace *models.Folder, changes *changes, evaluator
return fmt.Errorf("%w user cannot create alert rules in the folder %s", ErrAuthorization, namespace.Title)
}
for _, rule := range changes.New {
dsAllowed := evaluator(getEvaluatorForAlertRule(rule))
dsAllowed := authorizeDatasourceAccessForRule(rule, evaluator)
if !dsAllowed {
return fmt.Errorf("%w to create a new alert rule '%s' because the user does not have read permissions for one or many datasources the rule uses", ErrAuthorization, rule.Title)
}
@@ -211,7 +212,7 @@ func authorizeRuleChanges(namespace *models.Folder, changes *changes, evaluator
}
for _, rule := range changes.Update {
dsAllowed := evaluator(getEvaluatorForAlertRule(rule.New))
dsAllowed := authorizeDatasourceAccessForRule(rule.New, evaluator)
if !dsAllowed {
return fmt.Errorf("%w to update alert rule '%s' (UID: %s) because the user does not have read permissions for one or many datasources the rule uses", ErrAuthorization, rule.Existing.Title, rule.Existing.UID)
}