(2018-10-24) Setting/Fixing The Correct Permissions On Your ADFS Certificates And/Or On The Certificate Sharing Container
Posted by Jorge on 2018-10-24
Are the permissions on any of the private keys of your certificates in use by ADFS and/or the certificate sharing container screwed up? If YES, then you can use the PowerShell code below to fix those permissions for the account the ADFS Service is running under. Make sure to test this is a test environment first!
### Function To Permission Private Key Of Custom/Non-ADFS Managed Certificates
Function permissionPrivateKey($certificate,$certType,$svcAccount) {
$ace = $svcAccount,"Read,Synchronize","Allow"
$machineKeysLocation = $ENV:ALLUSERSPROFILE + "\Microsoft\Crypto\RSA\MachineKeys\"
$CertKeyFile = $certificate.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
$CertKeyFileFullPath = $MachineKeysLocation + $CertKeyFile
$CertKeyFileACL = Get-Acl $CertKeyFileFullPath
Write-Host "+++ RESULT +++" -ForeGroundColor Magenta
$certSubject = $null
$certSubject = $certificate.Subject
Write-Host "Certificate Type……..: $certType" -ForegroundColor Yellow
Write-Host "Certificate Subject…..: $certSubject" -ForegroundColor Yellow
Write-Host ""
Write-Host "Private Key Permissions (BEFORE)" -ForegroundColor Yellow
$CertKeyFileACL.Access | FT @{n='[Account]’;e={$_.IdentityReference}},@{n='[Control]’;e={$_.AccessControlType}},@{n='[Permissions]’;e={$_.FileSystemRights}}
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $ace
$CertKeyFileACL.SetAccessRule($accessRule)
$CertKeyFileACL | Set-Acl $CertKeyFileFullPath
$CertKeyFileACL = $null
$CertKeyFileACL = Get-Acl $CertKeyFileFullPath
Write-Host ""
Write-Host "Private Key Permissions (AFTER)" -ForegroundColor Yellow
$CertKeyFileACL.Access | FT @{n='[Account]’;e={$_.IdentityReference}},@{n='[Control]’;e={$_.AccessControlType}},@{n='[Permissions]’;e={$_.FileSystemRights}}
}
### Determining Current ADFS Service Account
$adfsService = Get-WmiObject win32_service -filter "name=’ADFSSRV’"
$currentADFSServiceAccount = $adfsService.StartName
### Determining Database Type Being Used
$adfsSTS = Get-WmiObject -namespace root/ADFS -class SecurityTokenService
$configDBConnectionString = $adfsSTS.ConfigurationDatabaseConnectionString
If ($configDBConnectionString.contains("\\.\pipe\")) {
Write-Host ""
Write-Host "Windows Internal Database Is Being Used" -ForegroundColor Yellow
$dbType = "WID"
$roleADFSServer = (Get-AdfsSyncProperties).Role
If ($roleADFSServer -eq "SecondaryComputer") {
Write-Host ""
Write-Host "Running On Secondary ADFS Server" -ForegroundColor Yellow
Function portConnectionCheck($fqdnServer,$port,$timeOut) {
$tcpPortSocket = $null
$portConnect = $null
$tcpPortWait = $null
$tcpPortSocket = New-Object System.Net.Sockets.TcpClient
$portConnect = $tcpPortSocket.BeginConnect($fqdnServer,$port,$null,$null)
$tcpPortWait = $portConnect.AsyncWaitHandle.WaitOne($timeOut,$false)
If(!$tcpPortWait) {
$tcpPortSocket.Close()
Return "ERROR"
} Else {
$ErrorActionPreference = "SilentlyContinue"
$tcpPortSocket.EndConnect($portConnect) | Out-Null
If (!$?) {
Return "ERROR"
} Else {
Return "SUCCESS"
}
$tcpPortSocket.Close()
$ErrorActionPreference = "Continue"
}
}
$primaryADFSServer = (Get-AdfsSyncProperties).PrimaryComputerName
$adfsWIDIsSecondary = $true
} Else {
Write-Host "Running On Primary ADFS Server" -ForegroundColor Yellow
$adfsWIDIsSecondary = $false
}
} Else {
Write-Host "SQL Server Is Being Used" -ForegroundColor Yellow
$dbType = "SQL"
}
### Getting ADFS Properties And Certificates
If ($dbType -eq "WID") {
If ($adfsWIDIsSecondary) {
$ports = 5985,443,80 # WinRM For Remote PowerShell, ADFS HTTPS, ADFS HTTP
$connectionCheckOK = $true
$ports | %{
$port = $null
$port = $_
$connectionResult = $null
$connectionResult = portConnectionCheck $primaryADFSServer $port 500
If ($connectionResult -eq "ERROR") {
$connectionCheckOK = $false
}
}
If ($connectionCheckOK) {
$primaryADFSServerSession = New-PSSession -ComputerName $primaryADFSServer
$fedSvcConfig = Invoke-Command -Session $primaryADFSServerSession -ScriptBlock {
$fedSvcProperties = Get-AdfsProperties
$fedSvcCertificates = Get-AdfsCertificate
Return $fedSvcProperties,$fedSvcCertificates
}
Remove-PSSession $primaryADFSServerSession
$fedSvcProps = $fedSvcConfig[0]
$fedSvcCerts = $fedSvcConfig[1]
} Else {
Write-Host ""
Write-Host "The Primary ADFS Server IS NOT Reachable" -ForegroundColor Red
Write-Host "Aborting…" -ForegroundColor Red
Write-Host ""
EXIT
}
} Else {
$fedSvcProps = Get-AdfsProperties
$fedSvcCerts = Get-AdfsCertificate
}
}
If ($dbType -eq "SQL") {
$fedSvcProps = Get-AdfsProperties
$fedSvcCerts = Get-AdfsCertificate
}
### Checking If Certificate Sharing Container Has Been Configured
If ($fedSvcProps.CertificateSharingContainer) {
Write-Host ""
Write-Host "Certificate Sharing Container IS Configured" -ForegroundColor Yellow
$certSharingContainerConfigured = $true
$certSharingContainerState = "Configured"
$certSharingContainerDN = ($fedSvcProps.CertificateSharingContainer).ToString()
} Else {
Write-Host ""
Write-Host "Certificate Sharing Container IS NOT Configured" -ForegroundColor Yellow
$certSharingContainerConfigured = $false
$certSharingContainerState = "NOT Configured"
$certSharingContainerDN = "N.A."
}
### Checking If Custom Certificates Are Being Used Or ADFS Managed Self-Signed Certificates For Token Signing/Encryption
If ($fedSvcProps.AutoCertificateRollover -eq $false) {
Write-Host ""
Write-Host "ADFS Managed Self-Signed Certs ARE NOT Being Used" -ForegroundColor Yellow
$adfsManagedCerts = $false
$certManagement = "NON-ADFS Managed"
} ElseIf ($fedSvcProps.AutoCertificateRollover -eq $true) {
Write-Host ""
Write-Host "ADFS Managed Self-Signed Certs ARE Being Used" -ForegroundColor Yellow
$adfsManagedCerts = $true
$certManagement = "ADFS Managed"
}
### Displaying All The Info Gathered
Invoke-Command -ScriptBlock {
Write-Host ""
Write-Host "Database Type………………………: $dbType" -ForegroundColor Yellow
Write-Host ""
Write-Host "Certificate Sharing Container State…..: $certSharingContainerState" -ForegroundColor Yellow
Write-Host ""
Write-Host "Certificate Sharing Container DN……..: $certSharingContainerDN" -ForegroundColor Yellow
Write-Host ""
Write-Host "Certificate Management………………: $certManagement" -ForegroundColor Yellow
Write-Host ""
Write-Host "Current Service Account……………..: $currentADFSServiceAccount" -ForegroundColor Yellow
Write-Host ""
Write-Host "Token-Signing Certificate(s)…" -ForegroundColor Yellow
$fedSvcTokenSigningCert = $fedSvcCerts | ?{$_.CertificateType -eq "Token-Signing"}
$fedSvcTokenSigningCert | FT Thumbprint,@{n=’Subject’;e={$_.Certificate.Subject}},@{n=’Not Before’;e={$_.Certificate.NotBefore}},@{n=’Not After’;e={$_.Certificate.NotAfter}}
Write-Host "Token-Encryption Certificate(s)…" -ForegroundColor Yellow
$fedSvcTokenEncryptCert = $fedSvcCerts | ?{$_.CertificateType -eq "Token-Decrypting"}
$fedSvcTokenEncryptCert | FT Thumbprint,@{n=’Subject’;e={$_.Certificate.Subject}},@{n=’Not Before’;e={$_.Certificate.NotBefore}},@{n=’Not After’;e={$_.Certificate.NotAfter}}
Write-Host "Service Communications / SSL Certificate…" -ForegroundColor Yellow
$fedSvcSvcCommCert = $fedSvcCerts | ?{$_.CertificateType -eq "Service-Communications"}
$fedSvcSvcCommCert | FT Thumbprint,@{n=’Subject’;e={$_.Certificate.Subject}},@{n=’Not Before’;e={$_.Certificate.NotBefore}},@{n=’Not After’;e={$_.Certificate.NotAfter}}
}
### Setting Permissions On Private Key Of Custom Token Certificates
If (!$adfsManagedCerts) {
Write-Host ""
Write-Host "Permissioning Custom Token Certificates" -ForegroundColor Yellow
$certStoreLocation = "Cert:\LocalMachine\My"
$fedSvcCerts | ?{$_.CertificateType -ne "Service-Communications"} | %{
$certificateType = $null
$certificateType = $_.CertificateType
$certificateThumbprint = $null
$certificateThumbprint = $_.Thumbprint
$certificateInStore = $null
$certificateInStore = Get-ChildItem $($certStoreLocation + "\" + $certificateThumbprint) -ErrorAction SilentlyContinue
If ($certificateInStore -And $certificateInStore.HasPrivateKey) {
permissionPrivateKey $certificateInStore $certificateType $currentADFSServiceAccount
} Else {
Write-Host ""
Write-Host "The Certificate With Thumbprint ‘$certificateThumbprint’ ($certificateType) Does Not Exist" -ForegroundColor Red
Write-Host "Or" -ForegroundColor Red
Write-Host "The Certificate With Thumbprint ‘$certificateThumbprint’ ($certificateType) Does Not Have A Private Key" -ForegroundColor Red
Write-Host ""
}
}
}
### Setting Permissions On Private Key Of SSL/Service-Communication Certificate
$fedSvcCerts | ?{$_.CertificateType -eq "Service-Communications"} | %{
$certificateType = $null
$certificateType = $_.CertificateType
$certificateThumbprint = $null
$certificateThumbprint = $_.Thumbprint
$certificateInStore = $null
$certificateInStore = Get-ChildItem $($certStoreLocation + "\" + $certificateThumbprint) -ErrorAction SilentlyContinue
If ($certificateInStore -And $certificateInStore.HasPrivateKey) {
permissionPrivateKey $certificateInStore $certificateType $currentADFSServiceAccount
} Else {
Write-Host ""
Write-Host "The Certificate With Thumbprint ‘$certificateThumbprint’ ($certificateType) Does Not Exist" -ForegroundColor Red
Write-Host "Or" -ForegroundColor Red
Write-Host "The Certificate With Thumbprint ‘$certificateThumbprint’ ($certificateType) Does Not Have A Private Key" -ForegroundColor Red
Write-Host ""
}
}
### If Configured Setting Permissions On Certificate Sharing Container
### WARNING: ADDS PowerShell Module Required!!! – Will Be Installed!
If ($certSharingContainerConfigured) {
Write-Host ""
Write-Host "Certificate Sharing Container Is Configured Used" -ForegroundColor Yellow
# Install RSAT PowerShell Tools And Load Module
Install-WindowsFeature RSAT-AD-Tools -IncludeAllSubFeature
Import-Module ActiveDirectory
# Get The Certificate Sharing Container DN, Its ACL And Present The Results Of That
$dnPathCertSharingContainer = ($fedSvcProps.CertificateSharingContainer).ToString()
$dnPathCertSharingContainerPath = $(Join-Path "AD:\" $dnPathCertSharingContainer)
Write-Host ""
Write-Host "Certificate Sharing Container Permissions (BEFORE)" -ForegroundColor Yellow
$aclCertSharingContainer = Get-Acl $dnPathCertSharingContainerPath
$aclCertSharingContainer.Access | FT @{n='[Account]’;e={$_.IdentityReference}},@{n='[Control]’;e={$_.AccessControlType}},@{n='[Permissions]’;e={$_.ActiveDirectoryRights}}
# Object Class And Inheritance Scope
$schemaIDGUIDScopedObject = [guid]"00000000-0000-0000-0000-000000000000"
$inheritanceScope = "All"
# Security Principal To Assign Permissions To
$securityPrincipalAccount = $currentADFSServiceAccount
$securityPrincipalObject = New-Object System.Security.Principal.NTAccount($securityPrincipalAccount)
# Define ACE
$rightsCollection = [System.DirectoryServices.ActiveDirectoryRights]::"CreateChild","Self","WriteProperty","DeleteTree","GenericRead","WriteOwner"
$aclType = [System.Security.AccessControl.AccessControlType]::"Allow"
$aceDefinition = $securityPrincipalObject,$rightsCollection,$aclType,$schemaIDGUIDScopedObject,$inheritanceScope
$accessRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($aceDefinition)
# Set The New Access Rule
$aclCertSharingContainer.AddAccessRule($accessRule)
$aclCertSharingContainer | Set-Acl $dnPathCertSharingContainerPath
# Get The Certificate Sharing Container ACL And Present The Results Of That
Write-Host ""
Write-Host "Certificate Sharing Container Permissions (AFTER)" -ForegroundColor Yellow
$aclCertSharingContainer = Get-Acl $dnPathCertSharingContainerPath
$aclCertSharingContainer.Access | FT @{n='[Account]’;e={$_.IdentityReference}},@{n='[Control]’;e={$_.AccessControlType}},@{n='[Permissions]’;e={$_.ActiveDirectoryRights}}
$aclCertSharingContainer.Access | ?{$_.IdentityReference -eq $securityPrincipalAccount} | FT @{n='[Account]’;e={$_.IdentityReference}},@{n='[Control]’;e={$_.AccessControlType}},@{n='[Permissions]’;e={$_.ActiveDirectoryRights}}
$aclCertSharingContainer.Access | ?{$_.IdentityReference -eq $securityPrincipalAccount}
}
–
Cheers,
Jorge
————————————————————————————————————————————————————-
This posting is provided "AS IS" with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER: https://jorgequestforknowledge.wordpress.com/disclaimer/
————————————————————————————————————————————————————-
########################### Jorge’s Quest For Knowledge ##########################
#################### http://JorgeQuestForKnowledge.wordpress.com/ ###################
————————————————————————————————————————————————————-
Michael Hall said
You can very safely rename the CertificateSharingContainer in ADSI edit. Just rename it old at the end. Then run Set-AdfsCertSharingContainer -ServiceAccount contoso\serviceaccount01$. This command will make a whole brand new one with the right keys and permissions. This is how you fix this error: Update-AdfsCertificate -CertificateType: Token-Signing
Update-AdfsCertificate : The server was unable to process the request due to an internal error. For more information
about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the
configuration behavior) on the server in order to send the exception information back to the client, or
turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs.
LikeLike