INFO: When to Use Identity Permissions with Declarative Security vs. Imperative Security (318169)



The information in this article applies to:

  • Microsoft Visual Studio .NET (2002), Professional Edition

This article was previously published under Q318169

SUMMARY

Identity permissions control code access from one assembly to another. You can use identity permissions, which are a subset of code access permissions, either declaratively or imperatively. This article outlines some of the differences between declarative security and imperative security for identity permissions.

MORE INFORMATION

Unlike imperative security, declarative security does not require that every block of code that is on the stack must have permission settings checked against the caller. Because of this, identity permissions are more efficient with declarative security. Moreover, if you use code access permissions declaratively, the permissions are evaluated at load time or just-in-time (JIT). This is more efficient than if you use code access permissions imperatively, which evaluate the permissions at run time.

For load-time declarative security use the LinkDemand code attribute. If you apply the LinkDemand code attribute, the security is checked on the immediate caller during JIT compilation. The LinkDemand code attribute specifies what permissions the caller must have to access the code. If you try to access the code, and if you do not have the proper LinkDemand permissions, a security exception is thrown.

Imperative security uses code that is executed at run time to enforce security. At run time, when a Demand method is called from an Identity Permission class, the call stack is evaluated to verify the code. If there is a point in the call stack where assemblies that were previously called do not have the same identity as the code, exceptions are thrown.

You can initiate a Security Exception in this code sample if you create a new key file with the same name as the original key. Use the new file to overwrite the original key file. Create the new key, recompile, and then run the unchanged application. The application fails at load time because the embedded key does not match the key that is listed in the declarative attribute.
Sample Code:
============
Note: Encryption keys must be generated as security evidence

1. Generate the encryption keys: sn -k Key.SNK

2. Extract the public key: sn -p Key.SNK  PublicKey.SNK

3. Display the public key in hexadecimal: sn -tp PublicKey.SNK

4. Copy the text output from step 3 under the heading "Public key is" 
   into the StrongNameIdentityPermissionAttribute code attribute on 
   the Sample Declarative class below where PublicKey = "0x0024...518ce".
   It must be a full 320 character string (exclusive of the '0x'
   hexadecimal specifier). 

5. Create the following Console Application below. This code can be 
   compiled with the command line (assuming the code is in Class1.cs):
   
      csc /target:exe Class1.cs
      
   Alternatively, you can create a Console Application project in 
   Visual C# .NET and replace the default Class1.cs file with the
   code specified below. Note that the AssemblyKeyFile attribute
   specified  below will be duplicated in the default project       AssemblyInfo.cs file. You can comment out the duplicate
   entry in AssemblyInfo.cs (or delete
   AssemblyInfo.cs from the project entirely). In a Visual Studio .NET 
   (Visual C# .NET) project you also must change the
   AssemblyKeyFile path because of the project directory structure and
   build rules to:
      
      [assembly: AssemblyKeyFile("..\\..\\Key.snk")]   
       
// C#
using System;
using System.Security.Permissions;
using System.Reflection;
using System.Runtime.CompilerServices;

// Include the key file in the assembly
[assembly: AssemblyKeyFile("key.snk")]

namespace Q318169 {

    class Class1 {

        [STAThread]
        static void Main(string[] args) {
            SampleImperative si = new SampleImperative();
            si.Verify();

            SampleDeclarative sd = new SampleDeclarative();
            sd.Verify();
        }
    }

    // Imperative Security (code based)

    public class SampleImperative {

        public void Verify () {
            Type ThisType = this.GetType();
            Assembly ThisAssembly = ThisType.Assembly;
            AssemblyName an = ThisAssembly.GetName();
            byte[] MyKey = an.GetPublicKey();
            StrongNamePublicKeyBlob KeyBlob 
                = new StrongNamePublicKeyBlob(MyKey);

            StrongNameIdentityPermission p 
                = new StrongNameIdentityPermission
                (KeyBlob,null,null);

            try {
                // Imperative (runtime) Security 'Demand'
                p.Demand();
                Console.WriteLine("Imperative Security Verified");
            }
            catch (System.Security.SecurityException se) {
                // If Demand fails execute 
                // on the SecurityException
            }
        }
    }

    // Declarative Security (attribute based)

    [StrongNameIdentityPermissionAttribute (SecurityAction.LinkDemand, PublicKey = "0x0024...518ce")]
    public class SampleDeclarative {

        public void Verify () {
            Console.WriteLine("Declarative Security Verified");
        }
    }
}

				

REFERENCES

Visual Studio .NET Documentation

Modification Type:MajorLast Reviewed:5/17/2002
Keywords:kbinfo kbSecurity kbSrcControl KB318169