Documentation
¶
Overview ¶
Package gorbac provides a lightweight role-based access control implementation in Golang.
For the purposes of this package:
- an identity has one or more roles.
- a role requests access to a permission.
- a permission is given to a role.
Thus, RBAC has the following model:
- many to many relationship between identities and roles.
- many to many relationship between roles and permissions.
- roles can have parent roles.
Index ¶
- Variables
- func AllGranted[T comparable](ctx context.Context, rbac RBAC[T], roles []T, permissions ...Permission[T]) (ok bool)
- func AnyGranted[T comparable](ctx context.Context, rbac RBAC[T], roles []T, permissions ...Permission[T]) (ok bool)
- func FilterExprsForRoles[T comparable](ctx context.Context, rbac RBAC[T], roles []T, ...) ([]string, error)
- func InherCircle[T comparable](ctx context.Context, rbac RBAC[T]) (err error)
- func NewFilterProgramFromCEL(schema filter.Schema, exprs []string, engineOpts ...filter.EngineOption) (*filter.Program, error)
- func Walk[T comparable](ctx context.Context, rbac RBAC[T], h WalkHandler[T]) (err error)
- type FilterPermission
- type LayerPermission
- type Permission
- type Permissions
- type RBAC
- type Role
- type Roles
- type StdPermission
- type StdRBAC
- func (rbac *StdRBAC[T]) Add(ctx context.Context, r Role[T]) (err error)
- func (rbac *StdRBAC[T]) Get(_ context.Context, id T) (r Role[T], err error)
- func (rbac *StdRBAC[T]) GetParents(_ context.Context, id T) ([]T, error)
- func (rbac *StdRBAC[T]) IsGranted(ctx context.Context, id T, p Permission[T]) (ok bool)
- func (rbac *StdRBAC[T]) Remove(_ context.Context, id T) (err error)
- func (rbac *StdRBAC[T]) RemoveParents(_ context.Context, id T, parents ...T) error
- func (rbac *StdRBAC[T]) RoleIDs(_ context.Context) []T
- func (rbac *StdRBAC[T]) SetParents(_ context.Context, id T, parents ...T) error
- type StdRole
- func (role *StdRole[T]) Assign(_ context.Context, perms ...Permission[T]) error
- func (role *StdRole[T]) FilterPermissions(_ context.Context) map[T]Permission[T]
- func (role *StdRole[T]) Get(_ context.Context, id T) (Permission[T], bool)
- func (role *StdRole[T]) ID() T
- func (role *StdRole[T]) Permissions(_ context.Context) []Permission[T]
- func (role *StdRole[T]) PermissionsMap(_ context.Context) map[T]Permission[T]
- func (role *StdRole[T]) Permit(_ context.Context, perms ...Permission[T]) bool
- func (role *StdRole[T]) Revoke(_ context.Context, perms ...Permission[T]) error
- type WalkHandler
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrRoleNotExist occurred if a role cann't be found ErrRoleNotExist = errors.New("Role does not exist") // ErrRoleExist occurred if a role shouldn't be found ErrRoleExist = errors.New("Role has already existed") )
var (
ErrFoundCircle = fmt.Errorf("found circle")
)
Functions ¶
func AllGranted ¶
func AllGranted[T comparable](ctx context.Context, rbac RBAC[T], roles []T, permissions ...Permission[T]) (ok bool)
AllGranted checks whether the role set grants all specified permissions.
func AnyGranted ¶
func AnyGranted[T comparable](ctx context.Context, rbac RBAC[T], roles []T, permissions ...Permission[T]) (ok bool)
AnyGranted checks whether the role set grants any specified permission.
func FilterExprsForRoles ¶
func FilterExprsForRoles[T comparable]( ctx context.Context, rbac RBAC[T], roles []T, requiredFilterPermissions []Permission[T], ) ([]string, error)
FilterExprsForRoles returns combined CEL expressions per role.
The required filter permissions are used only to select which filter expressions to compose; missing filters are treated as allow-all. Permission checks are expected to be handled separately.
func InherCircle ¶
func InherCircle[T comparable](ctx context.Context, rbac RBAC[T]) (err error)
InherCircle returns an error when detecting any circle inheritance.
func NewFilterProgramFromCEL ¶
func NewFilterProgramFromCEL( schema filter.Schema, exprs []string, engineOpts ...filter.EngineOption, ) (*filter.Program, error)
NewFilterProgramFromCEL compiles CEL expressions into a single filter.Program.
Expressions are OR-ed together. Optional `filter.EngineOption` values are forwarded to `filter.NewEngine`, including `filter.WithExtraFilterCEL(...)` which is AND-ed to the final condition.
func Walk ¶
func Walk[T comparable](ctx context.Context, rbac RBAC[T], h WalkHandler[T]) (err error)
Walk passes each Role to WalkHandler
Types ¶
type FilterPermission ¶
type FilterPermission[T comparable] struct { StdPermission[T] // Filter is a raw CEL boolean expression. // // It can reference: // - schema fields (rendered as SQL columns) // - extra CEL variables provided at runtime via filter.Bindings (rendered as placeholders) Filter string `json:"filter,omitempty"` }
FilterPermission is a Permission with an attached CEL filter expression.
The filter is intended for data-scope filtering (row-level filtering). The RBAC permission check remains unchanged: the permission ID still decides whether a role is granted; the filter decides which rows are accessible.
func NewFilterPermission ¶
func NewFilterPermission[T comparable](id T, celExpr string) FilterPermission[T]
func (FilterPermission[T]) CEL ¶
func (p FilterPermission[T]) CEL() (string, error)
CEL returns the attached CEL expression.
type LayerPermission ¶
LayerPermission uses string as a layered ID. Each layer splits by "/".
func NewLayerPermission ¶
func NewLayerPermission(id, sep string) LayerPermission
NewLayerPermission returns an instance of layered permission with `id`
func (LayerPermission) Match ¶
func (p LayerPermission) Match(parent Permission[string]) bool
Match another permission
type Permission ¶
type Permission[T comparable] interface { ID() T Match(Permission[T]) bool }
Permission interface T is the type of permission ID
func NewPermission ¶
func NewPermission[T comparable](id T) Permission[T]
type RBAC ¶
type RBAC[T comparable] interface { Add(ctx context.Context, role Role[T]) error Remove(ctx context.Context, id T) error Get(ctx context.Context, id T) (Role[T], error) RoleIDs(ctx context.Context) []T SetParents(ctx context.Context, id T, parents ...T) error GetParents(ctx context.Context, id T) ([]T, error) RemoveParents(ctx context.Context, id T, parents ...T) error IsGranted(ctx context.Context, roleID T, permission Permission[T]) bool }
RBAC defines the role-based access control contract.
Example (Int) ¶
ctx := context.Background()
rbac := gorbac.New[int]()
rA := gorbac.NewRole(1)
rB := gorbac.NewRole(2)
rC := gorbac.NewRole(3)
rD := gorbac.NewRole(4)
rE := gorbac.NewRole(5)
pA := gorbac.NewPermission(1)
pB := gorbac.NewPermission(2)
pC := gorbac.NewPermission(3)
pD := gorbac.NewPermission(4)
pE := gorbac.NewPermission(5)
must := func(err error) {
if err != nil {
panic(err)
}
}
must(rA.Assign(ctx, pA))
must(rB.Assign(ctx, pB))
must(rC.Assign(ctx, pC))
must(rD.Assign(ctx, pD))
must(rE.Assign(ctx, pE))
must(rbac.Add(ctx, rA))
must(rbac.Add(ctx, rB))
must(rbac.Add(ctx, rC))
must(rbac.Add(ctx, rD))
must(rbac.Add(ctx, rE))
must(rbac.SetParents(ctx, 1, 2))
must(rbac.SetParents(ctx, 2, 3, 4))
must(rbac.SetParents(ctx, 5, 4))
if rbac.IsGranted(ctx, 1, pA) &&
rbac.IsGranted(ctx, 1, pB) &&
rbac.IsGranted(ctx, 1, pC) &&
rbac.IsGranted(ctx, 1, pD) {
fmt.Println("The role-a has been granted permis-a, b, c and d.")
}
if rbac.IsGranted(ctx, 2, pB) &&
rbac.IsGranted(ctx, 2, pC) &&
rbac.IsGranted(ctx, 2, pD) {
fmt.Println("The role-b has been granted permis-b, c and d.")
}
// When a circle inheratance occurred,
must(rbac.SetParents(ctx, 3, 1))
// it could be detected as following code:
if err := gorbac.InherCircle(ctx, rbac); err != nil {
fmt.Println("A circle inheratance occurred.")
}
Output: The role-a has been granted permis-a, b, c and d. The role-b has been granted permis-b, c and d. A circle inheratance occurred.
Example (String) ¶
Suppose:
The role-a is inheriting from role-b. The role-b is inheriting from role-c, role-d. The role-c is individual. The role-d is individual. The role-e is inheriting from role-d. Every roles have their own permissions.
ctx := context.Background()
rbac := gorbac.New[string]()
rA := gorbac.NewRole("role-a")
rB := gorbac.NewRole("role-b")
rC := gorbac.NewRole("role-c")
rD := gorbac.NewRole("role-d")
rE := gorbac.NewRole("role-e")
pA := gorbac.NewPermission("permission-a")
pB := gorbac.NewPermission("permission-b")
pC := gorbac.NewPermission("permission-c")
pD := gorbac.NewPermission("permission-d")
pE := gorbac.NewPermission("permission-e")
must := func(err error) {
if err != nil {
panic(err)
}
}
must(rA.Assign(ctx, pA))
must(rB.Assign(ctx, pB))
must(rC.Assign(ctx, pC))
must(rD.Assign(ctx, pD))
must(rE.Assign(ctx, pE))
must(rbac.Add(ctx, rA))
must(rbac.Add(ctx, rB))
must(rbac.Add(ctx, rC))
must(rbac.Add(ctx, rD))
must(rbac.Add(ctx, rE))
must(rbac.SetParents(ctx, "role-a", "role-b"))
must(rbac.SetParents(ctx, "role-b", "role-c", "role-d"))
must(rbac.SetParents(ctx, "role-e", "role-d"))
if rbac.IsGranted(ctx, "role-a", pA) &&
rbac.IsGranted(ctx, "role-a", pB) &&
rbac.IsGranted(ctx, "role-a", pC) &&
rbac.IsGranted(ctx, "role-a", pD) {
fmt.Println("The role-a has been granted permis-a, b, c and d.")
}
if rbac.IsGranted(ctx, "role-b", pB) &&
rbac.IsGranted(ctx, "role-b", pC) &&
rbac.IsGranted(ctx, "role-b", pD) {
fmt.Println("The role-b has been granted permis-b, c and d.")
}
// When a circle inheratance occurred,
must(rbac.SetParents(ctx, "role-c", "role-a"))
// it could be detected as following code:
if err := gorbac.InherCircle(ctx, rbac); err != nil {
fmt.Println("A circle inheratance occurred.")
}
Output: The role-a has been granted permis-a, b, c and d. The role-b has been granted permis-b, c and d. A circle inheratance occurred.
type Role ¶
type Role[T comparable] interface { ID() T Assign(context.Context, ...Permission[T]) error Permit(context.Context, ...Permission[T]) bool Revoke(context.Context, ...Permission[T]) error Permissions(context.Context) []Permission[T] PermissionsMap(context.Context) map[T]Permission[T] Get(context.Context, T) (Permission[T], bool) FilterPermissions(context.Context) map[T]Permission[T] }
Role describes the role contract.
type StdPermission ¶
type StdPermission[T comparable] struct { SID T `json:"id"` }
BasicPermission has `SID` is shorten for `serialisable ID`
func (StdPermission[T]) Match ¶
func (p StdPermission[T]) Match(a Permission[T]) bool
Match another permission
type StdRBAC ¶
type StdRBAC[T comparable] struct { // contains filtered or unexported fields }
StdRBAC object, in most cases it should be used as a singleton.
func New ¶
func New[T comparable]() *StdRBAC[T]
New returns a StdRBAC structure. The default role structure will be used.
func (*StdRBAC[T]) GetParents ¶
GetParents return `parents` of the role `id`. If the role is not existing, an error will be returned. Or the role doesn't have any parents, a nil slice will be returned.
func (*StdRBAC[T]) IsGranted ¶
func (rbac *StdRBAC[T]) IsGranted(ctx context.Context, id T, p Permission[T]) (ok bool)
IsGranted tests if the role `id` has permission `p`.
func (*StdRBAC[T]) RemoveParents ¶
RemoveParents unbind `parents` from the role `id`. If the role or any parent is not existing, an error will be returned.
type StdRole ¶
type StdRole[T comparable] struct { // ID is the serialisable identity of role IDValue T `json:"id"` // contains filtered or unexported fields }
StdRole is the default role implementation. You can embed this struct into your own role implementation. T is the type of ID.
func NewRole ¶
func NewRole[T comparable](id T) *StdRole[T]
NewRole is the default role factory function.
func (*StdRole[T]) Assign ¶
func (role *StdRole[T]) Assign(_ context.Context, perms ...Permission[T]) error
Assign permissions to the role.
func (*StdRole[T]) FilterPermissions ¶
func (role *StdRole[T]) FilterPermissions(_ context.Context) map[T]Permission[T]
FilterPermissions returns a raw ref of CEL-carrying permissions keyed by ID.
func (*StdRole[T]) Get ¶
func (role *StdRole[T]) Get(_ context.Context, id T) (Permission[T], bool)
Get returns a permission by ID.
func (*StdRole[T]) Permissions ¶
func (role *StdRole[T]) Permissions(_ context.Context) []Permission[T]
Permissions returns all permissions into a slice.
func (*StdRole[T]) PermissionsMap ¶
func (role *StdRole[T]) PermissionsMap(_ context.Context) map[T]Permission[T]
PermissionsMap returns a raw ref of permissions keyed by ID.
type WalkHandler ¶
type WalkHandler[T comparable] func(Role[T], []T) error
WalkHandler is a function defined by user to handle role
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
rbac-wrapper
command
|
|
|
test-project/expr
command
|
|
|
Package filter compiles CEL filters into a dialect-agnostic condition tree.
|
Package filter compiles CEL filters into a dialect-agnostic condition tree. |
