Jorge's Quest For Knowledge!

All About Identity And Security On-Premises And In The Cloud – It's Just Like An Addiction, The More You Have, The More You Want To Have!

(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/ ###################
————————————————————————————————————————————————————-

One Response to “(2018-10-24) Setting/Fixing The Correct Permissions On Your ADFS Certificates And/Or On The Certificate Sharing Container”

  1. 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.

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.