mirror of https://github.com/grafana/grafana
Authz: Account for fixed roles when running oss and using authz service (#99244)
* Extract "PermissionStore" from general store interface * Add static and union permission stores * Add GetStaticRoles * Use accesscontrol.Service for inproc to provide static permissionspull/99268/head
parent
0baf3a8f95
commit
7329d2c34b
@ -0,0 +1,159 @@ |
||||
package store |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"github.com/grafana/authlib/claims" |
||||
|
||||
"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 claims.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 claims.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 claims.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 claims.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 |
||||
} |
Loading…
Reference in new issue