package native import ( "context" "errors" "github.com/tech/sendico/pkg/auth/internal/native/nstructures" "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" ) // PermissionManager manages permissions using Casbin. type PermissionManager struct { logger mlogger.Logger enforcer *Enforcer } // GrantToRole adds a permission to a role in Casbin. func (m *PermissionManager) GrantToRole(ctx context.Context, policy *model.RolePolicy) error { objRef := "any" 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)), ) assignment := nstructures.PolicyAssignment{ Policy: policy.Policy, RoleRef: policy.RoleDescriptionRef, } if err := m.enforcer.pdb.Create(ctx, &assignment); err != nil { m.logger.Warn("Failed to grant policy", zap.Error(err), 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))) return err } return nil } // RevokeFromRole removes a permission from a role in Casbin. func (m *PermissionManager) RevokeFromRole(ctx context.Context, policy *model.RolePolicy) error { objRef := "*" 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)), ) if err := m.enforcer.pdb.Remove(ctx, policy); err != nil { m.logger.Warn("Failed to revoke policy", zap.Error(err), 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))) return err } return nil } // GetPolicies retrieves all policies for a specific role. func (m *PermissionManager) GetPolicies( ctx context.Context, roleRef primitive.ObjectID, ) ([]model.RolePolicy, error) { m.logger.Debug("Fetching policies for role", mzap.ObjRef("role_ref", roleRef)) assinments, err := m.enforcer.pdb.PoliciesForRole(ctx, roleRef) if errors.Is(err, merrors.ErrNoData) { m.logger.Debug("No policies found", mzap.ObjRef("role_ref", roleRef)) return []model.RolePolicy{}, nil } policies := make([]model.RolePolicy, len(assinments)) for i, assinment := range assinments { policies[i] = model.RolePolicy{ Policy: assinment.Policy, RoleDescriptionRef: assinment.RoleRef, } } m.logger.Debug("Policies fetched successfully", mzap.ObjRef("role_ref", roleRef), zap.Int("count", len(policies))) return policies, nil } // Save persists changes to the Casbin policy store. func (m *PermissionManager) Save() error { m.logger.Info("Policies successfully saved") // do nothing return nil } func NewPermissionManager(logger mlogger.Logger, enforcer *Enforcer) *PermissionManager { return &PermissionManager{ logger: logger.Named("permission"), enforcer: enforcer, } }