Earlier, we saw how to use imperative CAS: We created an instance of a CodeAccessPermission -derived class, such as UrlIdentityPermission , and then called its Deny method to restrict the associated action. It is also possible to accomplish this declaratively using CodeAccessSecurityAttribute -derived classes. We will see this shortly, using UrlIdentityPermissionAttribute . The main difference with attributes is that we do not normally instantiate the attribute class in the imperative way using the new operator. Instead, we apply the attribute to the target assembly, class, or method, using square bracket declaration syntax. The other difference is that the information declared by a security attribute is stored in the metadata of the assembly and is accessible to the CLR at assembly load time. This also allows the PermView.exe tool to display the assembly's permission attributes at the command prompt. Square Bracket Attribute Declaration SyntaxAttribute-style declarative syntax looks a bit different from traditional imperative-style syntax. The idea is that attributes are applied to a program construct, such as an assembly, a class, or a method, as part of the construct's declaration. Thus, the effect is made at compile time, and the result is stored as part of the assembly's metadata. The special declarative syntax uses square brackets in the following manner. [<attribute_class_name>( <default_property_value> <property_name>=<property_value>...)] The square brackets contain the name of the attribute class followed by parentheses. The parentheses can contain a number of property values, the first of which may be the default property that does not require a name, followed by property name /value pairs. To make this more concrete, consider the following code snippet taken from the upcoming DeclarativeCAS example. The name of the attribute is UrlIdentityPermission , and it is being initialized with SecurityAction.LinkDemand for its default Action property, and "file://C:/.../TrustedClient.exe" for its named Url property. [UrlIdentityPermission( SecurityAction.LinkDemand, Url="file://C:/.../TrustedClient.exe")] You may be wondering how you determine the valid program constructs that the attribute can be applied to and what default property and named properties are provided. The answers can be found in the documentation for the attribute class. First, you locate the documentation for the attribute class, which will have an AttributeUsage attribute applied to it that lists the valid program constructs that it can be applied against. Possibilities include assembly, class, and method. Then, take a look at the attribute class's constructor. The constructor parameter indicates which attribute property is the default property. [26] This is the property that does not require an explicit name in the square bracket syntax. To see the named properties supported by the attribute, simply look at the properties defined by the attribute class. The key to all this is the attribute class documentation. Let's look at the UrlIdentityPermissionAttribute class as a concrete example.
The URL Identity Permission AttributeBefore we look at the DeclarativeCAS example, we briefly look at the UrlIdentityPermissionAttribute class. We are not interested in all of the details of this class. For our needs, it is sufficient to focus on only those aspects that relate to how the attribute works in the context of the square bracket attribute syntax just described. THE URLIDENTITYPERMISSIONATTRIBUTE CLASSHere is the UrlIdentityPermissionAttribute class declaration. As you can see, its AttributeUsage attribute indicates that it can be applied to the following target constructs: assembly, class, struct, constructor, and method. [ AttributeUsage (AttributeTargets. Assembly AttributeTargets. Class AttributeTargets. Struct AttributeTargets. Constructor AttributeTargets. Method )] [Serializable] public sealed class UrlIdentityPermissionAttribute : CodeAccessSecurityAttribute THE URLIDENTITYPERMISSIONATTRIBUTE CONSTRUCTORHere is the UrlIdentityPermissionAttribute constructor. You can see that this constructor takes one parameter of type SecurityAction . This means that the attribute has a default property for specifying one of the values defined by the SecurityAction values, such as LinkDemand, InheritanceDemand, Demand, Deny, RequestMinimum , and so on. [AttributeUsage(AttributeTargets.Assembly AttributeTargets.Class AttributeTargets.Struct AttributeTargets.Constructor AttributeTargets.Method)] [Serializable] public UrlIdentityPermissionAttribute ( SecurityAction action ); THE URL PROPERTYThe documentation also shows that the UrlIdentityPermissionAttribute class has a string type property named Url . This means that this property can be used as a named property in the square bracket attribute syntax described previously. Here is the Url property declaration. [AttributeUsage(AttributeTargets.Assembly AttributeTargets.Class AttributeTargets.Struct AttributeTargets.Constructor AttributeTargets.Method)] [Serializable] public string Url {get; set;} The SecurityAction ClassWe have just seen that the UrlIdentityPermissionAttribute constructor takes a parameter of type SecurityAction . The values defined by the SecurityAction enumeration can therefore be used in the square bracket syntax for this attribute. The following list shows the possible values for SecurityAction along with a short description of their purposes.
THE DECLARATIVECAS EXAMPLEThe DeclarativeCAS example is exactly like the UrlIdentityPermission example except that the declarative approach is used rather than the imperative approach. The EvilClient and TrustedClient source files are identical to the UrlIdentityPermission example, and therefore they are not listed again here. Let's now look at how declarative CAS is used in the DeclarativeCASComponent.cs source file. Again, in the actual source code the full path is specified in the UrlIdentityPermission attribute, but for display purposes, it has been trimmed down in size using the three-dot notation. As you can see, instead of creating an instance of UrlIdentityPermission and calling its Demand method, we just declare the DoSomethingForClient method using the UrlIdentityPermission attribute. // DeclarativeCASComponent .cs using System; using System.Security; using System.Security.Permissions; public class UrlIdentityPermissionComponent { [UrlIdentityPermission( SecurityAction.LinkDemand, Url="file://C:/.../TrustedClient.exe")] public static void DoSomethingForClient() { //if we got this far then all is OK Console.WriteLine( "Client call permitted"); } } When you run the TrustedClient , it works without throwing any exception. When you run the EvilClient program, it throws a SecurityException . There is really no difference between this example and the previous one except this one uses the declarative technique involving a permission attribute, and the previous one uses the imperative technique using the new operator to instantiate the permission object. |