Departmental Application Migration to Azure – Part 4 – ADFS with Azure web appSolution ·
This is part of a series of blogs. See the preceding blog entries:
- Departmental Application Migration to Azure – Part 1
- Departmental Application Migration to Azure – Part 2 – ADFS Installation
- Departmental Application Migration to Azure – Part 3 – ADFS with on-premise web app
As mentioned before on this blog series, for me the authentication is the major challenge for this proof of concept. I need this web application to support Enterprise Single Sign-On through Active Directory. I’ve decided to use ADFS 2.0 and Windows Identity Foundation (WIF). In the last article, I’ve showed how to get an on-premise web application using ADFS for authentication. On this blog entry, I’m going to the cloud, so let’s get started!
You need to have ADFS 2.0 installed. This was covered in a previous blog entry from this series.
You’ll also need the Windows Identity Foundation (WIF) SDK. You can download it at http://www.microsoft.com/downloads/details.aspx?familyid=C148B2DF-C7AF-46BB-9162-2C9422208504&displaylang=en.
You’ll also need the Windows Azure SDK. I’m using the one from June 2010, you can download it at http://www.microsoft.com/downloads/details.aspx?familyid=21910585-8693-4185-826E-E658535940AA&displaylang=en.
To top it all, you can install the Windows Azure Tools for Microsoft Visual Studio 1.2 (also from June 2010). You can download it at http://www.microsoft.com/downloads/details.aspx?familyid=2274A0A8-5D37-4EAC-B50A-E197DC340F6F&displaylang=en.
I’ll use Visual Studio 2010.
Creating a web role in Dev Fabric
Let’s start by creating a vanilla web role in Dev Fabric. The Dev Fabric is the dev environment provided with the Windows Azure SDK, basically, the developer work station.
I start by creating an empty solution which I name AdfsAuthenticatedAzure.
I then create a Windows Azure Cloud Service named MyCloudFacade.
A Cloud service is a unit of deployment. A service contains different roles and a configuration for the service. The roles are all deployed together in one package.
I create one role within that service, a web role named AdfsAuthenticatedWebRole.
Like the solution on-premise I did in the last blog entry, I’m trimming the boiler-plate web project:
- Delete the Account folder since ADFS will perform those functions.
- In web.config:
- Delete the connection string.
- Delete the authentication xml node.
- Delete the membership xml node.
- Delete the profile xml node.
- Delete the roleManager xml node.
I can now hit F5 and look at my wonderful generic web site!
Deploying to Azure
To integrate with ADFS, I’ll need my web site to be using SSL. I’ll attach a certificate to my service and enable an https input endpoint. I’ll start at the properties of my web role.
At the certificates tab:
I then add a certificate and select one of my local (self-issued) certificates.
I then go at the Endpoints tab, check the HTTPS check box and select the SSL certificate name I just added.
The Windows Azure Tools for Microsoft Visual Studio 1.2 allow you to deploy to Azure directly, instead of simply packaging (where you have to deploy the package using the web console). There are plenty of web resources showing how to deploy an Azure service to the cloud. If you have questions, please ask.
While it’s deploying, I’ll add the same certificate to my service in the cloud. In my Azure Service Web console:
I need a PFX file to upload. I use IIS Server Certificates module and export the same self-issued certificate I used in Visual Studio.
I can then save the certificate locally and protect it with a password. I can then import it in the Azure web console, using the same password.
I first deploy to staging then to production. As I mentioned in a previous blog entry, staging isn’t a real staging as Microsoft recommend to have a separate subscription altogether for staging vs production. This is important here, since staging would be harder to integrate with ADFS given its unpredictable URL (Azure generates staging URLs using a GUID).
Of course I get warnings because my certificate is self-issued and hence unrecognized by IE as trustworthy.
Integrating ADFS in Dev Fabric
The steps here are a repetition of what I covered in the previous blob entry of this series, so I won’t go into much details.
First, I choose to Add STS Reference and set https://localhost:444.
(The https in-point port is set to 443, which is the default https port, but this port being used by IIS, the web role responds to port 443 in the dev environment)
For the rest of the Wizard, it’s the same steps I used in the precedent blog of this blog series.
I then run the modified web role in my dev environment. I get an error from the ADFS site since my application isn’t recognized there yet. So in the ADFS console, I create a relying trust party named Adfs Authenticated Dev. The reason I append the name by dev is that we’ll need to create an entry for the production endpoint as well, since it has a different URL. In the claims rules, I make sure ADFS will send me a few claims (e.g. windows name, email, title, etc.).
I can now use my local web role, after doing the form validation fix I spoke about last time. I also remove the HTTP input endpoint since ADFS will only trust me if I come from HTTPS. Finally, I add a grid view showing all the user claims like I did last time.
Integrating ADFS with Azure
I then run the Add STS Reference in Visual Studio again. This time I use my production Windows Azure URL (https://****.cloudapp.net). I then go in the federation metadata file and remove reference to localhost:
After this, my meta isn’t usable for dev, but I only need to maintain it for production.
I run the ADFS relying party trust wizard again, still pointing to that meta data file. I call this party Adfs Authenticated Prod.
The problem I’ll run into now is that the w-reply query string will forward me to my production web role. This is related to how WIF is creating the URL to the STS. It uses a URL specified in the configuration file. The fix for this is documented in the Windows Azure training kit: override the query string using the WS-Federation authentication module by adding the following code in the Global.asax.
/// Retrieves the address that was used in the browser for accessing
/// the web application, and injects it as WREPLY parameter in the
/// request to the STS
void WSFederationAuthenticationModule_RedirectingToIdentityProvider(object sender, RedirectingToIdentityProviderEventArgs e)
// In the Windows Azure environment, build a wreply parameter for the SignIn request
// that reflects the real address of the application.
HttpRequest request = HttpContext.Current.Request;
Uri requestUrl = request.Url;
StringBuilder wreply = new StringBuilder();
wreply.Append(requestUrl.Scheme); // e.g. "http" or "https"
wreply.Append(request.Headers["Host"] ?? requestUrl.Authority);
e.SignInRequestMessage.Reply = wreply.ToString();
e.SignInRequestMessage.Realm = wreply.ToString();
We also need to add an audience URI in the web.config for 127.0.0.1 (if like me you did register to the STS as localhost).
<add value="https://127.0.0.1:444/" />
<add value="https://localhost:444/" />
I am now prepared to deploy my application in Windows Azure.
Now here is an issue that took me a lot of time to resolve. Every time you put dlls that aren’t part of the .NET Framework or your projects, you have to specify Copy Local to true in the assembly property.
This is our case for the WIF assemblies. This setting will force the WIF assembly to be packaged and sent to the cloud with the rest of the custom code.
Deploying ADFS integration to the cloud
I deploy the application to the staging Windows Azure environment. As mentioned before, this environment won’t fully work since the URL is not constant.
Once it’s in staging I flick it to production.
So, not too trivial to setup, but in the range of the feasible ;)