Authenticating Your Users in Azure Websites, the old way and the new way.
The Cloud Zone is brought to you in partnership with Mendix. Better understand the aPaaS landscape and how the right platform can accelerate your software delivery cadence and capacity with the Gartner 2015 Magic Quadrant for Enterprise Application Platform as a Service.
In the course of writing ASP.NET applications, most developers have found the need from time to time to add support to their applications for multiple users. According to Wikipedia (as of this writing), "Multi-user is a term that defines an operating system or application software that allows concurrent access by multiple users of a computer." For the purposes of a typical ASP.NET website, this roughly means that if you care to either secure your application to a particular set of people, or customize it in any way for users, then you are building a "multi-user" website. Linguistically speaking, you might think that any website that multiple users visit would qualify, but in this case, we're really talking about the need to write extra code that provides authentication, authorization, and profiling.
Let's dig into those three problem spaces a little deeper. The first two problems (authentication and authorization) tend to go hand in hand, and profiling is really complementary to these.
Authentication refers to the problem of reliably proving that someone is who they purport to be. In the "real world", it's a problem that we solve by the use of IDs, such as driver's licenses and passports. When we demand someone's identity, we expect them to produce a form of identification that is issued by a trusted authority, such as the local Department of Motor Vehicles, or a Passport Agency. We assume that if someone can produce one of these, then they are who they purport to be.
Authorization makes the assumption that a person is who they claim to be (via the Authentication services from above), but then helps to make the decision as to what rights that person has. So Authentication helps to prove that I am Adam Hoffman, but then Authorization helps to determine if I have the right to delete all of that data that I'm asking to delete.
Finally, Profiling helps to keep track of additional data that is useful for the application. Maybe your application wants to be able to say "Hello Adam" when I visit your site. My first name ("Adam") would typically be stored in some sort of profiling system, along with the other user data that was used for Authentication. Other typical types of Profiling data might include geo-location, user preferences (colors, fonts, etc.), and the like.
So, as an ASP.NET developer who is building a site that needs to support multiple logged in (and authorized) users, how should we proceed? There are basically two paths to follow, one of which has served us well for many years, and the other of which is newer, but solves a few sticky problems. These paths are the ASP.NET provider model, or Claims Based Authentication and Authorization using Windows Identity Foundation (WIF).
The Tried and True - ASP.NET Providers
Historically, ASP.NET has always provided support for these type of operations. The earliest (and still supported) version of these services were known as the Membership, Role and Profile providers, where Membership = Authentication, Role = Authorization and Profile = Profile. For an excellent introduction to the concept of Membership in ASP.NET, see http://aka.ms/ASPNETMembership . The "provider model" is a design pattern conceived by Microsoft during the 1.1 days, and formally used in ASP.NET since ASP.NET 2.0. For a description of the pattern, see http://aka.ms/ProviderModel . It allows applications to choose an implementation of functionality at runtime, from a collection of "providers" that adhere to a set of Interfaces and typically derive from an abstract base class. ASP.NET contains multiple types of providers that provide all of these services, and there are many more provided by third parties. Each of these provider types inherits from System.Configuration.Provider.ProviderBase (http://aka.ms/ProviderBase) and gets more specific from there. See the following table for details on the implementations of these services in ASP.NET.
|Provider Type||Base Class||Implementations|
So, these are the particular implementations of the various providers that .NET provides out of the box, but you could, of course, roll your own providers if you wanted, by implementing against the abstract bases, per type. For example, to implement a perfectly valid Authentication provider, you simply need to code up something that inherits from System.Web.Security.MembershipProvider (documented at http://aka.ms/MembershipProvider ).
This is all well and good, but how would we move this technique to Azure? Well, using this technique, several different providers have already been created that do just that:
Cloudship (http://aka.ms/Cloudship) is a Membership provider that is re-implemented to use Azure Table Storage (which I discussed in my previous post in the series at http://www.stratospher.es/blog/post/windows-azure-storage-for-the-aspnet-developer ).
Similarly, the Azure Providers project on CodePlex implements Membership, Role, Profile (and Session State) providers. You can see the details of it at http://aka.ms/AzureProviders .
Additionally, Microsoft has now released (via Nuget) a set of "universal" providers for ASP.NET 4.0 and above that adds support for SQL Azure based providers. You can check that out at http://aka.ms/UniversalProviders .
So now we've looked at lots of easy ways to move to the cloud if you're already using the provider models for multi-user applications, but isn't there a different way to handle user authentication, you might ask?
The Shiny New Stuff (That Helps to Solve Some Sticky Problems)
How many times have you gone to a website and been asked to sign up for an account on the website? If you're like me, you have accounts for your various email accounts (I think I have about 7), your bank's website, LinkedIn (ahem...), Amazon.com, Sears.com, each of your credit cards, Home Depot, your car loans, insurance companies, doctor's offices, and probably dozens of geek sites, like Github, CodeProject, MSDN, and so on. I would guess that I have about 50 of these, and that's just the ones I remember now. Undoubtedly, I've abandoned many more over the years.
Also, to be sure that a hacker who steals passwords off of one of these sites doesn't then have access to my entire life, I create random, hard to remember passwords for everything, and then keep track of these in a password safe. At the end of the day, it's effective, but quite a hassle. It would be a lot easier if I could just remember fewer passwords...
And that's just from the user's point of view. Now imagine it from the developer's side: You might have noticed that while the previous providers technologies that help us to authenticate and authorize our users, we're still left in the uncomfortable situation of maintaining passwords in our own databases. That makes us a target, and adds a fair bit of responsibility to our applications. Yes, the passwords in our databases using the providers is encrypted, but that doesn't mean they'll always be unbreakable. I don't know about you, but as a developer, I'd much rather be able to authenticate my users without having to bear the responsibility of managing their passwords in my database. I'd like to not ever have to worry about implementing the whole series of administrative pages that are required for "forgot username", "forgot password" and "reset password" pages that a site which uses the providers must have. Is there another way?
Claims Based Identity to the rescue. Imagine a world where you can just know that the users who show up to your site are really who they claim they are. If I show up, and tell you that I am Adam Hoffman, you can just trust me and proceed under the assumption that I am, indeed, Adam Hoffman. Well, OK. Maybe that's a little too optimistic. How about if someone else that you really, really, really trusted told you that I was Adam Hoffman? That, in a nutshell, is how Claims Based Identity under the Windows Identity Framework (aka WIF) works.
Using Claims Based Identity in Windows, via the Authentication Control Service (aka ACS), your Azure applications can simply trust that the user is who they claim to be, and that the various data that the user claims about him or herself, like their name, email address, and so on, is accurate.
How does it do this? By trusting providers of identity services that we already have, like Microsoft Live ID, Google ID, Yahoo and Facebook. Most of us already have one of these types of identifications, and ACS allows us to simply reuse these authentication providers and trust them, similar to the way that we trust the local department of motor vehicles to provide our driver's license, or the passport agency to issue passports. When provided with a state issued driver's license, we assume that the claims on it (such as a person's name and birthdate) are valid. Similarly, when provided with information from a provider like Live ID, Google ID, Yahoo or Facebook, we can assume validity as well, because we trust Microsoft, Google, Yahoo and Facebook. By outsourcing the storage of account details and passwords to these trusted providers, we can simultaneously avoid storing passwords in our applications, and still be assured that our users are who they claim to be. In addition to being able to use these providers for authentication decisions, ACS also allows you to reuse your company's Active Directory by exposing it via ADFS (Active Directory Federation Services). In this way, you can even log into your Azure web applications using the same account and password that you use at work. For a virtual "chalk talk" on this subject, see the great video at http://aka.ms/ACSandADFS .
Visually, authentication using one of these trusted providers looks a bit like the following. In these diagrams, the Issuer used by Azure applications is provided by ACS:
OK, so this sounds great, but how can you do it? As it turns out, the process of using Live ID, Google ID or Yahoo ID is simple, and very similar. You can find step by step guides to supporting each of these three providers at:
The process of using Facebook is a little different. Essentially, in addition to the configuration of your application in Azure, you must also do a little more work in Facebook to obtain a Facebook Application ID and Facebook Application Secret. For a step by step walkthrough of this process, see http://aka.ms/ACSFacebookId .
Finally, if you're interested in exposing your company's Active Directory as an authentication provider, you'll likely need to do a little more work (and sometimes a bit of social engineering with your IT staff). Typically, you'll want to include certificates into the mix, in order to strengthen the security of the system and prevent tampering with the token provided by your Active Directory. To understand this process, check out the "chalk talk" video mentioned above, or see the walkthrough at http://aka.ms/ACSandADFSWalkthrough .
For more details on this, and an excellent overview of Claims Based Identity and Access Control, including the use of ACS in Azure, see the Patterns and Practice Group's guide at http://aka.ms/ClaimsBasedIdentity . For a practical walkthrough of ACS, including how to configure your ASP.NET application to use the ACS services, see the excellent MSDN article by Vittorio Bertocci and Wade Wegner at http://aka.ms/AzureACS .
So far, we've looked at outsourcing our authentication needs via ACS and WIF. This system generates a set of claims that we can use to make authorization decisions in our application, but by default, the various authentication providers pass through a relatively thin set of claims. For example, while Google ID passes along claims for "nameidentifier", "name" and "emailaddress" upon successful login, Live ID only provides "nameidentifier". ACS allows us to create rule sets to add additional claims to the token either through Token Transformation via Rules (seehttp://aka.ms/TokenTransformationRules) or by "enriching" these basic claims in a Claims Authorization Library. To create a Claims Authorization Library, we create a class that inherits from ClaimsAuthorizationManager, and override its Authenticate method. Typically, we would use an additional data store or some business logic that maps one of the available claims (typically "nameidentifier") to add the other claims that our applications require (like "ismanager" or "purchaselimit", etc.) Once we have these additional claims, we can then do our authorization. For a walkthrough of using your Claims Authorization Library to authorize your users, see http://aka.ms/ClaimsAuthorizationLibrary . For more on transforming claims in this library, see http://aka.ms/ClaimsTransformation . To really drive all this learning home, I highly recommend the lab at http://aka.ms/IdentityLab . This is a great example of securing a WCF Service, but the principles are the same as those for securing an ASP.NET application.
Most developers will find reasons from time to time to build secured ASP.NET applications and services. Doing this in Azure is quite simple using either the older provider techniques, or the newer claims based models.