grafana/pkg/registry/apis/iam/resourcepermission/templates.go

293 lines
8.9 KiB
Go

package resourcepermission
import (
"embed"
"fmt"
"text/template"
"time"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/storage/legacysql"
"github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate"
)
// Templates setup.
var (
//go:embed queries/*.sql
sqlTemplatesFS embed.FS
sqlTemplates = template.Must(template.New("sql").ParseFS(sqlTemplatesFS, `queries/*.sql`))
resourcePermissionsQueryTplt = mustTemplate("resource_permission_query.sql")
resourcePermissionDeletionQueryTplt = mustTemplate("resource_permission_deletion_query.sql")
roleInsertTplt = mustTemplate("role_insert.sql")
assignmentInsertTplt = mustTemplate("assignment_insert.sql")
permissionInsertTplt = mustTemplate("permission_insert.sql")
permissionRemoveTplt = mustTemplate("permission_remove.sql")
pageQueryTplt = mustTemplate("page_query.sql")
latestUpdateTplt = mustTemplate("latest_update_query.sql")
)
func mustTemplate(filename string) *template.Template {
if t := sqlTemplates.Lookup(filename); t != nil {
return t
}
panic(fmt.Sprintf("template file not found: %s", filename))
}
type pageQueryTemplate struct {
sqltemplate.SQLTemplate
Query *PageQuery
PermissionTable string
RoleTable string
ManagedRolePattern string
}
func (r pageQueryTemplate) Validate() error {
return nil
}
func buildPageQueryFromTemplate(dbHelper *legacysql.LegacyDatabaseHelper, query *PageQuery) (string, []interface{}, error) {
req := pageQueryTemplate{
SQLTemplate: sqltemplate.New(dbHelper.DialectForDriver()),
Query: query,
PermissionTable: dbHelper.Table("permission"),
RoleTable: dbHelper.Table("role"),
ManagedRolePattern: "managed:%",
}
rawQuery, err := sqltemplate.Execute(pageQueryTplt, req)
if err != nil {
return "", nil, fmt.Errorf("execute template %q: %w", pageQueryTplt.Name(), err)
}
return rawQuery, req.GetArgs(), nil
}
type latestUpdateTemplate struct {
sqltemplate.SQLTemplate
OrgID int64
ScopePatterns []string
PermissionTable string
RoleTable string
ManagedPattern string
}
func (l latestUpdateTemplate) Validate() error {
if l.OrgID <= 0 {
return fmt.Errorf("orgID must be set")
}
if len(l.ScopePatterns) == 0 {
return fmt.Errorf("at least one scope pattern is required")
}
return nil
}
func buildLatestUpdateQueryFromTemplate(dbHelper *legacysql.LegacyDatabaseHelper, orgID int64, scopePatterns []string) (string, []interface{}, error) {
req := latestUpdateTemplate{
SQLTemplate: sqltemplate.New(dbHelper.DialectForDriver()),
OrgID: orgID,
ScopePatterns: scopePatterns,
PermissionTable: dbHelper.Table("permission"),
RoleTable: dbHelper.Table("role"),
ManagedPattern: "managed:%",
}
rawQuery, err := sqltemplate.Execute(latestUpdateTplt, req)
if err != nil {
return "", nil, fmt.Errorf("execute template %q: %w", latestUpdateTplt.Name(), err)
}
return rawQuery, req.GetArgs(), nil
}
type listResourcePermissionsQueryTemplate struct {
sqltemplate.SQLTemplate
Query *ListResourcePermissionsQuery
PermissionTable string
RoleTable string
UserTable string
TeamTable string
BuiltinRoleTable string
UserRoleTable string
TeamRoleTable string
ManagedRolePattern string
}
func (r listResourcePermissionsQueryTemplate) Validate() error {
return nil
}
func buildListResourcePermissionsQueryFromTemplate(dbHelper *legacysql.LegacyDatabaseHelper, query *ListResourcePermissionsQuery) (string, []interface{}, error) {
req := listResourcePermissionsQueryTemplate{
SQLTemplate: sqltemplate.New(dbHelper.DialectForDriver()),
Query: query,
PermissionTable: dbHelper.Table("permission"),
RoleTable: dbHelper.Table("role"),
UserTable: dbHelper.Table("user"),
TeamTable: dbHelper.Table("team"),
BuiltinRoleTable: dbHelper.Table("builtin_role"),
UserRoleTable: dbHelper.Table("user_role"),
TeamRoleTable: dbHelper.Table("team_role"),
ManagedRolePattern: "managed:%",
}
rawQuery, err := sqltemplate.Execute(resourcePermissionsQueryTplt, req)
if err != nil {
return "", nil, fmt.Errorf("execute template %q: %w", resourcePermissionsQueryTplt.Name(), err)
}
return rawQuery, req.GetArgs(), nil
}
type insertRoleTemplate struct {
sqltemplate.SQLTemplate
RoleTable string
OrgID int64
UID string
Name string
Now string
}
func (t insertRoleTemplate) Validate() error {
return nil
}
func buildInsertRoleQuery(dbHelper *legacysql.LegacyDatabaseHelper, orgID int64, uid string, name string) (string, []any, error) {
req := insertRoleTemplate{
SQLTemplate: sqltemplate.New(dbHelper.DialectForDriver()),
RoleTable: dbHelper.Table("role"),
OrgID: orgID,
UID: uid,
Name: name,
Now: timeNow().Format(time.DateTime),
}
rawQuery, err := sqltemplate.Execute(roleInsertTplt, req)
if err != nil {
return "", nil, fmt.Errorf("rendering sql template: %w", err)
}
return rawQuery, req.GetArgs(), nil
}
type insertAssignmentTemplate struct {
sqltemplate.SQLTemplate
AssignmentTable string
AssignmentColumn string
RoleID int64
OrgID int64
SubjectID any // int64 or string
Now string
}
func (t insertAssignmentTemplate) Validate() error {
if t.AssignmentTable == "" {
return fmt.Errorf("assignment table is required")
}
if t.AssignmentColumn == "" {
return fmt.Errorf("assignment column is required")
}
return nil
}
func buildInsertAssignmentQuery(dbHelper *legacysql.LegacyDatabaseHelper, orgID int64, roleID int64, assignment rbacAssignmentCreate) (string, []any, error) {
req := insertAssignmentTemplate{
SQLTemplate: sqltemplate.New(dbHelper.DialectForDriver()),
AssignmentTable: dbHelper.Table(assignment.AssignmentTable),
AssignmentColumn: assignment.AssignmentColumn,
RoleID: roleID,
OrgID: orgID,
SubjectID: assignment.SubjectID,
Now: timeNow().Format(time.DateTime),
}
rawQuery, err := sqltemplate.Execute(assignmentInsertTplt, req)
if err != nil {
return "", nil, fmt.Errorf("rendering sql template: %w", err)
}
return rawQuery, req.GetArgs(), nil
}
type insertPermissionTemplate struct {
sqltemplate.SQLTemplate
PermissionTable string
RoleID int64
Permission accesscontrol.Permission
Now string
}
func (t insertPermissionTemplate) Validate() error {
return nil
}
func buildInsertPermissionQuery(dbHelper *legacysql.LegacyDatabaseHelper, roleID int64, permission accesscontrol.Permission) (string, []any, error) {
req := insertPermissionTemplate{
SQLTemplate: sqltemplate.New(dbHelper.DialectForDriver()),
PermissionTable: dbHelper.Table("permission"),
RoleID: roleID,
Permission: permission,
Now: timeNow().Format(time.DateTime),
}
rawQuery, err := sqltemplate.Execute(permissionInsertTplt, req)
if err != nil {
return "", nil, fmt.Errorf("rendering sql template: %w", err)
}
return rawQuery, req.GetArgs(), nil
}
type removePermissionTemplate struct {
sqltemplate.SQLTemplate
PermissionTable string
RoleTable string
Scope string
Action string
OrgID int64
RoleName string
}
func (t removePermissionTemplate) Validate() error {
return nil
}
func buildRemovePermissionQuery(dbHelper *legacysql.LegacyDatabaseHelper, scope, action, roleName string, orgID int64) (string, []any, error) {
req := removePermissionTemplate{
SQLTemplate: sqltemplate.New(dbHelper.DialectForDriver()),
PermissionTable: dbHelper.Table("permission"),
RoleTable: dbHelper.Table("role"),
Scope: scope,
Action: action,
OrgID: orgID,
RoleName: roleName,
}
rawQuery, err := sqltemplate.Execute(permissionRemoveTplt, req)
if err != nil {
return "", nil, fmt.Errorf("rendering sql template: %w", err)
}
return rawQuery, req.GetArgs(), nil
}
type deleteResourcePermissionsQueryTemplate struct {
sqltemplate.SQLTemplate
Query *DeleteResourcePermissionsQuery
PermissionTable string
RoleTable string
ManagedRolePattern string
}
func (r deleteResourcePermissionsQueryTemplate) Validate() error {
return nil
}
func buildDeleteResourcePermissionsQueryFromTemplate(sql *legacysql.LegacyDatabaseHelper, query *DeleteResourcePermissionsQuery) (string, []interface{}, error) {
req := deleteResourcePermissionsQueryTemplate{
SQLTemplate: sqltemplate.New(sql.DialectForDriver()),
Query: query,
PermissionTable: sql.Table("permission"),
RoleTable: sql.Table("role"),
ManagedRolePattern: "managed:%",
}
rawQuery, err := sqltemplate.Execute(resourcePermissionDeletionQueryTplt, req)
if err != nil {
return "", nil, fmt.Errorf("execute template %q: %w", resourcePermissionDeletionQueryTplt.Name(), err)
}
return rawQuery, req.GetArgs(), nil
}