.NET Security and Cryptography
User-based security and CAS are the two major branches of the .NET security story, and they both require an understanding of a common concept known as permissions. For user -based security, the PrincipalPermission class is used to check against the identity of the current user of the calling thread. For CAS, the many CodeAccessPermission -derived classes are used to check against the individual permissions that have been granted or denied to all threads executing the current method. We bring up the concept of permissions in this chapter because this is where we first use the concept. In the next chapter on CAS, we make heavier use of permissions; however, this discussion of the permission concept will not be repeated there, so please read this prerequisite material before moving on. Permissions are objects that describe sets of operations that can be permitted or denied for securing specific resources based on existing security policy. For CAS permissions (but not for user permissions), the .NET CLR uses a stack-walking mechanism to determine if all calling stack frames [11] have been granted a specified permission. A permission object contains specific permission information. If a permission reference is set to null, then it is treated in the same way as a permission object with the state PermissionState.None , meaning that it provides no permissions. Permissions are typically used in the following ways: [11] By convention, the call stack is represented as growing downward, so methods higher in the call stack call methods lower in the call stack, and the current stack frame is therefore at the very bottom of the stack.
It is also possible to work with permission sets, which are collections that can contain many different types of permission objects. This is accommodated by the PermissionSet class, which allows a permission set to be managed as a group of permissions. The IPermission Interface
The IPermission interface encapsulates the fundamental idea of permission. The IPermission interface supports the following public methods:
THE IPERMISSION DEMAND METHOD
Probably the most important member of the IPermission interface is the Demand method, which takes no parameters, returns void, and can throw a SecurityException . Here is its signature. void Demand(); The Demand method checks that all callers of the current method have permission to access a specified resource in a specified way and throws its exception if this check fails. The particular type of resource that is being protected depends on the specific type of IPermission interface-implementing derived class that is being used. For example, the FileIOPermission class protects disk files, and the RegistryPermission class protects registry entries. Of course, before the Demand can be used, the permission object must first be established, specifying the resource to be protected and the type of access being considered . In the case of file IO permissions, a FileIOPermission object must be established that specifies the file to be protected and the type of file access being considered, such as read, write, and append operations. This can be established using the appropriate constructor, and the Copy, Intersect , and Union methods may be used to tailor new objects from existing ones. It is not all that intuitive, but it is important to remember that the permissions of the code that call the Demand method are not checked. The checking begins with the immediate caller on the call stack and continues on up the call stack. Obviously, Demand succeeds only if no exception is raised. THE IPERMISSION COPY, INTERSECT, UNION, AND ISSUBSETOF METHODS
The methods for manipulating a permission object are Copy, Intersect , and Union . The method for testing a permission object is IsSubsetOf . Here are the syntax signatures for these four methods. IPermission Copy(); IPermission Intersect( IPermission target ); IPermission Union( IPermission target ); bool IsSubsetOf( IPermission target ); The IPermission Inheritance Hierarchy
The IPermission interface has only two derived implementation classes: PrincipalPermission and CodeAccessPermission. PrincipalPermission allows security checks to be made against the current, active principal object, which is the basic idea behind user-base security. The principal associated with the current thread or application domain is determined at logon time, and a specific principal object may be defined declaratively or imperatively in the application code. We will postpone a discussion of the CodeAccessPermission class until Chapter 8, which describes how to program using CAS. Figure 7-8 shows the IPermission inheritance hierarchy. Individual namespaces are not shown in this figure, but you should know that these permission classes are defined in several different namespaces. The most commonly used namespace for permission classes is System.Security.Permissions . Figure 7-8. The IPermission inheritance hierarchy.
The PrincipalPermission Class
As we have just seen, the PrincipalPermission class implements the IPermission interface. As we will see in the PrincipalPermission program example later in this chapter, the PrincipalPermission class is used to check against the current principal object for user verification purposes. For a full understanding of what the PrincipalPermission class represents, you probably need to know more about what a principal object is, which we have not yet discussed in detail. For now, however, it is sufficient to know that a principal object represents a logged on user that you would like to discriminate on for security purposes. We provide a deeper explanation of what a principal object is shortly. Now, with the IPermission inheritance still fresh in our minds, let's look at some of the more important members of the PrincipalPermission class. The Demand method, which has the same syntax as we saw in the IPermission inheritance, determines whether the current principal matches the specified PrincipalPermission object. The SecurityException is thrown if the check fails. Again, this method is used to enforce that the identity of the active principal is authorized to proceed without exception. public void Demand(); The other methods of IPermission work for PrincipalPermission as expected, including the Copy, Intersect , and Union methods. For a brief example of how to use just one of these methods, consider the following code snippet. This code shows how to combine two principal permission objects using the Union method. After the call on Union , the subsequent call on Demand will succeed only if the principal object pp represents a user that is either the user Abbott in the role of StraightMan or the user Costello in the role of FunnyMan. String user1 = "Abbott"; String role1 = "StraightMan"; PrincipalPermission PrincipalPerm1 = new PrincipalPermission(user1, role1); String user2 = "Costello"; String role2 = "FunnyMan"; PrincipalPermission pp = new PrincipalPermission(user2, role2); PrincipalPermission. Union (pp). Demand (); THE PRINCIPALPERMISSION CONSTRUCTORS
To create a PrincipalPermission object with a specified PermissionState enumeration, use the following constructor. The PermissionState enumeration specifies either a permission with all access ( PermissionState.Unrestricted ) or no access ( PermissionState.None ) to the protected resource. public PrincipalPermission( PermissionState state ); To create a PrincipalPermission object with a specified name and role, use the following constructor. public PrincipalPermission( string name, string role ); To create a PrincipalPermission object with a specified name and role and authentication status, use the following constructor: public PrincipalPermission( string name, string role, bool isAuthenticated ); THE FROMXML, TOXML, AND ISUNRESTRICTED METHODS
Beyond the methods defined by IPermission , such as Copy and Demand , and those methods defined by Object , such as Equals and GetHashCode , the PrincipalPermission class also defines the following three additional methods.
Here are the syntax signatures of these three new methods. Note that a SecurityElement is used as the parameter in the FromXml method and as the return value in the ToXml method. The SecurityElement class represents a simple XML object model for encoding security objects as a set of tags, attributes, child nodes, and text elements. public void FromXml( SecurityElement elem ); public SecurityElement ToXml(); public bool IsUnrestricted(); |