Implementing Smart Card Authentication with ASP.NET - Introduction
Page 1 of 9
In my previous article last October on Smart Card Authentication with ASP.NET, I introduced the topic of using Smart Cards to handle Authentication and Authorization with ASP.NET for non-Active Directory users. This is a more complete follow-up article now that I have done a bit more research into the topic and now have a full working implementation that I’m happy with.
In this implementation, the IIS Web Server is handling the basics of the Smart Card authentication, much like Windows authentication works.
The goals of this project are to provide the following:
- A tight interface to strongly typed objects that are Smart Card aware
- Allow these typed objects to be available to the entire web application on every page request
- Provide Role based authorization via the smart card through groups. This will require a mechanism to associate a User’s smart card with an associated group
If you do not need to apply role authorization through Principals then this methodology may be more then you need. If specific requirements stipulate you need information on the Smart Card/Client Certificate to display on the screen or track the Certificate Subject, simply using IIS for Authentication and the HttpCertificate property of the Context object (Context.Request.ClientCertificate) will be sufficient.
If you plan on doing Client Certificate Mapping to User Accounts on the OS or Domain, this methodology is not necessary. If the reason is not immediately obvious to you, the short answer is that when using Certificate to AD Account mapping, IIS is taking the smart card and mapping it to a Windows Account – so in the end, IIS is using Windows Authentication. Once you have mapped an account from a smart card to a windows account, you can use Windows Authentication in the Web.Config and the WindowsPrincipal object for Authorization based on Windows Groups.
In my original implementation of Smart Card authentication and authorization with ASP.NET, I used Forms Authentication in combination with the Request.ClientCertificate to automatically authentication the user. Instead of having the user enter their credentials on the Forms Login Page, this methodology still redirected them to the forms login page, but instead of the user needing to type in their username and password, the code behind automatically resolved the Request.ClientCertificate and authenticated them against the database. Next the code created the FormsAuthenticationTicket (which included the roles) as a cookie, and then redirected them back to the original page they were requesting. Finally, the Principal was attached to the Context.User object in Application_AuthenticateRequest event of the Global.asax. For implementation details, see: How To: Create GenericPrincipal Objects with Forms Authentication and How To: Use Forms Authentication with SQL Server 2000 – I combined and modified these two methodologies for use with the Smart Card.
After having used Forms Authentication in the original version, here are some lessons learned I will share. The Forms Authentication approach ended up not being a very good approach for several reasons:
- Forms Authentication relies on page redirects to handle authentication via a Login page. This adds unnecessary overhead since there is no reason for the browser to jump around via redirects to retrieve the Request.ClientCertificate. The certificate is immediately available once the user is authenticated via IIS.
- Forms Authentication relies on encrypted cookies to store the users’ authentication data in the FormsAuthenticationTicket.UserData property (which was the users’ roles are typically stored). Since we already have the Request.ClientCertificate, using cookies for authentication adds additional complexity to the code.
- Encrypting and decrypting the FormsAuthenticationTicket adds extra processing overhead.
- It does not make sense to push data down to the client in a cookie since we’ve received all authentication information we need already. From a threats/countermeasures perspective, since the cookie comes from the client, we must treat it suspiciously and perform extra validation on the User Data to make sure it was not tampered with. Yes, even though its 3DES encrypted MAC is enabled –the threat must be considered where one is able to crack the 3DES key, however unlikely, and decrypt the FormsAuthenticationTicket. If we put nothing on the client, this threat will never be realized.
- Forms Authentication adds unnecessary authentication complexity to the code in Global.asax as well as code in the Forms Login page.
- The Forms authentication mechanism caches the login for duration and has ‘logout’ functionality via cookie expiration. Smart Cards in ASP.NET do not ever ‘log out’, they timeout. Since IIS handles the re-authentication transparently to ASP.NET, the .NET authentication code need not handle timeout and re-authentication.
A more appropriate way of handling the Smart Card authentication and authorization is using a feature of ASP.NET called HTTP Modules.
ASP.NET has built in a nice way to insert code into the HTTP Pipeline. This is an ideal place to insert code to handle new types of Authentication (as well as many other things). This will not be any shock to those already familiar with the ASP.NET HTTP pipeline – the other authentication models in ASP.NET (Forms, Windows, and Passport) are implemented in the HTTP pipeline using HTTP Modules. Session management and URL Authorization are also handled with HTTP Modules. If you are not familiar with HTTP Modules and the HTTP Pipeline in ASP.NET see Appendix A for more reading on the topic.
The concept behind the HTTP Pipeline is simple. A web request comes in from IIS. If the page is mapped to run through the ASP.NET engine, IIS passes the request off to ASP.NET and then ASP.NET moves the request through all the HTTP Modules installed in the machine.config as well as the web.config. Here is a picture demonstrating the pipeline:
To resolve programmatically the HTTP Modules loaded currently in ASP.NET, drop the following code in the _Load event of any ASP.NET page:
1 private void Page_Load(object sender, System.EventArgs e)
3 Response.Write("<b>Loaded HTTP Modules</b>");
6 foreach (string httpModule in this.Context.ApplicationInstance.Modules)
1 Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
2 Handles MyBase.Load
4 Response.Write ("<b>Loaded HTTP Modules</b>")
5 Response.Write ("<br>")
7 For Each httpModule As String In Me.Context.ApplicationInstance.Modules
11 End Sub
The output will look something like this:
Figure 2 – ASPX page lists the currently running ASP.NET modules.
Notice that all of the HTTP Modules that come with ASP.NET are loaded even when a particular feature is not being used (i.e. Session Management, Forms Authentication). While loaded, they do not do any work on the Request unless the web.config file is used to enable it.
Here is an outline of the steps the rest of this article will cover:
- How to Build a Smart Card HTTP Module
- Configure an ASP.NET application to use the Smart Card HttpModule in the web.config file.
- Configure IIS to support Smart Cards
- Create the Smart Card Principal and Smart Card Identity objects and add the logic
Page 1 of 9