Choosing Imperative or Declarative Security
Declarative security is simpler to implement than imperative security. Declarative security attributes can be viewed with Permview.exe or mscorcfg.msc, allowing the callers of code to see what permissions the code requires. Imperative security is not evident to the callers of code. Because the permissions requirements are embedded inside the code, you cannot see what is happening unless coding a demand.
In some cases the choice between declarative and imperative security is obvious because some security actions can be performed in only one of the two ways. For example, minimum, optional, and refused permission requests are only available declaratively.
But how do you choose which approach to use when both approaches provide equivalent support for the functions you need? If a security action can be performed both declaratively and imperatively, the decision depends on the developer's preference. The performance difference between the two is insignificant, for the most part, however, you can would have to choose imperative syntax over declarative syntax when you are going to construct the initial permission state of security in your code with information that is only available at run time.
A declarative demand is a way of invoking a security check without adding any statements to your code. You make a declarative demand by placing information at the class or member level, indicating the permissions you want callers to have. You can also implement Deny actions declaratively. If you place a declarative security check at the class level, it applies to each class member, including methods, properties, and fields. If you place a declarative security check at the member level, it applies to only that member and overrides any permission specified at the class level. Declarative demands degrade performance only at JIT compilation. In fact, the use of declarative demands can actually increase the performance of an application in which a demand is made many times.
The imperative demand that you place in your code protects all of the remaining code in the method from which the Demand method is called. The security check is performed when the Demand method executes; if the security check fails, a security exception is thrown and the rest of the code in that method or member is not executed unless the exception is caught and handled. Consider using an imperative (rather than declarative) demand when information that you need to specify permission becomes known only at runtime.
When an assembly is requested, the CLR searches for evidence of the assembly's origin. In simple terms, the CLR asks the following questions:
From which site does the assembly come?
From which URL does the assembly come?
From which zone does the assembly come?
Who has signed the assembly?
What is the strong (public/private keyâ€"signed assembly) name of the assembly?
Based on the evidence it collects, the CLR learns the identity of the assembly and assigns the appropriate identity permissions. These identity permissions "earn" an assembly its membership to a code group. Developers and administrators do not have influence over the identity permissions of an assembly. The CLR just takes a requested assembly, examines its evidence, and assigns the identity permissions based on that evidence. To associate a set of identity permissions with a code group, the administrator must set up security policies.
Some of the identity permission classes in the framework are
SiteIdentityPermission, which represents the Web site from which the assembly originated;
URLIdentityPermission, which represents the URL from which the assembly originated;
ZoneIdentityPermission, which represents the security zone from which the assembly originated. The zone identity is one of the values of the System.Security.SecurityZone enumeration.
PublisherIdentityPermission, which represents the Authenticode publisher of the assembly; and
StrongNameIdentityPermission, which represents the strong name of the assembly.
Even if identity permissions can be demanded, they are granted only if an assembly can show evidence of the proper identity. This also holds true for code access permissions. Identity and code access permissions are very closely related in that they share the same underlying concept and derive from the same base class, CodeAccessSecurity.
Link demands, the permissions a caller must have when calling code, can be used to limit which classes can be linked to your classes. You must set link demands declaratively because they can be evaluated at JIT compilation time by the system and performed against the caller of the code. If the caller does not possess enough permission to satisfy the link demand, the system throws an exception. The CLR does not perform a stack walk for link demands, so you can avoid the potential impact on performance.
Link demands can be associated with identity permissions to control who or what can call your code. For example, you can develop assemblies that can be called only by other assemblies from a specific publisher.
Listing 22.6 illustrates how you can implement LinkDemand declarative security.
Listing 22.6 -LinkDemand Illustration
' code to restrict callers
<ZoneIdentityPermission(SecurityAction.LinkDemand, Zone:=SecurityZone.MyComputer)> _
Public Class test
Inheritance demands are similar to link demands except that they are used to restrict how entities inherit characteristics at the class level. For example, you can place inheritance demands declaratively at the class level to ensure that only code with the specified permission can inherit from your class. You can place inheritance demands on methods to ensure that any code that overloads the method has the specified permission to do so.
Listing 22.7 illustrates how you can implement class-level InheritanceDemand declarative security.
Listing 22.7 -InheritanceDemand Illustration
' code to restrict subclassing
public class test2
// Some code
You know now how the CLR controls the permissions of your code. Now it's time to explore how you can control the rights of a user.
Every role you have -whether parent or child, shopper or billpayer, developer or administrator - has certain behaviors and responsibilities associated with it. Security designers have recognized how useful this concept of role-associated behaviors can be in IT and have designed a security check that grants permissions based on roles.
When you write a software system, the design phase usually reveals certain roles that users play based upon actual workflow. Role-based security allows the developer to check whether a user is functioning within a certain role when requesting access to resources.
Unlike identity permissions and code access permissions, role-based permissions have nothing to do with the rights a piece of code possesses but rather with the workflow-based permission of a user. The term workflow-based permission implies a sequence of steps or hierarchical permissions that colleagues require to see a task through to completion. For example, a bellhop with no permissions takes a guest's bags to a hotel room designated by a desk clerk with specific permissions. A housekeeper with very few permissions freshens the room; and at checkout, the desk manager's more extensive permissions are required to remove unauthorized charges from the guest's bill and to discount the room rate.
Role-based permissions are not derived from the CodeAccessPermission class, as identity permissions and code access permissions are. Instead they share the same base class with the common principal-based (also known as Windows identity) permissions; both are derived from the PrincipalPermission class. To understand role-based permissions, we must look at two other classes: Identity and Principal.
The Identity class represents users in a software or operating system. In contrast, the Principal class represents the security context (Windows user group) of a user (Windows identity. Basically, Principal represents all the roles to which a user is assigned. A PrincipalPermission is the object used to demand a role from a user. If the user belongs to the necessary Principal class (i.e., if the user has been assigned the requisite roles), the request succeeds. PrincipalPermission is therefore an easy way to check role assignments.
We have seen the different security concepts related to a specified software system. Yet, that software system is embedded in the operating system and the .NET runtime host, so there must be other permissions that manage your rights to control the runtime.
All permissions related to the runtime environment and the controlling of it are represented through the SecurityPermission class found in the System.Security.Permissions namespace. With this class, you can request runtime environment permissions.
The class takes a SecurityPermissionFlag enumeration in its constructor. This enumeration contains an item called Assertion, which is responsible for trying to execute the assertion for permission. If an assembly does not possess Assertion rights, it is not possible to call the Assert method to assert specific permissions and therefore you cannot disable the stack walk of the code access permissions.
Treat with extreme caution any permissions represented by SecurityPermission objects. If you assign rights through this enumeration, be sure you know what the code does and whether it really needs these rights. If you obtain code over the Internet or from other uncontrollable sources, never assign it permissions if you don't know what the code contains.
In VB.NET, any security violation throws one of three exception types -security, policy, or verification -which can be caught and handled appropriately by exception-handling routines. An object is created to represent exceptions as they occur. All three security-related exceptions that follow inherit from Object.Exception.SystemException.
SecurityException is thrown when a security violation is detected, typically at runtime.
PolicyException is thrown when policy forbids code to run. This exception, which usually occurs as the code is loading, is thrown when the code requests more permission than the policy will grant or the policy is configured to prohibit running the code.
VerificationException can occur either when code that is verifiable does not pass verification rules or when code that is not verifiable is run without SkipVerify permissions enabled for that particular zone, such as the intranet zone. Verification includes memory allocations, proper casting of variables, and type safety. Code can be verified during JIT compilation because it contains nothing but MSIL statements. However, code in which SkipVerify permission is set is omitted.
Hope this article would have helped you in understanding how to Choosing Security and Role-Based Permissions in VB.NET.