* Use alert:create action for folder search with edit permissions. This matches the action that is used to query dashboards (the update will be addressed later) * Update rule store to use FindDashboards instead of folder service to list folders the user has access to view alerts. Folder service does not support query type and additional filters. * Do not check whether the user can save to folder if FGAC is enabled because it is checked on API level.
139 lines
4.5 KiB
Go
139 lines
4.5 KiB
Go
package permissions
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/grafana/grafana/pkg/models"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
|
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
|
)
|
|
|
|
type DashboardPermissionFilter struct {
|
|
OrgRole models.RoleType
|
|
Dialect migrator.Dialect
|
|
UserId int64
|
|
OrgId int64
|
|
PermissionLevel models.PermissionType
|
|
}
|
|
|
|
func (d DashboardPermissionFilter) Where() (string, []interface{}) {
|
|
if d.OrgRole == models.ROLE_ADMIN {
|
|
return "", nil
|
|
}
|
|
|
|
okRoles := []interface{}{d.OrgRole}
|
|
if d.OrgRole == models.ROLE_EDITOR {
|
|
okRoles = append(okRoles, models.ROLE_VIEWER)
|
|
}
|
|
|
|
falseStr := d.Dialect.BooleanStr(false)
|
|
|
|
sql := `(
|
|
dashboard.id IN (
|
|
SELECT distinct DashboardId from (
|
|
SELECT d.id AS DashboardId
|
|
FROM dashboard AS d
|
|
LEFT JOIN dashboard_acl AS da ON
|
|
da.dashboard_id = d.id OR
|
|
da.dashboard_id = d.folder_id
|
|
WHERE
|
|
d.org_id = ? AND
|
|
da.permission >= ? AND
|
|
(
|
|
da.user_id = ? OR
|
|
da.team_id IN (SELECT team_id from team_member AS tm WHERE tm.user_id = ?) OR
|
|
da.role IN (?` + strings.Repeat(",?", len(okRoles)-1) + `)
|
|
)
|
|
UNION
|
|
SELECT d.id AS DashboardId
|
|
FROM dashboard AS d
|
|
LEFT JOIN dashboard AS folder on folder.id = d.folder_id
|
|
LEFT JOIN dashboard_acl AS da ON
|
|
(
|
|
-- include default permissions -->
|
|
da.org_id = -1 AND (
|
|
(folder.id IS NOT NULL AND folder.has_acl = ` + falseStr + `) OR
|
|
(folder.id IS NULL AND d.has_acl = ` + falseStr + `)
|
|
)
|
|
)
|
|
WHERE
|
|
d.org_id = ? AND
|
|
da.permission >= ? AND
|
|
(
|
|
da.user_id = ? OR
|
|
da.role IN (?` + strings.Repeat(",?", len(okRoles)-1) + `)
|
|
)
|
|
) AS a
|
|
)
|
|
)
|
|
`
|
|
|
|
params := []interface{}{d.OrgId, d.PermissionLevel, d.UserId, d.UserId}
|
|
params = append(params, okRoles...)
|
|
params = append(params, d.OrgId, d.PermissionLevel, d.UserId)
|
|
params = append(params, okRoles...)
|
|
return sql, params
|
|
}
|
|
|
|
type AccessControlDashboardPermissionFilter struct {
|
|
User *models.SignedInUser
|
|
dashboardActions []string
|
|
folderActions []string
|
|
}
|
|
|
|
// NewAccessControlDashboardPermissionFilter creates a new AccessControlDashboardPermissionFilter that is configured with specific actions calculated based on the models.PermissionType and query type
|
|
func NewAccessControlDashboardPermissionFilter(user *models.SignedInUser, permissionLevel models.PermissionType, queryType string) AccessControlDashboardPermissionFilter {
|
|
needEdit := permissionLevel > models.PERMISSION_VIEW
|
|
folderActions := []string{dashboards.ActionFoldersRead}
|
|
var dashboardActions []string
|
|
if queryType == searchstore.TypeAlertFolder {
|
|
folderActions = append(folderActions, accesscontrol.ActionAlertingRuleRead)
|
|
if needEdit {
|
|
folderActions = append(folderActions, accesscontrol.ActionAlertingRuleCreate)
|
|
}
|
|
} else {
|
|
dashboardActions = append(dashboardActions, accesscontrol.ActionDashboardsRead)
|
|
if needEdit {
|
|
folderActions = append(folderActions, accesscontrol.ActionDashboardsCreate)
|
|
dashboardActions = append(dashboardActions, accesscontrol.ActionDashboardsWrite)
|
|
}
|
|
}
|
|
return AccessControlDashboardPermissionFilter{User: user, folderActions: folderActions, dashboardActions: dashboardActions}
|
|
}
|
|
|
|
func (f AccessControlDashboardPermissionFilter) Where() (string, []interface{}) {
|
|
var args []interface{}
|
|
builder := strings.Builder{}
|
|
builder.WriteString("(")
|
|
|
|
if len(f.dashboardActions) > 0 {
|
|
builder.WriteString("((")
|
|
|
|
dashFilter, _ := accesscontrol.Filter(f.User, "dashboard.uid", dashboards.ScopeDashboardsPrefix, f.dashboardActions...)
|
|
builder.WriteString(dashFilter.Where)
|
|
args = append(args, dashFilter.Args...)
|
|
|
|
builder.WriteString(" OR dashboard.folder_id IN(SELECT id FROM dashboard WHERE ")
|
|
dashFolderFilter, _ := accesscontrol.Filter(f.User, "dashboard.uid", dashboards.ScopeFoldersPrefix, f.dashboardActions...)
|
|
|
|
builder.WriteString(dashFolderFilter.Where)
|
|
builder.WriteString(")) AND NOT dashboard.is_folder)")
|
|
args = append(args, dashFolderFilter.Args...)
|
|
}
|
|
|
|
if len(f.folderActions) > 0 {
|
|
if len(f.dashboardActions) > 0 {
|
|
builder.WriteString(" OR ")
|
|
}
|
|
builder.WriteString("(")
|
|
folderFilter, _ := accesscontrol.Filter(f.User, "dashboard.uid", dashboards.ScopeFoldersPrefix, f.folderActions...)
|
|
builder.WriteString(folderFilter.Where)
|
|
builder.WriteString(" AND dashboard.is_folder)")
|
|
args = append(args, folderFilter.Args...)
|
|
}
|
|
builder.WriteString(")")
|
|
return builder.String(), args
|
|
}
|