159 lines
3.9 KiB
Go
159 lines
3.9 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/grafana/authlib/types"
|
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
|
"github.com/grafana/grafana/pkg/storage/legacysql"
|
|
"github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate"
|
|
)
|
|
|
|
type PermissionStore interface {
|
|
GetUserPermissions(ctx context.Context, ns types.NamespaceInfo, query PermissionsQuery) ([]accesscontrol.Permission, error)
|
|
}
|
|
|
|
type PermissionsQuery struct {
|
|
OrgID int64
|
|
UserID int64
|
|
Action string
|
|
ActionSets []string
|
|
TeamIDs []int64
|
|
Role string
|
|
IsServerAdmin bool
|
|
}
|
|
|
|
func NewSQLPermissionStore(sql legacysql.LegacyDatabaseProvider, tracer tracing.Tracer) *SQLPermissionsStore {
|
|
return &SQLPermissionsStore{sql, tracer}
|
|
}
|
|
|
|
var _ PermissionStore = (*SQLPermissionsStore)(nil)
|
|
|
|
type SQLPermissionsStore struct {
|
|
sql legacysql.LegacyDatabaseProvider
|
|
tracer tracing.Tracer
|
|
}
|
|
|
|
var sqlUserPerms = mustTemplate("permission_query.sql")
|
|
|
|
type getPermissionsQuery struct {
|
|
sqltemplate.SQLTemplate
|
|
Query *PermissionsQuery
|
|
|
|
PermissionTable string
|
|
UserRoleTable string
|
|
TeamRoleTable string
|
|
BuiltinRoleTable string
|
|
}
|
|
|
|
func (r getPermissionsQuery) Validate() error {
|
|
return nil
|
|
}
|
|
|
|
func newGetPermissions(sql *legacysql.LegacyDatabaseHelper, q *PermissionsQuery) getPermissionsQuery {
|
|
return getPermissionsQuery{
|
|
SQLTemplate: sqltemplate.New(sql.DialectForDriver()),
|
|
Query: q,
|
|
PermissionTable: sql.Table("permission"),
|
|
UserRoleTable: sql.Table("user_role"),
|
|
TeamRoleTable: sql.Table("team_role"),
|
|
BuiltinRoleTable: sql.Table("builtin_role"),
|
|
}
|
|
}
|
|
|
|
func (s *SQLPermissionsStore) GetUserPermissions(ctx context.Context, ns types.NamespaceInfo, query PermissionsQuery) ([]accesscontrol.Permission, error) {
|
|
ctx, span := s.tracer.Start(ctx, "authz_direct_db.database.GetUserPermissions")
|
|
defer span.End()
|
|
|
|
sql, err := s.sql(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
query.OrgID = ns.OrgID
|
|
req := newGetPermissions(sql, &query)
|
|
q, err := sqltemplate.Execute(sqlUserPerms, req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
res, err := sql.DB.GetSqlxSession().Query(ctx, q, req.GetArgs()...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer func() {
|
|
if res != nil {
|
|
_ = res.Close()
|
|
}
|
|
}()
|
|
|
|
var perms []accesscontrol.Permission
|
|
for res.Next() {
|
|
var perm accesscontrol.Permission
|
|
if err := res.Scan(&perm.Kind, &perm.Attribute, &perm.Identifier, &perm.Scope); err != nil {
|
|
return nil, err
|
|
}
|
|
perms = append(perms, perm)
|
|
}
|
|
|
|
return perms, nil
|
|
}
|
|
|
|
var _ PermissionStore = (*StaticPermissionStore)(nil)
|
|
|
|
func NewStaticPermissionStore(ac accesscontrol.Service) *StaticPermissionStore {
|
|
return &StaticPermissionStore{ac}
|
|
}
|
|
|
|
type StaticPermissionStore struct {
|
|
ac accesscontrol.Service
|
|
}
|
|
|
|
func (s *StaticPermissionStore) GetUserPermissions(ctx context.Context, ns types.NamespaceInfo, query PermissionsQuery) ([]accesscontrol.Permission, error) {
|
|
roles := []string{query.Role}
|
|
if query.IsServerAdmin {
|
|
roles = append(roles, "Grafana Admin")
|
|
}
|
|
|
|
static := s.ac.GetStaticRoles(ctx)
|
|
|
|
var permissions []accesscontrol.Permission
|
|
for _, name := range roles {
|
|
r, ok := static[name]
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
for _, p := range r.Permissions {
|
|
if p.Action == query.Action {
|
|
permissions = append(permissions, p)
|
|
}
|
|
}
|
|
}
|
|
|
|
return permissions, nil
|
|
}
|
|
|
|
var _ PermissionStore = (*UnionPermissionStore)(nil)
|
|
|
|
func NewUnionPermissionStore(stores ...PermissionStore) *UnionPermissionStore {
|
|
return &UnionPermissionStore{stores}
|
|
}
|
|
|
|
type UnionPermissionStore struct {
|
|
stores []PermissionStore
|
|
}
|
|
|
|
func (u *UnionPermissionStore) GetUserPermissions(ctx context.Context, ns types.NamespaceInfo, query PermissionsQuery) ([]accesscontrol.Permission, error) {
|
|
var permissions []accesscontrol.Permission
|
|
for _, s := range u.stores {
|
|
result, err := s.GetUserPermissions(ctx, ns, query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
permissions = append(permissions, result...)
|
|
}
|
|
return permissions, nil
|
|
}
|