Hello all. You may recall from older posts on this blog (2012) that we’ve played around in the past with Home Realm Discovery (HRD) in AD FS.

First with IWA and forms logon here and then a little bit more for good measure. Since then it’s been a little quiet on the HRD fence and not a subject delved into much since. That is, until an issue a colleague and I ran into an issue recently… confronted with the following AD FS R2 access conundrum:

“ How can we route (automatically) external logon requests to a third-party claims provider, continue to route internal logon requests to the native AD claims provider (i.e. maintain transparent SSO), eliminating any Home Realm Discovery (HRD) for our users to have to walk through and select?”

Or… to put it more simply. How can one automatically route external route requests to claims provider A, continue to route internal requests to (AD) claims provider B, whilst altogether avoiding Home Realm Discovery (HRD) for all users?

We’ll discuss the exact use case in a moment. This is a RP-initiated work-flow. No IDP-initiated flow or smart links are allowed.

First, a bit of background. Let’s head back to the first look posts on AD FS 2012 R2 in 2013/2014. In there I wrote:

“In AD FS R2, HRD customization options through PowerShell now allow us to determine how the UI is presented to the end-user during logon, based on:

With the move to kernel-mode in R2, customization previously possible under IIS in AD FS 2.0 was no longer applicable. To redress this issue and to provide greater flexibility, the above customization options were provided. Suffix routing enables AD FS 2012 R2 to select an appropriate claims provider based on the domain suffix credentials provided by that user. Broadly speaking, this is just how O365/Azure AD works in attempting to discover the Federated home realm v Microsoft realm of the connecting user. Similarly, for on-premise AD FS, suffix routing enables us to refine our logon decision-making based on the home realm of the connecting user. Here’s an example:

Wonderful! Using this approach can be a little hit and miss though. It’s making certain assumptions about the level at which we’re prepared to divert authentication on, i.e. the domain level. That’s not always the case.

We could, alternatively, opt for the other method: targeting claims provider selection at the Relying Party Trust level. Again, this is useful functionality. Here’s an example.

This makes the “BodgeIT Inventory” Relying Party/Web Application, available to users of the Cranky Nuts organization, bypassing the local AD claims provider. Should we need to extend access to additional claims providers, such as our local Active Directory, then we can add that issuer to the mix. The downside of this option, is that we’re forced into making a home-realm discovery selection during logon.

The Suffix and RP-specific claims provider options, therefore, do have some limitations. Indeed, for the scenario that we were faced with, neither option fit. In our situation, two claims providers existed for a single organization, with each CP containing the same set of users. The use case? Two-factor authentication. The upstream claims provider (CP) provides two-factor authentication (2FA) for users connecting from the outside , while the incumbent local AD claims provider covers local Windows logon.

Of course, two claims providers means Home Realm Discovery (HRD) and HRD can be confusing. We can remedy this for internal users, ensuring they don’t get the HRD prompt by defaulting to the use of the local AD claims provider via Powershell:

Set-ADFSProperties –IntranetUseLocalClaimsProvider $True

This doesn’t solve the problem for access from the outside. Moreover, we expressly wish to send all connecting users to our 2FA claims provider, rather than to the in-build AD claims provider…. We could use auxiliary authentication provided by the MFA Adapter in AD FS 2012 R2, thereby eliminating the use of the upstream claims provider. However, that might not be feasible as:

Leading with the AD password as the primary authentication credential may not be allowed.

The vendor has an MFA adapter for AD FS 2012 R2.

Even where the latter is available, the (security) policy prerogative might be that use of 1) is not allowed, thereby overriding (2).

PointSharp possess both a Security Token Service (STS) that can stip atop AD FS as a 2FA claims provider role and also have an MFA adapter for AD FS 2012 R2 / 2016. Since use of the MFA adapter has been prohibited by the customer according to the rules above (not wanting to lead with AD password as a primary authentication credential), the STS as a Claims Provider was selected instead.

You’ll recall we turned off HRD for internal users by setting the IntranetUseLocalClaimsProvider setting to TRUE. With the PointSharp STS configured as a claims provider, external users will get continue to get the HRD screen as AD FS cannot determine where the user lives without the appropriate “hint”. In AD FS 2.0 it was possible to workaround this by customizing the AD FS 2.0 proxy configuration, modifying the Page_Init section of the homerealmdiscovery.aspx.cs file. We could then remove Active Directory as a claims provider (0)

PassiveIdentityProvidersDropDownList.Items.RemoveAt(0);

Once that was done, default realm selection would fall to our other claims provider (STS)

As you are no doubt aware, IIS has been supplanted in AD FS 2012 R2 with everything running in kernel-mode. Thankfully, all is not lost though. Some of the functionality previously possible under IIS has moved to Javascript and customization of the onload.js script is covered in a couple of scenarios here..

Variables previously living in .NET code-behind are visible in the View Source of the web page of the HRD screens. Options for both claims providers are visible.

HRD.selection is the main feature of interest. There’s an action on clicking the realm manually that specifies the HRD we require. We can automate this by moving the selection to the onload.js script, thereby automating selection of the PointSharp Claims Provider. First, we need to customize our AD FS setup.

We create a new theme called PointSharp based on the default AD FS theme

New-AdfsWebTheme –Name PointSharp –SourceName default

Export the default theme to allow our customization

Export-AdfsWebTheme –Name default –DirectoryPath c:\scripts

Copy the default onload.js to the C:\Scripts folder and edit it. At the end of the script, we simply add the reference to the PointSharp claims provider using the following syntax (replace with your own CP) :

External users will be now routed to the PointSharp claims provider for login, whilst AD logon for internal users is still preserved. Please note that this is a GLOBAL change affecting all users of the AD FS farm and test extensively as it might not be your cup of tea…

You may recall a previous post from a few weeks back, concerning customization of AD FS Relying Parties in Windows Server 2016. This functionality is now out-of-the-box in the latest version of AD FS. What was less well-documented was examples of how this could be accomplished in Windows Server 2012 R2. Pierre Audonet from Microsoft has thankfully solved that problem by posting this great article on Technet, that describes how to customize the onload.js script for registering custom URIs and illustrations to bind to your relying parties. Thanks Pierre!