142 lines
3.3 KiB
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
|
|
}
|
|
|