New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RBAC: Improve performance of dashboard filter query #56813
Changes from all commits
0b3836e
f79589c
e7f26dd
169d1f9
19faaad
3c82359
5213a24
c0af53d
25b5bd0
c19d6cc
d3a840c
289e89c
0b17bbb
0e3f80b
e3d00d2
5010cd4
4e25bee
d50c3f2
7df4766
7f328ad
cd425e9
d04c4e8
9b8e446
dbad0a7
290b335
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -80,9 +80,9 @@ func (d DashboardPermissionFilter) Where() (string, []interface{}) { | |
} | ||
|
||
type AccessControlDashboardPermissionFilter struct { | ||
User *user.SignedInUser | ||
dashboardActions []string | ||
user *user.SignedInUser | ||
folderActions []string | ||
dashboardActions []string | ||
} | ||
|
||
// NewAccessControlDashboardPermissionFilter creates a new AccessControlDashboardPermissionFilter that is configured with specific actions calculated based on the models.PermissionType and query type | ||
|
@@ -102,39 +102,80 @@ func NewAccessControlDashboardPermissionFilter(user *user.SignedInUser, permissi | |
dashboardActions = append(dashboardActions, dashboards.ActionDashboardsWrite) | ||
} | ||
} | ||
return AccessControlDashboardPermissionFilter{User: user, folderActions: folderActions, dashboardActions: dashboardActions} | ||
return AccessControlDashboardPermissionFilter{user: user, folderActions: folderActions, dashboardActions: dashboardActions} | ||
} | ||
|
||
func (f AccessControlDashboardPermissionFilter) Where() (string, []interface{}) { | ||
if f.user == nil || f.user.Permissions == nil || f.user.Permissions[f.user.OrgID] == nil { | ||
return "(1 = 0)", nil | ||
} | ||
dashWildcards := accesscontrol.WildcardsFromPrefix(dashboards.ScopeDashboardsPrefix) | ||
folderWildcards := accesscontrol.WildcardsFromPrefix(dashboards.ScopeFoldersPrefix) | ||
|
||
filter, params := accesscontrol.UserRolesFilter(f.user.OrgID, f.user.UserID, f.user.Teams, accesscontrol.GetOrgRoles(f.user)) | ||
rolesFilter := "AND role_id IN(SELECT distinct id FROM role " + filter + ")" | ||
var args []interface{} | ||
builder := strings.Builder{} | ||
builder.WriteString("(") | ||
|
||
builder.WriteRune('(') | ||
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...) | ||
actionsToCheck := make([]interface{}, 0, len(f.dashboardActions)) | ||
for _, action := range f.dashboardActions { | ||
var hasWildcard bool | ||
for _, scope := range f.user.Permissions[f.user.OrgID][action] { | ||
if dashWildcards.Contains(scope) || folderWildcards.Contains(scope) { | ||
hasWildcard = true | ||
break | ||
} | ||
} | ||
if !hasWildcard { | ||
actionsToCheck = append(actionsToCheck, action) | ||
} | ||
} | ||
|
||
builder.WriteString(" OR dashboard.folder_id IN(SELECT id FROM dashboard WHERE ") | ||
dashFolderFilter, _ := accesscontrol.Filter(f.User, "dashboard.uid", dashboards.ScopeFoldersPrefix, f.dashboardActions...) | ||
if len(actionsToCheck) > 0 { | ||
builder.WriteString("(dashboard.uid IN (SELECT substr(scope, 16) FROM permission WHERE action IN (?" + strings.Repeat(", ?", len(actionsToCheck)-1) + ") AND scope LIKE 'dashboards:uid:%' " + rolesFilter + " GROUP BY role_id, scope HAVING COUNT(action) = ?) AND NOT dashboard.is_folder)") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't the Edit: How likely is the edge case of actions been granted through different roles? Not that likely. |
||
args = append(args, actionsToCheck...) | ||
args = append(args, params...) | ||
args = append(args, len(actionsToCheck)) | ||
kalleep marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
builder.WriteString(dashFolderFilter.Where) | ||
builder.WriteString(")) AND NOT dashboard.is_folder)") | ||
args = append(args, dashFolderFilter.Args...) | ||
builder.WriteString(" OR ") | ||
builder.WriteString("(dashboard.folder_id IN (SELECT id FROM dashboard as d WHERE d.uid IN (SELECT substr(scope, 13) FROM permission WHERE action IN (?" + strings.Repeat(", ?", len(actionsToCheck)-1) + ") AND scope LIKE 'folders:uid:%' " + rolesFilter + " GROUP BY role_id, scope HAVING COUNT(action) = ?)) AND NOT dashboard.is_folder)") | ||
args = append(args, actionsToCheck...) | ||
args = append(args, params...) | ||
args = append(args, len(actionsToCheck)) | ||
} else { | ||
builder.WriteString("NOT dashboard.is_folder") | ||
} | ||
} | ||
|
||
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...) | ||
|
||
actionsToCheck := make([]interface{}, 0, len(f.folderActions)) | ||
for _, action := range f.folderActions { | ||
var hasWildcard bool | ||
for _, scope := range f.user.Permissions[f.user.OrgID][action] { | ||
if folderWildcards.Contains(scope) { | ||
hasWildcard = true | ||
break | ||
} | ||
} | ||
if !hasWildcard { | ||
actionsToCheck = append(actionsToCheck, action) | ||
} | ||
} | ||
|
||
if len(actionsToCheck) > 0 { | ||
builder.WriteString("(dashboard.uid IN (SELECT substr(scope, 13) FROM permission WHERE action IN (?" + strings.Repeat(", ?", len(actionsToCheck)-1) + ") AND scope LIKE 'folders:uid:%' " + rolesFilter + " GROUP BY role_id, scope HAVING COUNT(action) = ?) AND dashboard.is_folder)") | ||
args = append(args, actionsToCheck...) | ||
args = append(args, params...) | ||
args = append(args, len(actionsToCheck)) | ||
} else { | ||
builder.WriteString("dashboard.is_folder") | ||
} | ||
} | ||
builder.WriteString(")") | ||
builder.WriteRune(')') | ||
return builder.String(), args | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would place this in a function to dedup some code and ease reading.