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:
co-authored by
Ieva
Emil Tullstedt
parent
2648fcb833
commit
988a120d6d
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user