diff --git a/src/BuildingBlocks/Shared/Identity/IdentityPermissionConstants.cs b/src/BuildingBlocks/Shared/Identity/IdentityPermissionConstants.cs index 67aca149c4..860a11e56d 100644 --- a/src/BuildingBlocks/Shared/Identity/IdentityPermissionConstants.cs +++ b/src/BuildingBlocks/Shared/Identity/IdentityPermissionConstants.cs @@ -8,6 +8,7 @@ public static class Users public const string Create = "Permissions.Users.Create"; public const string Update = "Permissions.Users.Update"; public const string Delete = "Permissions.Users.Delete"; + public const string ManageRoles = "Permissions.Users.ManageRoles"; } public static class Roles diff --git a/src/Modules/Identity/Modules.Identity/Authorization/PathAwareAuthorizationHandler.cs b/src/Modules/Identity/Modules.Identity/Authorization/PathAwareAuthorizationHandler.cs index b06e8e1fe2..2299c44c6a 100644 --- a/src/Modules/Identity/Modules.Identity/Authorization/PathAwareAuthorizationHandler.cs +++ b/src/Modules/Identity/Modules.Identity/Authorization/PathAwareAuthorizationHandler.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization.Policy; using Microsoft.AspNetCore.Http; @@ -38,7 +38,7 @@ public async Task HandleAsync( // If no endpoint is found, return 404 explicitly context.Response.StatusCode = StatusCodes.Status404NotFound; - await context.Response.WriteAsync("Endpoint not found."); + await context.Response.WriteAsync("Endpoint not found.", context.RequestAborted).ConfigureAwait(false); return; } diff --git a/src/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationHandler.cs b/src/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationHandler.cs index ae9a13d9af..e9f7a0a908 100644 --- a/src/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationHandler.cs +++ b/src/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationHandler.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Shared.Identity.Claims; +using FSH.Framework.Shared.Identity.Claims; using FSH.Modules.Identity.Contracts.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -12,9 +12,10 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext ArgumentNullException.ThrowIfNull(context); ArgumentNullException.ThrowIfNull(requirement); + var httpContext = context.Resource as HttpContext; var endpoint = context.Resource switch { - HttpContext httpContext => httpContext.GetEndpoint(), + HttpContext ctx => ctx.GetEndpoint(), Endpoint ep => ep, _ => null, }; @@ -27,7 +28,9 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context.Succeed(requirement); return; } - if (context.User?.GetUserId() is { } userId && await userService.HasPermissionAsync(userId, requiredPermissions.First())) + + var cancellationToken = httpContext?.RequestAborted ?? CancellationToken.None; + if (context.User?.GetUserId() is { } userId && await userService.HasPermissionAsync(userId, requiredPermissions.First(), cancellationToken).ConfigureAwait(false)) { context.Succeed(requirement); } diff --git a/src/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs b/src/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs index 9deb92fb79..fac44d76be 100644 --- a/src/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs +++ b/src/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs @@ -1,4 +1,6 @@ -using FSH.Modules.Identity.Contracts.v1.Users.AssignUserRoles; +using FSH.Framework.Shared.Identity; +using FSH.Framework.Shared.Identity.Authorization; +using FSH.Modules.Identity.Contracts.v1.Users.AssignUserRoles; using Mediator; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; @@ -27,6 +29,7 @@ internal static RouteHandlerBuilder MapAssignUserRolesEndpoint(this IEndpointRou }) .WithName("AssignUserRoles") .WithSummary("Assign roles to user") - .WithDescription("Assign one or more roles to a user."); + .WithDescription("Assign one or more roles to a user.") + .RequirePermission(IdentityPermissionConstants.Users.ManageRoles); } } diff --git a/src/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs b/src/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs index 12962e6cdd..57b84d04a8 100644 --- a/src/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs +++ b/src/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs @@ -21,6 +21,7 @@ internal static RouteHandlerBuilder MapChangePasswordEndpoint(this IEndpointRout }) .WithName("ChangePassword") .WithSummary("Change password") - .WithDescription("Change the current user's password."); + .WithDescription("Change the current user's password.") + .RequireAuthorization(); } } diff --git a/src/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs b/src/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs index 627d3d82b7..e3affb8e09 100644 --- a/src/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs +++ b/src/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs @@ -1,5 +1,7 @@ using System.Security.Claims; using FSH.Framework.Core.Exceptions; +using FSH.Framework.Shared.Identity; +using FSH.Framework.Shared.Identity.Authorization; using FSH.Framework.Shared.Identity.Claims; using FSH.Modules.Identity.Contracts.v1.Users.GetUserPermissions; using Mediator; @@ -24,6 +26,7 @@ internal static RouteHandlerBuilder MapGetCurrentUserPermissionsEndpoint(this IE }) .WithName("GetCurrentUserPermissions") .WithSummary("Get current user permissions") - .WithDescription("Retrieve permissions for the authenticated user."); + .WithDescription("Retrieve permissions for the authenticated user.") + .RequirePermission(IdentityPermissionConstants.Users.View); } } diff --git a/src/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs b/src/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs index b64e88b7a3..e5bc00fa77 100644 --- a/src/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs +++ b/src/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs @@ -24,6 +24,7 @@ internal static RouteHandlerBuilder MapGetMeEndpoint(this IEndpointRouteBuilder }) .WithName("GetCurrentUserProfile") .WithSummary("Get current user profile") - .WithDescription("Retrieve the authenticated user's profile from the access token."); + .WithDescription("Retrieve the authenticated user's profile from the access token.") + .RequireAuthorization(); } }