Add SGU credential provider and authentication broker
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
[CmdletBinding(SupportsShouldProcess)]
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string]$PublishPath,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[string]$ServerCertificateSubject,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[ValidatePattern('^[0-9A-Fa-f ]{40,59}$')]
|
||||
[string[]]$AllowedClientThumbprints,
|
||||
|
||||
[string]$NtlmEndpoint = 'https://sgu.ulsa.edu.mx/',
|
||||
[string[]]$AllowedNtlmRedirectHosts = @('sgu.ulsa.edu.mx'),
|
||||
[string]$LdapHost = 'localhost',
|
||||
[string]$BaseDn = 'DC=lci,DC=lasalle,DC=mx',
|
||||
[string]$DomainNetbios = 'LCI',
|
||||
[string]$UpnSuffix = 'lci.lasalle.mx',
|
||||
[switch]$CreateMissingOus,
|
||||
[switch]$DisableCertificateRevocationCheckForLab
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$serviceName = 'SGUAuthBroker'
|
||||
$installPath = Join-Path $env:ProgramFiles 'SGU\AuthBroker'
|
||||
$normalizedClientThumbprints = @($AllowedClientThumbprints | ForEach-Object { $_ -replace ' ', '' })
|
||||
if ($normalizedClientThumbprints.Where({ $_.Length -ne 40 }).Count -gt 0) {
|
||||
throw 'Client certificate thumbprints must contain exactly 40 hexadecimal characters.'
|
||||
}
|
||||
|
||||
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$principal = [Security.Principal.WindowsPrincipal]::new($identity)
|
||||
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||
throw 'Run this script from an elevated PowerShell session on the broker server.'
|
||||
}
|
||||
|
||||
$serverCertificate = Get-ChildItem Cert:\LocalMachine\My |
|
||||
Where-Object { $_.Subject -like "*$ServerCertificateSubject*" -and $_.HasPrivateKey } |
|
||||
Sort-Object NotAfter -Descending |
|
||||
Select-Object -First 1
|
||||
if (-not $serverCertificate) {
|
||||
throw 'The HTTPS server certificate with private key was not found in LocalMachine\My.'
|
||||
}
|
||||
if (-not $serverCertificate.Verify()) {
|
||||
throw 'The HTTPS server certificate chain is not trusted or is outside its validity period. Import the issuing CA chain; for a self-signed lab certificate, trust its public .cer in LocalMachine\Root.'
|
||||
}
|
||||
|
||||
if ($CreateMissingOus) {
|
||||
Import-Module ActiveDirectory -ErrorAction Stop
|
||||
$usersOuName = 'Usuarios-SGU'
|
||||
$usersOuDn = "OU=$usersOuName,$BaseDn"
|
||||
if (-not (Get-ADOrganizationalUnit -LDAPFilter "(ou=$usersOuName)" -SearchBase $BaseDn -SearchScope OneLevel -Server $LdapHost -ErrorAction SilentlyContinue)) {
|
||||
New-ADOrganizationalUnit -Name $usersOuName -Path $BaseDn -ProtectedFromAccidentalDeletion $true -Server $LdapHost | Out-Null
|
||||
}
|
||||
|
||||
foreach ($ouName in @('Docentes', 'Alumnos', 'Administrativos')) {
|
||||
$targetOu = Get-ADOrganizationalUnit -LDAPFilter "(ou=$ouName)" -SearchBase $usersOuDn -SearchScope OneLevel -Properties ProtectedFromAccidentalDeletion -Server $LdapHost -ErrorAction SilentlyContinue
|
||||
if ($targetOu) {
|
||||
if (-not $targetOu.ProtectedFromAccidentalDeletion) {
|
||||
$targetOuDn = [string]$targetOu.DistinguishedName
|
||||
Set-ADOrganizationalUnit -Identity $targetOuDn -ProtectedFromAccidentalDeletion $true -Server $LdapHost -Confirm:$false
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
$legacyOu = Get-ADOrganizationalUnit -LDAPFilter "(ou=$ouName)" -SearchBase $BaseDn -SearchScope OneLevel -Properties ProtectedFromAccidentalDeletion -Server $LdapHost -ErrorAction SilentlyContinue
|
||||
if ($legacyOu) {
|
||||
$legacyOuDn = [string]$legacyOu.DistinguishedName
|
||||
try {
|
||||
if ($legacyOu.ProtectedFromAccidentalDeletion) {
|
||||
Set-ADOrganizationalUnit -Identity $legacyOuDn -ProtectedFromAccidentalDeletion $false -Server $LdapHost -Confirm:$false
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
Move-ADObject -Identity $legacyOuDn -TargetPath $usersOuDn -Server $LdapHost -Confirm:$false -ErrorAction Stop
|
||||
}
|
||||
finally {
|
||||
$currentOu = Get-ADOrganizationalUnit -LDAPFilter "(ou=$ouName)" -SearchBase $usersOuDn -SearchScope OneLevel -Properties ProtectedFromAccidentalDeletion -Server $LdapHost -ErrorAction SilentlyContinue
|
||||
if (-not $currentOu) {
|
||||
$currentOu = Get-ADOrganizationalUnit -LDAPFilter "(ou=$ouName)" -SearchBase $BaseDn -SearchScope OneLevel -Properties ProtectedFromAccidentalDeletion -Server $LdapHost -ErrorAction SilentlyContinue
|
||||
}
|
||||
if ($currentOu) {
|
||||
$currentOuDn = [string]$currentOu.DistinguishedName
|
||||
Set-ADOrganizationalUnit -Identity $currentOuDn -ProtectedFromAccidentalDeletion $true -Server $LdapHost -Confirm:$false
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
New-ADOrganizationalUnit -Name $ouName -Path $usersOuDn -ProtectedFromAccidentalDeletion $true -Server $LdapHost | Out-Null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($file in @('SGU.AuthBroker.exe', 'SGU.AuthBroker.dll', 'appsettings.json')) {
|
||||
if (-not (Test-Path -LiteralPath (Join-Path $PublishPath $file))) {
|
||||
throw "PublishPath is missing $file."
|
||||
}
|
||||
}
|
||||
|
||||
$productionSettings = @{
|
||||
Kestrel = @{
|
||||
Endpoints = @{
|
||||
Https = @{
|
||||
Url = 'https://0.0.0.0:8443'
|
||||
Certificate = @{
|
||||
Subject = $ServerCertificateSubject
|
||||
Store = 'My'
|
||||
Location = 'LocalMachine'
|
||||
AllowInvalid = $false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Broker = @{
|
||||
Tls = @{
|
||||
AllowedClientThumbprints = $normalizedClientThumbprints
|
||||
CheckCertificateRevocation = -not $DisableCertificateRevocationCheckForLab
|
||||
}
|
||||
Ntlm = @{
|
||||
Endpoint = $NtlmEndpoint
|
||||
Domain = ''
|
||||
TimeoutSeconds = 15
|
||||
MaxRedirects = 5
|
||||
AllowedRedirectHosts = $AllowedNtlmRedirectHosts
|
||||
}
|
||||
Directory = @{
|
||||
LdapHost = $LdapHost
|
||||
BaseDn = $BaseDn
|
||||
DomainNetbios = $DomainNetbios
|
||||
UpnSuffix = $UpnSuffix
|
||||
ProfessorOuDn = "OU=Docentes,OU=Usuarios-SGU,$BaseDn"
|
||||
StudentOuDn = "OU=Alumnos,OU=Usuarios-SGU,$BaseDn"
|
||||
AdministrativeOuDn = "OU=Administrativos,OU=Usuarios-SGU,$BaseDn"
|
||||
CreateMissingOus = [bool]$CreateMissingOus
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($PSCmdlet.ShouldProcess($installPath, 'Install the SGU Authentication Broker Windows service')) {
|
||||
if (Get-Service -Name $serviceName -ErrorAction SilentlyContinue) {
|
||||
Stop-Service -Name $serviceName -Force
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Path $installPath -Force | Out-Null
|
||||
Copy-Item -Path (Join-Path $PublishPath '*') -Destination $installPath -Recurse -Force
|
||||
$settingsJson = $productionSettings | ConvertTo-Json -Depth 8
|
||||
$utf8WithoutBom = New-Object System.Text.UTF8Encoding($false)
|
||||
[System.IO.File]::WriteAllText(
|
||||
(Join-Path $installPath 'appsettings.Production.json'),
|
||||
$settingsJson,
|
||||
$utf8WithoutBom)
|
||||
|
||||
if (-not (Get-Service -Name $serviceName -ErrorAction SilentlyContinue)) {
|
||||
New-Service -Name $serviceName `
|
||||
-DisplayName 'SGU Authentication Broker' `
|
||||
-Description 'Validates SGU NTLM credentials and synchronizes Active Directory accounts.' `
|
||||
-BinaryPathName ('"{0}"' -f (Join-Path $installPath 'SGU.AuthBroker.exe')) `
|
||||
-StartupType Automatic
|
||||
}
|
||||
|
||||
if (-not (Get-NetFirewallRule -DisplayName 'SGU Authentication Broker (mTLS)' -ErrorAction SilentlyContinue)) {
|
||||
New-NetFirewallRule -DisplayName 'SGU Authentication Broker (mTLS)' `
|
||||
-Direction Inbound -Action Allow -Protocol TCP -LocalPort 8443 -Profile Domain | Out-Null
|
||||
}
|
||||
|
||||
Start-Service -Name $serviceName
|
||||
}
|
||||
|
||||
Get-Service -Name $serviceName | Select-Object Name, Status, StartType
|
||||
Reference in New Issue
Block a user