CAS 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.
Creating Custom Code-Access Permissions
All code-access
permissions must meet the following requirements:
Implement the IPermission interface
Implement the IStackWalk interface
Implement the ISecurityEncodable interface
Implement the IUnrestrictedPermission interface
Provide a constructor that takes a PermissionState
argument
Be serializable
The simplest way to meet these requirements is to derive your
permission class from the abstract
CodeAccessPermission class, which we discussed in
Section 2.1CodeAccessPermission 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: earlier in this
chapter.
IPermission methods
Copy
Intersect
IsSubsetOf
Union
ISecurityEncodable methods
IUnrestrictedPermision method
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.
The CodeAccessPermission class defines an
InheritenceDemand for the
ControlEvidence and
ControlPolicy elements of the
SecurityPermissionCodeAccessPermission must have
these permissions, or the runtime throws a
SecurityException. class. The assembly containing
your subclass of
|
|
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:
Implement a single constructor that takes a
SecurityAction argument
Override the CreatePermission method
Implement public properties that enable the configuration of the
attribute's state
1. Designing the RadioPermission class
To 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:
Turn the radio on and off
Adjust the volume of the radio
Change the station the radio is tuned 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 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:
RadioPermission
-
The custom code-access permission that controls access to the managed
library for the radio tuner
RadioPermissionAttribute
-
The attribute counterpart to RadioPermission that
provides declarative syntax support
RadioAction
-
An enumeration that defines values that represent each of the
controlled actions
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.
2. Defining imports and assembly scope attributes
Aside 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. 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
3. Defining the RadioAction enumeration
RadioPermission
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 1 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.
Table 1. Values of the RadioAction enumeration
Value
|
Binary value
|
Hex value
|
Description
|
---|
None
|
000
|
0
|
No access to perform any actions with the radio
|
StartStop
|
001
|
1
|
Permission to turn the radio on and off
|
Channel
|
010
|
2
|
Permission to change the radio's channel
|
Volume
|
100
|
4
|
Permission to change the radio's volume
|
All
|
111
|
7
|
Permission to perform any of the above actions
|
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
4. Defining the RadioPermission class
The 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 RadioPermissionActions
property to provide controlled access to the private
RadioActions member:
object grants access. Implement the
# 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 RadioActionsRadioAction.None, whereas passing the
PermissionState.Unrestricted value creates a
RadioPermission object representing full
permission by setting RadioActionsRadioAction.All. to
to
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
5. Implementing the IUnrestrictedPermission interface
The 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
6. Implementing the IPermission interface
Both the
IStackWalk and
IPermission interfaces define a method named
Demand. The
CodeAccessPermission base class implements all
members of the IStackWalkDemand method from the
IPermission interface, leaving you with the
Copy, Intersect,
Union, and IsSubsetOf interface, and you do
not need to implement the 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 RadioPermissionRadioPermission 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 RadioPermissionVolume 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. represents
permission to perform a discrete set of actions, the intersection of
two that
grants only
# 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 RadioPermissionChannel 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: grants
# 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. Implementing the ISecurityEncodable interface
The ToXml
method returns a
SecurityElement. 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. 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
8. Defining the RadioPermissionAttribute class
We 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
SecurityActionSection 1.2 for
details: enumeration, which describes the
CAS operation invoked by a declarative security statement; see
# 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
9. Building the Radio.dll library
The 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
10. Using RadioPermission to enforce security
RadioPermission 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.