feat: better admin permissions (#5755)
* feat: add casbin admin permissions * feat: improve audit logging to associate logs with actual operators and target users * feat: enhance admin permissions and UI interactions for sensitive actions * Refactor authz RBAC and tighten channel permissions * Split channel authz field policy * Address channel authz review findings
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
package authz
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/QuantumNous/new-api/common"
|
||||
"github.com/casbin/casbin/v2"
|
||||
casbinmodel "github.com/casbin/casbin/v2/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var (
|
||||
enforcerMu sync.RWMutex
|
||||
enforcer *casbin.SyncedEnforcer
|
||||
)
|
||||
|
||||
const modelText = `
|
||||
[request_definition]
|
||||
r = sub, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = sub, obj, act, eft
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act && p.eft == "allow"
|
||||
`
|
||||
|
||||
func Init(db *gorm.DB) error {
|
||||
if common.IsMasterNode {
|
||||
if err := seedBuiltInRoles(db); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := resetBuiltInRolePolicies(db); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
m, err := casbinmodel.NewModelFromString(modelText)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e, err := casbin.NewSyncedEnforcer(m, newGormAdapter(db))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.EnableAutoSave(true)
|
||||
|
||||
enforcerMu.Lock()
|
||||
enforcer = e
|
||||
enforcerMu.Unlock()
|
||||
|
||||
if !common.IsMasterNode {
|
||||
return nil
|
||||
}
|
||||
return seedDefaultPolicies()
|
||||
}
|
||||
|
||||
func currentEnforcer() *casbin.SyncedEnforcer {
|
||||
enforcerMu.RLock()
|
||||
defer enforcerMu.RUnlock()
|
||||
return enforcer
|
||||
}
|
||||
|
||||
func ReloadPolicy() error {
|
||||
enforcerMu.Lock()
|
||||
defer enforcerMu.Unlock()
|
||||
if enforcer == nil {
|
||||
return fmt.Errorf("authz enforcer is not initialized")
|
||||
}
|
||||
return enforcer.LoadPolicy()
|
||||
}
|
||||
|
||||
// StartPolicySync periodically reloads the authorization policy from the database.
|
||||
// The enforcer keeps an in-memory snapshot, and permission changes are written
|
||||
// straight to the DB (see SetUserPermissionsInTx) with only the local node's
|
||||
// snapshot refreshed afterwards. Without this loop other instances in a
|
||||
// multi-node deployment would keep serving stale permissions (including not
|
||||
// honoring a revoked grant) until restart. Mirrors model.SyncOptions polling.
|
||||
func StartPolicySync(frequency int) {
|
||||
if frequency <= 0 {
|
||||
return
|
||||
}
|
||||
for {
|
||||
time.Sleep(time.Duration(frequency) * time.Second)
|
||||
if err := ReloadPolicy(); err != nil {
|
||||
common.SysError("failed to reload authz policy: " + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user