live-sfu-demo/internal/auth/enforcer.go

142 lines
3.3 KiB
Go

package auth
import (
"fmt"
"path/filepath"
"sync"
"github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model"
fileadapter "github.com/casbin/casbin/v2/persist/file-adapter"
)
type EnforcerWrapper struct {
mu sync.RWMutex
enforcer *casbin.Enforcer
store *UserStore
modelPath string
policyPath string
}
func NewEnforcer(modelPath, policyPath string, store *UserStore) (*EnforcerWrapper, error) {
m, err := model.NewModelFromFile(modelPath)
if err != nil {
return nil, fmt.Errorf("load casbin model: %w", err)
}
adapter := fileadapter.NewAdapter(policyPath)
enforcer, err := casbin.NewEnforcer(m, adapter)
if err != nil {
return nil, fmt.Errorf("new enforcer: %w", err)
}
if err := enforcer.LoadPolicy(); err != nil {
return nil, fmt.Errorf("load policy: %w", err)
}
w := &EnforcerWrapper{enforcer: enforcer, store: store, modelPath: modelPath, policyPath: policyPath}
w.syncGrouping()
return w, nil
}
func NewEnforcerWithModelText(modelText string, policyPath string, store *UserStore) (*EnforcerWrapper, error) {
m, err := model.NewModelFromString(modelText)
if err != nil {
return nil, err
}
var adapter = fileadapter.NewAdapter(policyPath)
e, err := casbin.NewEnforcer(m, adapter)
if err != nil {
return nil, err
}
_ = e.LoadPolicy()
w := &EnforcerWrapper{enforcer: e, store: store}
w.syncGrouping()
return w, nil
}
func (w *EnforcerWrapper) syncGrouping() {
if w.store == nil {
return
}
w.mu.Lock()
defer w.mu.Unlock()
for _, u := range w.store.List() {
_, _ = w.enforcer.AddGroupingPolicy(u.Username, u.Role)
}
for _, role := range AllRoles() {
_, _ = w.enforcer.AddGroupingPolicy(role, role)
}
_, _ = w.enforcer.AddGroupingPolicy(RoleGuest, RoleGuest)
}
func (w *EnforcerWrapper) AddUserRole(username, role string) error {
w.mu.Lock()
defer w.mu.Unlock()
roles, _ := w.enforcer.GetRolesForUser(username)
for _, r := range roles {
if r != role {
_, _ = w.enforcer.RemoveGroupingPolicy(username, r)
}
}
added, err := w.enforcer.AddGroupingPolicy(username, role)
if err != nil {
return err
}
if added {
_ = w.enforcer.SavePolicy()
}
return nil
}
func (w *EnforcerWrapper) RemoveUser(username string) error {
w.mu.Lock()
defer w.mu.Unlock()
_, err := w.enforcer.RemoveFilteredGroupingPolicy(0, username)
if err != nil {
return err
}
_ = w.enforcer.SavePolicy()
return nil
}
func (w *EnforcerWrapper) Enforce(sub, obj, act string) (bool, error) {
w.mu.RLock()
defer w.mu.RUnlock()
return w.enforcer.Enforce(sub, obj, act)
}
func (w *EnforcerWrapper) EnforceWithRole(username, role, obj, act string) (bool, error) {
sub := username
if sub == "" {
sub = role
if sub == "" {
sub = RoleGuest
}
}
return w.Enforce(sub, obj, act)
}
func (w *EnforcerWrapper) GetEnforcer() *casbin.Enforcer { return w.enforcer }
func (w *EnforcerWrapper) ReloadPolicy() error {
w.mu.Lock()
defer w.mu.Unlock()
return w.enforcer.LoadPolicy()
}
func (w *EnforcerWrapper) SavePolicy() error {
w.mu.Lock()
defer w.mu.Unlock()
return w.enforcer.SavePolicy()
}
func (w *EnforcerWrapper) ModelPath() string { return w.modelPath }
func (w *EnforcerWrapper) PolicyPath() string { return w.policyPath }
func EnsurePolicyFile(path string) string {
if path == "" {
return ""
}
abs, _ := filepath.Abs(path)
return abs
}