Search v1: Add support for inherited folder permissions if nested folders are enabled (#63275)

* Add features dependency to SQLBuilder

* Add features dependency to AccessControlDashboardPermissionFilter

* Add test for folder inheritance

* Dashboard permissions: Return recursive query

* Recursive query for inherited folders

* Modify search builder

* Adjust db.SQLBuilder

* Pass flag to SQLbuilder if CTEs are supported

* Add support for mysql < 8.0

* Add benchmarking for search with nested folders

* Set features to AlertStore

* Update pkg/infra/db/sqlbuilder.go

Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>

* Set features to LibraryElementService

* SQLBuilder tests with nested folder flag set

* Apply suggestion from code review

Co-authored-by: IevaVasiljeva <ieva.vasiljeva@grafana.com>
Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>
This commit is contained in:
Sofia Papagiannaki
2023-04-06 11:16:15 +03:00
committed by GitHub
co-authored by Ieva Emil Tullstedt
parent 2648fcb833
commit 988a120d6d
24 changed files with 1487 additions and 105 deletions
@@ -13,6 +13,7 @@ import (
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/permissions"
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
@@ -42,6 +43,7 @@ func validateTimeRange(item *annotations.Item) error {
type xormRepositoryImpl struct {
cfg *setting.Cfg
features featuremgmt.FeatureToggles
db db.DB
log log.Logger
maximumTagsLength int64
@@ -299,13 +301,15 @@ func (r *xormRepositoryImpl) Get(ctx context.Context, query *annotations.ItemQue
}
}
var acFilter acFilter
if !ac.IsDisabled(r.cfg) {
acFilter, acArgs, err := getAccessControlFilter(query.SignedInUser)
var err error
acFilter, err = r.getAccessControlFilter(query.SignedInUser)
if err != nil {
return err
}
sql.WriteString(fmt.Sprintf(" AND (%s)", acFilter))
params = append(params, acArgs...)
sql.WriteString(fmt.Sprintf(" AND (%s)", acFilter.where))
params = append(params, acFilter.whereParams...)
}
if query.Limit == 0 {
@@ -314,6 +318,14 @@ func (r *xormRepositoryImpl) Get(ctx context.Context, query *annotations.ItemQue
// order of ORDER BY arguments match the order of a sql index for performance
sql.WriteString(" ORDER BY a.org_id, a.epoch_end DESC, a.epoch DESC" + r.db.GetDialect().Limit(query.Limit) + " ) dt on dt.id = annotation.id")
if acFilter.recQueries != "" {
var sb bytes.Buffer
sb.WriteString(acFilter.recQueries)
sb.WriteString(sql.String())
sql = sb
params = append(acFilter.recParams, params...)
}
if err := sess.SQL(sql.String(), params...).Find(&items); err != nil {
items = nil
return err
@@ -325,13 +337,23 @@ func (r *xormRepositoryImpl) Get(ctx context.Context, query *annotations.ItemQue
return items, err
}
func getAccessControlFilter(user *user.SignedInUser) (string, []interface{}, error) {
type acFilter struct {
where string
whereParams []interface{}
recQueries string
recParams []interface{}
}
func (r *xormRepositoryImpl) getAccessControlFilter(user *user.SignedInUser) (acFilter, error) {
var recQueries string
var recQueriesParams []interface{}
if user == nil || user.Permissions[user.OrgID] == nil {
return "", nil, errors.New("missing permissions")
return acFilter{}, errors.New("missing permissions")
}
scopes, has := user.Permissions[user.OrgID][ac.ActionAnnotationsRead]
if !has {
return "", nil, errors.New("missing permissions")
return acFilter{}, errors.New("missing permissions")
}
types, hasWildcardScope := ac.ParseScopes(ac.ScopeAnnotationsProvider.GetResourceScopeType(""), scopes)
if hasWildcardScope {
@@ -347,13 +369,27 @@ func getAccessControlFilter(user *user.SignedInUser) (string, []interface{}, err
}
// annotation read permission with scope annotations:type:dashboard allows listing annotations from dashboards which the user can view
if t == annotations.Dashboard.String() {
dashboardFilter, dashboardParams := permissions.NewAccessControlDashboardPermissionFilter(user, dashboards.PERMISSION_VIEW, searchstore.TypeDashboard).Where()
recursiveQueriesAreSupported, err := r.db.RecursiveQueriesAreSupported()
if err != nil {
return acFilter{}, err
}
filterRBAC := permissions.NewAccessControlDashboardPermissionFilter(user, dashboards.PERMISSION_VIEW, searchstore.TypeDashboard, r.features, recursiveQueriesAreSupported)
dashboardFilter, dashboardParams := filterRBAC.Where()
recQueries, recQueriesParams = filterRBAC.With()
filter := fmt.Sprintf("a.dashboard_id IN(SELECT id FROM dashboard WHERE %s)", dashboardFilter)
filters = append(filters, filter)
params = dashboardParams
}
}
return strings.Join(filters, " OR "), params, nil
f := acFilter{
where: strings.Join(filters, " OR "),
whereParams: params,
recQueries: recQueries,
recParams: recQueriesParams,
}
return f, nil
}
func (r *xormRepositoryImpl) Delete(ctx context.Context, params *annotations.DeleteParams) error {