Click here to Skip to main content
Click here to Skip to main content

Insight into Security Model using Principal and Identity Objects in .NET

By , 9 Oct 2003
 

Introduction

The buzz word ‘Security’ strikes me all the time when I think of designing an application. According to me, paramount importance should be given to security of any application, as hackers are always on the move. Security is something an application should possess and not be a feature.

Microsoft.NET as a technology, has given various models/patterns, towards implementing security. The patterns can be customized to suit our requirement and hence is extensible in nature.

Microsoft.NET framework provides certain objects in the name ‘Principal’ and ‘Identity’ objects which would be our primary area of thought. This article mainly focuses on security model by adopting ‘Principal’ and ‘Identity’ objects and proposes a security model for a .NET application.

What are Principal and Identity objects?

Before we proceed any further, it is important for us understand that the very intent of Principal and Identity objects is to authenticate and authorize the end user.

In simple terms, authentication is the process by which the identity of the user is verified and authorization is the process by which access to an application/feature is granted based on the identity.

Identity:

This object stores information about the user. This object encapsulates the name of the user being authenticated. We can relate this object to a data store which stores information (User Name) about a user. Identity objects are of two types.

  • WindowsIdentity: This object encapsulates the Windows login user name and the type of protocol adopted for authentication by Windows. Anytime we need to know the Windows login username, WindowsIdentity objects have the information.
  • GenericIdentity: also stores information about a user, but is used when an application needs to implement custom logon. This object can be created by specifying the User name (usually accepted via custom logon screens) and can be propagated across various application tiers for authorization purposes.

We shall be discussing more in detail about this at a later stage in this article.

Principal:

This object represents the security context for the running process or the AppDomain. Each thread has a context and it holds the principal object. Principal objects encapsulate Identity and the Role/Group membership of a user. Role based security can best be implemented with the help of Principal objects. A Principal object can be created with the help of identity and role of a user. Principal objects are very handy while implementing role based authorization for an application.

Principal objects are of two types:

  • GenericPrincipal: This object encapsulates the identity object and the role. While implementing custom logon with role based authorization, GenericPrincipal objects are to be created.
  • WindowsPrincipal: also stores identity and the Windows group membership of the user. This would very much qualify to implement role based security for an application.

Implementing role based security with Principal objects

The above theory can be well understood by considering a few of the real time scenarios.

Scenario A: Windows authentication (Identity) with roles available from database

Assumption

In this scenario, if roles are found for a user in the database, then the user is a valid user. If a role does not exist for a user in the database, then the user is anonymous and hence should not get access to any feature in the system. Also, there would be an entry for a user in the database only if role(s) are allocated.

In most cases, for an intranet/Windows based application, Windows authentication is preferred with roles being application specific and existing in a data store. Under such circumstances, we would be creating a GenericPrincipal object with Identity as Windows Logon user and roles picked up from the data store for a specific identity. This amounts to Windows identity being used for authentication and GenericPrincipal object built with roles from database used for authorization.

Meaning, we would retrieve the Windows identity, get the user name from the identity object, and query the data store for roles of the user. Once we get the user roles we can construct a GenericPrincipal object and the same can be set to the context/thread.

Now the obvious question would be, who would access the context and how does authorization happen? Let’s consider a hypothetical case wherein we need to grant access to a feature in the application based on the user role.

Authentication

This would be a seamless login from the user’s point of view. The user’s identity can be retrieved with the help of the following code:

Windows application

WindowsIdentity.GetCurrent() method would give us the identity object of the logon user

Imports System.Security.Principal
Module SecurityModule
    Sub Main()
        Dim winIdent As WindowsIdentity = WindowsIdentity.GetCurrent()
        Console.WriteLine(winIdent.Name())
    End Sub
End Module
Web application

By doing the following the identity of the Windows user is obtained

  • Set the authentication mode to Windows and deny authorization to anonymous users in Web.Config file.
  • Implement the WindowsAuthentication_OnAuthenticate event in the Global.asax file. The WindowsAuthenticationEventArgs argument received from this event gives the identity of the Windows user.
<!--Web.Config File Data-->
<authentication mode="Windows"/>
<authorization>
    <deny users="?" />  <!--Deny anonymous users -->
    <allow users="*" /> <!--Allow all users -->
<authorization/>

Global.asax code: The below event is triggered for every request made on the web application.

Sub WindowsAuthentication_OnAuthenticate(ByVal Source As Object, _
                    ByVal e As WindowsAuthenticationEventArgs)
    Dim userIdentity As String
    userIdentity = e.Identity.Name()
End Sub

Authorization

To authorize the users, we got to have roles associated with the identities and hence build the principal object. For the identity obtained from the above global.asax event, query the database and retrieve the roles. Authorization check would be performed in each page of the web application to grant or deny access to a particular feature/page in the application.

The below code explains the complete cycle involved in authorizing a user in accessing an application

Windows application

During application start-up (wherever applicable), for the identity, get the roles from the database accordingly. With the roles and the identity, the principal object needs to be created which would be accessed throughout the application. The below code explains the entire process.

Module SecurityModule
    Public genPrincipal As GenericPrincipal

    Sub Main()
        Dim ident As WindowsIdentity = WindowsIdentity.GetCurrent()
        Dim roles() As String

        roles = <retrieve from database>
        genPrincipal = New GenericPrincipal(ident, roles)
    End Sub
End Module

The above generic principal object would be accessed in each of the Windows forms in deciding whether to grant or deny access to the requested feature, as shown below:

Private Sub Form1_Load(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles MyBase.Load

    If genPrincipal.IsInRole("Managers") = False Then
        MessageBox.Show("You do not have access to this form")
    End If
End Sub
Web application

For a web application, before we proceed with authentication check, we got to build the principal object. And, for the web page to access this principal object, the same has to be persisted in the HTTP context. The code below explains this process:

In WindowsAuthentication_OnAuthenticate event, get the roles for the identity obtained. This completes the authentication bit. The next event to get fired just after this is the Application_AuthenticateRequest wherein the principal object needs to be built. Hence the identity and the roles obtained in WindowsAuthentication_OnAuthenticate event have to be persisted for Application_AuthenticateRequest to build the principal object. The same is performed by creating an authentication ticket out of identity-roles, and send as cookie. Now the Application_AuthenticateRequest event can access the cookie and build the Principal object as shown below

Sub WindowsAuthentication_OnAuthenticate(ByVal Source As Object, _
        ByVal e As WindowsAuthenticationEventArgs)
    
    'Note that since IIS has already performed 
    'authentication, the provided identity is used.

    Dim userIdentity As String
    Dim userRoles As String
    Dim formsAuthTicket As FormsAuthenticationTicket
    Dim httpcook As HttpCookie
    Dim encryptedTicket As String

    userIdentity = e.Identity.Name()
    useRoles =<Retrieve from Database>

    formsAuthTicket = New FormsAuthenticationTicket(1, _
        e.Identity.Name(), _
        DateTime.Now,DateTime.Now.AddMinutes(60), _
        False, userRoles)

    encryptedTicket = FormsAuthentication.Encrypt(formsAuthTicket)

    httpcook = New HttpCookie("authCookie", encryptedTicket)
    Response.Cookies.Add(httpcook)
End Sub
Sub Application_AuthenticateRequest(ByVal sender As Object, _
            ByVal e As EventArgs)

    ' Fires upon attempting to authenticate the user
    Dim formsAuthTicket As FormsAuthenticationTicket
    Dim httpcook As HttpCookie
    Dim genIdentity As GenericIdentity
    Dim roles() As String
    Dim genPrincipal As GenericPrincipal

    httpcook = Context.Request.Cookies("authCookie ")
    formsAuthTicket = FormsAuthentication.Decrypt(httpcook.Value)

    genIdentity = New GenericIdentity(formsAuthTicket.Name())
    roles = formsAuthTicket.UserData.Split("|") 'if more than one role

    genPrincipal = New GenericPrincipal(genIdentity, roles)

    'The principal object thus created would be accessed 
    'in the ‘application pages before allowing access 
    'to the individual functionality 
    HttpContext.Current.User = genPrincipal
End Sub

Now after the Principal object has been set, let’s move over to the web page to authorize the user. In the Form_Load event of the web page (PageA.aspx), let’s say, we have to grant access only to users of role ‘Managers’. The below code would perform the authorization check

Private Sub Page_Load(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles MyBase.Load

    Dim genPrincipal As IPrincipal

    ' Access the principal object from HTTPContext
    genPrincipal = HttpContext.Current.User

    If genPrincipal.IsInRole("Managers") = False then
        Response.Write("You do not have access to this Page.")
        ' Now the controls on the form can be hidden
        ' or the user can be redirected 
        ' to a different page
        ' < Code to implement the above goes here >
    End if
End Sub

The above would not give access to PageA.aspx, to any user who does not belong to ‘Managers’ role/group.

In all, this security model best suits for applications which need to implement role based security with roles as defined by the application and authentication performed by Windows.

Scenario B: Custom authentication (Identity) with roles available from database

This scenario best suits applications which have users as well as roles defined in the application. Such applications will have logon page/form which accepts username and password and performs authentication. The same code as explained in scenario A except for authentication mechanism can be adopted in this scenario as well. The authentication would follow with user ID and password being validated against a data store and continues to build the generic principal object with the help of GenericIdentity and roles retrieved from the database.

Scenario C: Windows authentication (Identity) with Windows group membership as roles

This scenario best suits applications which depend on Windows for identity and roles. Identity would be the Windows username and the role would be the group membership of the Windows user. The concept of role based security remains the same and is similar to the code as mentioned in Scenario A. Instead of creating GenericPrincipal object, we got to be creating WindowsPrincipal object, by supplying the WindowsIdentity. Also, there is no need to get ‘roles’ from a data store as we are depending on Windows group membership for roles. The check that would be performed in each page/form remains the same.

Scenario analysis

In the above scenarios, all we are doing is building the principal objects which consists of identity and roles. The pages/forms need not worry about building the Principal objects. They just need to perform ‘IsInRole’ checks depending on the authorization rules as set by the application.

This demonstrates the clear segregation between authentication and authorization when Identity and Principal objects are adopted for implementing security. Also, throughout the life of the application, we are dealing with objects encapsulating identity, roles and are persisted across.

Conclusion

The scenarios just demonstrate the usage of Principal and Identity objects. They do not imply any rules on its usage. The scenarios were chosen as a means to understand the concepts better. In all, the Principal and Identity objects provide a means to implement security for any application in .NET.

Using the code

The code snippets mentioned throughout this article is part of the source code available for download with this article. On downloading the source code (Zip File), extract the same to web folder (wwwroot) to successfully open the solution. In the IIS Settings for the web application, make sure anonymous access is unchecked in Directory Security tab.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

* Sandeep Alur
Web Developer
India India
Member
Sandeep Alur, is from Bangalore, India. He works for Wipro Technologies, one of the leading software services company. His aspiration is to contribute his learnings from his experience,to the developer community. You can find quite a few of his technical articles published at DevelopersDex portal.
 
He is also a Microsoft Certified Solution Developer(MCSD.NET) in .Net

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralNice Article - Get your 5mentorKunalChowdhury20 May '10 - 18:07 
Hi Sandeep,
 
It's a nice one. Get 5 from me. Thumbs Up | :thumbsup:
Thank you for posting it in CodeProject.
Regards - Kunal Chowdhury | Software Developer | Chennai | India | My Blog | My Tweets | Silverlight Tutorial

GeneralGood WorkmemberRajeshCR30 Jan '05 - 20:00 
Itz Good work. Hope will get good article from you.
Rajesh- cr.rajesh@gmail.com
 
Rajesh , HP, Bangalore
GeneralCookie Re-created EverytimesussAnonymous1 Jul '04 - 9:21 
Hi,
 
I just notice that WindowsAuthentication_OnAuthenticate is called on every request, so the cookie is created also on every request. This doesn't seem very efficient. Does anyone have any idea?
 
thank you
GeneralRe: Cookie Re-created Everytimemembercindyrod7 Aug '05 - 17:30 
I was wondering the same thing. I just added an if statement to check whether the cookie already exists or not. Like this:
 
protected void WindowsAuthentication_OnAuthenticate(Object source, WindowsAuthenticationEventArgs e)
{
if (Context.Request.Cookies["authCookie"] == null)
{
String userIdentity, userRoles, encryptedTicket;
FormsAuthenticationTicket formsAuthTicket;
HttpCookie httpcook;
 
userIdentity = e.Identity.Name;
userRoles = ;
 
formsAuthTicket = new FormsAuthenticationTicket(
1,
e.Identity.Name,
System.DateTime.Now,
DateTime.Now.AddMinutes(60),
false,
userRoles);
 
encryptedTicket = FormsAuthentication.Encrypt(formsAuthTicket);
 
httpcook = new HttpCookie("authCookie", encryptedTicket);
Response.Cookies.Add(httpcook);
}
}

 
It's working for me, at least for now. Hopefully this will help other beginners like myself! Big Grin | :-D

GeneralRe: Cookie Re-created EverytimememberPiddy26 Mar '06 - 17:37 
Thanks .. helped this noob out!
GeneralRole Hierarchiesmembergmgerstner8 Apr '04 - 10:35 
How would you handle role hierarchies.
 
For example let's say a particular section requires role "A". A user isn't in "A" but he is in the role "B" and the role "B" is a member of "A", therefore the user is indirectly entitled to that section. If you tried user.IsInRole("A") you will get false since the user isn't a direct member of that role.
 
Is there some way to specify that a role is a member of another role?

GeneralRe: Role HierarchiessussAnonymous6 May '04 - 7:14 
You can create a Principal object that belongs to multiple roles. So, there's no reason why you couldn't have that member have both roles "A" AND "B".
GeneralRe: Role Hierarchiesmembergmgerstner10 May '04 - 4:07 
Let's say we have two roles: "Bridge Officers" and "Science Officers" (Star Trek analogy)
 
Let's assume also that the "Science Officers" role is a member of the "Bridge Officers". This could be a business rule that could be changed easily by removing Science Officers from Bridge Officers if the business changes.
 
Then we go and hire Mr. Spock as our new science officer. It would nice to simply add Spock to the Science Officer role and be happy with that. By adding Spock to the Science Officers role he is automatically a Bridge Officer.
 
If one day we remove Science Officers from the Bridge Officers (because the Science Officers now have a new lab all for themselves now) then we just need to remove the Science Officers from Bridge Officers and Spock would automatically lose access the Bridge.
 
But wait... let's also say Spock is a member of the Commanders role and the Commanders role is also a member of the Bridge Officers role. Now, by removing the Science Officers role from the Bridge Officers role Spock still keeps his Bridge access because he is still a Commander.
 
Let's say in our windows accounts we decide to make Spock a Science Officer, a Commander, and Bridge Officer. Then a year later (after a lot of turnover and thus forgetting where we put which users in which roles) we remove then Science Officers from the Bridge Officers role. Should we have to manually remove Spock from any other roles. Should Spock still be allowed in the Bridge Officers role? Who knows. Without rummaging through the entire Active Directory we will never know. Not to mention we will most likely screw something up. Plus, was Spock in the Bridge Officers role because he was directly entitled to it or did we add him there last year because he was a member of some other role that was a subrole of this role and we needed a work around for something? Again, who knows.
 
Windows, of course, handles all this for us automatically as long as we organize the roles with subroles neatly and not add users to roles indiscriminately. Then handling human resource (Vulcan resources?) would be a matter of adding users to roles and business management would be handled through managing the roles' subroles (aka. Role Hierarchies).
 
Now, if Bill Gates buys Star Fleet and installs the .NET Framework in the Enterprise's computers, how would we check if a user is allowed to see a windows form that requires that the user has Bridge Officers access (like, for example, Bridge Officer's Star Log)? Since Spock is a Science Officer and Science Officers are Bridge Officers (for now) Spock should be allowed to open the Bridge Officer's Star Log. Based on everything I've seen about the .NET security there doesn't seem to be a way to account for any of this without doing as you say manually adding Spock to both Science Officers and Bridge Officers.
 
For custom authentication this isn't really a big deal because at runtime I could add him to both roles through recursive searching (but handle security in the database properly). But doing this for Windows authentication is another matter entirely. I know there are ways to obtain information from Active Directory but I believe they require unmanaged code and you practically have to scan the entire Active Directory to recontruct the security structure. I think this would be a bad idea since I'm not crazy about programs rummaging through the Active Directory freely.
 
Is there no way of doing this with what's given in the .NET security or should I drop the idea and handle security myself without any of .NET's security features? The application I'm developing is a desktop app for an intranet, so Active Directory would be an ideal location to manage security.

GeneralRe: Role HierarchiesmemberTonyS31 May '05 - 15:29 
Don't have an answer to your questions but I love your analogy!!!
Generalwindows authentication thru a web formmemberBharat Biyani23 Jan '04 - 0:18 
I know how to do authenticate a user against active directory in a webform - there is a article at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetHT02.asp
 
Next thing I want is that I provide such form on CMS or Sharepoint server (eg. sps.domain.com is sharepoint server and here in I have sps.domain.com/login.aspx form which will authenticate the usre against ActiveDirectory. Now, next thing I want is that when user is access SPS website sps.domain.com his Windows credentials are passed (sharepoint sees this users as Windows Authenticated user).
 
To help you understand, explaining the problem in another way:
 
I login on sps.domain.com/login.aspx as "user1" who has been authenticated in login.aspx against ActiveDirectory (user1 is a windows account). now when I am vising sharepoint server sps.domain.com, I want that SPS recoginizes me as "user1" and give me access accordingly.
 

GeneralRe: windows authentication thru a web formsussAnonymous23 Aug '05 - 14:13 
delagation
GeneralQuestions on ACLs and Sub-GroupsmemberFull Meat25 Nov '03 - 20:43 
Great article. I am a newbie to .NET Security and this was a solid overview.
 
I'm implementing security for a web application, and I pose the following questions:
 
1) According to the article, .NET is promoting a role-based security model. What about granular user-based security requirements? For example: I'm building a file repository app that allows users to upload files to the application and share them with specific users and groups/roles. Suppose we have three roles (officer, manager, and employee). An officer uploads a sensitive document to which only officers are privy...with the exception of a single manager. This manager cannot simply be moved into the officer role, since he should not be privy to all files that officers can see. Is this a scenario that can be supported by the .NET Security model? It seems to me that each file would have to have its own ACL that contained roles and users.
 
2) Is the concept of role hierarchies supported? Working from my example in #1, officers should be able to see all files, managers see a subset(s), and employees see a subset(s) of that. Or do I have to explicity call .IsInRole for every group individually?
 
I'd appreciate any insight or pointers to more resources. Again, great article.
 
Full Meat
 

GeneralRe: Questions on ACLs and Sub-GroupsmemberJan Seda (MS)19 Dec '04 - 22:54 
Hello!
 
THis is a very specific topic and there are nearly no resources on Windows Advanced security topics. I'll wrote about security internals if developers will be interested. Some resources related to enterprise usage you can find here (it's in czech but I think it can be undestood, primary samples):
 
Presentation & Samples (in demo slides):
http://download.microsoft.com/download/7/b/7/7b7f6da5-3847-4011-ae47-b35a81d721a4/AuthenticationAuthorization.zip
 
Role-based security is interesting but when using in enterprise scenarios and with granular secuirty, you'll have to go inside of Windows core security, like SIDs, Tokens, Logon sessions etc. Then you can understand, why your impersonated users can't be authorized on other network resources in ASP.NET Wink | ;) or many other issues developers are trying to solve every day Wink | ;)
 
Regards,
Jan
AnswerRe: Questions on ACLs and Sub-Groupsmemberanon2356 Sep '06 - 12:51 
Handle the manager as a separate role.
QuestionHow can we log off when using windows authentication ?memberdfranco_miami@msn.com20 Nov '03 - 10:24 
How can we log off when using windows authentication without closing the browser?
I already tried Session.Abandon and Response.StatusCode=401 and it dint work
thanks
df

AnswerRe: How can we log off when using windows authentication ?member* Sandeep Alur20 Nov '03 - 19:21 
If you are using httpcontext to hold the identity, then you can clear the same.Also, have a session variable to maintain the status of login/logout (This is the only option I can think of at the moment)

AnswerRe: How can we log off when using windows authentication ?memberFull Meat25 Nov '03 - 20:23 
Session.Abandon();
System.Web.Security.FormsAuthentication.SignOut();
Server.Transfer("~/Login.aspx");
AnswerRe: How can we log off when using windows authentication ?membermkamoski120 Jul '04 - 8:59 
All--
 
FWIW, I had to do a bit more than just Abandon() and SignOut()
 
I had to reset the context user.
 
See the sample code below for details.
 
Thank you.
 
--Mark
 
Sample Code...
 

 
private void DoLogout()
{
string[] roles = "".Split(new char[]{'|'});
 
Session.Clear();
Response.Cookies.Clear();
Session.Abandon();
System.Web.Security.FormsAuthentication.SignOut();
 
//Note. 20040720. KamoskiM. Check here to see that
//the current user still has IsAuthenticated=true.
//
//IPrincipal p1 = HttpContext.Current.User;
//bool isAuthenticated1 = p1.Identity.IsAuthenticated;
 
//Reset the context user to a non-authenticated identity forcibly.
Context.User = new System.Security.Principal.GenericPrincipal(new System.Security.Principal.GenericIdentity(""), roles);
 
//Note. 20040720. KamoskiM. Check here to see that
//the current user still has IsAuthenticated=false.
//
//IPrincipal p2 = HttpContext.Current.User;
//bool isAuthenticated2 = p2.Identity.IsAuthenticated;
 
Server.Transfer(Constants.PathToPublicWebForms + "LogoutSuccess.aspx");
}
 


GeneralWeb Authenticationmemberabu-khiran15 Oct '03 - 19:21 
Great article
 
How can I handle the issue where the client has restricted the use of cookies???
GeneralRe: Web Authenticationmember* Sandeep Alur15 Oct '03 - 22:27 
These cookies are persistant only during server response and it should not be a problem. Extreme scenarios..You can persist the same as objects in Session....
GeneralRe: Web AuthenticationsussAnonymous27 Dec '03 - 7:36 
Given that these session are cookiless!

GeneralNicely Donememberjackm15 Oct '03 - 2:22 
Nothing new here, but a very nice summary of a confusing topic. Well done.
GeneralCool!memberworldspawn12 Oct '03 - 13:42 
I didn't know you could tack extra info on to the forms cookie! That's great!Currently i'm pulling the users roles from the db on every page load, no more!
 
Thanks
 
[worldspawn]

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 10 Oct 2003
Article Copyright 2003 by * Sandeep Alur
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid