In ADFS when the primary Token Signing certificate and the primary Token Encryption certificate are going to expire you MUST start the certificate change process to change the certificates in ADFS, but also in every connected system or application.
When updating the Token Signing certificate and the Token Encryption certificate the following is important to remember:
- From a connected system/application perspective:
- Downstream federation systems care about your Token Signing certificate and Token Encryption certificate
- Upstream federation systems and application only care about your Token Signing certificate
- From a certificate perspective:
- Token Signing certificate is important for both downstream federation systems and upstream federation systems and applications
- Token Encryption certificate is important for both downstream federation systems only
–
How you get the certificates to these systems and applications depends on your process, but in general:
- The federation metadata URL from ADFS is consumed
- The federation metadata from an XML file is consumed, after exporting it from the URL
- The certificates, in some format, are consumed by the application
–
Let’s focus on the first and second option.
–
By default:
- ADFS publishes the federation metadata through the following URL: /federationmetadata/2007-06/federationmetadata.xml">/federationmetadata/2007-06/federationmetadata.xml">https://<Federation Service FQDN>/federationmetadata/2007-06/federationmetadata.xml
- ADFS publishes ALL configured Token Signing certificates in the federation metadata, in the order from oldest to most recent (changing from primary to secondary or vice versa DOES NOT influence the order in the federation metadata!)
- ADFS only publishes the configured primary Token Encryption certificate in the federation metadata
- ADFS signs the federation metadata with the configured primary Token Signing certificate
–
In my TEST environment I have configured my ADFS server with 5 Token Signing certificates, so that it is as clear as possible.
–
The federation metadata contains 4 sections/nodes where all the Token certificates are specified:
- The ‘RoleDescriptor’ Node For The Type Of ‘fed:ApplicationServiceType’ Containing Only The Primary Token Encryption Certificate (not displayed below, as it is not important for this scenario)
- The ‘RoleDescriptor’ Node For The Type Of ‘fed:SecurityTokenServiceType’ Containing All Token Signing Certificates (displayed in figure 1)
- The ‘SPSSODescriptor’ Node Containing All Token Signing Certificates And The Primary Token Encryption Certificate (displayed in figure 2)
- The ‘IdPSSODescriptor’ Node Containing All Token Signing Certificates And The Primary Token Encryption Certificate (displayed in figure 3)
Figure 1: The ‘RoleDescriptor’ Node For The Type Of ‘fed:SecurityTokenServiceType’ Containing All Token Signing Certificates
–
Figure 2: The ‘SPSSODescriptor’ Node Containing All Token Signing Certificates (And The Primary Token Encryption Certificate)
–
Figure 3: The ‘IdPSSODescriptor’ Node Containing All Token Signing Certificates (And The Primary Token Encryption Certificate)
–
Now the following scenarios are possible when consuming the federation metadata:
- All Token Signing certificates are read and all are consumed by the application – The import of the federation metadata in the application can be done at ANY time!
- All Token Signing certificates are read and and only the LAST occurrence is consumed by the application – The import of the federation metadata in the application must only be done right after the switch of the Token Signing certificates (i.e. the newest secondary Token Signing certificate becomes the new primary Token Signing certificate)
- All Token Signing certificates are read and and only the FIRST occurrence is consumed by the application – The import of the federation metadata in the application must only be done right after the switch of the Token Signing certificates (i.e. the newest secondary Token Signing certificate becomes the new primary Token Signing certificate) AND the imported federation metadata MUST be adjusted before the import!
–
Preferably the application behaves like [1]. That is the BEST option without any issues. If that is not possible, it at least behaves like option [2], which requires somewhat more control and planning. With option [3], my opinion is that the application is by default broken and does not adhere to best practices. The person that build it, did not get it how things work.
–
As with option [3] the application only consumes the first Token Signing Certificate and ignores all others, the only way to make it read the last occurrence of the Token Signing certificate as the first one, is by removing all other occurrences. Looking at any of the pictures above, that means you need to remove all the occurrences of the section “<KeyDescriptor use="signing">…</KeyDescriptor>” before the LAST (newest) Token Signing certificate. You can do this either manually or through PowerShell
Through PowerShell, you can use the following script and command line option to remove all the Token Signing certificate occurrences, except the last occurrence, from the XML federation metadata file:
Invoke-Command -ScriptBlock {
# Get The Date And Time
$execDateTime = Get-Date
$execDateTimeCustom = Get-Date $execDateTime -Format "yyyy-MM-dd_HH.mm.ss"
# Federation Service FQDN
$federationServiceFQDN = "<Federation Service FQDN>" # e.g. "FS.COMPANY.COM"
# Folder Path For The Federation Metadata XML File
$fedMetadataXMLFolderPath = "<Folder Path For The Federation Metadata XML File>" # e.g. "C:\TEMP"
# File Path For The Federation Metadata XML File(s)
$fedMetadataXMLFilePath = Join-Path $fedMetadataXMLFolderPath $($federationServiceFQDN + "_FederationMetadata_" + $execDateTimeCustom + ".xml")
$fedMetadataXMLLastTSOnlyFilePath = Join-Path $fedMetadataXMLFolderPath $($federationServiceFQDN + "_FederationMetadata_" + $execDateTimeCustom + "LastTSOnlyNoSignature.xml")
# URL for the federation metadata: https://<Federation Service FQDN>/federationmetadata/2007-06/federationmetadata.xml
$fedMetadataURL = "https://$federationServiceFQDN/federationmetadata/2007-06/federationmetadata.xml"
# Download The Metadata To An XML File
$webClient = New-Object System.Net.WebClient
$webClient.DownloadFile($fedMetadataURL, $fedMetadataXMLFilePath)
# Read The Downloaded XML Metadata File And Define Several Variables With Namespace Info
$fedMetadataXMLMetadata = [xml](Get-Content $fedMetadataXMLFilePath)
$xmlnamespace = $fedMetadataXMLMetadata.EntityDescriptor.xmlns
$xmlds = $fedMetadataXMLMetadata.EntityDescriptor.Signature.ds
$xmlxsi = $fedMetadataXMLMetadata.EntityDescriptor.RoleDescriptor[0].xsi
$xmlfed = $fedMetadataXMLMetadata.EntityDescriptor.RoleDescriptor[0].fed
$namespace = @{xmlnamespace = $xmlnamespace;xmlds = $xmlds;xmlxsi = $xmlxsi;xmlfed = $xmlfed}
$ns = New-Object System.Xml.XmlNamespaceManager($fedMetadataXMLMetadata.NameTable)
$ns.AddNamespace("xmlnamespace", $xmlnamespace)
$ns.AddNamespace("xmlds", $xmlds)
$ns.AddNamespace("xmlxsi", $xmlxsi)
$ns.AddNamespace("xmlfed", $xmlfed)
# Save The Original Federation Metadata File So That It Has Prettier Format
$fedMetadataXMLMetadata.Save($fedMetadataXMLFilePath)
# Get The Nodes For The Role Descriptor And Count The Number Of Occurences Of The Token Signing Certificate
$roleDescriptorTSCerts = Select-Xml -Xml $fedMetadataXMLMetadata -XPath $("/xmlnamespace:EntityDescriptor/xmlnamespace:RoleDescriptor[@xmlxsi:type=’fed:SecurityTokenServiceType’]/xmlnamespace:KeyDescriptor[@use=’signing’]") -Namespace $namespace
$roleDescriptorTSCertsCount = $roleDescriptorTSCerts.Count
# Start And End Iteration Point
$start = $roleDescriptorTSCertsCount – 2
$end = 0
# Get The Parent Node Of The Token Signing Certificate Nodes In The Role Descriptor And The Specified Token Signing Certificates
$roleDescriptorTSCertsParent = $fedMetadataXMLMetadata.SelectNodes("/xmlnamespace:EntityDescriptor/xmlnamespace:RoleDescriptor[@xmlxsi:type=’fed:SecurityTokenServiceType’]", $ns)
$roleDescriptorTSCertsData = $fedMetadataXMLMetadata.SelectNodes("/xmlnamespace:EntityDescriptor/xmlnamespace:RoleDescriptor[@xmlxsi:type=’fed:SecurityTokenServiceType’]/xmlnamespace:KeyDescriptor[@use=’signing’]", $ns)
# Process And Delete All Ocurrences Of The Token Signing Certificate Except Last Token Signing Certificate
For ($i = $start; $i -ge $end; $i–) {
$roleDescriptorTSCertsParent.RemoveChild($roleDescriptorTSCertsData[$i]) | Out-Null
}
# Get The Parent Node Of The Token Signing Certificate Nodes In The IDP Descriptor And The Specified Token Signing Certificates
$idpSSODescriptorTSCertsParent = $fedMetadataXMLMetadata.SelectNodes("/xmlnamespace:EntityDescriptor/xmlnamespace:IDPSSODescriptor", $ns)
$idpSSODescriptorTSCertsData = $fedMetadataXMLMetadata.SelectNodes("/xmlnamespace:EntityDescriptor/xmlnamespace:IDPSSODescriptor/xmlnamespace:KeyDescriptor[@use=’signing’]", $ns)
# Process And Delete All Ocurrences Of The Token Signing Certificate Except Last Token Signing Certificate
For ($i = $start; $i -ge $end; $i–) {
$idpSSODescriptorTSCertsParent.RemoveChild($idpSSODescriptorTSCertsData[$i]) | Out-Null
}
# Get The Parent Node Of The Token Signing Certificate Nodes In The SP Descriptor And The Specified Token Signing Certificates
$spSSODescriptorTSCertsParent = $fedMetadataXMLMetadata.SelectNodes("/xmlnamespace:EntityDescriptor/xmlnamespace:SPSSODescriptor", $ns)
$spSSODescriptorTSCertsData = $fedMetadataXMLMetadata.SelectNodes("/xmlnamespace:EntityDescriptor/xmlnamespace:SPSSODescriptor/xmlnamespace:KeyDescriptor[@use=’signing’]", $ns)
# Process And Delete All Ocurrences Of The Token Signing Certificate Except Last Token Signing Certificate
For ($i = $start; $i -ge $end; $i–) {
$spSSODescriptorTSCertsParent.RemoveChild($spSSODescriptorTSCertsData[$i]) | Out-Null
}
# Remove The DS Signature Data From The XML Federation Metadata File
$dsSignatureDataParent = $fedMetadataXMLMetadata.SelectNodes("/xmlnamespace:EntityDescriptor", $ns)
$dsSignatureData = $fedMetadataXMLMetadata.SelectSingleNode("/xmlnamespace:EntityDescriptor/xmlds:Signature", $ns)
$dsSignatureDataParent.RemoveChild($dsSignatureData) | Out-Null
# Save The Adjusted Federation Metadata File
$fedMetadataXMLMetadata.Save($fedMetadataXMLLastTSOnlyFilePath)
# Display The File Paths
Write-Host ""
Write-Host "Original Federation Metadata File………………: $fedMetadataXMLFilePath" -ForegroundColor Magenta
Write-Host "Adjusted Federation Metadata File (Last TS only)…: $fedMetadataXMLLastTSOnlyFilePath" -ForegroundColor Magenta
Write-Host ""
}
This will export the original federation metadata to a file with the XML extension.
This will also export the adjusted federation metadata, with only the last Token Signing certificate, and the signature removed to a file with the XML extension.
REMARK: as mention above, ADFS signs the federation metadata with the primary Token Signing certificate to ensure its authenticity. By removing data from the federation metadata XML file, you basically break the signature as it does not match the data in the federation metadata. If the application consuming the XML federation metadata file does not check the signature, then that is not a problem. If it does check the signature, you also need to remove the “<ds:Signature>…</ds:Signature>” section/node. If the application requires a signed XML federation metadata file, then you have a problem. ADFS will only publish the last Token Signing certificate (the newest primary) after the previous primary Token Signing certificate has been removed AFTER it has become a secondary Token Signing certificate.
–
Have fun!
–
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/ ###################
————————————————————————————————————————————————————-