using Connected.Interop; using Connected.Middleware; using Connected.Security.Identity; using Connected.Security.Membership; using Connected.Security.Permissions; using Connected.ServiceModel; using Microsoft.Extensions.Logging; using System.Collections.Immutable; namespace Connected.Security.Authorization.Middleware; internal class RoleAuthorizationMiddleware : MiddlewareComponent, IAuthorizationMiddleware { public RoleAuthorizationMiddleware(IRoleService roleService, IUserService userService, ILogger logger, IMembershipService membershipService) { RoleService = roleService; UserService = userService; Logger = logger; MembershipService = membershipService; } public string Id => "Roles"; private IRoleService RoleService { get; } private IUserService UserService { get; } private ILogger Logger { get; } private IMembershipService MembershipService { get; } public Task Authorize(IPermission permission, AuthorizationArgs e, Dictionary state) { if (state["roles"] is not List roles) return Task.FromResult(AuthorizationProviderResult.NotHandled); if (!TypeConversion.TryConvert(permission.Evidence, out int evidence)) return Task.FromResult(AuthorizationProviderResult.NotHandled); if (roles.Contains(evidence)) { return permission.Value switch { PermissionValue.NotSet => Task.FromResult(AuthorizationProviderResult.NotHandled), PermissionValue.Allow => Task.FromResult(AuthorizationProviderResult.Success), PermissionValue.Deny => Task.FromResult(AuthorizationProviderResult.Fail), _ => throw new NotSupportedException(), }; } return Task.FromResult(AuthorizationProviderResult.NotHandled); } public async Task PreAuthorize(AuthorizationArgs e, Dictionary state) { var roles = await ResolveImplicitRoles(e); state.Add("roles", roles); if (e.User > 0) { var list = await MembershipService.Query(new MembershipQueryArgs { User = (int)e.User }); if (list is not null && list.Any()) roles.AddRange(list.Select(f => f.Role)); } if (await RoleService.Select(new NameArgs { Name = Roles.FullControl }) is IRole fullControl && roles.Contains(fullControl.Id)) return AuthorizationProviderResult.Success; return AuthorizationProviderResult.NotHandled; } public async Task> QueryDescriptors() { if (await RoleService.Query() is not ImmutableList roles) return ImmutableList.Empty; var result = new List(); foreach (var role in roles) { result.Add(new PermissionSchemaDescriptor { Title = role.Name, Id = role.Id.ToString() }); } return result.ToImmutableList(); } private async Task> ResolveImplicitRoles(AuthorizationArgs e) { var result = new List(); if (await RoleService.Select(Roles.Everyone) is IRole everyone) result.Add(everyone.Id); if (e.User == 0) { if (await RoleService.Select(Roles.Anonymous) is IRole anonymous) result.Add(anonymous.Id); } else { if (e.User is null || await UserService.Select(e.User) is null) { if (await RoleService.Select(Roles.Anonymous) is IRole anonymous) result.Add(anonymous.Id); Logger.LogWarning("Authenticated user not found. Request will be treated as anonymous {user}.", e.User); return result; } if (await RoleService.Select(Roles.Authenticated) is IRole authenticated) result.Add(authenticated.Id); } return result; } }