using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Nuuru.Server.Auth; using Nuuru.Server.Models; using System.Security.Claims; namespace Nuuru.Server.Services { public interface IPermissionService { Task GrantPermissionAsync(Guid userId, string permission); Task RevokePermissionAsync(Guid userId, string permission); Task> GetUserPermissionsAsync(Guid userId); Task UserHasPermissionAsync(Guid userId, string permission); Task SetUserPermissionsAsync(Guid userId, IEnumerable permissions); bool HasPermission(ClaimsPrincipal user, string permission); Task DenyPermissionAsync(Guid userId, string permission); Task RemoveDenyPermissionAsync(Guid userId, string permission); Task> GetDeniedPermissionsAsync(Guid userId); Task> GetEffectivePermissionsAsync(Guid userId); } public class PermissionService : IPermissionService { private readonly UserManager _userManager; private readonly RoleManager _roleManager; private readonly ILogger _logger; public PermissionService( UserManager userManager, RoleManager roleManager, ILogger logger) { _userManager = userManager; _roleManager = roleManager; _logger = logger; } public async Task GrantPermissionAsync(Guid userId, string permission) { var user = await _userManager.FindByIdAsync(userId.ToString()); if (user == null) { _logger.LogWarning("Attempted to grant permission to non-existent user: {UserId}", userId); return false; } var claim = new Claim(Permissions.ClaimType, permission); var result = await _userManager.AddClaimAsync(user, claim); if (result.Succeeded) { _logger.LogInformation("Granted permission {Permission} to user {UserId}", permission, userId); return true; } _logger.LogError("Failed to grant permission {Permission} to user {UserId}: {Errors}", permission, userId, string.Join(", ", result.Errors.Select(e => e.Description))); return false; } public async Task RevokePermissionAsync(Guid userId, string permission) { var user = await _userManager.FindByIdAsync(userId.ToString()); if (user == null) { _logger.LogWarning("Attempted to revoke permission from non-existent user: {UserId}", userId); return false; } var claims = await _userManager.GetClaimsAsync(user); var claimToRemove = claims.FirstOrDefault(c => c.Type == Permissions.ClaimType && c.Value == permission); if (claimToRemove == null) { _logger.LogWarning("User {UserId} does not have permission {Permission}", userId, permission); return false; } var result = await _userManager.RemoveClaimAsync(user, claimToRemove); if (result.Succeeded) { _logger.LogInformation("Revoked permission {Permission} from user {UserId}", permission, userId); return true; } _logger.LogError("Failed to revoke permission {Permission} from user {UserId}: {Errors}", permission, userId, string.Join(", ", result.Errors.Select(e => e.Description))); return false; } public async Task> GetUserPermissionsAsync(Guid userId) { var user = await _userManager.FindByIdAsync(userId.ToString()); if (user == null) { return Enumerable.Empty(); } var claims = await _userManager.GetClaimsAsync(user); return claims .Where(c => c.Type == Permissions.ClaimType) .Select(c => c.Value) .ToList(); } public async Task UserHasPermissionAsync(Guid userId, string permission) { var user = await _userManager.FindByIdAsync(userId.ToString()); if (user == null) { return false; } var claims = await _userManager.GetClaimsAsync(user); return claims.Any(c => c.Type == Permissions.ClaimType && c.Value == permission); } public async Task SetUserPermissionsAsync(Guid userId, IEnumerable permissions) { var user = await _userManager.FindByIdAsync(userId.ToString()); if (user == null) { _logger.LogWarning("Attempted to set permissions for non-existent user: {UserId}", userId); return false; } // Remove all existing permission claims var existingClaims = await _userManager.GetClaimsAsync(user); var permissionClaims = existingClaims .Where(c => c.Type == Permissions.ClaimType) .ToList(); if (permissionClaims.Any()) { var removeResult = await _userManager.RemoveClaimsAsync(user, permissionClaims); if (!removeResult.Succeeded) { _logger.LogError("Failed to remove existing permissions for user {UserId}", userId); return false; } } // Add new permission claims var newClaims = permissions .Select(p => new Claim(Permissions.ClaimType, p)) .ToList(); if (newClaims.Any()) { var addResult = await _userManager.AddClaimsAsync(user, newClaims); if (!addResult.Succeeded) { _logger.LogError("Failed to add new permissions for user {UserId}", userId); return false; } } _logger.LogInformation("Updated permissions for user {UserId}. New permissions: {Permissions}", userId, string.Join(", ", permissions)); return true; } public bool HasPermission(ClaimsPrincipal user, string permission) { if (user == null || !user.Identity?.IsAuthenticated == true) return false; // Check if user has the specific permission claim return user.HasClaim(Permissions.ClaimType, permission); } public async Task DenyPermissionAsync(Guid userId, string permission) { var user = await _userManager.FindByIdAsync(userId.ToString()); if (user == null) { _logger.LogWarning("Attempted to deny permission for non-existent user: {UserId}", userId); return false; } // Check if already denied var claims = await _userManager.GetClaimsAsync(user); if (claims.Any(c => c.Type == Permissions.DenyClaimType && c.Value == permission)) { _logger.LogWarning("Permission {Permission} is already denied for user {UserId}", permission, userId); return false; } var claim = new Claim(Permissions.DenyClaimType, permission); var result = await _userManager.AddClaimAsync(user, claim); if (result.Succeeded) { _logger.LogInformation("Denied permission {Permission} for user {UserId}", permission, userId); return true; } _logger.LogError("Failed to deny permission {Permission} for user {UserId}: {Errors}", permission, userId, string.Join(", ", result.Errors.Select(e => e.Description))); return false; } public async Task RemoveDenyPermissionAsync(Guid userId, string permission) { var user = await _userManager.FindByIdAsync(userId.ToString()); if (user == null) { _logger.LogWarning("Attempted to remove permission denial from non-existent user: {UserId}", userId); return false; } var claims = await _userManager.GetClaimsAsync(user); var claimToRemove = claims.FirstOrDefault(c => c.Type == Permissions.DenyClaimType && c.Value == permission); if (claimToRemove == null) { _logger.LogWarning("User {UserId} does not have permission {Permission} denied", userId, permission); return false; } var result = await _userManager.RemoveClaimAsync(user, claimToRemove); if (result.Succeeded) { _logger.LogInformation("Removed permission denial {Permission} from user {UserId}", permission, userId); return true; } _logger.LogError("Failed to remove permission denial {Permission} from user {UserId}: {Errors}", permission, userId, string.Join(", ", result.Errors.Select(e => e.Description))); return false; } public async Task> GetDeniedPermissionsAsync(Guid userId) { var user = await _userManager.FindByIdAsync(userId.ToString()); if (user == null) { return Enumerable.Empty(); } var claims = await _userManager.GetClaimsAsync(user); return claims .Where(c => c.Type == Permissions.DenyClaimType) .Select(c => c.Value) .ToList(); } public async Task> GetEffectivePermissionsAsync(Guid userId) { var user = await _userManager.FindByIdAsync(userId.ToString()); if (user == null) { return Enumerable.Empty(); } // Get role claims var roleClaims = new List(); var roles = await _userManager.GetRolesAsync(user); foreach (var roleName in roles) { var role = await _roleManager.FindByNameAsync(roleName); if (role != null) { var claims = await _roleManager.GetClaimsAsync(role); roleClaims.AddRange(claims); } } // Get user claims var userClaims = await _userManager.GetClaimsAsync(user); // Compute effective permissions using utility return PermissionCalculator.ComputeEffectivePermissionsFromClaims(roleClaims, userClaims); } } }