Retrieving the original RP context (wctx) at the IdP, after passing through ADFS as the FP / R-STS

In some cases, you may need to retrieve the context of the RP at the IdP end after passing through the FP.

For example, your IdP may want to know the name of the RP for which the token is being sought (although this may not a good design). In such cases it is possible to retrieve the context of the RP if you are using ADFS as the federation provider.

By default, the ADFS server encodes all the original context information about the relying party within a cookie when redirecting the user to the IdP. However, if you go the web.config file of ADFS and change the following context element to false, you will see now that the url when accessing the IdP contains a huge queryString  (about half a page long).

<context hidden=true />

What has happened is, ADFS instead of putting the original RP context into a cookie has stored it on the URL itself, but the original query sting is nested within another queryString, so if you are using a custom STS as your identity provider, you can use the following code to retrieve the original context.

string wctx = Request.QueryString[“wctx”];

string baseUrl = System.Web.HttpUtility.ParseQueryString(wctx).Get(“BaseUrl”);

Uri uri = new Uri(baseUrl.Replace(“\\”, “?”));

string wtRealm = System.Web.HttpUtility.ParseQueryString(uri.Query).Get(“wtrealm”);

Automating Home Realm Discovery (HRD)

In most common Identity Federation scenarios, there are multiple external Identity Providers (IdP), but the relying party (RP / claims aware app) depends and trusts only one STS (Security Token Service) to provide the claims.

This STS is known as the Federation Provider (FP) or R-STS (Relying Party STS). So when you access the relying party application, it will redirect you to the R-STS (the only STS it knows) to get authenticated, now since (typically) R-STS / FP is not an Identity Provider (IdP), it will (typically) provide you a list of trusted identity providers so that you can choose the one you wanted to get authenticated with.

But in some cases, especially if you are using the application frequently and you know which IdP you wanted to get authenticated with, you would like to avoid that annoying extra step / screen where you need to choose the IdP and wish the system knew it instead of asking every time.

Well there are multiple ways of achieving the same, below are some of the options:

 1.       The (default) cookie based approach

The default behaviour is that, the first time you select the Identity Provider and get successfully authenticated, a persistent cookie is created that is valid for 30 days. This means you don’t need to worry about selecting the identity provider for the next 30 days, however this can have the following issues:

a.        Every time you clean up / clear the cookies, you will need to set it up again

b.       If you want to change to another Identity Provider, you will need to clear the cookies or for temporary purposes use an “In Private” browser session

This default behaviour can be modified, in ADFS’s web.config located (default) at C:\inetpub\adfs\ls

 <persistIdentityProviderInformation enabled=true lifetimeInDays=30 />

You can either modify the lifetime of the cookie or make it a non-persistent cookie in which case, it will ask you for home realm discovery on every new browser session (not what we want)

 

2.       Using the WHR parameter within the queryString / URL

Another approach is to use the WHR parameter in the URL / queryString when accessing the relying party as shown below:

https://xxx.yyy.com/RPApp/?WHR=https://ppp.qqq.com/IdP/

ADFS by default understands the WHR parameter, however, you need a paste a little code in your global.asax of the relying party for WIF to go the magic. Here is the code that will do the trick:

void WSFederationAuthenticationModule_RedirectingToIdentityProvider(object sender, RedirectingToIdentityProviderEventArgs e)

        {

            string strWhr = HttpContext.Current.Request.QueryString[“whr”];

            if (strWhr != null)

            {

                   e.SignInRequestMessage.HomeRealm = strWhr;

 

            }

        }

What you are doing here is basically hooking up your code to the event WIF raises just before it calls out / redirects to the FP. In the code snippet above you are checking to see if the URL contains a querystring with a WHR parameter, if so you assign the value of that parameter to the HomeRealm property of the SignInRequestMessage.

 

3.      Hardcode the IdP’s endpoint within RP’s web.config

I would like mention here that the last two approaches we saw are useful for the end-user or the client browser to customise the behaviour, where each end user might want to choose a different identity provider for the same relying party. However, if you have a scenario where the users of your relying party can be authenticated by a particular identity provider, then you may have to resort to the technique mentioned in this section.

You might ask…, “…well, if the RP can be authenticated by one identity provider only, then why are we even providing a HRD page and choice of multiple Identity Provider?…”. Well you should be conscious of the fact that in a real production environment the Federation Provider may not be dedicated to your relying party alone, maybe it is an Org-wide FP and multiple RPs are using it to federate with various identity providers, but your scenario might demands that the FP redirects the user to a particular IdP only and not provide an option to choose from.

You can configure your relying party to automatically pass through the FP and get redirected to the designated IdP by assigning the IdP endpoint using the HomeRealm attribute of the <wsFederation> node in the <federationConfiguration> of the web.config as shown below:


<
system.identityModel.services>

    <federationConfiguration>

      <cookieHandler requireSsl=true />

      <wsFederation homeRealm=https://ppp.qqq.com/adfs/ls/

issuer=https://aaa.bbb.com/adfs/ls/

realm=https://xxx.yyy.com/RPApp/

reply=https://xxx.yyy.com/RPApp/

requireHttps=true

passiveRedirectEnabled=true />

    </federationConfiguration>

  </system.identityModel.services>

 

4.      Customise the HRD page.

Finally (for ultimate flexibility) you can modify the HomeRealmDiscovery.aspx file and the associated HomeRealmDiscovery.aspx.cs file and provide your own custom logic.

Or you can leave them intact as is, and provide your own custom HRD page and point to it from the ADFS web.config by modifying the element shown below.

<homeRealmDiscovery page=HomeRealmDiscovery.aspx />