Add SGU credential provider and authentication broker
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
using SGU.AuthBroker.Core.Identity;
|
||||
|
||||
namespace SGU.AuthBroker.Options;
|
||||
|
||||
public sealed class BrokerOptions
|
||||
{
|
||||
public const string SectionName = "Broker";
|
||||
|
||||
public TlsOptions Tls { get; init; } = new();
|
||||
|
||||
public NtlmOptions Ntlm { get; init; } = new();
|
||||
|
||||
public ActiveDirectoryOptions Directory { get; init; } = new();
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (Tls.AllowedClientThumbprints.Length == 0 ||
|
||||
Tls.AllowedClientThumbprints.Any(value => !IsCertificateThumbprint(value)))
|
||||
{
|
||||
throw new InvalidOperationException("At least one client certificate thumbprint is required.");
|
||||
}
|
||||
|
||||
if (!Uri.TryCreate(Ntlm.Endpoint, UriKind.Absolute, out Uri? endpoint) || endpoint.Scheme != Uri.UriSchemeHttps)
|
||||
{
|
||||
throw new InvalidOperationException("The institutional NTLM endpoint must be an absolute HTTPS URL.");
|
||||
}
|
||||
|
||||
if (Ntlm.AllowedRedirectHosts.Length == 0 ||
|
||||
!Ntlm.AllowedRedirectHosts.Contains(endpoint.IdnHost, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new InvalidOperationException("The NTLM endpoint host must be present in AllowedRedirectHosts.");
|
||||
}
|
||||
|
||||
if (Ntlm.TimeoutSeconds is < 2 or > 60 || Ntlm.MaxRedirects is < 0 or > 10)
|
||||
{
|
||||
throw new InvalidOperationException("NTLM timeout or redirect limits are outside the supported range.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Directory.LdapHost) ||
|
||||
string.IsNullOrWhiteSpace(Directory.BaseDn) ||
|
||||
string.IsNullOrWhiteSpace(Directory.DomainNetbios) ||
|
||||
string.IsNullOrWhiteSpace(Directory.UpnSuffix))
|
||||
{
|
||||
throw new InvalidOperationException("Active Directory connection and domain settings are required.");
|
||||
}
|
||||
|
||||
foreach (InstitutionalRole role in Enum.GetValues<InstitutionalRole>())
|
||||
{
|
||||
string ouDn = Directory.GetOuDn(role);
|
||||
if (string.IsNullOrWhiteSpace(ouDn))
|
||||
{
|
||||
throw new InvalidOperationException($"An OU mapping is required for {role}.");
|
||||
}
|
||||
|
||||
if (!ouDn.EndsWith($",{Directory.BaseDn}", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new InvalidOperationException($"The OU mapping for {role} must be beneath BaseDn.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsCertificateThumbprint(string value)
|
||||
{
|
||||
string normalized = value.Replace(" ", string.Empty, StringComparison.Ordinal);
|
||||
return normalized.Length == 40 && normalized.All(Uri.IsHexDigit);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TlsOptions
|
||||
{
|
||||
public string[] AllowedClientThumbprints { get; init; } = [];
|
||||
|
||||
public bool CheckCertificateRevocation { get; init; } = true;
|
||||
}
|
||||
|
||||
public sealed class NtlmOptions
|
||||
{
|
||||
public string Endpoint { get; init; } = "https://sgu.ulsa.edu.mx/";
|
||||
|
||||
public string Domain { get; init; } = string.Empty;
|
||||
|
||||
public int TimeoutSeconds { get; init; } = 15;
|
||||
|
||||
public int MaxRedirects { get; init; } = 5;
|
||||
|
||||
public string[] AllowedRedirectHosts { get; init; } = ["sgu.ulsa.edu.mx"];
|
||||
}
|
||||
|
||||
public sealed class ActiveDirectoryOptions
|
||||
{
|
||||
public string LdapHost { get; init; } = "localhost";
|
||||
|
||||
public string BaseDn { get; init; } = "DC=lci,DC=lasalle,DC=mx";
|
||||
|
||||
public string DomainNetbios { get; init; } = "LCI";
|
||||
|
||||
public string UpnSuffix { get; init; } = "lci.lasalle.mx";
|
||||
|
||||
public string ProfessorOuDn { get; init; } = "OU=Docentes,OU=Usuarios-SGU,DC=lci,DC=lasalle,DC=mx";
|
||||
|
||||
public string StudentOuDn { get; init; } = "OU=Alumnos,OU=Usuarios-SGU,DC=lci,DC=lasalle,DC=mx";
|
||||
|
||||
public string AdministrativeOuDn { get; init; } = "OU=Administrativos,OU=Usuarios-SGU,DC=lci,DC=lasalle,DC=mx";
|
||||
|
||||
public bool CreateMissingOus { get; init; }
|
||||
|
||||
public string GetOuDn(InstitutionalRole role) => role switch
|
||||
{
|
||||
InstitutionalRole.Professor => ProfessorOuDn,
|
||||
InstitutionalRole.Student => StudentOuDn,
|
||||
InstitutionalRole.Administrative => AdministrativeOuDn,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(role), role, null)
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user