mirror of
https://github.com/grafana/grafana.git
synced 2025-07-29 17:02:20 +08:00

* replace xorm.io/xorm imports * replace xorm from other go.mod files * clean up workspace * nolint does not make sense anymore as it is not a module * try if nolint directive helps * use nolint:all for xorm * add more nolints * try to skip xorm in linter config * exclude xorm differently * retrigger ci
142 lines
4.4 KiB
Go
142 lines
4.4 KiB
Go
package accesscontrol
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/grafana/grafana/pkg/util/xorm"
|
|
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
|
)
|
|
|
|
const AddActionSetMigrationID = "adding action set permissions"
|
|
|
|
func AddActionSetPermissionsMigrator(mg *migrator.Migrator) {
|
|
mg.AddMigration(AddActionSetMigrationID, &actionSetMigrator{})
|
|
}
|
|
|
|
type actionSetMigrator struct {
|
|
sess *xorm.Session
|
|
migrator *migrator.Migrator
|
|
migrator.MigrationBase
|
|
}
|
|
|
|
var _ migrator.CodeMigration = new(actionSetMigrator)
|
|
|
|
func (m *actionSetMigrator) SQL(migrator.Dialect) string {
|
|
return "code migration"
|
|
}
|
|
|
|
func (m *actionSetMigrator) Exec(sess *xorm.Session, migrator *migrator.Migrator) error {
|
|
m.sess = sess
|
|
m.migrator = migrator
|
|
return m.addActionSetActions()
|
|
}
|
|
|
|
func (m *actionSetMigrator) addActionSetActions() error {
|
|
var results []accesscontrol.Permission
|
|
|
|
// Find action sets and dashboard permissions for managed roles
|
|
// We don't need all dashboard permissions, just enough to help us determine what action set permissions to add
|
|
sql := `
|
|
SELECT permission.role_id, permission.action, permission.scope FROM permission
|
|
LEFT JOIN role ON permission.role_id = role.id
|
|
WHERE permission.action IN ('dashboards:read', 'dashboards:write', 'dashboards.permissions:read', 'dashboards:view', 'dashboards:edit', 'dashboards:admin', 'folders:view', 'folders:edit', 'folders:admin')
|
|
AND role.name LIKE 'managed:%'
|
|
`
|
|
if err := m.sess.SQL(sql).Find(&results); err != nil {
|
|
return fmt.Errorf("failed to query permissions: %w", err)
|
|
}
|
|
|
|
// group permissions by map[roleID]map[scope]actionSet
|
|
groupedPermissions := make(map[int64]map[string]string)
|
|
hasActionSet := make(map[int64]map[string]bool)
|
|
for _, result := range results {
|
|
// keep track of which dash/folder permission grants already have an action set permission
|
|
if isActionSetAction(result.Action) {
|
|
if _, ok := hasActionSet[result.RoleID]; !ok {
|
|
hasActionSet[result.RoleID] = make(map[string]bool)
|
|
}
|
|
hasActionSet[result.RoleID][result.Scope] = true
|
|
delete(groupedPermissions[result.RoleID], result.Scope)
|
|
continue
|
|
}
|
|
|
|
// don't add action set permissions where they already exist
|
|
if _, has := hasActionSet[result.RoleID]; has && hasActionSet[result.RoleID][result.Scope] {
|
|
continue
|
|
}
|
|
|
|
if _, ok := groupedPermissions[result.RoleID]; !ok {
|
|
groupedPermissions[result.RoleID] = make(map[string]string)
|
|
}
|
|
|
|
// store the most permissive action set permission
|
|
currentActionSet := groupedPermissions[result.RoleID][result.Scope]
|
|
switch result.Action {
|
|
case "dashboards:read":
|
|
if currentActionSet == "" {
|
|
groupedPermissions[result.RoleID][result.Scope] = "view"
|
|
}
|
|
case "dashboards:write":
|
|
if currentActionSet != "admin" {
|
|
groupedPermissions[result.RoleID][result.Scope] = "edit"
|
|
}
|
|
case "dashboards.permissions:read":
|
|
groupedPermissions[result.RoleID][result.Scope] = "admin"
|
|
}
|
|
}
|
|
|
|
toAdd := make([]accesscontrol.Permission, 0, len(groupedPermissions))
|
|
|
|
now := time.Now()
|
|
for roleID, permissions := range groupedPermissions {
|
|
for scope, action := range permissions {
|
|
// should never be the case, but keeping this check for extra safety
|
|
if _, ok := hasActionSet[roleID][scope]; ok {
|
|
continue
|
|
}
|
|
|
|
if strings.HasPrefix(scope, "folders:") {
|
|
action = fmt.Sprintf("folders:%s", action)
|
|
} else {
|
|
action = fmt.Sprintf("dashboards:%s", action)
|
|
}
|
|
|
|
kind, attr, identifier := accesscontrol.SplitScope(scope)
|
|
toAdd = append(toAdd, accesscontrol.Permission{
|
|
RoleID: roleID,
|
|
Scope: scope,
|
|
Action: action,
|
|
Kind: kind,
|
|
Attribute: attr,
|
|
Identifier: identifier,
|
|
Created: now,
|
|
Updated: now,
|
|
})
|
|
}
|
|
}
|
|
|
|
if len(toAdd) > 0 {
|
|
err := batch(len(toAdd), batchSize, func(start, end int) error {
|
|
m.migrator.Logger.Debug(fmt.Sprintf("inserting permissions %v", toAdd[start:end]))
|
|
if _, err := m.sess.InsertMulti(toAdd[start:end]); err != nil {
|
|
return fmt.Errorf("failed to add action sets: %w", err)
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
m.migrator.Logger.Debug("updated managed roles with dash and folder action set permissions")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func isActionSetAction(action string) bool {
|
|
return action == "dashboards:view" || action == "dashboards:edit" || action == "dashboards:admin" || action == "folders:view" || action == "folders:edit" || action == "folders:admin"
|
|
}
|