Created
March 1, 2024 09:39
-
-
Save realslacker/bf257d26e0234e6f0e98aa9dc6990ed3 to your computer and use it in GitHub Desktop.
PowerShell Universal Authentication Example Supporting Multiple Domains
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Set-PSUAuthenticationMethod -Type "Form" -ScriptBlock { | |
param( | |
[PSCredential]$Credential | |
) | |
Add-Type -AssemblyName System.DirectoryServices.AccountManagement | |
# is this a UPN? | |
if ( $Credential.UserName.IndexOf('@') -gt -1 ) { | |
# juggle back and forth from SID to get NTAccount format | |
$NTAccountName = ([System.Security.Principal.NTAccount]$Credential.UserName).Translate([System.Security.Principal.SecurityIdentifier]).Translate([System.Security.Principal.NTAccount]).Value | |
} elseif ( $Credential.UserName.IndexOf('\') -gt -1 ) { | |
# already NTAccount format | |
$NTAccountName = $Credential.UserName | |
} else { | |
# someone didn't enter their domain... | |
$NTAccountName = "NETBIOSDOMAIN\" + $Credential.GetNetworkCredential().UserName | |
} | |
# split domain and username | |
$DomainName, $UserName = $NTAccountName.Split('\',2) | |
# perform auth with AD | |
$PrincipalContext = New-Object System.DirectoryServices.AccountManagement.PrincipalContext( 'Domain', $DomainName ) | |
$Authenticated = $PrincipalContext.ValidateCredentials( $UserName, $Credential.GetNetworkCredential().Password, 'Negotiate, Sealing' ) | |
if ( $Authenticated ) { | |
# discover the user principal, needed for the user DN | |
$UserPrincipal = [System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($PrincipalContext, [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName, $NTAccountName ) | |
# get the user's domain | |
$UserDomainContext = [System.DirectoryServices.ActiveDirectory.DirectoryContext]::new( 'Domain', $DomainName, $Credential.UserName, $Credential.GetNetworkCredential().Password ) | |
$UserDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain( $UserDomainContext ) | |
# get the computer's domain | |
$ComputerDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain() | |
# hold all the user groups | |
[System.Collections.Generic.List[hashtable]]$Groups = @() | |
# get groups from user's domain | |
[adsisearcher]::new( $UserDomain.GetDirectoryEntry(), "(&(objectCategory=group)(objectClass=group)(member:1.2.840.113556.1.4.1941:=$($UserPrincipal.DistinguishedName)))", @('name') ).FindAll().ForEach({ | |
$Groups.Add(@{ | |
Type = 'Group' | |
Value = $_.Properties['name'][0] | |
Issuer = $UserDomain.Name | |
}) | |
}) | |
# get groups from the computer's domain (if different) | |
if ( $UserDomain.Name -ne $ComputerDomain.Name ) { | |
# lookup the user's foreign security principal in the computer's domain | |
$ForeignSecurityPrincipal = [adsisearcher]::new( $ComputerDomain.GetDirectoryEntry(), "(&(objectCategory=foreignSecurityPrincipal)(objectClass=foreignSecurityPrincipal)(name=$($UserPrincipal.Sid)))", @('distinguishedName') ).FindOne().Properties['distinguishedName'][0] | |
# find all the group memberships | |
[adsisearcher]::new( $ComputerDomain.GetDirectoryEntry(), "(&(objectCategory=group)(objectClass=group)(member:1.2.840.113556.1.4.1941:=$ForeignSecurityPrincipal))", @('name') ).FindAll().ForEach({ | |
$Groups.Add(@{ | |
Type = 'Group' | |
Value = $_.Properties['name'][0] | |
Issuer = $ComputerDomain.Name | |
}) | |
}) | |
} | |
New-PSUAuthenticationResult -Success -UserName $UserPrincipal.UserPrincipalName -Claims { | |
$Groups | ForEach-Object { New-PSUAuthorizationClaim @_ } | |
} | |
} else { | |
New-PSUAuthenticationResult -ErrorMessage 'Bad username or password' | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment