Implementing Role Based Security using C#

Role Based Security (RBS) is part of Microsoft's effort to improve the security of its products and developer tools. It involves granting permissions based on a user's role(s) and groups as defined in their Windows account. It increases your chances of preventing unwanted access to or behavior of your application.

Contributed by
Rating: 4 stars4 stars4 stars4 stars4 stars / 24
March 29, 2006
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

It is no secret that Microsoft has taken their lumps for security “issues” in their operating systems, Internet Explorer, ActiveX controls and IIS.  To address the issue Microsoft is mounting a Herculean effort with people, time and money, to dramatically improve the overall security landscape of their products and developer tools.  The best place to find the latest developer security information is the MSDN Security Developer Center.  There you’ll find links to the essential security articles that should be required reading for every developer:

Improving Web Application Security: Threats and Countermeasures

 Building Secure ASP.NET Applications

Security Tips Every Developer Must Know

Security in the .NET Framework

The area I’d like to explore in this article is coding for Role Based Security (RBS).  Role Based Security involves granting permissions based on a user’s role(s) and groups as defined in their Windows account.  As a developer you have the ability to restrict access to parts of your application according to the user’s account settings.  No security scheme is perfect, but by implementing multiple levels of security you increase your chances of preventing unwanted access to or behavior of your application.

Declarative and Imperative Security

The .NET framework allows you to use two different syntax schemes to implement security declarations. Declarative security uses the attribute syntax with security constraints stored in the assembly at compile time.  All security constraints can be specified using Declarative security and you can limit access to an entire method.  The downside is that tools are available that can extract your security requirements from the metadata in the assembly.  An example syntax is:

[PrincipalPermissionAttribute(SecurityAction.Demand, Name=@"myCompany\Emp_Role ")]

With Imperative security you write normal, everyday code, and can restrict portions of a method.  This gives you finer granularity and limits the security parameters contained in the metadata (i.e. available to prying eyes).  An example syntax is:

FileIOPermission MyFilePerm = new
           FileIOPermission( FileIOPermissionAccess.Write, n);
MyFilePerm.Demand();

Role Based Security in Your Code

The .NET framework provides several classes that allow you to access a user’s role or group membership.  The classes I’m talking about are:  WindowsIdentity, WindowsPrincipal, PrincipalPermission, GenericPrincipal, IPrincipal and IIdentity classes.  There are times when you need to explicitly verify a user's role or group membership before a method or section of code is accessed.  This is yet another example of the Defense in Depth principle--using multiple layers to secure your application.  You can easily configure your application to be accessed only by members of certain roles or groups.  But if for some reason this level is compromised, you can provide an additional layer of protection in your code by using the WindowsIdentity and WindowsPrincipal classes.

The WindowsIdentity Class

The WindowsIdentity class represents a user’s Windows account and will let you view the user's name and authentication type, as well as other information about the user.  Once you create a WindowsIdentity object you can access several useful properties:

  • AuthenticationType – A string representing they type of authentication.
  • IsAnonymous - Boolean
  • IsAuthenticated - Boolean indicating if the user is authenticated or not
  • IsGuest - Boolean
  • IsSystem - Boolean
  • Name - The user's domain\username
  • Token - The user's authentication token

To create a WindowsIdentity object you’ll call one of three methods:

GetAnonymous() - To mimic an anonymous unauthenticated user.  This is useful when you’re impersonating an anonymous user.

GetCurrent()  - The most common method used to create a WindowsIdentity object.  The current user’s name and group membership is returned.

Impersonate() - Used to impersonate a specific user.

The WindowsPrincipal Class

The WindowsPrincipal class provides access to the groups to which a user belongs, and is used in concert with the WindowsIdentity class.  To create a Principal object you have to get the current user's identity by creating an object of type WindowsIdentity and passing that to the WindowsPrincipal constructor.  Like this:

WindowsIdentity curIdentity = WindowsIdentity.GetCurrent();
WindowsPrincipal myPrincipal = new WindowsPrincipal(curIdentity);

You can also do this by querying the current thread (as usual there’s more than one way to perform a task).  First make sure the principal policy is set to use Windows Security; then you can create a WindowsPrincipal object.  Like this:

AppDomain.CurrentDomain.SetPrincipalPolicy
( PrincipalPolicy.WindowsPrincipal );
WindowsPrincipal myPrincipal = (WindowsPrincipal)
Thread.CurrentPrincipal;

Now you have a WindowsPrincipal Object. So what?

The first thing you want to do is verify that the user is authenticated. Prior to accessing your application, the user should have entered a userid and password and been allowed into the system.

if (curIdentity.IsAuthenticated)
{
// User is authenticated, proceed
}
else
{
// Not authenticated, DO NOT allow access
}

Once you’re satisfied that a user is authenticated, you can now verify they belong to a role that is allowed to access a section of code and/or a particular feature.  The work horse method you’ll use for this is called IsInRole().   To use IsInRole() you can pass in a Windows built-in role or a specific role that you may have created (a custom role or group).  This is how you can restrict access to sections of code.

if (myPrincipal.IsInRole( @"myCompany\Employee_Role”)
{
    // put code here
}
else
{
    // User is not allowed to access code above
    // do what you want here
}

Built in Role Member

Group

AccountOperator

Account Operators

Administrator

Administrators

BackupOperator

Backup Operators

Guest

Guests

PowerUser

Power Users

PrintOperator

Print Operators

Replicator

Replicator

SystemOperator

Server Operators

User

Users

You can use the Built in Roles like this:

If (myPrincipal.IsInRole(  WindowsBuiltInRole.PowerUser )
      // Then do something useful here

The use of Windows Built in Roles will vary from machine to machine.  If you query for a role and it doesn’t exist, an exception will be thrown.  Be prepared to catch the exception.

The PrincipalPermission Class

The PrincipalPermission Class enables you to demand that users of your code have been authenticated and/or belong to a specific role or group.  The Declarative syntax is used and the security context is checked before a method is executed.  You also can supply multiple security declarations for a method.

There are three properties that you MUST know:

  1. Authenticated - If true the caller must be authenticated.
  2. Name - The user's user name must match this string.
  3. Role - The user must at least be a member of this role. 

In the example below the user needs to be either a member of the Sr_Managers or Managers group to execute the method:

[PrincipalPermissionAttribute(SecurityAction.Demand,
                        Name=@"myCompany\Sr_Managers ")][PrincipalPermissionAttribute(SecurityAction.Demand, 
                        Name=@"myCompany\Managers ")]
Private void ManagersOnly()
{
      //Do something for managers only
}

Remember, only one of the security declarations needs to be true in order for the method to execute.

Design Principles to Implement Role Based Security

In this article I covered three different ways to access code based on a user’s membership in a group.  These ways were 1) WindowsPrincipal.IsInRole(),  2) using declarative demands and 3) using imperative security.  Each method serves a purpose and should be used in specific scenarios.

If you need to restrict access to an entire method, you should use Declarative security. If you need to restrict access to an entire method or portions of a method, you should use Imperative security because it gives you finer granularity. If you need to perform different actions based on a user's role, or you need to restrict portions of code, you should use WindowsPrincipal.IsInRole().

There is one more point to consider: maintenance.  Declarative security is slightly more secure because it protects you when changes are made to the code in the future.  Since the scope is for the entire method, any changes to the method will continue to be restricted by the security declarations.  If you’re using imperative security you run the risk of code changes being made in sections of the method where unauthorized users could execute code.  This typically occurs when changes are made to code outside of a try block.

The GenericPrincipal and GenericIdentity Classes

There is one more set of classes that need to be mentioned – the GenericPrincipal and GenericIdentity classes.  These classes are based on the IIdentity and iPrincipal interfaces and implement only the basic functionality of those interfaces.  GenericPrincipal and GenericIdentity are used to create custom identities and attach them to the current thread (remember that each thread runs as a user with its own security context).

The primary use of these classes is to assign group membership to users when you are using Forms Authentication, and not relying on users to have Windows domain accounts (typically used on Web applications where your user base is people outside of your company).  In this scenario you have user ids and passwords stored in a database.  When users log in they authenticate with the data in the database.  But this does not give your running application the security information it needs for these users.  To get around this problem you create an identity object for the user with the GenericIdentity class and specify the groups to which the user belongs.  The next step is to create a GenericPrincipal object and assign the user’s access rights to the current thread.  Then the rest of your application can execute using the security context you established for the user.

Conclusion

In this article I covered the basics of implementing Role Based Security (RBS) in your applications.  RBS is the ability to limit application access based on a user’s role and is an example of applying the principle of Defense in Depth – implementing multiple levels of security to provide the maximum amount of protection to your application.  During design you’ll have to decide which method you’re going to use to implement RBS (WindowsPrinciple, Declarative or Imperative).   The GenericPrincipal class is used to associate identity rights to users when Forms authentication is used.  Whatever your scenario, the .NET framework has the tools you need to secure your applications.

blog comments powered by Disqus
C# ARTICLES

- Beginning C#
- ASP.NET RedirectPermanent Method using C# an...
- C Programming Language and UNIX Pioneer Pass...
- Using Facebook JavaScript SDK in ASP.NET wit...
- ASP.NET Export to Excel and Word using VB.NE...
- WAV and MP3 Streaming with ASP.Net and C#
- Game Programming using SDL: the File I/O API
- C# and Java Developer Jobs on the Rise
- The Future Evolution of C# and VB.NET
- C# If and Else-if Statements
- How To Use the C# String Replace Method
- 5 Ways to Parse XML in C#
- C# Meets Design Patterns
- Coding a CRC-Generating Algorithm in C
- Cyclic Redundancy Check

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 3 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials