168 lines
5.4 KiB
Go
168 lines
5.4 KiB
Go
package casbin
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/tech/sendico/pkg/auth/anyobject"
|
|
"github.com/tech/sendico/pkg/auth/internal/casbin/serialization"
|
|
"github.com/tech/sendico/pkg/merrors"
|
|
"github.com/tech/sendico/pkg/mlogger"
|
|
"github.com/tech/sendico/pkg/model"
|
|
"github.com/tech/sendico/pkg/mutil/mzap"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// CasbinPermissionManager manages permissions using Casbin.
|
|
type CasbinPermissionManager struct {
|
|
logger mlogger.Logger // Logger for logging operations
|
|
enforcer *CasbinEnforcer // Casbin enforcer for managing policies
|
|
serializer serialization.Policy // Serializer for converting policies to/from Casbin
|
|
}
|
|
|
|
// GrantToRole adds a permission to a role in Casbin.
|
|
func (m *CasbinPermissionManager) GrantToRole(ctx context.Context, policy *model.RolePolicy) error {
|
|
objRef := anyobject.ID
|
|
if (policy.ObjectRef != nil) && (*policy.ObjectRef != primitive.NilObjectID) {
|
|
objRef = policy.ObjectRef.Hex()
|
|
}
|
|
|
|
m.logger.Debug("Granting permission to role",
|
|
mzap.ObjRef("role_ref", policy.RoleDescriptionRef),
|
|
mzap.ObjRef("permission_ref", policy.DescriptionRef),
|
|
zap.String("object_ref", objRef),
|
|
zap.String("action", string(policy.Effect.Action)),
|
|
zap.String("effect", string(policy.Effect.Effect)),
|
|
)
|
|
|
|
// Serialize permission
|
|
serializedPolicy, err := m.serializer.Serialize(policy)
|
|
if err != nil {
|
|
m.logger.Error("Failed to serialize permission while granting permission", zap.Error(err),
|
|
mzap.ObjRef("role_ref", policy.RoleDescriptionRef),
|
|
mzap.ObjRef("permission_ref", policy.DescriptionRef),
|
|
mzap.ObjRef("organization_ref", policy.OrganizationRef),
|
|
)
|
|
return err
|
|
}
|
|
|
|
// Add policy to Casbin
|
|
added, err := m.enforcer.enforcer.AddPolicy(serializedPolicy...)
|
|
if err != nil {
|
|
m.logger.Error("Failed to add policy to Casbin", zap.Error(err))
|
|
return err
|
|
}
|
|
if added {
|
|
m.logger.Info("Policy added to Casbin",
|
|
mzap.ObjRef("role_ref", policy.RoleDescriptionRef),
|
|
mzap.ObjRef("permission_ref", policy.DescriptionRef),
|
|
zap.String("object_ref", objRef),
|
|
)
|
|
} else {
|
|
m.logger.Warn("Policy already exists in Casbin",
|
|
mzap.ObjRef("role_ref", policy.RoleDescriptionRef),
|
|
mzap.ObjRef("permission_ref", policy.DescriptionRef),
|
|
zap.String("object_ref", objRef),
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// RevokeFromRole removes a permission from a role in Casbin.
|
|
func (m *CasbinPermissionManager) RevokeFromRole(ctx context.Context, policy *model.RolePolicy) error {
|
|
objRef := anyobject.ID
|
|
if policy.ObjectRef != nil {
|
|
objRef = policy.ObjectRef.Hex()
|
|
}
|
|
m.logger.Debug("Revoking permission from role",
|
|
mzap.ObjRef("role_ref", policy.RoleDescriptionRef),
|
|
mzap.ObjRef("permission_ref", policy.DescriptionRef),
|
|
zap.String("object_ref", objRef),
|
|
zap.String("action", string(policy.Effect.Action)),
|
|
zap.String("effect", string(policy.Effect.Effect)),
|
|
)
|
|
|
|
// Serialize policy
|
|
serializedPolicy, err := m.serializer.Serialize(policy)
|
|
if err != nil {
|
|
m.logger.Error("Failed to serialize policy while revoking permission from role",
|
|
zap.Error(err), mzap.ObjRef("role_ref", policy.RoleDescriptionRef),
|
|
mzap.ObjRef("policy_ref", policy.DescriptionRef))
|
|
return err
|
|
}
|
|
|
|
// Remove policy from Casbin
|
|
removed, err := m.enforcer.enforcer.RemovePolicy(serializedPolicy...)
|
|
if err != nil {
|
|
m.logger.Error("Failed to remove policy from Casbin", zap.Error(err))
|
|
return err
|
|
}
|
|
if removed {
|
|
m.logger.Info("Policy removed from Casbin",
|
|
mzap.ObjRef("role_ref", policy.RoleDescriptionRef),
|
|
mzap.ObjRef("permission_ref", policy.DescriptionRef),
|
|
zap.String("object_ref", objRef),
|
|
)
|
|
} else {
|
|
m.logger.Warn("Policy does not exist in Casbin",
|
|
mzap.ObjRef("role_ref", policy.RoleDescriptionRef),
|
|
mzap.ObjRef("permission_ref", policy.DescriptionRef),
|
|
zap.String("object_ref", objRef),
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetPolicies retrieves all policies for a specific role.
|
|
func (m *CasbinPermissionManager) GetPolicies(
|
|
ctx context.Context,
|
|
roleRef primitive.ObjectID,
|
|
) ([]model.RolePolicy, error) {
|
|
m.logger.Debug("Fetching policies for role", mzap.ObjRef("role_ref", roleRef))
|
|
|
|
// Retrieve Casbin policies for the role
|
|
policies, err := m.enforcer.enforcer.GetFilteredPolicy(0, roleRef.Hex())
|
|
if err != nil {
|
|
m.logger.Warn("Failed to get policies", zap.Error(err), mzap.ObjRef("role_ref", roleRef))
|
|
return nil, err
|
|
}
|
|
if len(policies) == 0 {
|
|
m.logger.Info("No policies found for role", mzap.ObjRef("role_ref", roleRef))
|
|
return nil, merrors.NoData("no policies")
|
|
}
|
|
|
|
// Deserialize policies
|
|
var result []model.RolePolicy
|
|
for _, policy := range policies {
|
|
permission, err := m.serializer.Deserialize(policy)
|
|
if err != nil {
|
|
m.logger.Warn("Failed to deserialize policy", zap.Error(err), zap.String("policy", policy[0]))
|
|
continue
|
|
}
|
|
result = append(result, *permission)
|
|
}
|
|
|
|
m.logger.Debug("Policies fetched successfully", mzap.ObjRef("role_ref", roleRef), zap.Int("count", len(result)))
|
|
return result, nil
|
|
}
|
|
|
|
// Save persists changes to the Casbin policy store.
|
|
func (m *CasbinPermissionManager) Save() error {
|
|
if err := m.enforcer.enforcer.SavePolicy(); err != nil {
|
|
m.logger.Error("Failed to save policies in Casbin", zap.Error(err))
|
|
return err
|
|
}
|
|
m.logger.Info("Policies successfully saved in Casbin")
|
|
return nil
|
|
}
|
|
|
|
func NewPermissionManager(logger mlogger.Logger, enforcer *CasbinEnforcer) *CasbinPermissionManager {
|
|
return &CasbinPermissionManager{
|
|
logger: logger.Named("permission"),
|
|
enforcer: enforcer,
|
|
serializer: serialization.NewPolicySerializer(),
|
|
}
|
|
}
|