SSO with Windows Identity Foundation: Part I - The basics

Updated 2017: You'd do well to check a more modern option for authentication at this day and age. https://github.com/IdentityServer/IdentityServer3 and OpenID Connect should be something to look at. WIF is now direly outdated technology. This article still explains well the general things and problems that relate to achieve SSO

The road to understanding the security and technical details of any security system is a truly perilous one with steep learning curves along the way. Toss in a side dish of single sign on and achieving that securely, and you're in for a ride. What I aim to do here is to challenge myself with a multipart blog post and try to shed some light on Windows Identity Foundation in an understandable way. Here's part one, and an introduction to the basics.

The basics:

To understand authentication in the web, you need to know a few facts: 

  • SSO on the web is difficult because cookies cannot be shared between domains. A server that runs in domain.com can only set cookies for domain.com. To authenticate yourself against domain1.com and domain2.com, you will have to make at least a single request to each of those domains for that cookie to appear on your browser.
  • There are several tried and tested solutions for SSO out there, make sure to check those out.
  • Security is really hard to get right.
  • Knowing the above, we'll be using a ready made technology that does all of the heavy lifting for us, and this technology is Windows Identity Foundation.
  • Windows Identity Foundation (WIF) at its core is concerned with how user data is both modeled within a system and then passed around between systems (that are in different domains) securely, because - did I say it already, that stuff is really hard! For a more modern technology, have a look at the OAuth based OpenID connect.

Starting with the simplest thing that works: Forms authentication

Well, we know forms authentication right? Maybe not?

To achieve forms auth you simply flick a switch in the web.config and configure your web site to use forms authentication, and you specify your login page as a parameter - You're all set.

 The technical details in Forms auth are (non-OWIN era):

  1. User sends a username and password in a HTTP POST to the server from the browser
  2. Server validates the username and password against some database or identity store.
  3. Server writes a cookie into the response object for it's own domain that contains the username
  4. On all subsequent requests, the browser will keep sending that cookie to the server as long as it's duration lasts. A system that is very early in the request pipeline in the backend intercepts the request, and checks the cookie value. It then validates the username in the cookie against the datastore again, and writes the HttpRequest.User object to be a certain IPrincipal object for the duration of the request. (Yes, HttpRequest.User being something is what we call being authenticated, when it's null, you are unauthenticated)

To recap on cookies - cookies are bits of information that the browser keeps track of. When a web request returns a Set-Cookie command, the browser saves that, and keeps sending it to the server (and keeps track of it) until it expires. The server interacts with the cookie by commanding the browser to change it's cookies via the responses that it receives. Client side javascript can equally write and change cookie values.

SSO with Forms Authentication

Forms authentication can be SSO as long as the domain remains the same. All subdomains of a single domain can share the same cookies.

So how do I get cross domain SSO?

To completely overly simplify to make the point, if we changed step 2 in the Forms login flow described above from "some database or identity store" to checking "some EXTERNAL database or identity store" like facebook.com instead of our own database, that would give us the starting point to achieve SSO.

When you first login, your login request is redirected to facebook.com instead. Then you log in on facebook.com, which sets a login cookie for your browser for facebook.com. 

Facebook then is happy that you logged in and redirects you back from facebook.com to your own domain.com -site. Within that redirect is a bunch of information for your website including all the stuff you need to know about the user.

Then it's as easy as writing the forms authentication cookie that you got from facebook.

With all that, SSO just means - whenever you have a piece of content that requires authorization, an automatic redirect is made to facebook.com which checks if the user already has a cookie there and then immediately comes back to your site. The round trip has to be made for each site, but you don't need to login twice because you already did it once.

Cross domain SSO just means you need a centralized authority domain to hold a cookie and rather than all your sites relying on theirselves to figure out if the user is logged in, they rely on this centralized truth.

Calling things in other domains

The problem with making a call to another domain is that that domain cannot by direct means communicate to your browser, that you are in fact authenticated.

You cannot call facebook.com and expect that domain.com is now authenticated because facebook.com cannot write cookies for domain.com.

Only domain.com can write cookies for itself, and then the only way facebook.com can work as a login provider for domain.com is if facebook and domain.com talk to eachother in some other way about what kind of cookie domain.com has to create for itself.

But that stuff is hard to do, and even harder to do right. Think about it, we have to build an identity provider that checks all the credentials, then we'd have to design some protocol with which can tell all the relying applications that a user just signed in. We'd have to implement quite a bit of things just to get a working solution for browser land. What about between web services? 

So no wonder there's a library that hides all this nasty protocol level stuff from us, and on the onset gives us a much higher chance of getting it right. The library we'll use is Windows Identity Foundation. It is a core part of .NET 4.5. Even when using a library though, it is essential in my mind to understand to some degree what it is doing for us.

Hopefully this introduction has given you a beginning understanding of what Windows Identity Foundation is all about, and what problems it is there to alleviate. You'll hopefully understand, that in browser land the technology limits the solution.

Next time we will delve further into understanding user identity in Windows. By the end of this series we'll have built a working functioning SSO solution of our own. (Fingers crossed)