Compare commits

...

4 Commits

Author SHA1 Message Date
khwezi 8140b5fe65 Merge pull request 'Added authentik configuration and service registration' (#68) from payments into master
Reviewed-on: #68
2026-06-03 12:53:55 +02:00
Khwezi Mngoma fda97db5fa Added authentik configuration and service registration
continuous-integration/drone/pr Build is passing
2026-06-03 12:52:59 +02:00
khwezi 9285cedfa9 Merge pull request 'Refactored token message' (#67) from payments into master
Reviewed-on: #67
2026-06-03 12:16:31 +02:00
Khwezi Mngoma 29574f4df0 Refactored token message
continuous-integration/drone/pr Build is passing
2026-06-03 12:15:31 +02:00
4 changed files with 112 additions and 52 deletions
@@ -0,0 +1,18 @@
namespace LiteCharms.Features.Api.Configuration;
public sealed class AuthentikSettings
{
public string? Authority { get; set; }
public string? ApiResourceName { get; set; }
public string? ApiResourceSecret { get; set; }
public string? RequiredClaimName { get; set; }
public string? RequiredClaimNameValue { get; set; }
public bool RequireHttpsMetadata { get; set; }
public bool BypassSslErrors { get; set; }
}
@@ -8,7 +8,7 @@ public sealed class OpenApiBearerSecuritySchemeTransformer : IOpenApiDocumentTra
{ {
Type = SecuritySchemeType.Http, Type = SecuritySchemeType.Http,
Scheme = "bearer", Scheme = "bearer",
Description = "JWT Authorization header using the Bearer scheme. Example: \"Bearer {token}\"", Description = "JWT Authorization header using the Bearer scheme",
}; };
document.AddComponent("Bearer", bearerScheme); document.AddComponent("Bearer", bearerScheme);
+57 -27
View File
@@ -1,5 +1,6 @@
using LiteCharms.Features.Abstractions; using LiteCharms.Features.Abstractions;
using LiteCharms.Features.Api; using LiteCharms.Features.Api;
using LiteCharms.Features.Api.Configuration;
namespace LiteCharms.Features.Extensions; namespace LiteCharms.Features.Extensions;
@@ -8,42 +9,34 @@ public static class Api
public const string Books = nameof(Books); public const string Books = nameof(Books);
public const string Payments = nameof(Payments); public const string Payments = nameof(Payments);
public static IApplicationBuilder MapEndpoints(this WebApplication app, IDictionary<int, RouteGroupBuilder> versionGroups) public static IServiceCollection AddAuthentic(this IServiceCollection services, IConfiguration configuration)
{ {
var endpoints = app.Services.GetRequiredService<IEnumerable<IEndpoint>>(); var authOptions = new AuthentikSettings();
foreach (var endpoint in endpoints) configuration.GetSection("Authentik").Bind(authOptions);
{
var versionAttributes = endpoint.GetType().GetCustomAttributes<ApiVersionTargetAttribute>().ToList();
if (versionAttributes.Count != 0) services.Configure<AuthentikSettings>(configuration.GetSection(nameof(AuthentikSettings)));
services.AddAuthentication(OAuth2IntrospectionDefaults.AuthenticationScheme)
.AddOAuth2Introspection(options =>
{ {
foreach (var attr in versionAttributes) options.Authority = options.Authority;
if (versionGroups.TryGetValue(attr.MajorVersion, out var targetGroup)) options.ClientId = options.ClientId;
endpoint.Map(targetGroup); options.ClientSecret = options.ClientSecret;
} options.DiscoveryPolicy.RequireHttps = authOptions.RequireHttpsMetadata;
else options.EnableCaching = true;
endpoint.Map(app); options.CacheDuration = TimeSpan.FromMinutes(10);
} });
return app; if (!string.IsNullOrWhiteSpace(authOptions.RequiredClaimName) && !string.IsNullOrWhiteSpace(authOptions.RequiredClaimNameValue))
} services.AddAuthorizationBuilder().AddPolicy("ApiScope", policy =>
policy.RequireClaim(authOptions.RequiredClaimName, authOptions.RequiredClaimNameValue));
public static IServiceCollection AddEndpoints(this IServiceCollection services, Assembly assembly) else
{ services.AddAuthorization();
ServiceDescriptor[] discriptors = [.. assembly.DefinedTypes
.Where(t => t is { IsInterface: false, IsAbstract: false })
.Where(t => t.IsAssignableTo(typeof(IEndpoint)))
.Select(t => ServiceDescriptor.Transient(typeof(IEndpoint), t))];
services.TryAddEnumerable(discriptors);
return services; return services;
} }
public static string ToEndpointName(this Type target, string? annotation = "") =>
$"{target.Name.Replace("Endpoint", string.Empty)}{annotation}".ToLower(CultureInfo.CurrentCulture);
public static IServiceCollection AddApiServices(this IServiceCollection services, IConfiguration configuration) public static IServiceCollection AddApiServices(this IServiceCollection services, IConfiguration configuration)
{ {
services.AddHttpClient(); services.AddHttpClient();
@@ -95,4 +88,41 @@ public static class Api
return services; return services;
} }
public static IApplicationBuilder MapEndpoints(this WebApplication app, IDictionary<int, RouteGroupBuilder> versionGroups)
{
var endpoints = app.Services.GetRequiredService<IEnumerable<IEndpoint>>();
foreach (var endpoint in endpoints)
{
var versionAttributes = endpoint.GetType().GetCustomAttributes<ApiVersionTargetAttribute>().ToList();
if (versionAttributes.Count != 0)
{
foreach (var attr in versionAttributes)
if (versionGroups.TryGetValue(attr.MajorVersion, out var targetGroup))
endpoint.Map(targetGroup);
}
else
endpoint.Map(app);
}
return app;
}
public static IServiceCollection AddEndpoints(this IServiceCollection services, Assembly assembly)
{
ServiceDescriptor[] discriptors = [.. assembly.DefinedTypes
.Where(t => t is { IsInterface: false, IsAbstract: false })
.Where(t => t.IsAssignableTo(typeof(IEndpoint)))
.Select(t => ServiceDescriptor.Transient(typeof(IEndpoint), t))];
services.TryAddEnumerable(discriptors);
return services;
}
public static string ToEndpointName(this Type target, string? annotation = "") =>
$"{target.Name.Replace("Endpoint", string.Empty)}{annotation}".ToLower(CultureInfo.CurrentCulture);
} }
@@ -29,6 +29,18 @@
<None Include="..\icon.png" Pack="true" PackagePath="\" /> <None Include="..\icon.png" Pack="true" PackagePath="\" />
</ItemGroup> </ItemGroup>
<!-- Security (IODC)-->
<ItemGroup>
<PackageReference Include="IdentityModel.AspNetCore" Version="4.3.0" />
<PackageReference Include="IdentityModel.AspNetCore.OAuth2introspection" Version="6.2.0" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
<PackageReference Include="IdentityModel" Version="6.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Certificate" Version="10.0.8" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.8" />
<Using Include="IdentityModel.AspNetCore.OAuth2Introspection"/>
</ItemGroup>
<!-- API Versioning --> <!-- API Versioning -->
<ItemGroup> <ItemGroup>
<PackageReference Include="AccessTokenClient.Extensions" Version="5.1.0" /> <PackageReference Include="AccessTokenClient.Extensions" Version="5.1.0" />