Now that you understand how security policy is managed, even if you aren't the person doing the managing, it is important to understand how we make use of code access security in our code. Much of the CLR already interacts with security policy using declarative and imperative security requests. These requests are made in the form of attributes and code that instantiates a specific security- related class. When security requests are made in the form of attributes, this is referred to as declarative security . When security requests are made in the form of lines of code within a method body, this is referred to as imperative security . The results are roughly the same regardless of the method used.
Listing 18.1 provides two examples. One demonstrates declarative security and the other precisely the same request using an imperative syntax. Note that while the code in Listing 18.1 demonstrates both declarative and imperative syntax, the PrincipalPermissionAttribute and the PrincipalPermission class are considered part of role-based security rather than code access security. (I chose this example to demonstrate syntax and introduce other forms of security in .NET.) Listing 18.1 Using Declarative and Imperative Role-Based Permissions Checks 1: Imports System.Security.Permissions 2: Imports System.Threading 3: Imports System.Security.Principal 4: 5: Public Class Form1 6: Inherits System.Windows.Forms.Form 7: 8: [ Windows Form Designer generated code ] 9: Private Const user As String = " domain\user " 10: Private Const role As String = Nothing 11: 12: Private Sub Button1_Click(ByVal sender As System.Object, _ 13: ByVal e As System.EventArgs) Handles Button1.Click 14: 15: Const mask As String = _ 16: "Current principal is: {0}" 17: 18: Debug.WriteLine(String.Format(mask, _ 19: Thread.CurrentThread.CurrentPrincipal.Identity.Name)) 20: 21: DeclarativePermissionRequired() 22: 23: End Sub 24: 25: Private Sub Button2_Click(ByVal sender As System.Object, _ 26: ByVal e As System.EventArgs) Handles Button2.Click 27: 28: Const mask As String = _ 29: "Current principal is: {0}" 30: 31: Debug.WriteLine(String.Format(mask, _ 32: Thread.CurrentThread.CurrentPrincipal.Identity.Name)) 33: 34: ImperativePermissionRequired() 35: 36: End Sub 37: 38: <PrincipalPermission(SecurityAction.Demand, _ 39: Name:=user, role:=role)> _ 40: Public Sub DeclarativePermissionRequired() 41: 42: MessageBox.Show("You have permission!") 43: 44: End Sub 45: 46: Public Sub ImperativePermissionRequired() 47: 48: Dim Permission As _ 49: System.Security.Permissions. _ 50: PrincipalPermission = _ 51: New System.Security.Permissions. _ 52: PrincipalPermission(user, role) 53: 54: Permission.Demand() 55: 56: MessageBox.Show("You have permission!") 57: End Sub 58: 59: Private Sub Form1_Load(ByVal sender As System.Object, _ 60: ByVal e As System.EventArgs) Handles MyBase.Load 61: 62: Thread.CurrentThread.CurrentPrincipal = _ 63: New WindowsPrincipal(WindowsIdentity.GetCurrent) 64: 65: End Sub 66: End Class The WindowsPrincipal class used in line 63 implements the IPrincipal interface. A principal object represents the user identity and roles under which the code is running. (This is part of roles-based security in .NET, but the example also demonstrates the declarative and imperative syntax.) The Form.Load event establishes the current Windows user as the current principal. This means that the code is running on behalf of the current user.
Lines 12 through 23 write the identity of the current principal and call DeclarativePermissionRequired . The subroutine DeclarativePermissionRequired uses the PrincipalPermissionAttribute ”a declarative demand ”to demand that the identity of the person running this method must be the name of the supplied user and be in the role defined by the argument role . Because role is initialized to Nothing in line 10 we are only verifying that the user is the user defined by the user variable. Lines 25 through 36 perform precisely the same task imperatively, that is, through statements inside the method. The real work occurs in ImperativePermissionRequired , which creates an instance of the System.Security.Permissions.PrincipalPermission class, initializing the class with user and role . Line 54 invokes the Demand method. If the current principal is not the one indicated by user and role , an exception is thrown. In fact, both the declarative and imperative forms of security throw the identical exception, as shown in Figure 18.4 Figure 18.4. The SecurityException dialog that appears if the permission demand fails.
The only real difference between the two forms of usage ”declarative and imperative security ”of the PrincipalPermission class is when the permission is evaluated. With the declarative example the procedure is not permitted to run at all, whereas the imperative example permits the code to run up to the point that the PrincipalPermission.Demand method is invoked.
The Advantages of Declarative SecurityDeclarative security offers a few distinct advantages over imperative security.
In general, declarative security has more advantages, but imperative security offers some benefits of its own. Let's take a moment to look at these. The Advantages of Imperative SecurityImperative security actions run as lines of code intermixed with your application's code. This offers a couple of distinct advantages.
Both approaches offer benefits. It is worthwhile to evaluate whether to use declarative or imperative security in particular situations relative to the benefits each approach offers. |