Auth: Implement requester interface in access control module (#74289)

* Implement requester interface in the access control module
This commit is contained in:
linoman
2023-09-06 11:16:10 +02:00
committed by GitHub
parent 9310bb632e
commit 13f4382214
22 changed files with 179 additions and 114 deletions
+17 -10
View File
@@ -6,12 +6,12 @@ import (
"strings"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/login"
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
"github.com/grafana/grafana/pkg/services/user"
)
// maximum possible capacity for recursive queries array: one query for folder and one for dashboard actions
@@ -23,7 +23,7 @@ type clause struct {
}
type accessControlDashboardPermissionFilter struct {
user *user.SignedInUser
user identity.Requester
dashboardActions []string
folderActions []string
features featuremgmt.FeatureToggles
@@ -46,7 +46,7 @@ type PermissionsFilter interface {
// NewAccessControlDashboardPermissionFilter creates a new AccessControlDashboardPermissionFilter that is configured with specific actions calculated based on the dashboards.PermissionType and query type
// The filter is configured to use the new permissions filter (without subqueries) if the feature flag is enabled
// The filter is configured to use the old permissions filter (with subqueries) if the feature flag is disabled
func NewAccessControlDashboardPermissionFilter(user *user.SignedInUser, permissionLevel dashboards.PermissionType, queryType string, features featuremgmt.FeatureToggles, recursiveQueriesAreSupported bool) PermissionsFilter {
func NewAccessControlDashboardPermissionFilter(user identity.Requester, permissionLevel dashboards.PermissionType, queryType string, features featuremgmt.FeatureToggles, recursiveQueriesAreSupported bool) PermissionsFilter {
needEdit := permissionLevel > dashboards.PERMISSION_VIEW
var folderActions []string
@@ -111,14 +111,21 @@ func (f *accessControlDashboardPermissionFilter) Where() (string, []any) {
}
func (f *accessControlDashboardPermissionFilter) buildClauses() {
if f.user == nil || f.user.Permissions == nil || f.user.Permissions[f.user.OrgID] == nil {
if f.user == nil || f.user.IsNil() || len(f.user.GetPermissions()) == 0 {
f.where = clause{string: "(1 = 0)"}
return
}
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))
userID := int64(0)
namespaceID, identifier := f.user.GetNamespacedID()
switch namespaceID {
case identity.NamespaceUser, identity.NamespaceServiceAccount:
userID, _ = identity.IntIdentifier(namespaceID, identifier)
}
filter, params := accesscontrol.UserRolesFilter(f.user.GetOrgID(), userID, f.user.GetTeams(), accesscontrol.GetOrgRoles(f.user))
rolesFilter := " AND role_id IN(SELECT id FROM role " + filter + ") "
var args []any
builder := strings.Builder{}
@@ -129,10 +136,10 @@ func (f *accessControlDashboardPermissionFilter) buildClauses() {
// useSelfContainedPermissions is true if the user's permissions are stored and set from the JWT token
// currently it's used for the extended JWT module (when the user is authenticated via a JWT token generated by Grafana)
useSelfContainedPermissions := f.user.AuthenticatedBy == login.ExtendedJWTModule
useSelfContainedPermissions := f.user.GetAuthenticatedBy() == login.ExtendedJWTModule
if len(f.dashboardActions) > 0 {
toCheck := actionsToCheck(f.dashboardActions, f.user.Permissions[f.user.OrgID], dashWildcards, folderWildcards)
toCheck := actionsToCheck(f.dashboardActions, f.user.GetPermissions(), dashWildcards, folderWildcards)
if len(toCheck) > 0 {
if !useSelfContainedPermissions {
@@ -236,7 +243,7 @@ func (f *accessControlDashboardPermissionFilter) buildClauses() {
builder.WriteString(" OR ")
}
toCheck := actionsToCheck(f.folderActions, f.user.Permissions[f.user.OrgID], folderWildcards)
toCheck := actionsToCheck(f.folderActions, f.user.GetPermissions(), folderWildcards)
if len(toCheck) > 0 {
if !useSelfContainedPermissions {
permSelector.WriteString("(SELECT substr(scope, 13) FROM permission WHERE scope LIKE 'folders:uid:%'")
@@ -392,10 +399,10 @@ func parseStringSliceFromInterfaceSlice(slice []any) []string {
return result
}
func getAllowedUIDs(actions []string, user *user.SignedInUser, scopePrefix string) []any {
func getAllowedUIDs(actions []string, user identity.Requester, scopePrefix string) []any {
uidToActions := make(map[string]map[string]struct{})
for _, action := range actions {
for _, uidScope := range user.Permissions[user.OrgID][action] {
for _, uidScope := range user.GetPermissions()[action] {
if !strings.HasPrefix(uidScope, scopePrefix) {
continue
}
@@ -5,6 +5,7 @@ import (
"strings"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
@@ -25,14 +26,21 @@ func (f *accessControlDashboardPermissionFilterNoFolderSubquery) LeftJoin() stri
}
func (f *accessControlDashboardPermissionFilterNoFolderSubquery) buildClauses() {
if f.user == nil || f.user.Permissions == nil || f.user.Permissions[f.user.OrgID] == nil {
if f.user == nil || f.user.IsNil() || len(f.user.GetPermissions()) == 0 {
f.where = clause{string: "(1 = 0)"}
return
}
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))
userID := int64(0)
namespaceID, identifier := f.user.GetNamespacedID()
switch namespaceID {
case identity.NamespaceUser, identity.NamespaceServiceAccount:
userID, _ = identity.IntIdentifier(namespaceID, identifier)
}
filter, params := accesscontrol.UserRolesFilter(f.user.GetOrgID(), userID, f.user.GetTeams(), accesscontrol.GetOrgRoles(f.user))
rolesFilter := " AND role_id IN(SELECT id FROM role " + filter + ") "
var args []any
builder := strings.Builder{}
@@ -43,10 +51,10 @@ func (f *accessControlDashboardPermissionFilterNoFolderSubquery) buildClauses()
// useSelfContainedPermissions is true if the user's permissions are stored and set from the JWT token
// currently it's used for the extended JWT module (when the user is authenticated via a JWT token generated by Grafana)
useSelfContainedPermissions := f.user.AuthenticatedBy == login.ExtendedJWTModule
useSelfContainedPermissions := f.user.GetAuthenticatedBy() == login.ExtendedJWTModule
if len(f.dashboardActions) > 0 {
toCheck := actionsToCheck(f.dashboardActions, f.user.Permissions[f.user.OrgID], dashWildcards, folderWildcards)
toCheck := actionsToCheck(f.dashboardActions, f.user.GetPermissions(), dashWildcards, folderWildcards)
if len(toCheck) > 0 {
if !useSelfContainedPermissions {
@@ -152,7 +160,7 @@ func (f *accessControlDashboardPermissionFilterNoFolderSubquery) buildClauses()
builder.WriteString(" OR ")
}
toCheck := actionsToCheck(f.folderActions, f.user.Permissions[f.user.OrgID], folderWildcards)
toCheck := actionsToCheck(f.folderActions, f.user.GetPermissions(), folderWildcards)
if len(toCheck) > 0 {
if !useSelfContainedPermissions {
permSelector.WriteString("(SELECT substr(scope, 13) FROM permission WHERE scope LIKE 'folders:uid:%'")