.NET Identity and Principal Objects
The .NET Framework includes a simple but very flexible identity-based security mechanism. By using it, you can exercise very fine-grained control over who is allowed to use your programs and which functions those users can perform. The key is a detailed understanding of the Principal and Identity objects.
The Microsoft .NET Framework provides a robust and flexible security infrastructure that can be split into two sections: code access security and identity-based security.
The code access security (CAS) model focuses on code identity instead of user identity. Using CAS, you set policies and permissions on assemblies according to their publisher or where they were loaded from, for example. The user identity of the hosting process is irrelevant in the permission granting logic.
Compared with CAS, identity-based security represents a classic approach with which most programmers are confident. However, you'll need to master some important concepts to get the most from the .NET Identity Based security infrastructure.
The main goal of this article is to provide an analysis of identity-based security. In a follow-up article, I'll go beyond the built-in authentication and authorization mechanism to show you how to develop custom authentication and authorization schemes.
Identity and Principal Objects
The .NET Framework abstracts the concepts of user and roles, making them independent of the underlying Windows platform. .NET identity-based security relies on two simple concepts: Identity objects and Principal objects.
An Identity object is basically a user account. Any .NET class implementing the IIdentity interface is a valid Identity object to use in .NET authorization mechanisms. IIdentity exposes three simple properties: AuthenticationType, IsAuthenticated, and Name.
The .NET Framework comes with four Identity classes out of the box:
The Generic Identity class is provided to ease the development of custom authentication mechanisms, but you can define your custom Identity class from scratch implementing IIdentity because there is no significant code you inherit from the GenericIdentity class.
You can match a .NET identity with a Windows Identitythat's what WindowsIdentity is for. (Later, you'll see how to do that.) The important point is that nothing makes a Windows Identity different from other Identity objects, as far as .NET is concerned.
The standard .NET authorization mechanisms are designed to accept and work with any kind of .NET Principal and Identity objects, totally oblivious of the underlying OS.
Of course, you can't bypass OS-related security checks. When you access an NTFS-protected file or any kind of resource that the OS is aware of, Windows triggers its authorization mechanisms against the identity of the process that is trying to access the resource (or eventually against the identity the process is impersonating).
A Principal object is a holder for all the roles the user belongs to (according to the active authentication mechanism). Again, any .NET class implementing the IPrincipal interface is a valid Principal object. The IPrincipal interface exposes the Identity property (returning the underlying Identity object) and the IsInRole method (more on this later).
The .NET Framework class library comes with two Principal objects: WindowsPrincipal and GenericPrincipal. When a WindowsIdentity, WindowsPrincipal pair is used, the Principal role list is built using the Windows groups the Windows user belongs to.