Files
git.stella-ops.org/src/StellaOps.Zastava.Core/DependencyInjection/ZastavaServiceCollectionExtensions.cs
master d8253ec3af up
2025-10-24 09:15:37 +03:00

99 lines
3.8 KiB
C#

using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Auth.Client;
using StellaOps.Zastava.Core.Configuration;
using StellaOps.Zastava.Core.Diagnostics;
using StellaOps.Zastava.Core.Security;
namespace Microsoft.Extensions.DependencyInjection;
public static class ZastavaServiceCollectionExtensions
{
public static IServiceCollection AddZastavaRuntimeCore(
this IServiceCollection services,
IConfiguration configuration,
string componentName)
{
ArgumentNullException.ThrowIfNull(services);
ArgumentNullException.ThrowIfNull(configuration);
if (string.IsNullOrWhiteSpace(componentName))
{
throw new ArgumentException("Component name is required.", nameof(componentName));
}
services.AddOptions<ZastavaRuntimeOptions>()
.Bind(configuration.GetSection(ZastavaRuntimeOptions.SectionName))
.ValidateDataAnnotations()
.Validate(static options => !string.IsNullOrWhiteSpace(options.Tenant), "Tenant is required.")
.Validate(static options => !string.IsNullOrWhiteSpace(options.Environment), "Environment is required.")
.PostConfigure(options =>
{
if (string.IsNullOrWhiteSpace(options.Component))
{
options.Component = componentName;
}
})
.ValidateOnStart();
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<LoggerFactoryOptions>, ZastavaLoggerFactoryOptionsConfigurator>());
services.TryAddSingleton<IZastavaLogScopeBuilder, ZastavaLogScopeBuilder>();
services.TryAddSingleton<IZastavaRuntimeMetrics, ZastavaRuntimeMetrics>();
ConfigureAuthorityServices(services, configuration);
services.TryAddSingleton<IZastavaAuthorityTokenProvider, ZastavaAuthorityTokenProvider>();
return services;
}
private static void ConfigureAuthorityServices(IServiceCollection services, IConfiguration configuration)
{
var authoritySection = configuration.GetSection($"{ZastavaRuntimeOptions.SectionName}:authority");
var authorityOptions = new ZastavaAuthorityOptions();
authoritySection.Bind(authorityOptions);
services.AddStellaOpsAuthClient(options =>
{
options.Authority = authorityOptions.Issuer.ToString();
options.ClientId = authorityOptions.ClientId;
options.ClientSecret = authorityOptions.ClientSecret;
options.AllowOfflineCacheFallback = authorityOptions.AllowStaticTokenFallback;
options.ExpirationSkew = TimeSpan.FromSeconds(Math.Clamp(authorityOptions.RefreshSkewSeconds, 0, 300));
options.DefaultScopes.Clear();
var normalized = new SortedSet<string>(StringComparer.Ordinal);
if (authorityOptions.Audience is not null)
{
foreach (var audience in authorityOptions.Audience)
{
if (string.IsNullOrWhiteSpace(audience))
{
continue;
}
normalized.Add($"aud:{audience.Trim().ToLowerInvariant()}");
}
}
if (authorityOptions.Scopes is not null)
{
foreach (var scope in authorityOptions.Scopes)
{
if (!string.IsNullOrWhiteSpace(scope))
{
normalized.Add(scope.Trim());
}
}
}
foreach (var scope in normalized)
{
options.DefaultScopes.Add(scope);
}
});
}
}