Introduction
Today I was working on moving my ADFS environment to a separate VM so I could test out a deployment guide I had been working on. On my VM1 I had installed ADFS with Windows Internal Database (WID) in a standalone mode. In my target VM2 I had installed ADFS on SQL 2008 R1 as a farm. I wanted to easily move all of the ADFS configuration and settings to VM2 but found that this is actually fairly difficult.
Attempts
Database Backup / Restore
The first thing I tried to do was to create a backup of the AdfsConfiguration and AdfsArtifactStore databases from VM1 and try to restore them on VM2. Before trying this I made a backup of my existing ADFS databases. Because the SQL version used with WID is SQL 2005 it is not possible to use a .bak file exported from WID and restored on SQL 2008, you get an error. So then I had to detach the files from the WID database and try to reattach the databases on the SQL 2008 VM. I was able to reattach the databases but there were problems afterward.
In order to detach the existing SQL 2008 AdfsConfiguration database on VM2, I had to stop the ADFS 2 service. Then after reattaching the new databases from WID, the ADFS 2 service would not start. So I stopped at this point and switched over to moving the artifacts using scripts. If anyone had any other tips for making this type of migration work, I would appreciate the feedback!
Scripted Move
After not being able to move the data over through database backups, I decided to try to script everything. This approach is just as challenging because you still need to go through all of the objects in the ADFS databases and this can take some time in building out the new scripts. I realized a tool that can generate the scripts for you would be a huge time saver.
Some of the PowerShell cmdlets for ADFS use parameters typed as System.Security.Cryptography.X509Certificates.X509Certificate2. So the parameters expect that you will be passing an object rather than the common name string. When I first saw this in the API reference, I started trying to translate .NET code over for pulling a certificate from the stores like in the code on this article: http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.aspx.
Translating the code from C# to PowerShell was very difficult and somewhat error prone. Eventually I gave up and looked for a better option. I finally found out that the certificate stores load as a PowerShell drive in PowerShell 2.0 and the certificates surface as X509Certificate2 objects. Here is an overview article on the certificate provider: http://technet.microsoft.com/en-us/library/dd347615.aspx. The certificate provider makes it very easy to reference a certificate when working with the ADFS API.
I was moving over claim issuers and relying parties that had mapped claim rules attached to them. The basic approach for handling this was to use the “Get-” cmdlet to output the claim rules, copy the rules to a text file, and then run the “Set-X-RulesFile” to reimport the rules. This is easier to understand when seen in an example.
- First I am going to get all of the claim issuers output to the PowerShell window:
Get-ADFSClaimsProviderTrust
This outputs something like this:
AcceptanceTransformRules : @RuleTemplate = “PassThroughClaims”
@RuleName = “Pass thru role”
c:[Type == “http://schemas.microsoft.com/ws/2008/06/identity/claims/role”%5D
=> issue(claim = c);@RuleTemplate = “PassThroughClaims”
@RuleName = “Pass Thru Name”
c:[Type == “http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name”%5D
=> issue(claim = c);I just take everything after the colon on the first line and copy to a text file called acceptanceTransformRules.txt.
- Finally, I am going to import a claims issuer’s rules (the claim issuer MySTS needs to already exist at this point:
# Refer to the rules file with an absolute path $curdir = Get-Location $curdirfile = Join-Path -Path $curdir -ChildPath "acceptanceTransformRules.txt" # Import the claim rules Set-ADFSClaimsProviderTrust -TargetName "MySTS" -AcceptanceTransformRulesFile $curdirfile
Moving a claims issuer from one server to another is resolved to two basic steps: 1. Installing the certificates, 2. Running a script referencing the installed certificates. Here is a PowerShell example combining the ADFS and Certificate APIs for creating a new issuer:
Write-Host "Loading ADFS Snap-In" Add-PSSnapin Microsoft.ADFS.PowerShell $certname = "CN=localhost" # Getting the certificate. How simple using the certificate provider! set-location cert:\localmachine\my $cert = Get-ChildItem | Where { $_.Subject -eq $certname } Set-Location c: # certificates are correctly specified here Add-ADFSClaimsProviderTrust -Name "MySTS" -Identifier "https://localhost/trust" -MonitoringEnabled $false -TokenSigningCertificate $cert -EncryptionCertificate $cert -AutoUpdateEnabled $false -AllowCreate $True Write-Host "Disabling CRL checking on claims issuer trust certs because these are self-signed" Set-ADFSClaimsProviderTrust -TargetName "MySTS" -SigningCertificateRevocationCheck "None" Set-ADFSClaimsProviderTrust -TargetName "MySTS" -EncryptionCertificateRevocationCheck "None"
Conclusion
After going through the process of creating scripts like this I realized it is not too much work to do a scripted move but it would be much nicer if you could just export to script from the ADFS mmc or execute some other cmdlet to handle this whole process for you. Maybe in the future I might try to spend some time making something like this and putting it on CodePlex. Thanks!
Leave a Reply