PDF version of SmartCard article
You can download it here.
This is a more complete follow-up article on how to implement Smart Card Authentication in ASP.NET using Http Modules. Sample code in C# is now available here. VB.Net Projects to be posted soon.
You can also download a PDF version of this article here.
I. Introduction
II. Building and Installing the Smart Card HttpModule
III. IIS Configuration
IV. Implementing SmartCardAuthenticationModule
V. SmartCardAuthenticationEventArgs Implementation
VI. SmartCardIdentity Implementation
VII. SmartCardPrincipal Implementation
VIII. Additional Implementation Details
Back to Table of Contents: Implementing SmartCard Authentication with ASP.NET
1. http://support.microsoft.com/kb/307985
INFO: ASP.NET HTTP Modules and HTTP Handlers Overview
This article introduces the ASP.NET HTTP modules and HTTP handlers
2. http://msdn.microsoft.com/msdnmag/issues/02/09/HTTPPipelines/
This article introduces the architecture of the pipeline and shows how you can use it to add sophisticated functionality to an ASP.NET-based app.
3. http://msdn.microsoft.com/msdnmag/issues/02/05/asp/default.aspx
A (brief) look at HTTP modules in ASP.NET.
4. http://support.microsoft.com/kb/887289
HTTP module to check for canonicalization issues with ASP.NET
To aid customers in protecting their ASP.NET applications, Microsoft has made available an HTTP module that implements canonicalization best practices.
5. http://msdn2.microsoft.com/en-us/library/aa479332.aspx
Using HTTP Modules and Handlers to Create Pluggable ASP.NET Components
In this article, Scott Mitchell and Atif Aziz show how you can use HTTP modules and handlers to add error logging to your ASP.NET applications. (22 printed pages)
6. http://msdn2.microsoft.com/en-us/library/ms972974.aspx
URL Rewriting in ASP.NET (using HTTP Handlers)
Examines how to perform dynamic URL rewriting with Microsoft ASP.NET. URL rewriting is the process of intercepting an incoming Web request and automatically redirecting it to a different URL. Discusses the various techniques for implementing URL rewriting, and examines real-world scenarios of URL rewriting. (31 printed pages)
7. http://support.microsoft.com/kb/313070
HOW TO: Configure Client Certificate Mappings in Internet Information Services (IIS) 5.0
8. http://support.microsoft.com/kb/272175/EN-US/
HOW TO: Configure Active Directory Certificate Mapping
9. http://support.microsoft.com/kb/216906/EN-US/
Comparing IIS 5.0 Certificate Mapping and Native Windows 2000 Active Directory Certificate Mapping
10. http://www.google.com/microsoft?q=HTTP+modules+&hq=microsoft&btnG=Google+Search
Back to Table of Contents: Implementing SmartCard Authentication with ASP.NET
Page 9 of 9
Previous Page: Additional Implementation Details | Next Page: Further Reading
Once you have your SmartCardPrincipal setup, there are several ways to implement authorization with the IPrincipal using Code Access Security (CAS) for authorization within ASP.NET.
We can configure Role base authorization using the web.config file, using PrincipalPermission Demands, or IPrincipal.IsInRole() checks in code.
Declarative
C#
using System.Security.Permissions;
...
[PrincipalPermission(SecurityAction.Demand, Role="Administrator"),
PrincipalPermission(SecurityAction.Demand, Role="Auditors")]
public void DoSomethingImportant()
{
...
}
VB.Net
Imports System.Security.Permissions
...
<PrincipalPermission(SecurityAction.Demand, Role:="Administrator"), _
PrincipalPermission(SecurityAction.Demand, Role:="Auditors")> _
Public Sub DoSomethingImportant()
...
End Sub
C#
using System.Security.Permissions;
...
public void DoSomethingImportant()
{
PrincipalPermission permCheck = new PrincipalPermission(Nothing, "Administrators");
permCheck.Demand();
}
Imports System.Security.Permissions
...
Public Sub DoSomethingImportant()
Dim permCheck As New PrincipalPermission(Nothing, "Administrators")
permCheck.Demand()
End Sub
C#
if (myPrincipal.IsInRole("Administrators")
{
...
}
If myPrincipal.IsInRole("Administrators") Then
...
End If
<configuration>
<system.web>
...
</system.web>
<location path="Admin">
<system.web>
<authorization>
<allow roles="Administrator" />
<deny users="*" />
</authorization>
</system.web>
</location>
<location path="Reports">
<system.web>
<authorization>
<allow roles="Auditor" />
<deny users="*" />
</authorization>
</system.web>
</location>
</configuration>
ASP.NET provides a powerful, yet simple way to implement custom authentication functionality in the HTTP Pipeline using HTTP Modules. IIS also has robust support for Client Certificates and when combined, Http Modules in ASP.NET and IIS make a great platform for developing sites that need to use Smart Cards for authentication and authorization.
Previous Page: Additional Implementation Details | Next Page: Further Reading
Page 9 of 9
Page 8 of 9
Previous Page: SmartCardPrincipal Implementation | Next Page: Implementing Authorization in ASP.NET
There are several more classes involved in this implementation, but they go beyond the scope of the HttpModule. If you download the sample code, you can take a look at my particular implementation. They are barely implemented so I’d recommend you use them at your own risk.
The Configuration Class
The Configuration class resolves some things like 401 error page, the database connection string, and the database connection timeout. The class had the following structure:
These values are retrieved from the web.config file:
1 <configuration>
2 <system.web>
3 …
4 </system.web>
5 <appSettings>
6 <add key="SmartCardAuthentication_UnauthorizedPage"
7 value="C:\WINNT\help\iisHelp\common\401-1.htm"/>
8 <add key="SmartCardAuthentication_ConnectionString"
9 value="integrated security=SSPI;data source=Server;initial catalog=Database"/>
10 <add key="SmartCardAuthentication_ConnectionTimeout"
11 value="180" />
12 </appSettings>
13 </configuration>
The DataAccess class had some methods for quickly retrieving data from the database.
The CryptoUtility Class
This class performed operations (hash compare, BinToHex() / HexToBin() conversions, etc.) on the X509 certificates. It also generates the Public Key hash used to retrieve users out of the database, and validates some simple properties on the X509 certificate for an internal sanity check. IIS should already be catching these problems before it gets to our code, but it can’t hurt to check again.

Once you have the SmartCardAuthenticationModule code up and running, a simple way to test it is as follows:
1 private void Page_Load(object sender, EventArgs e)
2 {
3 SmartCardIdentity smartCardIdentity = (SmartCardIdentity)Me.User.Identity;
4 SmartCardPrincipal smartCardPrincipal = (SmartCardPrincipal)Me.User;
5
6 Response.Write("Name: " + smartCardIdentity.Name + "<br>");
7 Response.Write("Is Authenticated: " + smartCardIdentity.IsAuthenticated + "<br>");
8 Response.Write("Authentication Type: " + smartCardIdentity.AuthenticationType + "<br>");
9 Response.Write("Elevated User: " & SmartCardPrincipal.IsElevatedUser + "<br>");
10 Response.Write("Is in role Administrator: " + this.User.IsInRole("Administrator"));
11 }
12
VB.Net
1 Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
2 Handles MyBase.Load
3
4 Dim smartCardIdentity As SmartCardIdentity = DirectCast(Me.User.Identity, SmartCardIdentity)
5 Dim smartCardPrincipal As SmartCardPrincipal = DirectCast (Me.User, SmartCardPrincipal)
6
7 Response.Write("Name: " & smartCardIdentity.Name & "<br>")
8 Response.Write("Is Authenticated: " & smartCardIdentity.IsAuthenticated & "<br>")
9 Response.Write("Authentication Type: " & smartCardIdentity.AuthenticationType & "<br>")
10 Response.Write("Elevated User: " & SmartCardPrincipal.IsElevatedUser & "<br>")
11 Response.Write("Is in role Administrator: " & Me.User.IsInRole("Administrator"))
12 End Sub
13
Page 8 of 9
Page 7 of 9
Previous Page: SmartCardIdentity Implementation | Next Page: Additional Implementation Details
The SmartCardPrincipal Class – Inherits from System.Security.Principal.IPrincipal
From the MSDN documentation, a principal object represents the security context of the user on whose behalf the code is running, including that user's identity (IIdentity) and any roles to which they belong. The Principal is the object that gets interrogated when a PrincipalPermission Demand is made to make sure it is in the proper role to perform the requested operation.
When SmartCardPrincipal.IsInRole() is called, our Smart Card aware object will return whether or not the Principal is in the requested role. On first run, this class will populate a Hashtable with the roles for the current user from the database. The key to lookup the Users’ Roles in the database will be a SHA256 hash of the Users’ public key.
Also notice that both IsElevatedUser and IsInRole() is virtual/Overridable – This allows for custom role resolution if you have a different methodology to resolve roles other then the database role resolution provided.
C#
1 using System;
2 using System.Configuration;
3 using System.Web;
4 using System.Web.Security;
5 using System.Collections;
6 using System.Security.Principal;
7
8 namespace SmartCardAuthentication
9 {
10 public class SmartCardPrincipal : IPrincipal
11 {
12 private SmartCardIdentity _identity;
13 private Hashtable _roles;
14 private bool _isElevatedUser;
15 private bool _rolesLoaded;
16 private bool _isElevatedLoaded;
17
18 public IIdentity Identity
19 {
20 get
21 {
22 return this._identity;
23 }
24 }
25
26 public SmartCardPrincipal(SmartCardIdentity identity)
27 {
28 this._identity = identity;
29 this._rolesLoaded = false;
30 this._isElevatedLoaded = false;
31 }
32
33
34 public virtual bool IsElevatedUser
35 {
36 get {
37 if (!_isElevatedLoaded)
38 {
39 lock (this)
40 {
41 // Evaluate the user against the database
42 // to see if they have an elevated account
43 DataAccess dAccess = new DataAccess();
44 this._isElevatedUser =
45 dAccess.AuthenticateUser(_identity.PublicKeyHash);
46 }
47 this._isElevatedLoaded = true;
48 }
49 return this._isElevatedUser;
50 }
51 }
52
53 public virtual bool IsInRole(string role)
54 {
55 if (!_rolesLoaded)
56 {
57 lock (this)
58 {
59 if (this.IsElevatedUser)
60 {
61 DataAccess dAccess = new DataAccess();
62 _roles = dAccess.GetPrincipalRoles(_identity.PublicKeyHash);
63 _roles.Add("User", "User");
64 }
65 else
66 {
67 _roles = new Hashtable(1);
68 _roles.Add("User", "User");
69 }
70 _rolesLoaded = true;
71 }
72 }
73 return _roles.Contains(role);
74 }
75 }
76 }
1 Imports System.Configuration
2 Imports System.Web
3 Imports System.Web.Security
4 Imports System.Collections
5 Imports System.Security.Principal
6
7 Public Class SmartCardPrincipal
8 Implements IPrincipal
9
10 Private _identity As SmartCardIdentity
11 Private _roles As Hashtable
12 Private _rolesLoaded As Boolean
13 Private _isElevatedLoaded As Boolean
14
15 Public ReadOnly Property Identity() As IIdentity _
16 Implements IPrincipal.Identity
17 Get
18 Return Me._identity
19 End Get
20 End Property
21
22 Public Sub New( _
23 ByVal identity As SmartCardIdentity _
24 )
25 Me._identity = identity
26 Me._rolesLoaded = False
27 Me._isElevatedLoaded = False
28 End Sub
29
30 Public Overridable ReadOnly Property IsElevatedUser() As Boolean
31 Get
32 If (Not _isElevatedLoaded) Then
33 SyncLock (Me)
34 ' Authenticate the user against the database
35 Dim dAccess As New DataAccess
36 _isElevatedUser = dAccess.AuthenticateUser(Me._identity.PublicKeyHash)
37
38 _isElevatedLoaded = True
39 End SyncLock
40 End If
41
42 Return _isElevatedUser
43 End Get
44 End Property
45
46 Public Overridable Function IsInRole(ByVal role As String) As Boolean _
47 Implements IPrincipal.IsInRole
48 If (Not _rolesLoaded) Then
49 SyncLock (Me)
50 If _identity.IsElevatedUser Then
51 ' If the user is elevated, retrieve roles from the database
52 Dim dAccess As New DataAccess
53 _roles = dAccess.GetPrincipalRoles(_identity.PublicKeyHash)
54 ' Finally add the Default Role
55 _roles.Add("User", "User")
56 Else
57 _roles = New Hashtable(1)
58 ' Regular user
59 _roles.Add("User", "User")
60 End If
61 _rolesLoaded = True
62 End SyncLock
63 End If
64 Return _roles.Contains(role)
65 End Function
66 End Class
Previous Page: SmartCardIdentity Implementation | Next Page: Additional Implementation Details
Page 7 of 9
Page 6 of 9
Previous Page: SmartCardAuthenticationEventArgs| Next Page: SmartCardPrincipal Implementation
SmartCardIdentity Class – Inherits from System.Security.Principal.IIdentity
The IIdentity Interface defines the basic functionality of an identity and is used to encapsulate information about the user or entity being validated (MSDN Documentation).
C#
1 using System;
2 using System.Web;
3 using System.Security.Cryptography.X509Certificates;
4 using System.Security.Principal;
5
6 namespace SmartCardAuthentication
7 {
8 public class SmartCardIdentity : IIdentity
9 {
10 private string _subject;
11 private string _email;
12 private string _publicKeyHash;
13 private X509Certificate _certificate;
14
15 public string AuthenticationType
16 {
17 get { return "SmartCard"; }
18 }
19
20 public bool IsAuthenticated
21 {
22 get { return true; }
23 }
24
25 public string Name
26 {
27 get { return _subject; }
28 }
29
30 public string PublicKeyHash
31 {
32 get { return _publicKeyHash; }
33 }
34
35 public string EmailAddress
36 {
37 get { return this._email; }
38 set { this._email = value; }
39 }
40 public X509Certificate Certificate
41 {
42 get { return this._certificate; }
43 }
44
45
46
47 public DateTime ExpirationDate
48 {
49 get
50 {
51 return DateTime.Parse(
52 this._certificate.GetExpirationDateString()
53 );
54 }
55 }
56
57 public string Subject
58 {
59 get { return this._subject; }
60 }
61
62 public SmartCardIdentity(HttpClientCertificate certificate)
63 {
64 this._certificate = new X509Certificate(certificate.Certificate);
65 this._publicKeyHash = CryptoUtility.GetPublicKeyHash(certificate);
66 this._subject = certificate.Subject;
67 }
68
69 public SmartCardIdentity(X509Certificate certificate)
70 {
71 this._certificate = certificate;
72 this._publicKeyHash = CryptoUtility.GetPublicKeyHash(certificate);
73 this._subject = certificate.GetName();
74 }
75 }
76 }
VB.Net
1 Imports System.Web
2 Imports System.Security.Cryptography.X509Certificates
3 Imports System.Security.Principal
4
5 Public Class SmartCardIdentity
6 Implements IIdentity
7
8 Private _subject As String
9 Private _email As String
10 Private _publicKeyHash As String
11 Private _certificate As X509Certificate
12
13 Public ReadOnly Property PublicKeyHash() As String
14 Get
15 Return _publicKeyHash
16 End Get
17 End Property
18
19 Public ReadOnly Property AuthenticationType() As String _
20 Implements IIdentity.AuthenticationType
21 Get
22 Return "SmartCard"
23 End Get
24 End Property
25
26 Public ReadOnly Property IsAuthenticated() As Boolean _
27 Implements IIdentity.IsAuthenticated
28 Get
29 ' The fact that this identity object exists means that
30 ' the user was Authenticated
31 Return True
32 End Get
33 End Property
34
35 Public ReadOnly Property Name() As String _
36 Implements IIdentity.Name
37 Get
38 Return _subject
39 End Get
40 End Property
41
42 Public Property EmailAddress() As String
43 Get
44 Return Me._email
45 End Get
46 Set(ByVal Value As String)
47 Me._email = Value
48 End Set
49 End Property
50
51 Public ReadOnly Property Certificate() As X509Certificate
52 Get
53 Return Me._certificate
54 End Get
55 End Property
56
57 Public ReadOnly Property ExpirationDate() As DateTime
58 Get
59 Return DateTime.Parse(Me._certificate.GetExpirationDateString())
60 End Get
61 End Property
62
63 Public ReadOnly Property Subject() As String
64 Get
65 Return Me._subject
66 End Get
67 End Property
68
69 Public Sub New(ByVal certificate As HttpClientCertificate)
70 Me._certificate = New X509Certificate(certificate.Certificate)
71 Me._publicKeyHash = CryptoUtility.GetPublicKeyHash(certificate)
72 Me._subject = certificate.Subject
73 End Sub
74
75 Public Sub New(ByVal certificate As X509Certificate)
76 Me._certificate = certificate
77 Me._publicKeyHash = CryptoUtility.GetPublicKeyHash(certificate)
78 Me._subject = certificate.GetName()
79 End Sub
80
81 End Class
82
Page 6 of 9
[security through absurdity] © 2008 by [security through absurdity] | Designed by Design Blog | Blogger Template by ThemeLib.com