rbac

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 18, 2026 License: Apache-2.0 Imports: 9 Imported by: 10

README

RBAC module for Go

Build Status Go Report Card GoDoc Coverage Status

Role-based access control for Go. The permission name is the basis of every check. An object is optional: it can compose the name and supply data for a callback. A Go type constraint is extra and only applies when you register a typed object.

Features

  • Roles with nested roles and permission preload by pattern.
  • SimplePermission — named right (account.register, access). Works with or without an object.
  • ResourcePermission{resource}.{action}[.{owner|account|all}].
  • RegisterObject — match by name and Go type (CheckType).
  • RegisterResource — match by name and RBACResourceName() only (DTO/proxy allowed).
  • Name resolution — full name, or short pattern + object (register + Account → account.register).
  • Owning suffixesRegisterNewOwningPermissions builds .owner / .account / .all. Instance rules live in your callback.
  • Custom checksfunc(ctx context.Context, resource any, perm Permission) bool.

Permission names

Style Example What happens
Manual account.register, user.view.owner Used as-is
Automatic register + object with RBACResourceName() == "account" Also tries account.register
Custom RBACPermissionPatterns(...) on the object Extra patterns from the object; originals are kept

GetResName uses RBACResourceName() when present, otherwise package.Type.

view.* matches view.owner, view.account, and view.all. Who is the owner is not built in — implement that in the callback.

HasPermission is a catalog check (no object, no callback). CheckPermissions authorizes a call.

RegisterObject vs RegisterResource

CheckPermissions
  → expand patterns from the object
  → match permission name
  → RegisterObject: also CheckType
  → RegisterResource / WithMatchByResourceName: also same RBACResourceName
  → optional callback
  • Object (default NewResourcePermission): same name + same Go type. A DTO with the same resource name is denied.
  • Resource: same name + same RBACResourceName. A PostAccess DTO can stand in for Post and carry Owner / AccountID.

Direct NewResourcePermission is typed unless you pass WithMatchByResourceName().

Installation

go get github.com/demdxx/rbac

Usage

Runnable end-to-end cases live in example_app_test.go (TestExampleAppSuite).

package app

import (
    "context"
    "strings"

    "github.com/demdxx/rbac"
)

type User struct {
    ID        uint64
    AccountID uint64
}

func (*User) RBACResourceName() string { return "user" }

type Post struct {
    AuthorID  uint64
    AccountID uint64
}

func (*Post) RBACResourceName() string { return "post" }

// DTO for checks that need extra fields the entity does not have.
type PostAccess struct {
    Owner     bool
    AccountID uint64
}

func (*PostAccess) RBACResourceName() string { return "post" }

func cover(perm rbac.Permission) string {
    name := perm.Name()
    if i := strings.LastIndex(name, "."); i >= 0 {
        return name[i+1:]
    }
    return name
}

func check(ctx context.Context, resource any, perm rbac.Permission) bool {
    switch cover(perm) {
    case rbac.OwnAll:
        return true
    case rbac.OwnOwner:
        if a, ok := resource.(*PostAccess); ok {
            return a.Owner
        }
        return false
    default:
        return false
    }
}

func setup(ctx context.Context) *rbac.Manager {
    pm := rbac.NewManager(nil)

    // Typed: *User only. A UserAccess DTO with name "user" will not match.
    pm.RegisterObject((*User)(nil), check)

    // Name-only: *Post or PostAccess with RBACResourceName() == "post".
    pm.RegisterResource((*Post)(nil), check)

    _ = pm.RegisterNewPermission(nil, "account.register")
    _ = pm.RegisterNewOwningPermissions((*User)(nil), []string{"view", "edit"})
    _ = pm.RegisterNewOwningPermissions((*Post)(nil), []string{"view", "edit"})

    pm.RegisterRole(ctx,
        rbac.MustNewRole("anonymous", rbac.WithPermissions(
            "account.register",
            "post.view.owner",
        )),
        rbac.MustNewRole("member", rbac.WithPermissions(
            "user.*.owner",
            "post.*.owner",
        )),
        rbac.MustNewRole("admin", rbac.WithPermissions(
            "account.register",
            "*.*.all",
        )),
    )
    return pm
}

func example(ctx context.Context, pm *rbac.Manager) {
    member := pm.Role(ctx, "member")
    admin := pm.Role(ctx, "admin")
    anonymous := pm.Role(ctx, "anonymous")

    // SimplePermission: full name, or short name + object.
    _ = anonymous.CheckPermissions(ctx, nil, "account.register")
    _ = anonymous.CheckPermissions(ctx, &struct{ n string }{}, "account.register") // still matches by name

    // Resource + DTO (RegisterResource).
    own := &PostAccess{Owner: true}
    _ = member.CheckPermissions(ctx, own, "edit.owner")
    _ = member.CheckPermissions(ctx, own, "edit.*")

    // Catalog (no instance check).
    _ = admin.HasPermission("post.view.all")
}

Without RBACResourceName(), the name is package.Type (for example rbac.testObject).

License

Apache 2.0. See LICENSE.

Contributing

Issues and pull requests are welcome.

Documentation

Overview

Package rbac provides role-based access control (RBAC) system

Index

Constants

View Source
const (
	OwnOwner   = `owner`   // The owner of the object (creator or user assigned as owner)
	OwnAccount = `account` // The account owner
	OwnAll     = `all`     // The system owner (can control all objects) *not recommended
)

Variables

View Source
var (
	// ErrInvalidOption for this type
	ErrInvalidOption = errors.New(`invalid option`)

	// ErrInvalidOptionParam if param is not valid
	ErrInvalidOptionParam = errors.New(`invalid option param`)
)
View Source
var (
	// ErrInvalidCheckParams in case of empty permission check params
	ErrInvalidCheckParams = errors.New(`invalid check params`)

	// ErrInvalidResouceType if parameter is Nil
	ErrInvalidResouceType = errors.New(`invalid resource type`)
)
View Source
var (
	ErrEmptyPermissionName   = errors.New(`empty permission name`)
	ErrInvalidPermissionName = errors.New(`invalid permission name`)
	ErrInvalidPattern        = errors.New(`invalid pattern`)
)
View Source
var ErrResourceTypeRequired = errors.New(`resource type required`)

Functions

func ExpandPermissionPatterns added in v1.0.0

func ExpandPermissionPatterns(resource any, patterns ...string) []string

ExpandPermissionPatterns resolves check patterns from a resource.

Rules:

  1. Always keep the original patterns (manual names stay valid).
  2. If resource implements PermissionPatternExpander, append its extra patterns.
  3. Otherwise if GetResName(resource) is not empty, append resName+"."+pattern for each pattern that does not already have that prefix.
  4. nil resource or empty name: originals only.

func GetResName

func GetResName(resource any) string

GetResName returns resource name

func GetResType

func GetResType(resource any) (res reflect.Type)

GetResType returns resource type

func Included added in v0.1.8

func Included(base Role, testRole Role) bool

Included returns true if testRole is included in the base role or equal

func MatchName added in v0.1.5

func MatchName(pattern, name string) (ok bool, err error)

MatchName permission pattern Example: `*` or `**` matches any string `test.*` matches `test.it`, `test.it.owner`, `test.it.admin `test.*.owner` matches `test.it.owner`, `test.object.owner` `test.*.*` matches `test.it.owner`, `test.object.owner` `test.*.?wner` matches `test.it.owner`, `test.object.owner `test.*.{owner|admin}` matches `test.it.owner`, `test.object.admin` `test.%r{[a-z]+}` matches `test.it.owner`, `test.object.admin` (regexp) `test.**` matches `test.it.owner`, `test.object.admin` (** must be at the end)

func WithoutCustomCheck

func WithoutCustomCheck(obj any) error

WithoutCustomCheck remove custom check

Types

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager of the roles and permissions

The manager is the main object of the system which contains all roles and permissions and provides methods to check permissions and roles for the object.

Default manager implements implies that all permissions will be defined in the code.

Default manager implements chain permission name type

Object permission name: `objectType.permissionName.owner|account|all`
where objectType is the object type name, permissionName is the permission name
and owner|account|all is the owner type

func NewManager

func NewManager(roleAccessor RoleAccessors) *Manager

NewManager creates new manager

func NewManagerWithLoader

func NewManagerWithLoader(roleLoader RoleLoader, lifetimeCache time.Duration) *Manager

NewManagerWithLoader creates new manager with role loader

func (*Manager) ObjectByName added in v0.1.3

func (mng *Manager) ObjectByName(name string) any

ObjectByName returns object by name

func (*Manager) ObjectPermissions

func (mng *Manager) ObjectPermissions(obj any, patterns ...string) []Permission

ObjectPermissions returns all or selected permissions for the object like .RBACResourceName() + `.` + pattern

func (*Manager) Permission

func (mng *Manager) Permission(name string) Permission

AddRole to the manager

func (*Manager) Permissions

func (mng *Manager) Permissions(patterns ...string) []Permission

Permissions returns all or selected permissions

func (*Manager) RegisterNewOwningPermissions

func (mng *Manager) RegisterNewOwningPermissions(resType any, names []string, options ...Option) error

RegisterNewOwningPermissions modifies permissions for owning with extension of the name > name.owner, name.account and name.all

func (*Manager) RegisterNewPermission

func (mng *Manager) RegisterNewPermission(resType any, name string, options ...Option) error

RegisterNewPermission in the system

func (*Manager) RegisterNewPermissions

func (mng *Manager) RegisterNewPermissions(resType any, names []string, options ...Option) error

RegisterNewPermissions multiple related to the resource type

func (*Manager) RegisterObject

func (mng *Manager) RegisterObject(objType, checkCallbac any) *Manager

RegisterObject registers a typed object. Created permissions match by permission name and Go type (CheckType), as before.

func (*Manager) RegisterPermission

func (mng *Manager) RegisterPermission(perms ...Permission) *Manager

RegisterPermission in the system

func (*Manager) RegisterResource added in v1.0.0

func (mng *Manager) RegisterResource(objType, checkCallbac any) *Manager

RegisterResource registers a resource by RBACResourceName. Created permissions match by permission name and resource name, without requiring the same Go type.

func (*Manager) RegisterRole

func (mng *Manager) RegisterRole(ctx context.Context, roles ...Role) *Manager

Roles returns all or selected roles

func (*Manager) Role

func (mng *Manager) Role(ctx context.Context, name string) Role

AddRole to the manager

func (*Manager) Roles added in v0.1.1

func (mng *Manager) Roles(ctx context.Context, names ...string) []Role

Role returns role by name

func (*Manager) RolesByFilter added in v0.1.2

func (mng *Manager) RolesByFilter(ctx context.Context, filter RoleFilter) []Role

RolesByFilter returns roles by filter

type Option

type Option func(obj any) error

Option apply function to object

func WithChildRoles

func WithChildRoles(roles ...Role) Option

WithChildRoles of the role

func WithCustomCheck

func WithCustomCheck(f any, data ...any) Option

WithCustomCheck function and additional data if need to use in checker. Callback signature: func(ctx context.Context, resource T, perm Permission) bool Resource argument type is not required to match the registered Go type (proxy objects allowed).

func WithDescription added in v0.1.8

func WithDescription(description string) Option

WithDescription of the role or permission

func WithExtData

func WithExtData(data any) Option

WithExtData for the role or permission

func WithMatchByResourceName added in v1.0.0

func WithMatchByResourceName() Option

WithMatchByResourceName matches ResourcePermission by RBACResourceName, not Go type.

func WithPermissions

func WithPermissions(permissions ...any) Option

WithPermissions apply subpermission

type Permission

type Permission interface {
	Name() string

	// Description of the permission
	Description() string

	// CheckPermissions to accept to resource
	CheckPermissions(ctx context.Context, resource any, patterns ...string) bool

	// CheckedPermission returns child permission for resource which has been checked as allowed
	CheckedPermissions(ctx context.Context, resource any, patterns ...string) Permission

	// ChildPermissions list returns list of child permissions
	ChildPermissions() []Permission

	// Permission returns permission by name
	Permission(name string) Permission

	// Permissions returns list of permissions by pattern
	Permissions(patterns ...string) []Permission

	// HasPermission returns true if permission has child permission
	HasPermission(patterns ...string) bool

	// MatchPermissionPattern returns true if permission matches any of the patterns
	MatchPermissionPattern(patterns ...string) bool

	// Ext returns additional user data
	Ext() any
}

Permission object checker

type PermissionPatternExpander added in v1.0.0

type PermissionPatternExpander interface {
	RBACPermissionPatterns(patterns ...string) []string
}

PermissionPatternExpander optionally expands check patterns using object knowledge. Original patterns are always kept; returned values are appended.

type ResourcePermission

type ResourcePermission struct {
	SimplePermission
	// contains filtered or unexported fields
}

ResourcePermission implementation for some specific object type

func MustNewResourcePermission

func MustNewResourcePermission(name string, resType any, options ...Option) *ResourcePermission

MustNewResourcePermission with name and resource type

func NewResourcePermission

func NewResourcePermission(name string, resType any, options ...Option) (*ResourcePermission, error)

NewResourcePermission object with custom checker and base type

func (*ResourcePermission) CheckPermissions

func (perm *ResourcePermission) CheckPermissions(ctx context.Context, resource any, patterns ...string) bool

CheckPermissions to accept to resource

func (*ResourcePermission) CheckResourceName added in v1.0.0

func (perm *ResourcePermission) CheckResourceName(resource any) bool

CheckResourceName reports whether resource shares this permission's RBAC resource name.

func (*ResourcePermission) CheckType

func (perm *ResourcePermission) CheckType(resource any) bool

CheckType of resource and target type

func (*ResourcePermission) CheckedPermissions

func (perm *ResourcePermission) CheckedPermissions(ctx context.Context, resource any, patterns ...string) Permission

CheckedPermission returns child permission for resource which has been checked as allowed

func (*ResourcePermission) ChildPermissions

func (perm *ResourcePermission) ChildPermissions() []Permission

ChildPermissions returns list of child permissions

func (*ResourcePermission) Ext

func (perm *ResourcePermission) Ext() any

Ext returns additional user data

func (*ResourcePermission) HasPermission

func (perm *ResourcePermission) HasPermission(patterns ...string) bool

HasPermission returns true if permission has permission

func (*ResourcePermission) MatchPermissionPattern

func (perm *ResourcePermission) MatchPermissionPattern(patterns ...string) bool

MatchPermissionPattern returns true if permission matches any of the patterns

func (*ResourcePermission) Name

func (perm *ResourcePermission) Name() string

Name returns permission name

func (*ResourcePermission) Permission

func (perm *ResourcePermission) Permission(name string) Permission

Permission returns permission by name

func (*ResourcePermission) Permissions

func (perm *ResourcePermission) Permissions(patterns ...string) []Permission

Permissions returns list of permissions by pattern

func (*ResourcePermission) ResourceName

func (perm *ResourcePermission) ResourceName() string

ResourceName returns resource name

func (*ResourcePermission) ResourceType

func (perm *ResourcePermission) ResourceType() reflect.Type

ResourceType returns resource type

type Role

type Role interface {
	Permission

	// ChildRoles returns list of child roles
	ChildRoles() []Role

	// Role returns role by name
	Role(name string) Role

	// HasRole returns true if role has role
	HasRole(name string) bool
}

Role base interface

func MustNewRole

func MustNewRole(name string, options ...Option) Role

MustNewRole or produce panic

func NewDummyPermission

func NewDummyPermission(name string, allow bool) Role

NewDummyPermission permission with predefined check

func NewRole

func NewRole(name string, options ...Option) (Role, error)

NewRole interface implementation

type RoleAccessors

type RoleAccessors interface {
	Role(ctx context.Context, name string) Role
	Roles(ctx context.Context, names ...string) []Role
	RolesByFilter(ctx context.Context, filter RoleFilter) []Role
}

RoleAccessors interface for accessing roles

type RoleFilter added in v0.1.2

type RoleFilter func(ctx context.Context, role Role) bool

RoleLoader function for filling roles by custom rules

type RoleLoader

type RoleLoader interface {
	ListRoles(ctx context.Context) []Role
}

RoleLoader interface for loading roles from the storage or other source

type SimplePermission

type SimplePermission struct {
	// contains filtered or unexported fields
}

SimplePermission implementation with simple functionality

func MustNewSimplePermission

func MustNewSimplePermission(name string, options ...Option) *SimplePermission

MustNewSimplePermission with name and resource type

func NewSimplePermission

func NewSimplePermission(name string, options ...Option) (*SimplePermission, error)

NewSimplePermission object with custom checker

func (*SimplePermission) CheckPermissions

func (perm *SimplePermission) CheckPermissions(ctx context.Context, resource any, patterns ...string) bool

CheckPermissions to accept to resource

func (*SimplePermission) CheckedPermissions

func (perm *SimplePermission) CheckedPermissions(ctx context.Context, resource any, patterns ...string) Permission

CheckedPermission returns child permission for resource which has been checked as allowed

func (*SimplePermission) ChildPermissions

func (perm *SimplePermission) ChildPermissions() []Permission

ChildPermissions returns list of child permissions

func (*SimplePermission) Description added in v0.1.8

func (perm *SimplePermission) Description() string

Description of the permission

func (*SimplePermission) Ext

func (perm *SimplePermission) Ext() any

Ext returns additional user data

func (*SimplePermission) HasPermission

func (perm *SimplePermission) HasPermission(patterns ...string) bool

HasPermission returns true if permission has permission

func (*SimplePermission) MatchPermissionPattern

func (perm *SimplePermission) MatchPermissionPattern(patterns ...string) bool

MatchPermissionPattern returns true if permission matches any of the patterns

func (*SimplePermission) Name

func (perm *SimplePermission) Name() string

Name of the permission

func (*SimplePermission) Permission

func (perm *SimplePermission) Permission(name string) Permission

Permission returns permission by name

func (*SimplePermission) Permissions

func (perm *SimplePermission) Permissions(patterns ...string) []Permission

Permissions returns list of permissions by pattern

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL