mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-18 11:02:54 +00:00
- Add CasbinService struct with enforcer/db fields and NewCasbinService constructor with GORM adapter initialization - Add Casbin model configuration with request_definition/policy_definition/role_definition/policy_effect/matchers for RBAC - Add initializeDefaultPolicies with admin (full access), operator (manage services/monitoring), and viewer (read-only) role permissions - Add CheckPermission method
212 lines
5.9 KiB
Go
212 lines
5.9 KiB
Go
package rbac
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/casbin/casbin/v2"
|
|
"github.com/casbin/casbin/v2/model"
|
|
gormadapter "github.com/casbin/gorm-adapter/v3"
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/nutcas3/telecom-platform/apps/api-server/internal/models"
|
|
)
|
|
|
|
// CasbinService provides sophisticated RBAC using Casbin
|
|
type CasbinService struct {
|
|
enforcer *casbin.Enforcer
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewCasbinService creates a new Casbin service
|
|
func NewCasbinService(db *gorm.DB) (*CasbinService, error) {
|
|
// Initialize GORM adapter for Casbin
|
|
adapter, err := gormadapter.NewAdapterByDB(db)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create Casbin adapter: %w", err)
|
|
}
|
|
|
|
// Casbin model configuration for RBAC
|
|
modelText := `
|
|
[request_definition]
|
|
r = sub, obj, act
|
|
|
|
[policy_definition]
|
|
p = sub, obj, act
|
|
|
|
[role_definition]
|
|
g = _, _
|
|
|
|
[policy_effect]
|
|
e = some(where (p.eft == allow))
|
|
|
|
[matchers]
|
|
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
|
|
`
|
|
|
|
// Create model from text
|
|
m, err := model.NewModelFromString(modelText)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create Casbin model: %w", err)
|
|
}
|
|
|
|
// Create enforcer
|
|
enforcer, err := casbin.NewEnforcer(m, adapter)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create Casbin enforcer: %w", err)
|
|
}
|
|
|
|
service := &CasbinService{
|
|
enforcer: enforcer,
|
|
db: db,
|
|
}
|
|
|
|
// Initialize default policies
|
|
if err := service.initializeDefaultPolicies(); err != nil {
|
|
log.Printf("Warning: failed to initialize default policies: %v", err)
|
|
}
|
|
|
|
return service, nil
|
|
}
|
|
|
|
// initializeDefaultPolicies sets up default RBAC policies
|
|
func (s *CasbinService) initializeDefaultPolicies() error {
|
|
// Default role permissions
|
|
defaultPolicies := [][]string{
|
|
// Admin permissions (full access)
|
|
{"admin", "/v1/services", "GET"},
|
|
{"admin", "/v1/services", "POST"},
|
|
{"admin", "/v1/monitoring", "GET"},
|
|
{"admin", "/v1/deploy", "GET"},
|
|
{"admin", "/v1/deploy", "POST"},
|
|
{"admin", "/v1/plugins", "GET"},
|
|
{"admin", "/v1/plugins", "POST"},
|
|
{"admin", "/v1/plugins", "DELETE"},
|
|
{"admin", "/v1/automation", "GET"},
|
|
{"admin", "/v1/automation", "POST"},
|
|
{"admin", "/v1/billing", "GET"},
|
|
{"admin", "/v1/billing", "POST"},
|
|
{"admin", "/v1/config", "GET"},
|
|
{"admin", "/v1/config", "POST"},
|
|
{"admin", "/v1/chaos", "GET"},
|
|
{"admin", "/v1/chaos", "POST"},
|
|
|
|
// Operator permissions (can manage services and monitoring)
|
|
{"operator", "/v1/services", "GET"},
|
|
{"operator", "/v1/services", "POST"},
|
|
{"operator", "/v1/monitoring", "GET"},
|
|
{"operator", "/v1/deploy", "GET"},
|
|
{"operator", "/v1/plugins", "GET"},
|
|
{"operator", "/v1/automation", "GET"},
|
|
{"operator", "/v1/billing", "GET"},
|
|
{"operator", "/v1/config", "GET"},
|
|
{"operator", "/v1/chaos", "GET"},
|
|
|
|
// Viewer permissions (read-only access)
|
|
{"viewer", "/v1/services", "GET"},
|
|
{"viewer", "/v1/monitoring", "GET"},
|
|
{"viewer", "/v1/deploy", "GET"},
|
|
{"viewer", "/v1/plugins", "GET"},
|
|
{"viewer", "/v1/automation", "GET"},
|
|
{"viewer", "/v1/billing", "GET"},
|
|
{"viewer", "/v1/config", "GET"},
|
|
{"viewer", "/v1/chaos", "GET"},
|
|
}
|
|
|
|
// Add policies if they don't exist
|
|
for _, policy := range defaultPolicies {
|
|
ok, err := s.enforcer.AddPolicy(policy)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to add policy %v: %w", policy, err)
|
|
}
|
|
if ok {
|
|
log.Printf("Added default policy: %v", policy)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// CheckPermission checks if a user has permission for a specific action on a resource
|
|
func (s *CasbinService) CheckPermission(ctx context.Context, userID uint, resource, action string) (bool, error) {
|
|
// Get user with role
|
|
var user models.User
|
|
if err := s.db.WithContext(ctx).First(&user, userID).Error; err != nil {
|
|
return false, fmt.Errorf("failed to get user: %w", err)
|
|
}
|
|
|
|
// Check user's role for permission
|
|
allowed, err := s.enforcer.Enforce(user.Role, resource, action)
|
|
if err != nil {
|
|
return false, fmt.Errorf("failed to enforce policy: %w", err)
|
|
}
|
|
|
|
return allowed, nil
|
|
}
|
|
|
|
// AddPolicy adds a new policy to Casbin
|
|
func (s *CasbinService) AddPolicy(role, resource, action string) error {
|
|
ok, err := s.enforcer.AddPolicy([]string{role, resource, action})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to add policy: %w", err)
|
|
}
|
|
if !ok {
|
|
return fmt.Errorf("policy already exists")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RemovePolicy removes a policy from Casbin
|
|
func (s *CasbinService) RemovePolicy(role, resource, action string) error {
|
|
ok, err := s.enforcer.RemovePolicy([]string{role, resource, action})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to remove policy: %w", err)
|
|
}
|
|
if !ok {
|
|
return fmt.Errorf("policy does not exist")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetPolicies returns all policies
|
|
func (s *CasbinService) GetPolicies() ([][]string, error) {
|
|
policies, err := s.enforcer.GetPolicy()
|
|
return policies, err
|
|
}
|
|
|
|
// GetRolesForUser returns all roles assigned to a user
|
|
func (s *CasbinService) GetRolesForUser(userID uint) ([]string, error) {
|
|
var user models.User
|
|
if err := s.db.First(&user, userID).Error; err != nil {
|
|
return nil, fmt.Errorf("failed to get user: %w", err)
|
|
}
|
|
|
|
return []string{user.Role}, nil
|
|
}
|
|
|
|
// AssignRole assigns a role to a user
|
|
func (s *CasbinService) AssignRole(userID uint, roleName string) error {
|
|
// This would typically involve updating the user_roles junction table
|
|
// For now, we'll assume this is handled by the user service
|
|
return nil
|
|
}
|
|
|
|
// RemoveRole removes a role from a user
|
|
func (s *CasbinService) RemoveRole(userID uint, roleName string) error {
|
|
// This would typically involve updating the user_roles junction table
|
|
// For now, we'll assume this is handled by the user service
|
|
return nil
|
|
}
|
|
|
|
// GetPermissionsForRole returns all permissions for a role
|
|
func (s *CasbinService) GetPermissionsForRole(role string) ([][]string, error) {
|
|
permissions, err := s.enforcer.GetPermissionsForUser(role)
|
|
return permissions, err
|
|
}
|
|
|
|
// HasPermissionForRole checks if a role has a specific permission
|
|
func (s *CasbinService) HasPermissionForRole(role, resource, action string) (bool, error) {
|
|
return s.enforcer.Enforce(role, resource, action)
|
|
}
|