[ Team LiB ] |
7.3 Extending the .NET FrameworkCAS is fully extensible and allows you to create your own permission classes that integrate with the security framework to provide capabilities equivalent to the standard permission classes. The creation of custom permissions is relatively straightforward. The complexity of the identity, actions, or resources that your permission class represents defines how difficult the development task is. In the following sections, we demonstrate how to create and implement custom code-access permissions. 7.3.1 Creating Custom Code-Access PermissionsAll code-access permissions must meet the following requirements:
The simplest way to meet these requirements is to derive your permission class from the abstract CodeAccessPermission class, which we discussed in Section 7.2.2.1 earlier in this chapter. CodeAccessPermission declares implementation of the IPermission, IStackWalk, and ISecurityEncodeable interfaces, but only provides concrete implementations of the IStackWalk interface methods. Because the logic of the following methods depends on permission-specific state, you must provide implementations of them in your class:
To meet the requirements of serialization, it is usually enough to apply the SerializableAttribute to your class definition. However, if your permission class requires nonstandard serialization processing because of the complex internal state it maintains, implement the ISerializable interface.
To support declarative security syntax, create an attribute counterpart to your permission class. This involves creating a class that extends the System.Security.Permissions.CodeAccessSecurityAttribute class. Your class must:
7.3.1.1 Designing the RadioPermission classTo demonstrate the creation and use of custom code-access permissions, imagine that we need to develop a managed library that allows an application to control a PC-based radio tuner. The radio tuner could be a hardware attachment to the PC or software that plays Internet-based radio stations; the implementation details are unimportant, but the library must allow code to:
The goal is to create a custom code-access permission that you can use to control access to each of these actions. After all, you do not want to allow malicious code downloaded from competitive radio stations to casually change the tuning of the radio. The best way to achieve fine-grained access control is to implement a code-access permission that represents a discrete set of actions; this is the same model used by the SecurityPermission class that we described in Section 7.2.2.2 earlier in this chapter. Because the number of possible actions is small and well-defined, this model fits your needs well. Another common approach is to implement a permission hierarchy, where permission to perform a highly trusted action gives permission to perform all lesser-trusted actions; however, the actions you need to represent in this case do not fit this model well. To give the programmers using the custom permission flexibility, you want to provide both imperative and declarative syntax support. This will also allow application developers to build permission requests for your permission into their assemblies. Create two classes and one enumeration:
For convenience, we include all three types in a single source file named Radio.cs (C#) and Radio.vb (Visual Basic .NET). We will build this into a library named Radio.dll, which programmers will use in the development of the managed radio tuner library, the configuration of .NET security policy, and to make permission requests in assemblies that access the managed library. Although the code is straightforward, it is lengthy, so we break the listings into manageable sections for explanation. 7.3.1.2 Defining imports and assembly scope attributesAside from importing the necessary namespace references, the first thing to do is to specify the assembly scope attributes AssemblyKeyFile and AssemblyVersion to give Radio.dll a strong name. Because Radio.dll contains security classes used to extend CAS, you must configure it as a fully trusted assembly in the runtime's security policy; we discuss fully trusted assemblies in Chapter 8. For this example, the AssemblyKeyFile attribute references a key file named Keys.snk, which you can generate later using the .NET Strong Name tool (Sn.exe): # C# using System; using System.Reflection; using System.Security; using System.Security.Permissions; [assembly:AssemblyKeyFile("Keys.snk")] [assembly:AssemblyVersion("1.0.0.0")] namespace OReilly.ProgrammingDotNetSecurity { # Visual Basic .NET Imports System Imports System.Reflection Imports System.Security Imports System.Security.Permissions <assembly:AssemblyKeyFile("Keys.snk")> <assembly:AssemblyVersion("1.0.0.0")> Namespace OReilly.ProgrammingDotNetSecurity 7.3.1.3 Defining the RadioAction enumerationRadioPermission represents control of a discrete set of actions. The RadioAction enumeration represents each of the actions to which RadioPermission controls access. RadioAction also includes a value to represent no permission and a value to represent full or unrestricted permission. To simplify the implementation of your permission model, apply the Flags attribute to the RadioAction enumeration. The Flags attribute allows you to use the values of the RadioAction enumeration as bit fields, enabling you to manipulate and compare RadioAction values with bitwise operators. Table 7-8 lists the members of RadioAction and shows their binary and hex values. From the binary values, it is easy to see how RadioAction identifies the individual actions to which a RadioPermission object represents access.
Finally, because you use RadioAction values inside SecurityPermission objects (which must be serializable), you also mark RadioAction as Serializable: # C# // Define enumeration to represent the set of possible permissions. [Flags, Serializable] public enum RadioAction { None = 0x00, // No permissions StartStop = 0x01, // Permission to start and stop the radio Channel = 0x02, // Permission to change the channel Volume = 0x04, // Permission to change the volume All = 0x07 // All permissions } # Visual Basic .NET ' Define enumeration to represent the set of possible permissions. <Flags, Serializable> _ Public Enum RadioAction None = &H00 ' No permissions StartStop = &H01 ' Permission to start and stop the radio Channel = &H02 ' Permission to change the channel Volume = &H04 ' Permission to change the volume All = &H07 ' All permissions End Enum 7.3.1.4 Defining the RadioPermission classThe class declaration for RadioPermission specifies that it is sealed (C#) and NotInheritable (Visual Basic .NET). There is no need to allow anybody to extend the RadioPermission class, and it stops malicious code from subclassing RadioPermission in an attempt to subvert security restrictions. RadioPermission extends CodeAccessPermission, implements the IUnrestricted interface, and is Serializable. The CodeAccessPermission base class already implements the functionality defined in the IStackWalk interface so you do not have to implement the Assert, Demand, Deny, and PermitOnly methods; this simplifies the development of custom code-access permissions. However, you still need to implement the permission-specific Copy, Intersect, IsSubsetOf, and Union methods defined in IPermission, and the FromXml and ToXml methods defined in ISecurityEncodable, all of which CodeAccessPermission declares as abstract. Declare a single private data member named RadioActions of type RadioAction. This holds a bit field representing the actions to which a specific RadioPermission object grants access. Implement the Actions property to provide controlled access to the private RadioActions member: # C# // Define the RadioPermission class. [Serializable] public sealed class RadioPermission : CodeAccessPermission, IUnrestrictedPermission { // Private member to signal permitted actions. private RadioAction RadioActions; // Property to provide access to the enabled radio actions. public RadioAction Actions { get { return RadioActions; } set { if ((value & (~RadioAction.All)) != 0) { throw new ArgumentException("Inavalid RadioAction value"); } else { RadioActions = value; } } } # Visual Basic .NET ' Define the RadioPermission class. <Serializable> _ Public NotInheritable Class RadioPermission Inherits CodeAccessPermission ' Private member to signal permitted actions. Private RadioActions As RadioAction ' Property to provide access to the enabled radio actions. Public Property Actions( ) As RadioAction Get Return RadioActions End Get Set (ByVal Value As RadioAction) If (value And (Not RadioAction.All)) <> 0 Then Throw New ArgumentException _ ("Inavalid RadioAction value") Else RadioActions = value End If End Set End Property Declare two constructors for RadioPermission. All code-access permission classes that extend CodeAccessPermission must implement a constructor that takes a PermissionState argument. Passing the constructor the value PermissionState.None creates a RadioPermission that represents no permissions by setting RadioActions to RadioAction.None, whereas passing the PermissionState.Unrestricted value creates a RadioPermission object representing full permission by setting RadioActions to RadioAction.All. Because you use a bit field to represent each permitted action, it is easy to represent an unrestricted permission simply by switching on all action bits (RadioAction.All equals 111 in binary). In other permission models, you may need to implement a separate Boolean data member to represent an unrestricted state. The second constructor takes a member of the RadioAction enumeration, confirms that it is valid, and sets the private RadioActions member to the value of the argument: # C# // Constructor that takes a PermissionState. public RadioPermission (PermissionState state) { if (state == PermissionState.None) { this.RadioActions = RadioAction.None; } else if (state == PermissionState.Unrestricted) { this.RadioActions = RadioAction.All; } else { throw new ArgumentException("state"); } } // Constructor that takes a RadioAction specifying the set // of actions permitted by this RadioPermission object. public RadioPermission (RadioAction actions) { // Ensure we have a valid actions value. if ((actions & (~RadioAction.All)) != 0) { throw new ArgumentException("Inavalid RadioAction value"); } else { RadioActions = actions; } this.RadioActions = actions; } # Visual Basic .NET ' Constructor that takes a PermissionState. Public Sub New(ByVal state As PermissionState) If state = PermissionState.None Then Me.RadioActions = RadioAction.None Else If state = PermissionState.Unrestricted Then Me.RadioActions = RadioAction.All Else Throw New ArgumentException("state") End If End Sub ' Constructor that takes a RadioAction specifying the set ' of actions permitted by this RadioPermission object. Public Sub New(ByVal actions As RadioAction) ' Ensure we have a valid actions value. If (actions And (Not RadioAction.All)) <> 0 Then Throw New ArgumentException("Inavalid RadioAction value") Else RadioActions = actions End If Me.RadioActions = actions End Sub 7.3.1.5 Implementing the IUnrestrictedPermission interfaceThe IUnrestrictedPermission interface defines the IsUnrestricted method, which returns a Boolean indicating whether a permission object represents an unrestricted state. In the case of RadioPermission, you can easily calculate the response by comparing the value of the private RadioActions member with the value RadioAction.All and returning the result: # C# // Return whether permission represents unrestricted access. public bool IsUnrestricted( ) { return RadioActions == RadioAction.All; } # Visual Basic .NET ' Return whether permission represents unrestricted access. Public Function IsUnrestricted( ) As Boolean Return RadioActions = RadioAction.All End Function 7.3.1.6 Implementing the IPermission interfaceBoth the IStackWalk and IPermission interfaces define a method named Demand. The CodeAccessPermission base class implements all members of the IStackWalk interface, and you do not need to implement the Demand method from the IPermission interface, leaving you with the Copy, Intersect, Union, and IsSubsetOf methods to implement. The Copy method returns a clone of the permission object. In the case of RadioPermission, this is a simple matter of calling one of the constructors and passing the current RadioActions value. If your permission class uses objects to represent state, Copy must perform a deep copy and create copies of all contained objects: # C# // Create a copy the RadioPermission. public override IPermission Copy( ) { return new RadioPermission(RadioActions); } # Visual Basic .NET ' Create a copy the RadioPermission. Public Overrides Function Copy( ) As IPermission Return New RadioPermission(RadioActions) End Function The Intersect method returns a new IPermission that represents the logical intersection of the current RadioPermission and another. Because RadioPermission represents permission to perform a discrete set of actions, the intersection of two RadioPermission objects is the set of actions permitted by both objects. For example, if the current RadioPermission grants Volume and Channel control and the other grants only Volume control, the intersection of the two is a RadioPermission that grants only Volume control. Because the Flags attribute allows you to treat values of the RadioAction enumeration as bit fields, you can express the intersection logic using a bitwise And on the RadioActions members of the two original RadioPermission objects. # C# // Return an intersection of this and another RadioPermission // object. public override IPermission Intersect(IPermission target) { // Return null if the target argument is null. if (target == null) { return null; } // Ensure the target argument is another RadioPermission // object, if not throw an ArgumentException. if (target is RadioPermission) { RadioPermission r = (RadioPermission)target; // Calculate the intersection of the radio actions // from this and the target RadioPermission. RadioAction i = this.RadioActions & r.RadioActions; // Return a new RadioPermission. return new RadioPermission(i); } else { throw new ArgumentException("target"); } } # Visual Basic .NET ' Return an intersection of this and another RadioPermission ' object. Public Overrides Function Intersect(ByVal target As IPermission) _ As IPermission ' Return null if the target argument is null. If target Is Nothing Then Return Nothing End If ' Ensure the target argument is another RadioPermission ' object, if not throw an ArgumentException. If TypeOf target Is RadioPermission Then Dim r As RadioPermission = _ CType(target, RadioPermission) ' Calculate the intersection of the radio actions ' from this and the target RadioPermission. Dim i As RadioAction = Me.RadioActions And _ r.RadioActions ' Return a new RadioPermission. Return New RadioPermission(i) Else Throw New ArgumentException("target") End If End Function The Union method returns a new IPermission that represents the logical union of the current RadioPermission and another. For example, if one RadioPermission grants Channel control and the other grants Volume control, the union of the two is a RadioPermission that grants both Volume and Channel control. The implementation of the Union method is similar to the Intersect method, but uses a bitwise Or operator on the RadioActions members of the two original RadioPermission objects to calculate the union: # C# // Return the union of this and another RadioPermission object. public override IPermission Union(IPermission other) { // Return null if the other argument is null. if (other == null) { return null; } // Ensure the other argument is another RadioPermission object // if not throw an ArgumentException. if (other is RadioPermission) { RadioPermission r = (RadioPermission)other; // Calculate the union of the radio actions // from this and the other RadioPermission. RadioAction u = this.RadioActions | r.RadioActions; // Return a new RadioPermission return new RadioPermission(u); } else { throw new ArgumentException("other"); } } # Visual Basic .NET ' Return the union of this and another RadioPermission object. Public Overrides Function Union(ByVal other As IPermission) _ As IPermission ' Return null if the other argument is null. If other Is Nothing Then Return Nothing End If ' Ensure the other argument is another RadioPermission object ' if not throw an ArgumentException. If TypeOf other Is RadioPermission Then Dim r As RadioPermission = CType(other, RadioPermission) ' Calculate the union of the radio actions ' from this and the other RadioPermission. Dim u As RadioAction = Me.RadioActions _ Or r.RadioActions ' Return a new RadioPermission Return New RadioPermission(u) Else Throw New ArgumentException("other") End If End Function The IsSubsetOf method returns a Boolean value indicating whether the current RadioPermission is a subset of the RadioPermission passed as an argument to the method. For example, if the current RadioPermission allowed Volume control, and the one specified by the argument allowed both Volume and Channel control, then the current RadioPermission is a subset of the other. As with the Intersect and Union methods, we perform the subset relationship test using bitwise operators. # C# // Determines if this RadioPermission is a subset of the provided // RadioPermission. public override bool IsSubsetOf(IPermission target) { // Return false if the target argument is null. if (target == null) { return false; } // Ensure the target argument is another RadioPermission // object, if not throw an ArgumentException. if (target is RadioPermission) { RadioPermission r = (RadioPermission)target; // Determine if the provided set of actions are // a subset of the current permissions actions. return (this.RadioActions & (~r.RadioActions)) == 0; } else { throw new ArgumentException("target"); } } # Visual Basic .NET ' Determines if this RadioPermission is a subset of the provided ' RadioPermission. Public Overrides Function IsSubsetOf _ (ByVal target As IPermission) As Boolean ' Return false if the target argument is null. If target Is Nothing Then Return False End If ' Ensure the target argument is another RadioPermission ' object, if not throw an ArgumentException. If TypeOf target Is RadioPermission Then Dim r As RadioPermission = _ CType(target, RadioPermission) ' Determine if the provided set of actions are ' a subset of the current permissions actions. Return (Me.RadioActions And _ (Not r.RadioActions)) = 0 Else Throw New ArgumentException("target") End If End Function 7.3.1.7 Implementing the ISecurityEncodable interfaceThe ToXml method returns a SecurityElement, which we discussed in Chapter 6. The SecurityElement contains a simple XML object model representing the state of the RadioPermission object. The runtime uses the ToString method of SecurityElement to render permission objects to XML for writing to the security policy files, which we discuss in Chapter 9. The XML representation is also useful when debugging CAS programming issues. The XML representation of all code-access permissions must have a root element named "IPermission." The internal structure of this element is up to you, as long as the FromXml method (discussed next) can accurately recreate the state of a permission object from the XML. Here is an example of the XML used to represent a RadioPermission object that represents access to the StartStop action only. <IPermission class="OReilly.ProgrammingDotNetSecurity.RadioPermission, Radio, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc5e18bc387194b3" version="1" StartStop="true"/> The XML structure you have implemented for RadioPermission is consistent with that used by the standard permission classes. Use attributes, as opposed to child elements, to store state data, and include active state only, assuming missing values have their default values. If the RadioPermission object represents access to all actions, include a single Unrestricted = true attribute instead of including values for each of the individual actions. The version attribute identifies the XML format to provide backward compatibility in case future versions of the RadioPermission use different XML representations: # C# // Convert the Radio Permission to a SecurityElement. public override SecurityElement ToXml( ) { // Create a new "IPermission" element. SecurityElement se = new SecurityElement("IPermission"); // Add fully qualified type name for the RadioPermission. se.AddAttribute("class",this.GetType( ).AssemblyQualifiedName); // Add version of "1" to be consistent with other permission // classes se.AddAttribute("version", "1"); // Add the radio action state, only write out active // permissions. if (this.IsUnrestricted( )) { // Write only the unrestricted attribute if the // permission is unrestricted. se.AddAttribute("Unrestricted", "true"); } else { // Write out the individual actions that are granted. if ((RadioActions & RadioAction.StartStop) != 0) { se.AddAttribute("StartStop", "true"); } if ((RadioActions & RadioAction.Channel) != 0) { se.AddAttribute("Channel", "true"); } if ((RadioActions & RadioAction.Volume) != 0) { se.AddAttribute("Volume", "true"); } } // Return the new SecurityElement. return se; } # Visual Basic .NET ' Convert the Radio Permission to a SecurityElement. Public Overrides Function ToXml( ) As SecurityElement ' Create a new "IPermission" element. Dim se As SecurityElement = New SecurityElement("IPermission") ' Add fully qualified type name for the RadioPermission. se.AddAttribute("class",Me.GetType( ).AssemblyQualifiedName) ' Add version of "1" to be consistent with other permission ' classes se.AddAttribute("version", "1") ' Add the radio action state, only write out active ' permissions. If Me.IsUnrestricted( ) Then ' Write only the unrestricted attribute if the ' permission is unrestricted. se.AddAttribute("Unrestricted", "true") Else ' Write out the individual actions that are granted. If (RadioActions And RadioAction.StartStop) <> 0 Then se.AddAttribute("StartStop", "true") End If If (RadioActions And RadioAction.Channel) <> 0 Then se.AddAttribute("Channel", "true") End If If (RadioActions And RadioAction.Volume) <> 0 Then se.AddAttribute("Volume", "true") End If End If ' Return the new SecurityElement. Return se End Function The FromXml method recreates the state of a RadioPermission object that was rendered previously to XML using the ToXml method. Check first to see if the XML represents an unrestricted permission; if it does not, look for each individual action: # C# // Extract state from a SecurityElement. public override void FromXml(SecurityElement e) { // Ensure we have a SecurityElement to work with if (e == null) throw new ArgumentNullException("e"); // Ensure the SecurityElement is an IPermission if (e.Tag != "IPermission") {throw new ArgumentException( "Element must be IPermission"); } else { // Determine if the permission is unrestricted if (e.Attribute("Unrestricted") == "true") { RadioActions = RadioAction.All; } else { // Look for each individual action attribute to // build the set of permissions RadioActions = RadioAction.None; if (e.Attribute("StartStop") == "true") { RadioActions = RadioActions | RadioAction.StartStop; } if (e.Attribute("Channel") == "true") { RadioActions = RadioActions | RadioAction.Channel; } if (e.Attribute("Volume") == "true") { RadioActions = RadioActions | RadioAction.Volume; } } } } } # Visual Basic .NET ' Extract state from a SecurityElement. Public Overrides Sub FromXml(ByVal e As SecurityElement) ' Ensure we have a SecurityElement to work with If e Is Nothing Then Throw New ArgumentNullException("e") End If ' Ensure the SecurityElement is an IPermission If e.Tag <> "IPermission" Then Throw New ArgumentException("Element must be IPermission") Else ' Determine if the permission is unrestricted If e.Attribute("Unrestricted") = "true" Then RadioActions = RadioAction.All Else ' Look for each individual action attribute to ' build the set of permissions RadioActions = RadioAction.None If e.Attribute("StartStop") = "true" Then RadioActions = _ RadioActions Or RadioAction.StartStop End If If e.Attribute("Channel") = "true" Then RadioActions = _ RadioActions Or RadioAction.Channel End If If e.Attribute("Volume") = "true" Then RadioActions = _ RadioActions Or RadioAction.Volume End If End If End If End Sub End Class 7.3.1.8 Defining the RadioPermissionAttribute classWe begin the declaration of the RadioPermissionAttribute class by using the AttributeUsage attribute to define the program elements you can apply the RadioPermissionAttribute to. RadioPermissionAttribute extends the CodeAccessSecurityAttibute class, which provides the base class from which all permission attributes must extend. Implement a single constructor that all permission attributes extending CodeAccessSecurityAttibute must define. The constructor takes a value from the SecurityAction enumeration, which describes the CAS operation invoked by a declarative security statement; see Section 7.2.1.2 for details: # C# [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Assembly, AllowMultiple = true, Inherited = false )] [Serializable] public sealed class RadioPermissionAttribute : CodeAccessSecurityAttribute { // Constructor to take SecurityAction, simply calls base // class constructor. public RadioPermissionAttribute(SecurityAction action): base( action ) {} # Visual Basic .NET <AttributeUsage(AttributeTargets.Method Or _ AttributeTargets.Constructor Or AttributeTargets.Class Or _ AttributeTargets.Struct Or AttributeTargets.Assembly, _ AllowMultiple := True, Inherited := False), Serializable> _ Public NotInheritable Class RadioPermissionAttribute Inherits CodeAccessSecurityAttribute ' Constructor to take SecurityAction, simply calls base ' class constructor. Public Sub New(ByVal action As SecurityAction) MyBase.New(action) End Sub As with RadioPermission, the RadioPermissionAttribute class contains a private data member named RadioActions (of type RadioAction) to identify which actions the RadioPermissionAttribute object represents. Four properties provide controlled access to configure the value of the private RadioActions member. The first property, named Actions, allows you to provide a RadioAction value to configure the state of all actions in a single call. The other three attributes, named StartStop, Channel, and Volume, allow you to configure the individual bits of RadioActions to set whether an individual action is permitted or not: # C# // Private member to signal permitted actions. private RadioAction RadioActions = RadioAction.None; // Property allows all actions to be configured in one call // using values from the RadioAction enumeration public RadioAction Actions { get { return RadioActions; } set { RadioActions = value; } } // Property to allow StartStop permission to be switched on // and off public bool StartStop { get { return (RadioActions & RadioAction.StartStop) != 0; } set { if (value) { RadioActions = RadioActions | RadioAction.StartStop; } else { RadioActions = RadioActions & ~RadioAction.StartStop; } } } // Property to allow Channel permission to be switched on // and off public bool Channel { get { return (RadioActions & RadioAction.Channel) != 0; } set { if (value) { RadioActions = RadioActions | RadioAction.Channel; } else { RadioActions = RadioActions & ~RadioAction.Channel; } } } // Property to allow Volume permission to be switched on // and off public bool Volume { get { return (RadioActions & RadioAction.Volume) != 0; } set { if (value) { RadioActions = RadioActions | RadioAction.Volume; } else { RadioActions = RadioActions & ~RadioAction.Volume; } } } # Visual Basic .NET ' Private member to signal permitted actions. Private RadioActions As RadioAction = RadioAction.None ' Property allows all actions to be configured in one call ' using values from the RadioAction enumeration Public Property Actions( ) As RadioAction Get Return RadioActions End Get Set (ByVal Value As RadioAction) RadioActions = value End Set End Property ' Property to allow StartStop permission to be switched on ' and off Public Property StartStop( ) As Boolean Get Return (RadioActions And RadioAction.StartStop) <> 0 End Get Set (ByVal Value As Boolean) If value Then RadioActions = RadioActions Or RadioAction.StartStop Else RadioActions = RadioActions And _ (Not RadioAction.StartStop) End If End Set End Property ' Property to allow Channel permission to be switched on ' and off Public Property Channel( ) As Boolean Get Return (RadioActions And RadioAction.Channel) <> 0 End Get Set (ByVal Value As Boolean) If value Then RadioActions = RadioActions Or RadioAction.Channel Else RadioActions = RadioActions And _ (Not RadioAction.Channel) End If End Set End Property ' Property to allow Volume permission to be switched on ' and off Public Property Volume( ) As Boolean Get Return (RadioActions And RadioAction.Volume) <> 0 End Get Set (ByVal Value As Boolean) If value Then RadioActions = RadioActions Or RadioAction.Volume Else RadioActions = RadioActions And _ (Not RadioAction.Volume) End IF End Set End Property Despite its simplicity, the CreatePermission method is the most important method of a permission attribute. It allows the runtime to create permission objects from the declarative security statements contained in your code. The CreatePermission method returns a newly created RadioPermission using the value of attributes RadioActions member: # C# // Creates and returns an RadioPermission object // based on the configured radio actions. public override IPermission CreatePermission( ) { return new RadioPermission(RadioActions); } } } # Visual Basic .NET ' Creates and returns an RadioPermission object ' based on the configured radio actions. Public Overrides Function CreatePermission( ) As IPermission Return New RadioPermission(RadioActions) End Function End Class End Namespace 7.3.1.9 Building the Radio.dll libraryThe RadioAction, RadioPermission, and RadioPermissionAttribute classes are all contained in a single source file named Radio.cs (C#) or Radio.vb (Visual Basic .NET). Before you can build the Radio.dll library containing the new security classes, you must create a key file named Keys.snk to satisfy the reference contained in the AssemblyKeyFile attribute. Create the Keys.snk file and compile the Radio.dll library using the following commands: # C# sn -k Keys.snk csc /target:library Radio.cs # Visual Basic .NET sn -k Keys.snk vbc /target:library Radio.vb 7.3.1.10 Using RadioPermission to enforce securityRadioPermission is now ready to protect the methods in the managed library that provides access to the radio tuner. As demonstrated in the following code fragments, you can use RadioPermission in exactly the same ways as the standard permission classes: # C# // An imperative assert of RadioPermission granting Volume control RadioPermission r = new RadioPermission(RadioAction.Volume); r.Assert( ); // A declarative demand for permission to change the radio channel [RadioPermission(SecurityAction.Demand, Channel = true)] // A minimum permission request for unrestricted access to the radio [assembly:RadioPermission(SecurityAction.RequestMinimum, Unrestricted = true)] # Visual Basic .NET ' An imperative assert of RadioPermission granting Volume control Dim r As RadioPermission = New RadioPermission(RadioAction.Volume) r.Assert( ) ' A declarative demand for permission to change the radio channel <RadioPermission(SecurityAction.Demand, Channel := True)> _ ' A minimum permission request for unrestricted access to the radio <assembly:RadioPermission(SecurityAction.RequestMinimum, _ Unrestricted := True)> Once you have developed the secure class library that enables managed code to control the PC radio tuner, you must configure the security policy to grant access to the appropriate code. First, you must understand how security policy calculates the set of permissions to grant to an assembly. Then you need to understand how to use the security administration tools supplied with the .NET Framework to configure security policy. We discuss security policy in Chapter 8 and the .NET administration tools in Chapter 9. |
[ Team LiB ] |