Converting Bootstrap Tokens to SAML Tokens

there comes a point where using an eavesdropping application to catch packets as they fly between Secure Token Services and Relying Parties becomes tiresome.  For me it came when I decided to give up on creating a man-in-the-middle between SSL sessions between ADFS and applications.  Mainly because ADFS doesn’t like that.  At all.

Needless to say I wanted to see the tokens.  Luckily, Windows Identity Foundation has the solution by way of the Bootstrap token.  To understand what it is, consider how this whole process works.  Once you’ve authenticated, the STS will POST a chunk of XML (the SAML Token) back to the RP.  WIF will interpret it as necessary and do it’s magic generating a new principal with the payload.  However, in some instances you need to keep this token intact.  This would be the case if you were creating a web service and needed to forward the token.  What WIF does is generate a bootstrap token from the SAML token, in the event you needed to forward it off to somewhere.

Before taking a look at it, let's add in some useful using statements:

using System;
using System.IdentityModel.Tokens;
using System.Text;
using System.Threading;
using System.Xml;
using Microsoft.IdentityModel.Claims;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Tokens.Saml11;

The bootstrap token is attached to IClaimsPrincipal identity:

SecurityToken bootstrapToken = ((IClaimsPrincipal)Thread.CurrentPrincipal).Identities[0].BootstrapToken;

However if you do this out of the box, BootstrapToken will be null.  By default, WIF will not save the token.  We need to explicitly enable this in the web.config file.  Add this line under <microsoft.IdentityModel><service><securityTokenHandlers>:

<securityTokenHandlerConfiguration saveBootstrapTokens="true" />

Once you’ve done that, WIF will load the token.

The properties are fairly straightforward, but you can’t just get a blob from it:

image

Luckily we have some code to convert from the bootstrap token to a chunk of XML:

SecurityToken bootstrapToken = ((IClaimsPrincipal)Thread.CurrentPrincipal).Identities[0].BootstrapToken;

StringBuilder sb = new StringBuilder();

using (var writer = XmlWriter.Create(sb))
{
     new Saml11SecurityTokenHandler(new SamlSecurityTokenRequirement()).WriteToken(writer, bootstrapToken);
}

string theXml = sb.ToString();

We get a proper XML document:

image

That’s all there is to it.

Videos on Identity Foundation and ADFS

Some videos from the last PDC…

LOTS of information…

Installing ADFS 2 and Federating an Application

From Microsoft Marketing, ADFS 2.0 is:

Active Directory Federation Services 2.0 helps IT enable users to collaborate across organizational boundaries and easily access applications on-premises and in the cloud, while maintaining application security. Through a claims-based infrastructure, IT can enable a single sign-on experience for end-users to applications without requiring a separate account or password, whether applications are located in partner organizations or hosted in the cloud.

So, it’s a Token Service plus some.  In a previous post I had said:

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.

The membership store in this case being Active Directory.

I thought it would be a good idea to run through how to install ADFS and set up an application to use it.  Since we already discussed how to federate an application using FedUtil.exe, I will let you go through the steps in the previous post.  I will provide information on where to find the Metadata later on in this post.

But First: The Prerequisites

  1. Join the Server to the Domain. (I’ve started the installation of ADFS three times on non-domain joined systems.  Doh!)
  2. Install the latest .NET Framework.  I’m kinda partial to using SmallestDotNet.com created by Scott Hanselman.  It’s easy.
  3. Install IIS.  If you are running Server 2008 R2 you can follow these steps in another post, or just go through the wizards.  FYI: The post installs EVERY feature.  Just remember that when you move to production.  Surface Area and what not…
  4. Install PowerShell.
  5. Install the Windows Identity Foundation: http://www.microsoft.com/downloads/details.aspx?FamilyID=eb9c345f-e830-40b8-a5fe-ae7a864c4d76&displaylang=en
  6. Install SQL Server.  This is NOT required.  You only need to install it if you want to use a SQL Database to get custom Claims data.  You could also use a SQL Server on another server…
  7. Download ADFS 2.0 RTW: http://www.microsoft.com/downloads/details.aspx?familyid=118c3588-9070-426a-b655-6cec0a92c10b&displaylang=en

The Installation

image

Read the terms and accept them.  If you notice, you only have to read half of what you see because the rest is in French.  Maybe the lawyers are listening…these things are getting more readable.

image

Select Federation Server.  A Server Proxy allows you to use ADFS on a web server not joined to the domain.

image

We already installed all of these things.  When you click next it will check for latest hotfixes and ask if you want to open the configuration MMC snap-in.  Start it.

image

We want to start the configuration Wizard and then create a new Federation Service:

image

Next we want to create a Stand-alone federation server:

image

We need to select a certificate for ADFS to use.  By default it uses the SSL certificate of the default site in IIS.  So lets add one.  In the IIS Manager select the server and then select Server Certificates:

image

We have a couple options when it comes to adding a certificate.  For the sake of this post I’ll just create a self-signed certificate, but if you have a domain Certificate Authority you could go that route, or if this is a public facing service create a request and get a certificate from a 3rd party CA.

image

Once we’ve created the certificate we assign it to the web site.  Go to the website and select Bindings…

image

Add a site binding for https:

image

Now that we’ve done that we can go back to the Configuration Wizard:

image

Click next and it will install the service.  It will stop IIS so be aware of that.

image

You may receive this error if you are installing on Server 2008:

image

The fix for this is here: http://www.syfuhs.net/2010/07/23/ADFS20WindowsServiceNotStartingOnServer2008.aspx

You will need to re-run the configuration wizard if you do this.  It may complain about the virtual applications already existing.  You two options: 1) delete the applications in IIS as well as the folder C:\inetpub\adfs; 2) Ignore the warning.

Back to the installation, it will create two new Virtual Applications in IIS:

image

Once the wizard finishes you can go back to the MMC snap-in and fiddle around.  The first thing we need to do is create an entry for a Relying Party.  This will allow us to create a web application to work with it.

image

When creating an RP we have a couple options to provide configuration data.

image

Since we are going to create a web application from scratch we will enter in manual data.  If you already have the application built and have Federation Metadata available for it, by all means just use that.

We need a name:

image

Very original, eh?

Next we need to decide on what profile we will be using.  Since we are building an application from scratch we can take advantage of the 2.0 profile, but if we needed backwards compatibility for a legacy application we should select the 1.0/1.1 profile.

image

Next we specify the certificate to encrypt our claims sent to the application.  We only need the public key of the certificate.  When we run FedUtil.exe we can specify which certificate we want to use to decrypt the incoming tokens.  This will be the private key of the same certificate.  For the sake of this, we’ll skip it.

image

The next step gets a little confusing.  It asks which protocols we want to use if we are federating with a separate STS.  In this case since we aren’t doing anything that crazy we can ignore them and continue:

image

We next need to specify the RP’s identifying URI.

image

Allow anyone and everyone, or deny everyone and add specific users later?  Allow everyone…

image

When we finish we want to edit the claim rules:

image

This dialog will allow us to add mappings between claims and the data within Active Directory:

image

So lets add a rule.  We want to Send LDAP Attributes as Claims

image

First we specify what data in Active Directory we want to provide:

image

Then we specify which claim type to use:

image

And ADFS is configured!  Lets create our Relying Party.  You can follow these steps: Making an ASP.NET Website Claims Aware with the Windows Identity Foundation.  To get the Federation Metadata for ADFS navigate to the URL that the default website is mapped to + /FederationMetadata/2007-06/FederationMetadata.xml.  In my case it’s https://web1.nexus.internal.test/FederationMetadata/2007-06/FederationMetadata.xml.

Once you finish the utility it’s important that we tell ADFS that our new RP has Metadata available.  Double click on the RP to get to the properties.  Select Monitoring:

image

Add the URL for the Metadata and select Monitor relying party.  This will periodically call up the URL and download the metadata in the event that it changes.

At this point we can test.  Hit F5 and we will redirect to the ADFS page.  It will ask for domain credentials and redirect back to our page.  Since I tested it with a domain admin account I got this back:

image

It works!

For more information on ADFS 2.0 check out http://www.microsoft.com/windowsserver2008/en/us/ad-fs-2-overview.aspx or the WIF Blog at http://blogs.msdn.com/b/card/

Happy coding!

Making an ASP.NET MVC Application Claims Aware with Windows Identity Foundation

A couple posts back I had discussed how you would make an ASP.NET webforms application claims aware. It was reasonably detailed an hopefully it was clear.  I say that because to make an MVC application Claims aware, you follow the exact same procedure.

The only difference is the small little chunk of code to see what claims were returned.  Just drop this little snipped into a view and you can muck about:

<ul>
    <%
    var claimsIdentity 
        = (System.Threading.Thread.CurrentPrincipal 
	   as Microsoft.IdentityModel.Claims.IClaimsPrincipal)
	  .Identities[0];
    foreach (var claim in claimsIdentity.Claims)
    {%>
    <li>
       <%: claim.ClaimType %>
    --
    <%: claim.Value %>
    
    <% } %>
    </li>
</ul>

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 :)