How to Create a Single Sign-On Experience for Windows Azure Applications Using AD FS 2.0 and the Windows Identity Foundation

How to create a Single Sign-On experience for Windows Azure applications using AD FS 2.0 and the Windows Identity Foundation.

There are a few different ways to create this solution, but I’ve selected the approach I read about in a Microsoft based whitepaper. Please feel free to email me with any questions at ira.bell@nimbo.com. As usual, all images will open up in a new screen with a higher resolution.

What is the Challenge?

The challenge is ensuring that end-users have a single sign-on experience when they’re accessing an application in Microsoft Windows Azure. The key is that they do not have to log in twice. When a user logs on to their machine with their active directory account and access a Windows Azure based application, it should be a seamless experience for them and they should not be prompted to enter their credentials. One of the driving forces of user adoption is typically a positive user experience. If you put this solution in place within your organization, you can have a Windows Azure application without the end user even knowing that the application is running in Microsoft’s cloud.

In order to solve this problem, you can use Active Directory Federation Services 2.0 (AD FS 2.0) and the Windows Identity Foundation (WIF). AD FS 2.0 will be installed on a server in the local domain environment and be a member of the active directory domain. WIF will be installed in your development environment, integrate with Visual Studio 2010, and be referenced in your Windows Azure application. As I explained in my presentation at the NY/NJ Windows Azure User Group Meetup, the key is to not over-complicate this. All we’re doing is to ensure we have a server in an environment which can talk to the domain controller – and then enable WIF in the Azure application and reference the location of the server in the internal environment.

Here’s an example of what’s happening:

The POC Environment

Note: This exercise leverages the concept of Claims-Based Identity and Access Control. I highly recommend that you read the Microsoft book entitled “A Guide to Claims-Based Identity and Access Control” by Dominick Baier, Vittorio Bertocci, Keith Brown, Eugenio Pace, and Matias Woloski. These are some extremely smart people. The ISBN number is: 9780735640597

The Proof of Concept (POC) environment I used to create this solution is relatively simple. We need to have a domain controller, an AD FS 2.0 server, a development environment, a firewall, and a Microsoft Windows Azure subscription. A visual representation of the lab environment is shown in the image below:

Please keep in mind that for this POC, I’ve chosen to have my development environment and AD FS 2.0 installed on the same machine. Whether you use the same setup or not doesn’t really matter, except that you’ll need to adjust your process for troubleshooting. One of the benefits of creating the environment this way to learn this process is that it’s much easier to isolate issues when you’re running the solution in your local Azure Development Fabric.

Installing the Prerequisites

First, you’ll need to ensure the following:

    • Create a Windows 2008 R2 Server installation and join it to your Active Directory domain. This will become the AD FS 2.0 server. I have named mine ACCESSCONTROL. Because it has been joined to the Nimbo.Local domain, the FQDN of the AD FS 2.0 server is ACCESSCONTROL.Nimbo.Local. For the rest of this article, I will refer to the AD FS 2.0 server as ACCESSCONTROL.

Note: Because ACCESSCONTROL.Nimbo.Local is not an internet routable address – I simply create a host record at my registrar (i.e. GoDaddy) which points to the public IP address of the firewall in front of my POC environment. Then, you simply set all requests for port 443 (SSL) to point to the internal address of the ACCESSCONTROL.Nimbo.Local server (i.e. 208.290.x.y:443 –> 192.168.x.y:443).

How to Configure the Stand Alone Federation Server

Once you’ve installed the prerequisites discussed above, the next step is to configure AD FS 2.0 on ACCESSCONTROL.

  • Open the AD FS 2.0 Server Configuration console by clicking Start, type AD FS in the search box, and click AD FS 2.0
  • Click AD FS 2.0 Federation Server Configuration Wizard in the center Overview section.

The steps above are displayed in the image below:

  • Select Create a new Federation Service and click Next

The step above is displayed in the image below:

  • Select Stand-alone federation server and click Next

The step above is displayed in the image below:

  • On the Specify the Federation Service Name, the default website’s SSL certificate will automatically be populated. Simply click Next on this screen.(Note: If you do not see this here – you’ve likely skipped the “Create a Self-Signed Certificate” step as documented in the prerequisites section above.)

The step above is displayed in the image below:

  • On the Ready to Apply Settings screen, click Next

The step above is displayed in the image below:

  • On the configuration results screen – wait for the wizard to complete and then click Close

The step above is displayed in the images below:

Configuring the Certificate in the Visual Studio 2010 Solution

You’ll need to have a cloud project created in Visual Studio in order to complete this step. I wrote a blog article about how to create a Windows Azure based Hello World application. You can click here to walk through those steps if you don’t know how to create a simple cloud based solution. The following steps are written on the assumption that you have a cloud solution open and ready to be configured for the single sign-on experience.

The objective here is to ensure that you’re using the same certificate for the solution that you created earlier in the “Create a Self-Signed Certificate” section. In a production environment, you may wish to use different certificate scenarios – but for this POC we want to keep it as simple as possible to get through the solution successfully.

  • In Visual Studio, right click the WebRole you created and click Properties

The step above is displayed in the image below:

  • Click the Certificates menu item on the left
  • Click Add Certificate

The steps above are shown in the image below:

  • Type a name for the certificate (for my example – I typed nimbosso
  • Click the ellipsis (…) button on the far right
  • Select the self signed certificate you generated in the prerequisites section of this article

The steps above are shown in the images below:

  • Next, select the Endpoints menu item on the left
  • Click Add Endpoint

The steps above are shown in the image below:

  • Type HttpsIn in the Nametext box
  • Select https for the Protocol
  • Select 443 for the Public Port
  • Select the named certificate you created in the steps above

The steps above are displayed in the image below:

  • Select the Configuration menu item on the left
  • Remove the check next to HTTP Endpoint (Note: We only want this to communicate over HTTPS so we remove the option for HTTP)

The steps above are displayed in the image below:

  • Run the solution in Visual Studio 2010 by clicking F5 or the Play Button
  • The application should run in the Azure Development Fabric. Make a note of the port your solution is using. In my example, my application is using port 444 for the Azure Development Fabric.

The steps above are displayed in the image below:

Changing the HOSTS File for Testing in the Azure Development Fabric

We want to change the hosts file to test the solution locally with the Fully Qualified Domain Name (FDQN). We want to do this so that we can simulate the real thing in the local development environment. Note: We will reverse this change later when we deploy the solution to Azure.

  • Browse to C:/Windows/System32/drivers/etc
  • Right Click the hosts file and click Open

The steps above are shown in the image below:

  • Select Notepad and click OK

The steps above are shown in the image below:

  • Add an entry to your hosts file which will be the URL of your application which points to the loopback address (127.0.0.1) (for my example, I’m using nimbosso.nimbocloud.com)
  • Click File and then Save

The steps above are shown in the images below:

  • Open up a command prompt and ping the FQDN you just entered. The objective is to verify that DNS will now resolve the FQDN to your local machine. This is a great way to test locally without being bothered to put a solution in Azure before you know whether it works or not.

The step above is shown in the image below:

Add an STS Reference to the Visual Studio Solution

A Security Token Service (STS) reference must be added to the solution. This helps you establish a trust relationship between a claims-aware application and the STS.

    • Right click the cloud project and click Add STS Reference

Note: If you are missing Add STS Reference in Visual Studio, you may want to have a look at this blog article: Click Here

The step above is shown in the image below:

    • In the Federation Utility wizard, click Browse to select the location of your Web.Config file

Note: This is the method in which the wizard will update your Web.Config file to change the authentication and make the application claims-aware.
Note: If the Federation Utility does not appear when you are at this point, please ensure that you’ve installed all of the prerequisites.

The step above is shown in the images below:

    • Type the FQDN (URL) of the entry you made in the hosts file along with the port number you documented earlier when you ran the application in the Azure Development Fabric (for my example, I typed https://nimbosso.nimbocloud.com:444

Note: We’ll change this port later as discussed. This simply ensures that the process will work in the development environment. Your port may be different than mine – depending on which port your environment allocates during the first time you run the Visual Studio Solution.

The step above is shown in the image below:

  • Select Use an existing STS and browse to the FederationMetadata.xml file which is typically located in the FederationMetadata/2007-06/ folder of your Visual Studio solution.

The steps above are displayed in the image below:

  • Select Disable certificate chain validation and click Next

The step above is displayed in the image below:

  • Click Next on the Offered claims screen

The step above is displayed in the image below:

  • Click Finish on the Summary screen

The step above is displayed in the image below:

  • Click OK on the Success notification window

The step above is displayed in the image below:

    • Run the solution in Visual Studio 2010 by clicking F5 or the Play Button
    • Enter the active directory credentials you have for the domain you’ll be using
    • Accept the warnings about the certificate

Note: The web site will generate an error because you have not configured AD FS 2.0 with a relying party that represents the application in the Azure Development Fabric. This is perfectly fine – because we’ll add the relying party trust to AD FS 2.0 next.

The steps above are shown in the images below:

Add a Relying Party Trust to AD FS

  • On ACCESSCONTROL, open the AD FS 2.0 Management Console by clicking Start, type AD FS in the search box, and click AD FS 2.0

The step above is shown in the image below:

  • Expand Trust Relationships on the left side menu, right click Relying Party Trusts, and click Add Relying Party Trust

The step above is shown in the image below:

  • On the Welcome screen, click Start

The step above is shown in the image below:

    • Select Import data about the relying party from a file
    • Click Browse to select the Federation metadata file location, select the file, and click Next

Note: The federation metadata file location will be the same as you select during the Add STS Token Reference

The steps above are shown in the images below:

  • Specify a display name and click Next (i entered Nimbo SSO – Dev Fabric

The step above is shown in the image below:

  • Select Permit all users to access this relying party and click Next

The step above is shown in the image below:

  • Review the Ready to Add Trust screen if desired, and click Next

The step above is shown in the image below:

  • Ensure that the check box next to Open the Edit Claim Rules dialog for this relying party trust when the wizard closes is checked, and click Close

The step above is shown in the image below:

Configure the Claim Rules for the Relying Party

  • In the Claim Rules configuration wizard, ensure that you’re on the Issuance Transform Rules tab and click the Add Rule… button

The step above is shown in the image below:

  • Select Send LDAP Attributes as Claims in the Claim rule template drop down menu and click Next

The step above is shown in the image below:

  • Enter LDAP Attributes in the Claim rule name section
  • Select Active Directory in the Attribute store drop down menu
  • Select Token-Groups – Unqualified Names in the LDAP Attribute section and select Role in the corresponding Outgoing Claim Type section
  • Click Finish

The steps above are shown in the image below:

  • Click OK to complete the configuration

The step above is shown in the image below:

Add a Request Validator to the Visual Studio Solution

In .NET 4.0, any page request which contains a WS-Federation authentication will end up with an error by default. This is due to cross-scripting exploits which were discovered. Essentially, you need to add a C# class to your solution which solves the error you encounter.

  • In the Visual Studio Solution, right click the WebRole project, click Add, and then click New Item

The step above is shown in the image below:

  • Click Web in the left side menu, select C# Class, and name your class (i’ve chosen NimboRequestValidator.cs)

The steps above are shown in the image below:

  • Paste the following code in to the NimboRequestValidator.cs file:


using System;
using System.Web;
using System.Web.Util;

using Microsoft.IdentityModel.Protocols.WSFederation;

public class NimboRequestValidator : RequestValidator
{
protected override bool IsValidRequestString( HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex )
{
validationFailureIndex = 0;

if ( requestValidationSource == RequestValidationSource.Form && collectionKey.Equals( WSFederationConstants.Parameters.Result, StringComparison.Ordinal ) )
{
SignInResponseMessage message = WSFederationMessage.CreateFromFormPost( context.Request ) as SignInResponseMessage;

if ( message != null )
{
return true;
}
}

return base.IsValidRequestString( context, value, requestValidationSource, collectionKey, out validationFailureIndex );
}
}

The steps above are shown in the image below:

    • Open the Web.Config file, and enter the following line of code directly after <system.web>:

<httpRuntime requestValidationType=”NimboRequestValidator” />

The step above is shown in the image below:

Using Claims in the Application

This is the point where we start leveraging the Windows Identity Foundation. We need to add the reference in the application and set the Copy Local property of the Microsoft.IdentityModel assembly to True.

  • In the Visual Studio Solution, right click References and click Add Reference

The step above is shown in the image below:

  • Select the .NET tab, highlight Microsoft.IndentityModel, and click OK

The steps above are shown in the image below:

  • Right click Microsoft.IndentityModel and click Properties

The steps above are shown in the image below:

  • Select True in the Copy Local property

The step above is shown in the image below:

  • Open the Default.aspx.cs file and add using Microsoft.IdentityModel.Claims;

The step above is shown in the image below:

  • Enter the following code in the Default.aspx.cs file:


protected void Page_Load(object sender, EventArgs e)
{
ContentPlaceHolder cph = (ContentPlaceHolder) this.Master.FindControl(“MainContent”);

IClaimsPrincipal claimsPrincipal = Page.User as IClaimsPrincipal;
IClaimsIdentity claimsIdentity = (IClaimsIdentity)claimsPrincipal.Identity;

Table claimsTable = new Table();
TableRow headerRow = new TableRow();

TableCell claimTypeCell = new TableCell();
claimTypeCell.Text = “Claim Type”;
claimTypeCell.BorderStyle = BorderStyle.Solid;

TableCell claimValueCell = new TableCell();
claimValueCell.Text = “Claim Value”;
claimValueCell.BorderStyle = BorderStyle.Solid;

headerRow.Cells.Add(claimTypeCell);
headerRow.Cells.Add(claimValueCell);
claimsTable.Rows.Add(headerRow);

TableRow newRow;
TableCell newClaimTypeCell, newClaimValueCell;
foreach (Claim claim in claimsIdentity.Claims)
{
newRow = new TableRow();
newClaimTypeCell = new TableCell();
newClaimTypeCell.Text = claim.ClaimType;

newClaimValueCell = new TableCell();
newClaimValueCell.Text = claim.Value;

newRow.Cells.Add(newClaimTypeCell);
newRow.Cells.Add(newClaimValueCell);

claimsTable.Rows.Add(newRow);
}

cph.Controls.Add(claimsTable);
}

The steps above are shown in the image below:

Testing the Application

At this point, you can execute the application and you shouldn’t be prompted for credentials. Remember that you still have the application configured to run in the Azure Development Fabric. When you are ready to put it in to Windows Azure – you’ll need to change your FederationMetadata document and your hosts file to reflect the respective Windows Azure IP address which your application is running on.

The code you placed in the default.aspx.cs file simply displays the claims it’s receiving from AD FS 2.0. Have a look at an example in the image below:

The next step is to make a few changes to get the solution running in Windows Azure.

Exporting the Certificate for Windows Azure

Windows Azure requires you to implement a certificate if you want the solution to run on HTTPS (SSL).

  • On the ACCESSCONTROL Server, go to Start, type MMC, and hit Enter to open the Microsoft Management Console
  • Click Certificates, then click Add
  • Click OK

The steps above are shown in the image below:

  • Select the location of your certificate (for me, it was Personal – Certificates
  • Right click the certificate, select All Tasks, then click Export (for me, it’s the nimbosso.nimbocloud.com certificate

The steps above are shown in the image below:

  • On the Welcome screen, click Next

The step above is shown in the image below:

  • Select Yes, export the private key and click Next

The step above is shown in the image below:

  • Leave the default settings as they appear and click Next

The step above is shown in the image below:

  • Type a password you will remember, as you will use this later when you import the certificate in Windows Azure
  • Click Next

The step above is shown in the image below:

  • Specify the name and path of the file you want to export, then click Next

The step above is shown in the image below:

  • Click Finish on the Completing the Certificate Export Wizard screen

The step above is shown in the image below:

Changing the URLs and Trust for the Azure Environment

Remember how we specified the unique port for our solution? This was based upon the Azure Development Fabric choosing a random port (remember mine was 444). In order to put this in to Azure, we wouldn’t have that custom port normally. Although – you could certainly specify the port to be whatever you required. At this time, however, we’re simply going to remove the specified port 444 from the solution (yours may have been different).

    • Browse to the location of the FederationMetadata.xml file (this is typically located in the FederationMetadata/2007-06/ folder of your Visual Studio solution.

Note: Make sure you click Test location which will create the Federation Metadata XML file if it doesn’t already exist.

  • Create a copy of the file, and rename the copy to FederationMetadata_BAK.xml
  • Edit the FederationMetadata.xml file and change the three URLs to remove the specific port number (we don’t need this anymore)

The steps above are shown in the images below:

    • Next, you have to create another relying party trust in AD FS 2.0 which references the new FederationMetadata.xml file
    • Complete the exact same steps as you did before, specifying the newly edited FederationMetadata.xml file

Note: I did not write these steps again here because it would be redundant. If you’re lost – just scroll up and view the Relying Party Trust section of this blog!

The steps above are shown in the images below:

Reconfigure the Claim Rules for the Azure Environment

This may not be required, but I always do it just to be safe and re-validate my choices. You’re going to complete the exact same steps as you did for in the Edit Claim Rules section of this blog. The images are provided below for guidance.

Deploying the Application to Windows Azure

The final step is to deploy the application to Windows Azure. Because Windows Azure has a FQDN with *.cloudapp.net and I’ve selected the URL of https://nimbosso.nimbocloud.com, we’re going to do a bit of a hack for this proof of concept. This involves deploying the application, pinging the given FQDN by Azure, and then entering the respective IP Address of the Azure application in our Hosts file for the https://nimbosso.nimbocloud.com URL.

Note: Make sure you edit the Web.Config file and remove any references to the custom port which was entered before. I prefer to comment the line out and then copy and paste a new line without the ports. This makes debugging easier when required.

  • In the Visual Studio solution, right click the Azure project and click Publish

The step above is shown in the image below:

  • Select Create Service Package Only and click OK

The step above is shown in the image below:

  • The location of the Azure package file and configuration files should open automatically. If it doesn’t for some reason, you can browse to the location. It’s typically in your solution folder under bin/Debug/Publish

The step above is shown in the image below:

  • Log in to the Windows Azure Portal click click New Hosted Service
  • Choose all of the typical options to import your newly published files, with the exception that you’ll be adding a certificate
  • Click Add Certificate to begin the import certificate process
  • Click Browse to locate the *.pfx file you created in the Export the Certificate steps earlier in this article
  • Select the file, then click Open
  • Type the password you created in the Export the Certificate steps earlier in this article and click OK

The step above is shown in the image below:

  • If you didn’t modify the ServiceConfiguration.cscfg file to specify more than 1 instance, you will get a warning. You can click Yes if it happens. You should always have more than one instance running in a production environment, but it’s not necessary for this exercise.

The warning message is shown in the image below:

  • When the deployment has finished, copy the DNS name of the deployment to your clipboard.

The step above is shown in the image below:

  • Ping the DNS name of the deployment and make a note of the IP Address shown.
  • Edit the Hosts file as you did before in the earlier steps of this article to reflect the IP Address shown with your FQDN/URL (mine was 157.55.172.204 nimbosso.nimbocloud.com).
    Note: It’s very important that you comment out the original hosts entry you created with the loopback address (127.0.0.1). You can do this by placing a # in front of the entry as I have done in the image below.

The steps above are shown in the image below:

Solution Complete

At this point, you can browse to the application by entering the URL in a web browser. If you’re logged on as a user in the active directory domain, you’ll simply need to accept the certificate warnings and you won’t be prompted for a password. You may need to add the site to your trusted sites in Internet Explorer for this to work properly, depending on the configuration of your machine. A fun thing you can do for the demonstration is to go in to Active Directory and create a new security group. Once you’ve done that, add the user account to the security group. Log off your machine and log back in before you visit the Azure application. When you do this, you should see the new security group displayed in the web application since the claim will be passed through.

Fun stuff!