This post contains three configuration tips I hope will help you configure several Active Directory Federation Services 3.0 (ADFS) servers to communicate with each other and allow your application relying parties (RP) to communicate through one ADFS server to request claims from a second ADFS server. AFDS works like a charm — but the documentation (especially for ADFS 3.0) is severely lacking. Microsoft offers only basic configuration doc spread all over the ‘Net. There seems to be little practical info available, leaving architects to piece everything together via trial and error. This post won’t replace some serious Google searching on your part but it might help if your objectives are similar to mine.
Let’s start with a serious (and, as of this writing) unfixed bug in ADFS 3.0 on Windows Server 2012 R2. If you run ADFS on your domain controller (as I did in a test environment in the cloud) and you select a group Managed Service Account (gMSA) for the ADFS service credentials, you will not be able to login to the server after a restart. This is, of course, a catastrophe when you run in the cloud (in our case, AWS).
I found a solution here. Set up a normal userid with Domain Admin privileges to use with ADFS. And set the Key Distribution service to start automatically at boot. Problem solved.
Update: February 27, 2015: Wrong, wrong, wrong! There is a problem, but I misunderstood it. The issue is the ADFS service must get a key from the Key Distribution Service which must, of course, start before the ADFS service. Yet ADFS on Windows Server 2012 R2 ships without the KdsSvc dependency included when on a domain controller.
Here’s the right way to fix ADFS running on a domain controller:
sc config adfssrv depend=HTTP/KdsSvc
You can do a before/after with this command:
sc qc adfssrv
Remember: you have do this before you reboot your server. If you don’t and it’s a cloud server, you’re dead. Microsoft really, really needs to fix this.
Update: October, 2016: If you install AD FS in Windows Server 2016 on a domain controller, you must still make sure you add the dependency on the key service after you configure AD FS on the domain controller and before you reboot the server. This screen shot shows what you should see after you’ve set up the dependency.
Now for the good stuff: how can we make one ADFS server a hub to serve our applications and users by supplying both local credentials and credentials from a remote ADFS server? Consider the following design.
Why would one ever do this? There are a couple of reasons. Suppose your ADFS server needs to act as a hub to permit authorization from multiple federated partners. By pointing users and claims-aware applications to your hub, relying parties can easily authenticate with different claims providers as needed. Another good reason is to allow your developers to test against your ADFS server without burdening the federation partner’s server(s).
Here are the most important considerations I discovered.
- The trust to your server from the remote ADFS server is a relying party trust
- The trust from your server to the remote ADFS server is a claims provider trust
- What makes it all hang together are pass-through claims rules on both trusts.
It’s easy to connect the two servers; just give your remote admin the metadata URL for your ADFS server. A more subtle requirement is that the two trusts must be identical in all respects. That means that when you are talking with the admin of the remote ADFS server, you need to ensure that he or she enters all the claims as he or she defines the relying party trust to you precisely as your relying party trust application expects them.
This screenshot shows an example of a single pass-through claims rule for a standard claim, “Surname”. In a two-server local and remote ADFS configuration, this claim is entered three times. Once is in the remote RP ADFS server’s claim rules for this trust (this is obviously done by the admin at the remote server). Second, you must enter the identical claim in your local server’s claims provider trust defining the remote ADFS server. And third, it is entered in the RP trust for your application. When you enter this rule on the claims provider trust, you’ll get a warning about security that’s safe to ignore.
My third tip is something I could not find clear, explicit documentation on how to do. How does one allow both local claims and remote claims to be provided to the local relying party application? It’s simple: just enter the claims rules for your local ADFS server in the same way and place as you did for the remote pass-through claims. See below for a screenshot showing both claims originating in the local ADFS server and claims coming for this relying party application from the remote AFDS server.
Once again, you must make certain that the claims rules for the remote connection match in every respect all the way through from the remote ADFS server through the claims provider trust on your local server and ending up in your local relying party application. It’s complex but if you think about it, it all makes sense.
Here’s a bonus tip that requires PowerShell. (You can leave a quarter in the slot.) I find it more convenient to force Home Realm Discovery every time our app or users hit our server. If you go with the defaults, ADFS stores a cookie for 30 days after initial HRD. If you are testing an app or a user needs to switch realms, they have to clear their cookies — an inconvenience. This self-documenting script forces HRD on every request.
Import-Module adfs Set-AdfsWebConfig -HRDCookieEnabled $false # Uncomment to require HRD on every login #Set-AdfsWebConfig -HRDCookieLifetime 30 -HRDCookieEnabled $true # Uncomment to set to default
Update July 26, 2016: See this post on how to use an ADFS PowerShell cmdlet to avoid a nasty surprise when you attempt to copy-and-paste token-signing and other ADFS certificates.
Leave a Reply