The University of Washington uses the InCommon Shibboleth SAML identity provider for web SSO. We run ADFS as a proxy between Office 365/Azure AD and our on-premise identity systems. Our ADFS is configured to use our Shib IdP as an additional “Claims Trust Provider” (CTP). We do this for two reasons: we want all web SSO to have the same login experience and we provide multi-factor authentication through our Shib service. The problem I was working to solve was how to configure ADFS 4.0 to require MFA through our Shib instance.
We initially set up what is known as ADFS 2.0. This was a downloadable upgrade to the original version of ADFS that shipped with Windows Server 2008. ADFS normally would show a “Home Realm Discovery” (HRD) page if there is more than one CTP (with AD being the default CTP). We wanted our ADFS relying parties (RPs) to go straight to Shibboleth, so we modified the HRD page code to effect this. We also used this modified code to require MFA for certain RPs. When ADFS 3.0 was released with WS 2012 R2 it threw a monkey wrench into this design. ADFS 3.0 no longer ran as an IIS web site such that the HRD page code was no longer accessible to be modified. We discovered that you can configure RPs to go to a specific CTP, but we were stymied as to how to require MFA. In the interim ADFS 4.0 was released with WS 2016 and yet the solution to the MFA problem remained elusive. I finally opened a support request with Microsoft to seek an answer to this problem. Here is what I’ve learned.
It turns out this is a two step solution. The first step is configuring your CTP for MFA. The second step is to configure RPs to require MFA.
Almost all advanced ADFS settings are accessed via PowerShell. There are new parameters to the familiar PS commandlets that are of interest. Here are those new commands and how they would be applied to solve our conundrum.
Configuring the Shibboleth CTP
You need to tell ADFS how to invoke MFA through the CTP. Our Shibboleth IdP will require MFA if it receives an AuthNRequest containing an AuthnContextClassRef with the value of
Note that this is the value that our Shibboleth is configured to look for. Your Shib installation may use a different URI to signal MFA.
Hint: use Firefox and its SAML Tracer plugin to trace a login session. SAML Tracer helpfully decodes the SAML token so you can examine it along with the rest of the HTTP exchange.
A WS-Federation authentication request can effect this request for MFA by setting the wauth parameter to the above value. ADFS translates this WS-Fed request into a SAMLP AuthnRequest with the required AuthnContextClassRef value of this URI. If you have a WS-Fed RP that can’t be configured to send the wauth parameter, or if you need to enforce MFA at the IdP, then this won’t work. Instead you configure ADFS so it knows how to make this request using the following PowerShell.
First, to get the current CTP state you can call
The parameter of interest is CustomMFAUri. Use the following code to set it.
Now ADFS knows how to ask for MFA from our SAML IdP.
Configuring Your Relying Parties
We want to send all of our RPs to our Shib CTP. Use the following PowerShell to do this.
You could script this by sending the output of Get-AdfsRelyingPartyTrust to the above command. Note also that since we set a display name on the CTP we had to use that rather than the URN identifier.
The next step is configuring those RPs of which you require MFA. That is done with this command
Now an incoming authentication request to the RP will result in our Shib prompting for the second factor after the entry of the correct user name and password.
I did a search on the RequestMFAFromClaimsProviders parameter after being told about its existence and didn’t find much. The MS documentation is useless and gives no examples of the use of this and the related parameters. I did find one non-MS blog post here, but it was rather general in nature. I hope these detailed instructions help those who want to use Shibboleth as their institutional identity provider via ADFS.