Claims from Different Providers

This is a compilation of claims that are sent from different providers when using Windows Azure Access Control Service.

Windows Live ID

The only two claims from Windows Live ID are:

Claim Type Example Value
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name iLO4AOwdo6pSpVSmKYiwL4/xIBGYHl/5f7vV/km/2lg=
http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider uri:WindowsLiveID

Google

Claim Type Example Value
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier https://www.google.com/accounts/o8/id?id=AItOawlREZ6oNiBdgeonz18vU93d2KqfH3VhH7o
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress henrik.olsson@somedomain.com
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name Henrik Olsson
http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider Google

ADFS 2.0

With ADFS 2.0, you can configure which AD attributes are mapped using claim rules. This is a sample mapping:

LDAP Attribute Outgoing Claim Type Example Value
  http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/windows
Display-Name http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name Henrik Olsson
E-Mail-Addresses http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress henrik.olsson@somedomain.com
User-Principal-Name http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn holsson@somedomain.com
Token-Groups – Unqualified names http://schemas.microsoft.com/ws/2008/06/identity/claims/role Domain Users
SAM-Account-Name http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname holsson

Hello, Claims!

This a step-by-step guide for converting a ASP.NET web application to claims-based authentication using Windows Identity Foundation and ADFS 2.0. It assumes you have a development environment consisting of Visual Studio 2010 with ASP.NET MVC 3 and Windows Identity Foundation SDK. You also need ADFS 2.0  – in my case I installed it on a virtual machine (called testad1) which is also domain controller (domain test1.se).

(Depending on your network setup, you may have to enter the FQN of the virtual machine, testad1.test1.se in my case, in the host C:\Windows\System32\Drivers\etc\hosts file.)

Create a Web Application with Forms Authentication

Create an ASP.NET MVC 3 Web Application (HelloClaimsWeb) and choose the Internet Application template and the Razor view engine.

Make sure IIS Default Web Site has application pool ASP.NET 4.0.

Publish the application to IIS.

image

Test the web application (https://hostname/HelloClaimsWeb/). Notice that the user name is displayed in the upper right corner.

Enable the World Wide Web Services rules in Windows Firewall.

Test the web application from the test domain (virtual machine).

Convert to Claims Based Authentication

Run the Federation Utility:

Then, publish the application to IIS again.

Changes Made by the Federation Utility

The utility is not some kind of magic – it makes some changes to web.config. From top to bottom:

It adds a new section in configSections:

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

(More on this later.)

It adds a new application setting which points to the STS federation metadata document location:

    <add key="FederationMetadataLocation" value="https://testad1.test1.se/FederationMetadata/2007-06/FederationMetadata.xml" />

Then there is an important change:

    <authentication mode="Forms" />

is changed to

    <authentication mode="None" />

This is because authentication is moved to a different part of the http pipeline. The following http modules are added in <system.web>:

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

The WSFederationAuthenticationModule redirects the user to the identity provider’s logon page. It also parses and validates the security token that is posted back. This module writes an encrypted cookie to avoid repeating the logon process. The SessionAuthenticationModule detects the logon cookie, decrypts it, and constructs the ClaimsPrincipal object.

These modules are also added to <system.webserver>:

    <modules runAllManagedModulesForAllRequests="true">
         <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>

Then, there is the large microsoft.identitymodel section:

  <microsoft.identityModel>
     <service>
       <audienceUris>
         <add value="https://<hostname>/HelloClaimsWeb/" />
       </audienceUris>
       <federatedAuthentication>
         <wsFederation passiveRedirectEnabled="true" issuer="https://testad1.test1.se/adfs/ls/" realm="https://stc11118m1.softronic.se/HelloClaimsWeb/" requireHttps="true" />
         <cookieHandler requireSsl="true" />
       </federatedAuthentication>
       <applicationService>
         <claimTypeRequired>
           <!--Following are the claims offered by STS 'http://TestAD1.test1.se/adfs/services/trust'. Add or uncomment claims that you require by your application and then update the federation metadata of this application.—>
           <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" optional="true" />
           <claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" optional="true" />
           <!--<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" optional="true" />—>
           <!--<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" optional="true" />—>
           <!--<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn" optional="true" />—>
           <!--<claimType type="http://schemas.xmlsoap.org/claims/CommonName" optional="true" />—>
           <!--<claimType type="http://schemas.xmlsoap.org/claims/EmailAddress" optional="true" />—>
           <!--<claimType type="http://schemas.xmlsoap.org/claims/Group" optional="true" />—>
           <!--<claimType type="http://schemas.xmlsoap.org/claims/UPN" optional="true" />—>
           <!--<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" optional="true" />—>
           <!--<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" optional="true" />—>
           <!--<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" optional="true" />—>
           <!--<claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationinstant" optional="true" />—>
           <!--<claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod" optional="true" />—>
           <!--<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/denyonlysid" optional="true" />—>
           <!--<claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarysid" optional="true" />—>
           <!--<claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarygroupsid" optional="true" />—>
           <!--<claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid" optional="true" />—>
           <!--<claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/primarygroupsid" optional="true" />—>
           <!--<claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid" optional="true" />—>
           <!--<claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname" optional="true" />—>
         </claimTypeRequired>
       </applicationService>
       <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
         <trustedIssuers>
           <add thumbprint="BA264CE398B297029466B7C547D4A2FB8B285991" name="http://TestAD1.test1.se/adfs/services/trust" />
         </trustedIssuers>
       </issuerNameRegistry>
       <certificateValidation certificateValidationMode="None" />
     </service>
   </microsoft.identityModel>

Configure ADFS 2.0

If you try to browse the web application now, you will get an error.

In the AD FS 2.0 Management console, add a new relying party trust.

  • Choose Import data about the relying party from a file and specify the file with path <web project folder>\FederationMetadata\2007-06\FederationMetadata.xml.
  • Type a display name, e.g. HelloClaimsWeb.

Add a new transform rule:

  • Select claim rule template Send LDAP Attributes as Claims.
  • As claim rule name, type LDAP attributes.
  • Select Active Directoryas attribute store.
  • Map from Display-Name to Name and from Token-Groups – Unqualified Names to Role.

Code Changes

Modify the home page to display the collection of claims as follows:

Add a reference to Microsoft.IdentityModel.

Change HomeController.Index with the following code:

            var principal = Thread.CurrentPrincipal;
            var identity = principal.Identity as IClaimsIdentity;
            var claims = identity.Claims;
            return View(claims);

Change the index view (Index.cshtml) as follows:

<p>    
    @{
        var grid = new WebGrid(Model);
        @grid.GetHtml(columns: grid.Columns(grid.Column("ClaimType"), grid.Column("Value")));
    }
</p>

Now if you run the web application from the virtual machine, you will get the following error:

A potentially dangerous Request.Form value was detected from the client (wresult=”<t:RequestSecurityTo…”).

This is described in detail in Request Validation – Preventing Script Attacks and the solution in this article: http://social.technet.microsoft.com/wiki/contents/articles/windows-identity-foundation-wif-a-potentially-dangerous-request-form-value-was-detected-from-the-client-wresult-quot-lt-t-requestsecurityto-quot.aspx

Moving the Web Application to the Cloud

Create Windows Azure Project

Add a new project of type Windows Azure and call it HelloClaimsCloud. Right-click on Roles and add Web Role Project in Solution.

Right-click on the newly added role and select Properties. Change VM size to Extra small.

Follow the following guide to add MVC dependencies: http://msdn.microsoft.com/en-us/library/hh369932.aspx#PublishMVC

image

You must now delete the four WebMatrix files in _bin_DeployableAssemblies; otherwise the web application tries to redirect to ~/Account/Login.

Then, set reference Microsoft.IdentityModel property Copy Local to True.

Create and Use SSL Certificate

Start a Visual Studio command prompt and create a certificate using makecert:
makecert -r -pe -n "CN=helloclaims.cloudapp.net" -b 01/01/2010 -e 01/01/2036 -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localMachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12
Right-click the HelloClaimsWeb role and select properties. Select the Certificates tab. Add the newly created certificate. Then switch to the Endpoints tab and add a new endpoint with protocol https, port 443 and the certificate just added.

Then export the certificate, including private key, and upload it as a service certificate using the Windows Azure Platform Management Portal.

Reconfigure the Application

In web.config, there are a couple of entries that specifies the application URL. These must be changed. For that purpose, create a new project and solution configuration and call it e.g. Cloud. Right-click on web.config and select Add Config Transforms. Then, edit Web.Cloud.config and add the following before </configuration>:

  <microsoft.identityModel>
    <service>
      <audienceUris>
        <add value="https://helloclaims.cloudapp.net/" xdt:Transform="Replace"/>
      </audienceUris>
      <federatedAuthentication>
        <wsFederation realm="https://helloclaims.cloudapp.net/" xdt:Transform="SetAttributes(realm)"/>
      </federatedAuthentication>
    </service>
  </microsoft.identityModel>

Build and deploy this configuration to Windows Azure.

Configure ADFS 2.0

In the AD FS 2.0 Management console, add a new relying party trust.

  • Take a copy of the existing application federation metadata file (<web project folder>\FederationMetadata\2007-06\FederationMetadata.xml).
  • Edit the copy and change all three instances of the old URL (https://hostname/HelloClaimsWeb/) to the cloud URL (https://helloclaims.cloudapp.net/ in my case).
  • Choose Import data about the relying party from a file and specify the new modified file.
  • Type a display name, e.g. HelloClaimsCloud.

Add the same transform rule as before:

  • Select claim rule template Send LDAP Attributes as Claims.
  • As claim rule name, type LDAP attributes.
  • Select Active Directory as attribute store.
  • Map from Display-Name to Name and from Token-Groups – Unqualified Names to Role.

References

Claims-Based Identity for Windows

AD FS 2.0 Federation with a WIF Application Step-by-Step Guide

Single Sign-On from Active Directory to a Windows Azure Application