|
|
|
|
using Connected.Entities;
|
|
|
|
|
using Connected.Middleware;
|
|
|
|
|
using Connected.Security.Authorization;
|
|
|
|
|
using Connected.Security.Identity;
|
|
|
|
|
using System.Collections.Immutable;
|
|
|
|
|
using System.Security;
|
|
|
|
|
|
|
|
|
|
namespace Connected.Services.Authorization;
|
|
|
|
|
|
|
|
|
|
public abstract class ServiceAuthorizationMiddleware : MiddlewareComponent, IServiceAuthorizationMiddleware
|
|
|
|
|
{
|
|
|
|
|
protected ServiceAuthorizationMiddleware(IAuthorizationService authorizationService, IIdentityService identityService)
|
|
|
|
|
{
|
|
|
|
|
AuthorizationService = authorizationService;
|
|
|
|
|
IdentityService = identityService;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected IAuthorizationService AuthorizationService { get; }
|
|
|
|
|
protected IIdentityService IdentityService { get; }
|
|
|
|
|
|
|
|
|
|
public Task<ImmutableArray<string>> ResolveClaims(ImmutableArray<string> claims)
|
|
|
|
|
{
|
|
|
|
|
return OnResolveClaims(claims);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual Task<ImmutableArray<string>> OnResolveClaims(ImmutableArray<string> claims)
|
|
|
|
|
{
|
|
|
|
|
return Task.FromResult(claims);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task Authorize<TArgs>(ServiceAuthorizationMiddlewareArgs<TArgs> args) where TArgs : IDto
|
|
|
|
|
{
|
|
|
|
|
await OnAuthorize(args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual async Task OnAuthorize<TArgs>(ServiceAuthorizationMiddlewareArgs<TArgs> args) where TArgs : IDto
|
|
|
|
|
{
|
|
|
|
|
foreach (var claim in args.Claims)
|
|
|
|
|
{
|
|
|
|
|
var result = await AuthorizationService.Authorize(new AuthorizationArgs
|
|
|
|
|
{
|
|
|
|
|
User = IdentityService.CurrentUser?.Id,
|
|
|
|
|
Claim = claim,
|
|
|
|
|
Component = args.Context.Sender.GetType().Name,
|
|
|
|
|
Method = args.Context.Method,
|
|
|
|
|
Schema = new AuthorizationSchema
|
|
|
|
|
{
|
|
|
|
|
EmptyPolicy = EmptyPolicyBehavior.Alow,
|
|
|
|
|
Strategy = AuthorizationStrategy.Pessimistic
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!result.Success)
|
|
|
|
|
throw new AccessViolationException($"{SR.PolicyAuthorizationFailed} ({result.Reason})");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<TComponent> Authorize<TArgs, TComponent>(ServiceAuthorizationMiddlewareArgs<TArgs> args, TComponent component)
|
|
|
|
|
where TArgs : IDto
|
|
|
|
|
{
|
|
|
|
|
return await OnAuthorize(args, component);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected async Task<TComponent> OnAuthorize<TArgs, TComponent>(ServiceAuthorizationMiddlewareArgs<TArgs> args, TComponent component)
|
|
|
|
|
where TArgs : IDto
|
|
|
|
|
{
|
|
|
|
|
var entity = component as IEntity;
|
|
|
|
|
|
|
|
|
|
var primaryKey = entity is null ? component.ToString() : entity.PrimaryKeyValue();
|
|
|
|
|
|
|
|
|
|
foreach (var claim in args.Claims)
|
|
|
|
|
{
|
|
|
|
|
var result = await AuthorizationService.Authorize(new AuthorizationArgs
|
|
|
|
|
{
|
|
|
|
|
User = IdentityService.CurrentUser?.Id,
|
|
|
|
|
Claim = claim,
|
|
|
|
|
Component = args.Context.Sender.GetType().Name,
|
|
|
|
|
Method = args.Context.Method,
|
|
|
|
|
Schema = new AuthorizationSchema
|
|
|
|
|
{
|
|
|
|
|
EmptyPolicy = EmptyPolicyBehavior.Alow,
|
|
|
|
|
Strategy = AuthorizationStrategy.Pessimistic
|
|
|
|
|
},
|
|
|
|
|
Entity = entity.EntityId(),
|
|
|
|
|
PrimaryKey = primaryKey
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!result.Success)
|
|
|
|
|
throw new SecurityException($"{SR.PolicyAuthorizationFailed} ({result.Reason})");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return component;
|
|
|
|
|
}
|
|
|
|
|
}
|