Added skoruba api integration
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
|
||||
namespace PostFundManagement.Application.Abstractions;
|
||||
namespace PostFundManagement.Application.Abstractions.Services;
|
||||
|
||||
public abstract class S3ServiceBase(IAmazonS3 amazonS3)
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace PostFundManagement.Application.Abstractions;
|
||||
namespace PostFundManagement.Application.Abstractions.Services;
|
||||
|
||||
public abstract class ServiceCacheBase
|
||||
{
|
||||
@@ -1,6 +1,7 @@
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Security;
|
||||
using PostFundManagement.Domain.Security.Configuration;
|
||||
using PostFundManagement.Domain.Attributes;
|
||||
using PostFundManagement.Domain.Configuration.Security;
|
||||
using PostFundManagement.Infrastructure.Security;
|
||||
|
||||
namespace PostFundManagement.Application.Extensions;
|
||||
|
||||
|
||||
@@ -1,13 +1,53 @@
|
||||
using PostFundManagement.Application.Interceptors;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain.Security.Configuration;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using PostFundManagement.Domain.Configuration.Security;
|
||||
using PostFundManagement.Domain.Extensions;
|
||||
using PostFundManagement.Domain.Security.Sdk;
|
||||
using PostFundManagement.Infrastructure.Database;
|
||||
using PostFundManagement.Infrastructure.Security;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
namespace PostFundManagement.Application.Extensions;
|
||||
|
||||
public static class Security
|
||||
{
|
||||
public static IServiceCollection AddSkorubaApiService(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
var configSection = configuration.GetSection(nameof(MachineIdentitySettings));
|
||||
|
||||
var authOptions = new MachineIdentitySettings();
|
||||
configSection.Bind(authOptions);
|
||||
|
||||
services.Configure<MachineIdentitySettings>(configSection);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(authOptions.Authority))
|
||||
return services;
|
||||
|
||||
if (!authOptions.Authority.EndsWith('/')) authOptions.Authority += "/";
|
||||
|
||||
services.AddClientCredentialsTokenManagement()
|
||||
.AddClient(SkorubaCredentialClient, client =>
|
||||
{
|
||||
client.TokenEndpoint = new Uri($"{authOptions.Authority}connect/token");
|
||||
client.ClientId = ClientId.Parse(authOptions.ClientId!);
|
||||
client.ClientSecret = ClientSecret.Parse(authOptions.ClientSecret!);
|
||||
client.Scope = Duende.AccessTokenManagement.Scope.ParseOrDefault(authOptions.Scope);
|
||||
});
|
||||
|
||||
services.AddHttpClient(SkorubaHttpClient, client =>
|
||||
{
|
||||
client.BaseAddress = new Uri(configuration.GetConnectionString("SkorubaApi")!);
|
||||
}).AddClientCredentialsTokenHandler(ClientCredentialsClientName.Parse(SkorubaCredentialClient));
|
||||
|
||||
services.AddScoped<AuditInterceptor>();
|
||||
services.AddScoped<LoggingInterceptor>();
|
||||
services.AddSingleton<ProxyGenerator>();
|
||||
|
||||
services.AddLoggedAuditedServiceScoped<ISkorubaUserService, SkorubaUserService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddSecurityApiSdk(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
var configSection = configuration.GetSection(nameof(SecurityClientSettings));
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
using PostFundManagement.Application.Interceptors;
|
||||
|
||||
namespace PostFundManagement.Application.Extensions;
|
||||
|
||||
public static class ServiceExtensionTools
|
||||
{
|
||||
public static IServiceCollection AddLoggedCachedServiceScoped<TInterface, TImplementation, TCacheDecorator>(this IServiceCollection services)
|
||||
where TInterface : class
|
||||
where TImplementation : class, TInterface
|
||||
where TCacheDecorator : class, TInterface
|
||||
{
|
||||
services.AddScoped<TImplementation>();
|
||||
services.AddScoped<TCacheDecorator>();
|
||||
|
||||
services.AddScoped(provider =>
|
||||
{
|
||||
var proxyGenerator = provider.GetRequiredService<ProxyGenerator>();
|
||||
var loggingInterceptor = provider.GetRequiredService<LoggingInterceptor>();
|
||||
|
||||
var actual = provider.GetRequiredService<TImplementation>();
|
||||
|
||||
var cached = ActivatorUtilities.CreateInstance<TCacheDecorator>(provider, actual);
|
||||
|
||||
return proxyGenerator.CreateInterfaceProxyWithTarget<TInterface>(cached,
|
||||
loggingInterceptor.ToInterceptor());
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddLoggedAuditedCachedServiceScoped<TInterface, TImplementation, TCacheDecorator>(this IServiceCollection services)
|
||||
where TInterface : class
|
||||
where TImplementation : class, TInterface
|
||||
where TCacheDecorator : class, TInterface
|
||||
{
|
||||
services.AddScoped<TImplementation>();
|
||||
services.AddScoped<TCacheDecorator>();
|
||||
|
||||
services.AddScoped(provider =>
|
||||
{
|
||||
var proxyGenerator = provider.GetRequiredService<ProxyGenerator>();
|
||||
var auditInterceptor = provider.GetRequiredService<AuditInterceptor>();
|
||||
var loggingInterceptor = provider.GetRequiredService<LoggingInterceptor>();
|
||||
|
||||
var actual = provider.GetRequiredService<TImplementation>();
|
||||
|
||||
var cached = ActivatorUtilities.CreateInstance<TCacheDecorator>(provider, actual);
|
||||
|
||||
return proxyGenerator.CreateInterfaceProxyWithTarget<TInterface>(cached,
|
||||
loggingInterceptor.ToInterceptor(),
|
||||
auditInterceptor.ToInterceptor());
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddLoggedAuditedServiceScoped<TInterface, TImplementation>(this IServiceCollection services)
|
||||
where TInterface : class
|
||||
where TImplementation : class, TInterface
|
||||
{
|
||||
services.AddScoped<TImplementation>();
|
||||
|
||||
services.AddScoped(provider =>
|
||||
{
|
||||
var proxyGenerator = provider.GetRequiredService<ProxyGenerator>();
|
||||
var auditInterceptor = provider.GetRequiredService<AuditInterceptor>();
|
||||
var loggingInterceptor = provider.GetRequiredService<LoggingInterceptor>();
|
||||
|
||||
var actual = provider.GetRequiredService<TImplementation>();
|
||||
|
||||
return proxyGenerator.CreateInterfaceProxyWithTarget<TInterface>(actual,
|
||||
loggingInterceptor.ToInterceptor(),
|
||||
auditInterceptor.ToInterceptor());
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -15,56 +15,6 @@ namespace PostFundManagement.Application.Extensions;
|
||||
|
||||
public static class Services
|
||||
{
|
||||
public static IServiceCollection AddLoggedCachedServiceScoped<TInterface, TImplementation, TCacheDecorator>(this IServiceCollection services)
|
||||
where TInterface : class
|
||||
where TImplementation : class, TInterface
|
||||
where TCacheDecorator : class, TInterface
|
||||
{
|
||||
services.AddScoped<TImplementation>();
|
||||
services.AddScoped<TCacheDecorator>();
|
||||
|
||||
services.AddScoped(sp =>
|
||||
{
|
||||
var proxyGenerator = sp.GetRequiredService<ProxyGenerator>();
|
||||
var loggingInterceptor = sp.GetRequiredService<LoggingInterceptor>();
|
||||
|
||||
var actual = sp.GetRequiredService<TImplementation>();
|
||||
|
||||
var cached = ActivatorUtilities.CreateInstance<TCacheDecorator>(sp, actual);
|
||||
|
||||
return proxyGenerator.CreateInterfaceProxyWithTarget<TInterface>(cached,
|
||||
loggingInterceptor.ToInterceptor());
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddLoggedAuditedCachedServiceScoped<TInterface, TImplementation, TCacheDecorator>(this IServiceCollection services)
|
||||
where TInterface : class
|
||||
where TImplementation : class, TInterface
|
||||
where TCacheDecorator : class, TInterface
|
||||
{
|
||||
services.AddScoped<TImplementation>();
|
||||
services.AddScoped<TCacheDecorator>();
|
||||
|
||||
services.AddScoped(sp =>
|
||||
{
|
||||
var proxyGenerator = sp.GetRequiredService<ProxyGenerator>();
|
||||
var auditInterceptor = sp.GetRequiredService<AuditInterceptor>();
|
||||
var loggingInterceptor = sp.GetRequiredService<LoggingInterceptor>();
|
||||
|
||||
var actual = sp.GetRequiredService<TImplementation>();
|
||||
|
||||
var cached = ActivatorUtilities.CreateInstance<TCacheDecorator>(sp, actual);
|
||||
|
||||
return proxyGenerator.CreateInterfaceProxyWithTarget<TInterface>(cached,
|
||||
loggingInterceptor.ToInterceptor(),
|
||||
auditInterceptor.ToInterceptor());
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddRegisterServicesWithCaching(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddScoped<AuditInterceptor>();
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
<!-- API Documentation -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Castle.Core.AsyncInterceptor" Version="2.1.0" />
|
||||
<PackageReference Include="Duende.AccessTokenManagement" Version="4.2.0" />
|
||||
<PackageReference Include="Duende.AccessTokenManagement.OpenIdConnect" Version="4.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.12" />
|
||||
<PackageReference Include="Microsoft.Extensions.Validation" Version="10.0.12" />
|
||||
<PackageReference Include="Scalar.AspNetCore" Version="2.17.4" />
|
||||
@@ -37,6 +39,8 @@
|
||||
<!-- Shared Usings -->
|
||||
<ItemGroup>
|
||||
<Using Include="Humanizer" />
|
||||
<Using Include="Duende.AccessTokenManagement.OpenIdConnect" />
|
||||
<Using Include="Duende.AccessTokenManagement" />
|
||||
<Using Include="Castle.DynamicProxy" />
|
||||
<Using Include="Microsoft.FeatureManagement" />
|
||||
<Using Include="System.ComponentModel.DataAnnotations" />
|
||||
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
using PostFundManagement.Application.Abstractions;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using PostFundManagement.Application.Abstractions;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using PostFundManagement.Application.Abstractions;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using PostFundManagement.Application.Abstractions;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using PostFundManagement.Application.Abstractions;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using PostFundManagement.Application.Abstractions;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using PostFundManagement.Application.Abstractions;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Domain.Abstractions;
|
||||
using static PostFundManagement.Domain.Extensions.Constants;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using PostFundManagement.Application.Abstractions;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Shared;
|
||||
|
||||
|
||||
@@ -12,9 +12,10 @@ public sealed class IdentityService(IDbContextFactory<ApplicationDbContext> cont
|
||||
{
|
||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
// TODO: Ensure TenantUser status is checked
|
||||
var userExistsAndActive = await context.Users
|
||||
.AnyAsync(u => u.Id == userId && u.Status == ActivityStatus.Active, cancellationToken);
|
||||
var userExistsAndActive = await context.TenantUsers
|
||||
.Include(i => i.User)
|
||||
.AnyAsync(u => u.UserId == userId && u.Status == ActivityStatus.Active &&
|
||||
u.User!.Status == ActivityStatus.Active, cancellationToken);
|
||||
|
||||
return Result.OkIf(userExistsAndActive, NotFoundError.Create());
|
||||
}));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using PostFundManagement.Domain.Configuration.Security;
|
||||
using PostFundManagement.Domain.Errors;
|
||||
using PostFundManagement.Domain.Security.Configuration;
|
||||
using PostFundManagement.Domain.Security.Models;
|
||||
using PostFundManagement.Domain.Security.Sdk;
|
||||
using PostFundManagement.Domain.Models.Security;
|
||||
using PostFundManagement.Infrastructure.Security;
|
||||
|
||||
namespace PostFundManagement.Application.Services.Shared;
|
||||
|
||||
@@ -9,10 +9,10 @@ public sealed class TokenService(ISecurityConnectApi connectApi, IOptions<Securi
|
||||
{
|
||||
private readonly SecurityClientSettings clientSettings = clientOptions.Value;
|
||||
|
||||
public async Task<Result<Domain.Security.Models.TokenResponse>> GenerateAsync(CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Domain.Security.Models.TokenResponse>>>)(async () =>
|
||||
public async Task<Result<Domain.Models.Security.TokenResponse>> GenerateAsync(CancellationToken cancellationToken = default) =>
|
||||
await Result.Try((Func<Task<Result<Domain.Models.Security.TokenResponse>>>)(async () =>
|
||||
{
|
||||
using var response = await connectApi.GetToken(new Domain.Security.Models.TokenRequest
|
||||
using var response = await connectApi.GetToken(new Domain.Models.Security.TokenRequest
|
||||
{
|
||||
ClientId = clientSettings.ClientId,
|
||||
ClientSecret = clientSettings.ClientSecret,
|
||||
@@ -27,14 +27,14 @@ public sealed class TokenService(ISecurityConnectApi connectApi, IOptions<Securi
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var tokenResponse = JsonSerializer.Deserialize<Domain.Security.Models.TokenResponse>(contentRaw);
|
||||
var tokenResponse = JsonSerializer.Deserialize<Domain.Models.Security.TokenResponse>(contentRaw);
|
||||
|
||||
return Result.FailIf(string.IsNullOrWhiteSpace(tokenResponse?.AccessToken),
|
||||
NotFoundError.Create("Authentication succeeded, but no access token was found in the response payload."))
|
||||
.ToResult(tokenResponse!);
|
||||
}
|
||||
|
||||
return await Result.Try((Func<Task<Result<Domain.Security.Models.TokenResponse>>>)(async () =>
|
||||
return await Result.Try((Func<Task<Result<Domain.Models.Security.TokenResponse>>>)(async () =>
|
||||
{
|
||||
var errorResult = JsonSerializer.Deserialize<TokenErrorResponse>(contentRaw);
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using PostFundManagement.Application.Abstractions;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Shared;
|
||||
using PostFundManagement.Domain;
|
||||
|
||||
Reference in New Issue
Block a user