Modifying and Securing the ADFS 2 Web Application

When you install an instance of Active Directory Federation Services v2, amongst other things it will create a website within IIS to use as it’s Secure Token Service.  This is sort of fundamental to the whole design.  There are some interesting things to note about the situation though.

When Microsoft (or any ISV really) releases a new application or server that has a website attached to it, they usually deliver it in a precompiled form, so all we do is point IIS to the binaries and config files and we go from there.  This serves a number of purposes usually along the lines of performance, Intellectual Property protection, defense in depth protection, etc.  Interestingly though, when the installer creates the application for us in IIS, it drops source code instead of a bunch of assemblies.

There is a valid reason for this.

It gives us the opportunity to do a couple things.  First, we can inspect the code.  Second, we can easily modify the code.  Annoyingly, they don’t give us a Visual Studio project to do so.  Let’s create one then.

First off, lets take a look at what was created by the installer.  By default it drops the files in c:\inetpub\adfs\ls.  We are given a few files and folders:

image

There isn’t much to it.  These files only contain a few lines of code.  Next we create the actual project.

DISCLAIMER:  I will not be held responsible if things break or the server steals your soul.  Please do NOT (I REPEAT) do NOT do this with production servers please!  (Notice I said please twice?)

Since we want to create a Visual Studio project, and since ADFS cannot be installed on a workstation, we have two options:

  1. Install Visual Studio on the server running ADFS
  2. Copy the files to your local machine

Each options have their tradeoffs.  The first requires a bit of a major overhaul of your development environment.  It’s very similar to SharePoint 2007 development.  The second option makes developing a lot easier, but testing is a pain because the thing won’t actually work properly without the Windows Services running.  You would need to deploy the code to a test server with ADFS installed.

Since I have little interest in rebuilding my development box, I went with the second option.

Okay, back to Visual Studio.  The assemblies referenced were all built on Framework 3.5, so for the sake of simplicity lets create a 3.5 Web Application:

image

I haven’t tested 4.0 yet.

Since this is a Web Application and not a Web Site within Visual Studio, we need to generate the *.designer.cs files for all the *.aspx pages.  Right-click your project and select Convert to Web Application:

image

At this point if you tried to compile the application it wouldn’t work.  We are missing a few assembly references.  First, add Microsoft.IdentityModel.  This should be in the GAC or the Reference Assemblies folder in Program Files.  Next, go back to the ADFS server and navigate to C:\Program Files\Active Directory Federation Services 2.0 and copy the following files:

  • Microsoft.IdentityServer.dll
  • Microsoft.IdentityServer.Compression.dll

Add these assemblies as references.  The web application should compile successfully.

Next we need to sign the web application’s assemblies.  If you have internal policies on assembly signing, follow those.  Otherwise double-click the properties section in Solution Explorer and navigate to Signing:

image

Choose a key file or create a new one.  Rebuild the web application.

So far we haven’t touched a line of code.  This is all general deployment stuff.  You can deploy the web application back to the ADFS server and it should work as if nothing had changed.  You have a few options for this.  The Publishing Features in Visual Studio 2010 are awesome.  Right click the project and Publish it:

image

Since I set up a test box for ADFS development, I’m just going to overwrite the files on the server:

image

Pro Tip: If you do something terrible and need to revert back to original code (what part of don’t do this on a production box didn’t make sense? Winking smile) you can access the original files from C:\Program Files\Active Directory Federation Services 2.0\WSFederationPassive.Web.

At this point we haven’t done much, but we now have a stepping point to modify the default behavior of ADFS.  This could range from simple theme changes to better suit corporate policy, or to completely redefine the authentication workflow.

This also gives us the ability to better protect our code in the event that IIS craps out and shows contents of files, not to mention the (albeit minor) performance boost we get because the website doesn’t need to be recompiled.

Have fun!

Making an ASP.NET Website Claims Aware with the Windows Identity Foundation

Straight from Microsoft this is what the Windows Identity Foundation is:

Windows Identity Foundation helps .NET developers build claims-aware applications that externalize user authentication from the application, improving developer productivity, enhancing application security, and enabling interoperability. Developers can enjoy greater productivity, using a single simplified identity model based on claims. They can create more secure applications with a single user access model, reducing custom implementations and enabling end users to securely access applications via on-premises software as well as cloud services. Finally, they can enjoy greater flexibility in application development through built-in interoperability that allows users, applications, systems and other resources to communicate via claims.

In other words it is a method for centralizing user Identity information, very much like how the Windows Live and OpenID systems work.  The system is reasonably simple.  I have a Membership data store that contains user information.  I want (n) number of websites to use that membership store, EXCEPT I don’t want each application to have direct access to membership data such as passwords.  The way around it is through claims.

In order for this to work you need a central web application called a Secure Token Service (STS).  This application will do authentication and provide a set of available claims.  It will say “hey! I am able to give you the person’s email address, their username and the roles they belong to.”  Each of those pieces of information is a claim.  This message exists in the application’s Federation Metadata

So far you are probably saying “yeah, so what?”

What I haven’t mentioned is that every application (called a Relying Party) that uses this central application has one thing in common: each application doesn’t have to handle authentication – at all.  Each application passes off the authentication request to the central application and the central application does the hard work.  When you type in your username and password, you are typing it into the central application, not one of the many other applications.  Once the central application authenticates your credentials it POST’s the claims back to the other application.  A diagram might help:

image

Image borrowed from the Identity Training kit (http://www.microsoft.com/downloads/details.aspx?familyid=C3E315FA-94E2-4028-99CB-904369F177C0&displaylang=en)

The key takeaway is that only one single application does authentication.  Everything else just redirects to it.  So lets actually see what it takes to authenticate against an STS (central application).  In future posts I will go into detail about how to create an STS as well as how to use Active Directory Federation Services, which is an STS that authenticates directly against (you guessed it) Active Directory.

First step is to install the Framework and SDK.

WIF RTW: http://www.microsoft.com/downloads/details.aspx?FamilyID=eb9c345f-e830-40b8-a5fe-ae7a864c4d76&displaylang=en

WIF SDK: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=c148b2df-c7af-46bb-9162-2c9422208504

The SDK will install sample projects and add two Visual Studio menu items under the Tools menu.  Both menu items do essentially the same thing, the difference being that “Add STS Reference” pre-populates the wizard with the current web application’s data.

Once the SDK is installed start up Visual Studio as Administrator.  Create a new web application.  Next go to the Properties section and go into the Web section.  Change the Server Settings to use IIS.  You need to use IIS.  To install IIS on Windows 7 check out this post.

image

So far we haven’t done anything crazy.  We’ve just set a new application to use IIS for development.  Next we have some fun.  Let’s add the STS Reference.

To add the STS Reference go to Tools > Add Sts Reference… and fill out the initial screen:

image


Click next and it will prompt you about using an HTTPS connection.  For the sake of this we don’t need HTTPS so just continue.  The next screen asks us about where we get the STS Federation Metadata from.  In this case I already have an STS so I just paste in the URI:

image

Once it downloads the metadata it will ask if we want the Token that the STS sends back to be encrypted.  My recommendation is that we do, but for the sake of this we won’t.

image

As an aside: In order for the STS to encrypt the token it will use a public key to which our application (the Relying Party) will have the private key.  When we select a certificate it will stick that public key in the Relying Party’s own Federation Metadata file.  Anyway… When we click next we are given a list of available Claims the STS can give us:

image
There is nothing to edit here; it’s just informative.  Next we get a summary of what we just did:

image

We can optionally schedule a Windows task to download changes.

We’ve now just added a crap-load of information to the *.config file.  Actually, we really didn’t.  We just told ASP.NET to use the Microsoft.IdentityModel.Web.WSFederationAuthenticationModule to handle authentication requests and Microsoft.IdentityModel.Web.SessionAuthenticationModule to handle session management.  Everything else is just boiler-plate configuration.  So lets test this thing:

  1. Hit F5 – Compile compile compile compile compile… loads up http://localhost/WebApplication1
  2. Page automatically redirects to https://login.myweg.com/login.aspx?ReturnUrl=%2fusers%2fissue.aspx%3fwa%3dwsignin1.0%26wtrealm%3dhttp%253a%252f%252flocalhost%252fWebApplication1%26wctx%3drm%253d0%2526id%253dpassive%2526ru%253d%25252fWebApplication1%25252f%26wct%3d2010-08-03T23%253a03%253a40Z&wa=wsignin1.0&wtrealm=http%3a%2f%2flocalhost%2fWebApplication1&wctx=rm%3d0%26id%3dpassive%26ru%3d%252fWebApplication1%252f&wct=2010-08-03T23%3a03%3a40Z (notice the variables we’ve passed?)
  3. Type in our username and password…
  4. Redirect to http://localhost/WebApplication1
  5. Yellow Screen of Death

Wait.  What?  If you are running IIS 7.5 and .NET 4.0, ASP.NET will probably blow up.  This is because the data that was POST’ed back to us from the STS had funny characters in the values like angle brackets and stuff.  ASP.NET does not like this.  Rightfully so, Cross Site Scripting attacks suck.  To resolve this you have two choices:

  1. Add <httpRuntime requestValidationMode="2.0" /> to your web.config
  2. Use a proper RequestValidator that can handle responses from Token Services

For the sake of testing add <httpRuntime requestValidationMode="2.0" /> to the web.config and retry the test.  You should be redirected to http://localhost/WebApplication1 and no errors should occur.

Seems like a pointless exercise until you add a chunk of code to the default.aspx page. Add a GridView and then add this code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Threading;
using System.IdentityModel;
using System.IdentityModel.Claims;
using Microsoft.IdentityModel.Claims;

namespace WebApplication1
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            IClaimsIdentity claimsIdentity = ((IClaimsPrincipal)(Thread.CurrentPrincipal)).Identities[0];

            GridView1.DataSource = claimsIdentity.Claims;
            GridView1.DataBind();
        }
    }
}

Rerun the test and you should get back some values.  I hope some light bulbs just turned on for some people :)

Installing IIS 7.5 on Windows 7 from the Command Line

This is more of a place for me to store something I use fairly often, but can never remember off the top of my head.  This script, when run as administrator, will install all the features of IIS for developing on Windows 7.  Mind you, this is the prettified* version so it’s web-readable.

START /WAIT DISM /Online /Enable-Feature
/FeatureName:IIS-ApplicationDevelopment
/FeatureName:IIS-ASP
/FeatureName:IIS-ASPNET
/FeatureName:IIS-BasicAuthentication
/FeatureName:IIS-CGI
/FeatureName:IIS-ClientCertificateMappingAuthentication
/FeatureName:IIS-CommonHttpFeatures
/FeatureName:IIS-CustomLogging
/FeatureName:IIS-DefaultDocument
/FeatureName:IIS-DigestAuthentication
/FeatureName:IIS-DirectoryBrowsing
/FeatureName:IIS-FTPExtensibility
/FeatureName:IIS-FTPServer
/FeatureName:IIS-FTPSvc
/FeatureName:IIS-HealthAndDiagnostics
/FeatureName:IIS-HostableWebCore
/FeatureName:IIS-HttpCompressionDynamic
/FeatureName:IIS-HttpCompressionStatic
/FeatureName:IIS-HttpErrors
/FeatureName:IIS-HttpLogging
/FeatureName:IIS-HttpRedirect
/FeatureName:IIS-HttpTracing
/FeatureName:IIS-IIS6ManagementCompatibility
/FeatureName:IIS-IISCertificateMappingAuthentication
/FeatureName:IIS-IPSecurity
/FeatureName:IIS-ISAPIExtensions
/FeatureName:IIS-ISAPIFilter
/FeatureName:IIS-LegacyScripts
/FeatureName:IIS-LegacySnapIn
/FeatureName:IIS-LoggingLibraries
/FeatureName:IIS-ManagementConsole
/FeatureName:IIS-ManagementScriptingTools
/FeatureName:IIS-ManagementService
/FeatureName:IIS-Metabase
/FeatureName:IIS-NetFxExtensibility
/FeatureName:IIS-ODBCLogging
/FeatureName:IIS-Performance
/FeatureName:IIS-RequestFiltering
/FeatureName:IIS-RequestMonitor
/FeatureName:IIS-Security
/FeatureName:IIS-ServerSideIncludes
/FeatureName:IIS-StaticContent
/FeatureName:IIS-URLAuthorization
/FeatureName:IIS-WebDAV
/FeatureName:IIS-WebServer
/FeatureName:IIS-WebServerManagementTools
/FeatureName:IIS-WebServerRole
/FeatureName:IIS-WindowsAuthentication
/FeatureName:IIS-WMICompatibility
/FeatureName:WAS-ConfigurationAPI
/FeatureName:WAS-NetFxEnvironment
/FeatureName:WAS-ProcessModel
/FeatureName:WAS-WindowsActivationService

*Interesting that “prettified” is a word according to Live Writer.

IIS 7 Certificate Request Completion breaking with &amp;ldquo;ASN1 bad tag value met 0x8009310b&amp;rdquo;

Only took a couple quick searches Googling with Bing, but in IIS 7 if you create a request for a certificate, create it by a CA and then complete the request, and find it blows up with this message box:

CertEnroll::CX509Enrollment::p_InstallResponse: ASN1 bad tag value met. 0x8009310b (ASN: 267)

All it means is that the CA that issued the certificate isn’t trusted on the server.  I came across this in a test environment I was building.  I had a Domain with CA Services, and a server that existed outside the domain.  I used the domain CA to create the certificate, but because the web server wasn’t part of the domain, it didn’t trust the CA.

My fix was to add the CA as a trusted Root Authority on the web server.

Exchange 2010 Beta

A couple days ago Daniel Shapiro offered 10 people Virtual Servers hosted by Rack Force.  I jumped on the offer, as I’ve been wanting to migrate this website to it’s own privately hosted server.  It really came down to never having the time to test out hosts, so this was a perfect opportunity.  Shortly thereafter I found out Exchange 2010 hit beta, and I wanted to run it through it’s paces.

After installing Active Directory, I installed the beta, which went really smooth.  Given that it went smooth, I decided to update the DNS MX records for syfuhs.net to point to this server.

One thing I didn’t realize is you have to set up Receive Connectors and Send Connectors.  The wording is kinda misleading, so I ended up setting my first Send Connector to only route mail going to syfuhs.net from syfuhs.net.  Not so useful.  The Receive connector was the same way.  However, this is all similar to Exchange 2007.

Now some pictures:

image Outlook Web Access

image Exchange Management Console

image

 IIS Manager Hosting Outlook Web Access

image