|
|
|
|
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<RoleAuthorizationMiddleware> 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<RoleAuthorizationMiddleware> Logger { get; }
|
|
|
|
|
private IMembershipService MembershipService { get; }
|
|
|
|
|
|
|
|
|
|
public Task<AuthorizationProviderResult> Authorize(IPermission permission, AuthorizationArgs e, Dictionary<string, object> state)
|
|
|
|
|
{
|
|
|
|
|
if (state["roles"] is not List<int> 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<AuthorizationProviderResult> PreAuthorize(AuthorizationArgs e, Dictionary<string, object> 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<ImmutableList<IPermissionSchemaDescriptor>> QueryDescriptors()
|
|
|
|
|
{
|
|
|
|
|
if (await RoleService.Query() is not ImmutableList<IRole> roles)
|
|
|
|
|
return ImmutableList<IPermissionSchemaDescriptor>.Empty;
|
|
|
|
|
|
|
|
|
|
var result = new List<IPermissionSchemaDescriptor>();
|
|
|
|
|
|
|
|
|
|
foreach (var role in roles)
|
|
|
|
|
{
|
|
|
|
|
result.Add(new PermissionSchemaDescriptor
|
|
|
|
|
{
|
|
|
|
|
Title = role.Name,
|
|
|
|
|
Id = role.Id.ToString()
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result.ToImmutableList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<List<int>> ResolveImplicitRoles(AuthorizationArgs e)
|
|
|
|
|
{
|
|
|
|
|
var result = new List<int>();
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|