Windows Identity Foundation 101’s : WS-Federation Passive Requestor Profile (part 2 of 2)

In the previous post we saw how easy it is to get basic Relying Party (RP) and Identity Provider (IdP) websites up and running using a minimal amount of coding with Windows Identity Foundation (WIF).

I now want to extend these examples.

In this post I will look at how the RP website can be enhanced, not by adding to the code already written, but by removing it altogether! What I mean by that is the problem we have been trying to solve with custom code has already been solved and incorporated into WIF, and so there is no point in reinventing the wheel.

As a quick reminder, here is the scenario we are currently concentrating on:

image_6_674AD2C8

  1. End-user attempts to access RP website
  2. Client is redirected to IdP website
  3. End-user logs in
  4. IdP sends a claim-rich token back to the client
  5. Client presents token to RP

The RP application as it currently stands is lacking in a number of areas:

  • Federation logic is mixed in with the presentation layer
  • No token validation is being performed
  • The developer is left with a complicated token to deal with

Federation Utility Tool

The federation utility tool (FedUtil) is added to Visual Studio through with the WIF SDK. Using this tool it is possible to create new applications, or modify existing ones, so that they are claims aware with a good degree of security and reliability.

We start by modifying the RP application created in the previous post:

  1. Right click the project and choose to ‘Add STS reference’
    • This opens the FedUtil tool
  2. Set the ‘Application configuration location’ to the RP web.config file and the ‘Application URI’ to ‘https://wifrelyingparty’
  3. Click Next
  4. Choose to ‘Create a new STS project in the current solution’
  5. Click Finish

That is all that is required to set up the RP application. NB – a new STS project has also been created but ignore it for now.

The outcome of these steps is an update to the web.config file for the RP website. In order to understand what has been added and therefore what has been gained, it is instructive to go through each config file change.

The first addition is a reference to the assembly that enables the microsoft.identityModel config section to be deserialized:

 <configSections>
    <section name="microsoft.identityModel"
             type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</configSections>

Next, access to the RP federation metadata endpoint is given to all users. This is so that entities external to the RP website can consume the RP metadata and form clients.

 

 <location path="FederationMetadata">
    <system.web>
        <authorization>
            <allow users="*" />
        </authorization>
    </system.web>
</location>

 

Next, anonymous access is denied to all other pages (of course this can be changed if required):

 <authorization>
  <deny users="?" />
</authorization>

Things now start to get more interesting with the addition of two HTTP modules:

 <modules>
    <add name="WSFederationAuthenticationModule"
         type="Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         preCondition="managedHandler" />
    <add name="SessionAuthenticationModule"
         type="Microsoft.IdentityModel.Web.SessionAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         preCondition="managedHandler" />
</modules>

The WSFederationAuthenticationModule module encapsulates all of the protocol logic for the WS-Federation Passive Requestor Profile, including:

  • Signin
  • Response handling
  • Token deserialization
  • Claims authentication/transformation (optional)
  • Token cookie creation
  • Signout

The SessionAuthenticationModule creates a cookie containing a session token describing the IClaimsPrincipal instance identified by the signin process. Upon subsequent requests the IClaimsPrincipal is restored from the cookie and made available to the main application.

microsoft.identityModel configuration section

Finally, the microsoft.identityModel config section is included, within which a <service> instance is placed (NB - The FedUtil tool doesn’t address the entire microsoft.identityModel schema but an excellent overview is given here).

 <microsoft.identityModel>
    <service>
        <audienceUris>
            <add value="https://wifrelyingparty/" />
        </audienceUris>
        <federatedAuthentication>
            <wsFederation passiveRedirectEnabled="true"
                          issuer="https://WIFRelyingParty_STS/"
                          realm="https://wifrelyingparty"
                          requireHttps="false" />
            <cookieHandler requireSsl="true" />
        </federatedAuthentication>
        <applicationService>
            <claimTypeRequired>
                <!--Following are the claims offered by STS 'https://localhost:30920/WIFRelyingParty_STS/'. -->
                <!--Add or uncomment claims that you require by your application and then update the federation metadata of this application.-->
                <claimType type="https://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" optional="true" />
                <claimType type="https://schemas.microsoft.com/ws/2008/06/identity/claims/role" optional="true" />
            </claimTypeRequired>
        </applicationService>
        <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
            <trustedIssuers>
                <add thumbprint="55B7A7A0CE02912B806F91460A3FB5E200C0F83E"
                     name="https://localhost:30920/WIFRelyingParty_STS/" />
            </trustedIssuers>
        </issuerNameRegistry>
    </service>
</microsoft.identityModel>

The <audienceUris> collection mandates that the RP website will only trust tokens whose audience restriction matches the given Uri. In the case of SAML 1.1 tokens, the intended audience set for the token is located within the <AudienceRestrictionCondition> element:

 <saml:Assertion MajorVersion="1" MinorVersion="1"
                AssertionID="_37ab6cb9-6c53-4df7-8472-4051bab5d3bd"
                Issuer="PassiveSigninSTS"
                IssueInstant="2010-09-07T19:03:03.279Z"
                xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion">
    <saml:Conditions NotBefore="2010-09-07T19:03:03.279Z"
                     NotOnOrAfter="2010-09-07T20:03:03.279Z">
        <saml:AudienceRestrictionCondition>
            <saml:Audience>https://wifrelyingparty</saml:Audience>
        </saml:AudienceRestrictionCondition>
    </saml:Conditions>
    ......
</saml:Assertion>

The <federatedAuthentication> element contains several properties each of which are:

  • The @passiveRedirectEnabled attribute specifies whether the WSFederationAuthenticationModule module is enabled to initiate WS-Federation passive protocol redirects
    • This mode of operation of the module enables its use in scenarios that do not employ the Federated Passive SignIn ASP.NET control
  • The @issuer attribute contains the token issuer URL that the browser will be redirected to
  • The @realm attribute describes the RP to the issuer so that the issuer can make decisions based upon the identity of the RP 
  • The @requireHttps attribute indicates whether the issuer URL must be secured with SSL

The <cookieHandler> element describes various attributes about the RP environment concerning the cookie that will be used by the federation modules. The only default attribute included by the FedUtil tool is @requireSsl which indicates whether or not the RP website must be secured with SSL.

The <applicationService> element contains a list of claims that the issuer must supply in a token, although the optional attribute can be set. In fact this list of required claims is purely descriptive and by default no error occurs if a mandatory claim is missing. However, this list can be used by a ClaimsAuthenticationManager implementation to enforce mandatory claims.

The <issuerNameRegistry> element is used to verify the digital signatures of tokens received from issuers. i.e – only those tokens that contain an entry in the registry will be considered valid. The default implementation is the Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry but a custom implementation can be plugged in if required. e.g – the registry may be the local machine certificate store.

What about the custom code?

Finally, what does all of this mean for the RP code written in the previous post? As a quick reminder, here is the code behind class for content.aspx:

 protected void Page_Load(object sender, EventArgs e)
{
    if (HttpContext.Current.Request.Form[WSFederationConstants.Parameters.Result]
        != null)
    {
        // This is a response from the STS
        SignInResponseMessage mess =
            WSFederationMessage.CreateFromNameValueCollection(
            WSFederationMessage.GetBaseUrl(HttpContext.Current.Request.Url),
            HttpContext.Current.Request.Form)
            as SignInResponseMessage;
 
        // DO PRESENTATION LAYER STUFF
    } 
    else
    {
        // This is a new request
        SignInRequestMessage mess = new SignInRequestMessage(
            new Uri("https://localhost/WIFIdentityProvider/Login.aspx"),
            "https://WIFRelyingParty",
            https://localhost/WIFRelyingParty/Content.aspx);
 
            HttpContext.Current.Response.Redirect(mess.WriteQueryString());
    }
}

With the modifications made by the federation utility tool, this code can now be reduced to the following:

 

 protected void Page_Load(object sender, EventArgs e)
{
    // DO PRESENTATION LAYER STUFF
}

The presentation layer developer no longer needs to consider the complexities of the authentication/authorisation mechanisms for the website.

 

Summary

In summary, this article demonstrates that it is possible to make RP applications claims aware with a high degree of security and reliability using the federation utility tool. The fact that all of the code for enabling federation is hidden away in a set of HTTP modules means that the ASP.NET developer need only be concerned with the presentation layer.

This post concludes a 2 part series that covered the WS-Federation Passive Requestor Profile and how it is enabled by Windows Identity Foundation.

Written by Bradley Cotier