Role-Based Security


As you have seen, code access security gives the CLR the ability to make intelligent decisions behind the scenes as to whether code should run and with what permissions based on the evidence it presents. In addition, .NET provides role-based security that specifies whether code can perform actions on the basis of evidence about the user and their role, rather than just the code. You'll probably be glad to hear that this is done without walking the stack!

Role-based security is especially useful in situations where access to resources is an issue. A primary example is the finance industry, where employees' roles define what information they can access and what actions they can perform.

Role-based security is also ideal for use in conjunction with Windows accounts, Microsoft Passport, or a custom user directory to manage access to Web-based resources. For example, a Web site could restrict access to its content until a user registers with the site, and then additionally provide access to special content only, if the user is a paying subscriber. In many ways, ASP.NET makes role-based security easier because much of the code is based on the server.

For example, if you want to implement a Web service that requires authentication, you could use the account subsystem of Windows and write the Web method in such a way that it ensures the user is a member of a specific Windows user group before allowing access to the method's functionality.

The Principal

.NET gives the current thread easy access to the application user, which it refers to as a principal. The principal is at the core of the role-based security that .NET provides, and through it, you can access the user's identity, which will usually map to a user account of one of these types:

image from book
Figure 16-16

  • Windows account

  • Passport account

  • ASP.NET cookie-authenticated user

As an added bonus, the role-based security in .NET has been designed so that you can create your own principals by implementing the IPrincipal interface. If you are not relying on Windows authentication, Passport, or simple cookie authentication, you should look at creating your own using a custom principal class.

With access to the principal, you can make security decisions based on the principal's identity and roles. A role is a collection of users who have the same security permissions, and it is the unit of administration for users. For example, if Windows authentication is used to authenticate the users, you will use the WindowsIdentity type as the identity. You can use that type to find out whether the user is a member of a specific Windows user account group. You can then use that information to decide whether to grant or deny access to code and resources.

You'll generally find that it's much easier to manage security if you allow access to resources and functionality on the basis of roles rather than individual users. Imagine a scenario where you have three methods and each provides access to a feature over which you need tight control to ensure only authorized personnel can access it. Assume that the application has four users; you could quite easily specify within each method which users can and which users cannot access the method. However, imagine a time in the future where the number of features has extended to nine; to allow access to an additional user potentially requires changing every one of the nine methods even though this is an administrative task! Even worse, as users move between roles in the company you would have to change the code each time that happens. If you had implemented the system using roles instead, you could simply add users to and remove users from roles, rather than adding and removing individual users to and from the application. This simplifies the application because for each method you simply request that the userbe a member of a specific role. It also simplifies the management of roles, because the administrator can do it rather than the application developer. The developer should be concerned with ensuring that, for example, managers but not secretaries can access a method.

.NET's role-based security builds on an idea that has been provided in MTS and COM+, and offers a flexible framework that can be used to build fences around sections of the application that have to be protected. If COM+ is installed on a machine, its role-based security will interoperate with .NET; however, COM is not required for .NET's role-based security to function.

Windows Principal

In the following example, you create a console application that gives access to the principal in an application that, in turn, enables you to access the underlying Windows account. You need to import the System.Security.Principal and System.Threading namespaces. First of all, you must specify that.NET automatically hooks up the principal with the underlying Windows account, because .NET does not automatically populate the thread's CurrentPrincipal property for security reasons. You can do that like this:

 // Example WindowsPrincipal using System; using System.Security.Principal; using System.Security.Permissions; using System.Threading; namespace Wrox.ProCSharp.Security { class Program { static void Main(string[] args) { AppDomain.CurrentDomain.SetPrincipalPolicy( PrincipalPolicy.WindowsPrincipal); 

It's possible to use WindowsIdentity.GetCurrent() to access the Windows account details; however, that method is best used when you're only going to look at the principal once. If you want to access the principal a number of times it is more efficient to set the policy so that the current thread provides access to the principal for you. By using the SetPrincipalPolicy method it is specified that the principal in the current thread should hold a WindowsIdentity object. All identity classes, like WindowsIdentity, implement the IIdentity interface. The interface contains three properties (AuthenticationType, IsAuthenticated, and Name) for all derived identity classes to implement.

Add some code to access the principal's properties from the Thread object:

 WindowsPrincipal principal = (WindowsPrincipal)Thread.CurrentPrincipal; WindowsIdentity identity = (WindowsIdentity)principal.Identity; Console.WriteLine("IdentityType: " + identity.ToString()); Console.WriteLine("Name: " + identity.Name); Console.WriteLine("'Users'?: " + principal. Console.WriteLine("'Administrators'?: " + principal.IsInRole(WindowsBuiltInRole.Administrator)); Console.WriteLine("Authenticated: " + identity.IsAuthenticated); Console.WriteLine("AuthType: " + identity.AuthenticationType); Console.WriteLine("Anonymous?: " + identity.IsAnonymous); Console.WriteLine("Token: " + identity.Token); Console.ReadLine(); } } } 

The output from this console application looks similar to the following lines, depending on your machine configuration and the roles associated with the account under which you're signed in:

IdentityType:System.Security.Principal.WindowsIdentity Name: cnagel\christian 'Users'?: True 'Administrators'?:  Authenticated: True AuthType: NTLM Anonymous?: False Token: 364

It is enormously beneficial to be able to easily access details about the current users and their roles. With this information you can make decisions about what actions should be permitted or denied. The ability to make use of roles and Windows user groups provides the added benefit that administration can be done by using standard user administration tools, and you can usually avoid altering the code when user roles change. The following section looks at roles in more detail.

Roles

Imagine a scenario with an intranet application that relies on Windows accounts. The system has a group called Manager and one called Assistant; users are assigned to these groups dependent on their role within the organization. Say the application contains a feature that displays information about employees that should only be accessed by users in the Managers group. You can easily use code that checks whether the current user is a member of the Managers group and whether he is permitted or denied access.

However, if you decide later to rearrange the account groups and to introduce a group called Personnel that also has access to employee details, you will have a problem. You have to go through all the code and update it in order to include rules for this new group.

A better solution would be to create a permission called something like ReadEmployeeDetails and to assign it to groups where necessary. If the code applies a check for the ReadEmployeeDetails permission, updating the application to allow those in the Personnel group access to employee details is simply a matter of creating the group, placing the users in it, and assigning the ReadEmployeeDetails permission.

Declarative Role-Based Security

Just as with code access security, you can implement role-based security requests ("the user must be in the Administrators group") using imperative requests (as you saw in the preceding section), or using attributes. You can state permission requirements declaratively at the class level like this:

 // Example RoleBasedSecurity using System; using System.Security; using System.Security.Principal; using System.Security.Permissions; namespace Wrox.ProCSharp.Security { class Program { static void Main(string[] args) { AppDomain.CurrentDomain.SetPrincipalPolicy( PrincipalPolicy.WindowsPrincipal); try { ShowMessage(); } catch (SecurityException exception) { Console.WriteLine("Security exception caught (" + exception.Message + ")"); Console.WriteLine("The current principal must be in the local" + "Users group"); } Console.ReadLine(); } [PrincipalPermissionAttribute(SecurityAction.Demand, Role = "BUILTIN\\Users")] static void ShowMessage() { Console.WriteLine("The current principal is logged in locally "); Console.WriteLine("(they are a member of the local Users group)"); } } } 

The ShowMessage() method will throw an exception unless you execute the application in the context of a user in the Windows local Users group. For a Web application, the account under which theASP.NET code is running must be in the group, although in a "real-world" example you would certainly avoid adding this account to the administrators group!

If you run the preceding code using an account in the local Users group, the output will look like this:

The current principal is logged in locally  (they are a member of the local Users group)

For more information on role-based security in .NET, your first stop should be the MSDN documentation for the System.Security.Principal namespace.




Professional C# 2005
Pro Visual C++ 2005 for C# Developers
ISBN: 1590596080
EAN: 2147483647
Year: 2005
Pages: 351
Authors: Dean C. Wills

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net