66 lines
3.4 KiB
C#
66 lines
3.4 KiB
C#
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
using Microsoft.Extensions.Options;
|
|
using ZB.MOM.WW.Auth.Abstractions.Ldap;
|
|
using ZB.MOM.WW.Auth.Ldap;
|
|
|
|
namespace ZB.MOM.WW.Auth.AspNetCore;
|
|
|
|
/// <summary>
|
|
/// Dependency-injection helpers that wire up the ZB.MOM.WW LDAP authentication provider
|
|
/// from configuration. Composes the concrete implementation living in the
|
|
/// <c>ZB.MOM.WW.Auth.Ldap</c> package so consuming apps register a provider with a single call.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// API-key DI wiring lives in <c>ZB.MOM.WW.Auth.ApiKeys</c>
|
|
/// (<c>ZB.MOM.WW.Auth.ApiKeys.DependencyInjection.ApiKeyServiceCollectionExtensions.AddZbApiKeyAuth</c>)
|
|
/// so that an LDAP-only consumer can reference this package without pulling in SQLite.
|
|
/// </remarks>
|
|
public static class ServiceCollectionExtensions
|
|
{
|
|
/// <summary>
|
|
/// Registers LDAP authentication: binds and validates <see cref="LdapOptions"/> from the
|
|
/// configuration section at <paramref name="sectionPath"/>, and registers
|
|
/// <see cref="ILdapAuthService"/>.
|
|
/// </summary>
|
|
/// <param name="services">The service collection to add to.</param>
|
|
/// <param name="config">The application configuration.</param>
|
|
/// <param name="sectionPath">Path of the configuration section holding the LDAP options.</param>
|
|
/// <returns>The same <paramref name="services"/> instance, for chaining.</returns>
|
|
public static IServiceCollection AddZbLdapAuth(
|
|
this IServiceCollection services,
|
|
IConfiguration config,
|
|
string sectionPath)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(services);
|
|
ArgumentNullException.ThrowIfNull(config);
|
|
ArgumentException.ThrowIfNullOrWhiteSpace(sectionPath);
|
|
|
|
// Bind via the options builder and opt into start-time validation. An IValidateOptions<T>
|
|
// otherwise only runs when the options are first materialized (IOptions<T>.Value) — which
|
|
// here is the first login (ILdapAuthService factory below), not boot. ValidateOnStart hooks
|
|
// the host's start-time options validation so a misconfigured directory (e.g. insecure
|
|
// transport without AllowInsecure) fails fast at startup rather than on first login.
|
|
services.AddOptions<LdapOptions>()
|
|
.Bind(config.GetSection(sectionPath))
|
|
.ValidateOnStart();
|
|
|
|
// Fail fast at startup on a misconfigured directory rather than on first login.
|
|
services.AddSingleton<IValidateOptions<LdapOptions>, LdapOptionsValidator>();
|
|
|
|
// LdapAuthService opens/disposes a connection per call and is not IDisposable. Its only
|
|
// mutable state is the sticky endpoint preference used by FallbackServers failover —
|
|
// which is precisely why the instance must be shared, so a primary-DC outage is paid
|
|
// for once rather than on every login. Singleton is correct; TryAdd mirrors the pattern
|
|
// in AddZbApiKeyAuth (idempotency). The logger is resolved with GetService, not
|
|
// GetRequiredService, so a host without logging configured still resolves the service.
|
|
services.TryAddSingleton<ILdapAuthService>(sp =>
|
|
new LdapAuthService(
|
|
sp.GetRequiredService<IOptions<LdapOptions>>().Value,
|
|
sp.GetService<Microsoft.Extensions.Logging.ILogger<LdapAuthService>>()));
|
|
|
|
return services;
|
|
}
|
|
}
|