Method Level CAS (Code Access Security)

1. Introduction to CAS Method Level

In the early Example on C# category, we saw Assembly Level Security. Here, in this example, we are going to explore Method Level CAS actions with the help of permission to access environment variable.

In windows, permissions are first checked by the OS through its user account and role(s). For Example, a user account that belongs to administrators’ group can have entry to the system32 folder and can read sensitive data such as system environment variable whilst same cannot be done by a Guest User. Assembly level security (Explained in the past article) comes next to this OS security. The third level of security can be carried out through methods.

In Dot.Net application world, to access a secured resource, first we should have access to the resource from Operating System. This is decided by the logged in user and his/her membership with a role like admin or guest. Then the Dot.Net assembly should have the proper grant(s) for the access and finally comes the method which can claim for the access or even reject the access. This kind of layering is shown in the below picture:

Code Access Security - Layers
Code Access Security – Layers

The Method Level Security comes with different Security Actions and those are below:

  1. Demand Action
  2. Link Demand Action
  3. Inheritance Demand Action
  4. Deny Action
  5. PermitOnly Action
  6. Assert Action

We can use all the above said security actions through two different methods. One is Declarative Method, and another one is Imperative Method. In this article, we will try each method with the help of sample EXE and Demo videos.

2. About the Method Level CAS – Example

The below picture shows the Example we will create here to study the Method Level CAS (Code Access Security):

Example - CAS Method Level Security
Example – CAS Method Level Security

The text boxes (Markers 1 & 2) will display the value of the environment variables UserName and SecTest. The two read buttons (Markers 3 & 4) try to read those environment variables and sets the retrieved values in the corresponding text boxes 1 and 2. 

The Radio button options (Marker 5) invoke the methods which had applied with the corresponding security attributes. We are going to debug the methods by picking an option here (marker 5) and hitting the Read buttons.

The check box (Marker 6) is used to explain how the security actions like Deny and Demand are invoked through imperative method. One can use the same imperative style for other security actions as well.

3. Method Level CAS- Declarative Technique

In the Declarative Method, we impose security rules through security attributes. We can apply these attributes at the assembly level, class level, and at methods level. In the past example, we saw how the security attributes applied at the assembly level. In this example, we will learn how to apply Permission at the class method & class level. We are going to try above said six security actions in this Example. Like the early article, we are going to use the EnvironmentPermission to read the UserName and SecTest environment variables. Let us start one by one.

3.1 Demand & Deny – Method Level Security Actions

The Demand Security Action looks for the permission grant in all the methods which engage in the call stack. For example, if Function fx claims the permission to read an environment variable X, then all the functions in the call stack should have the claimed that permission. The Deny Action is used to reject any security permits.

3.1.1 NameSpace Needed

Before we test these, first we need to add the needed using directives as shown in the below code:

3.1.2 Read Button Handler

After adding the required using directive, we add the below piece of codes in the Read button handler. Both the read button handler create the object of SecMethodsCheck and call the function GetEnv_DemandLevel1 by passing the corresponding Environment variable names. We will define the class SecMethodsCheck in the next section.

3.1.3 SecMethodsCheck Class For Testing The Security Actions

Below is the code for the class SecMethodsCheck which examines the Demand as well as Deny Security Actions:

Here, we have three member functions. The function GetEnv_DemandLevel1 calls GetEnv_DemandLevel2 and which in turn calls GetEnvDemand. At the very first method in the call stack, we denied the permit to read the SecTest Env. variable.  We use the  EnvironmentPermission Attribute to deny reading the SecTest environment variable by defining the Security action ‘ SecurityAction.Deny’. In the GetEnvDemand function, we are claiming the read access to both the Env. variables SecTest and UserName. We mark the Demand Action using the enumeration constant ‘ SecurityAction.Demand’.

The first two methods invoke the other methods inside the Try block. In the catch block, we catch the  SecurityException and print the message from it to the debugger output window.

In this example, we will get an Exception in the method GetEnv_DemandLevel2. This is because; GetEnvDemand, claims the Read permission for both SecTest and UserName. But, in the call stack, the method GetEnv_DemandLevel1 denies the read access to the Env. variable SecTest. This fails the function call to GetEnvDemand as we marked it with Demand action. The below video explains the Demand and Deny security actions.

Video 1: SecurityAction.Demand and SecurityAction.Deny

3.2 PermitOnly & LinkDemand – Method Level CAS Actions

3.2.1 About PermitOnly & LinkDemand

The security action, PermitOnly assures to allow only the requested permission, and it also denies all the other permissions. This will make sure it permits only the desired permission. The security action LinkDemand makes sure the calling function in the call stack has the claimed permission.  Unlike Demand action, the LinkDemand checks the grant only one level deep in the call stack. In simple terms, it ensures the calling function to have the granted security permit.

3.2.2 Code Example

In the SecMethodsCheck class, we added three functions to test how the PermitOnly and LinkDemand security actions works. Now, have a look at the function below:

3.2.3 PermitOnly Security Action

In the above example, the function GetEnv_PermitOnlyLevel1 allows only the Read access to the Env. variable SecTest. The security action is  PermitOnly, and hence the function naturally bans all other grants. This means that it will deny the grant to read the UserName Env. variable. Note, this overrides the grant from Security Zone. Recall, we configured our example as an intranet zone App. 

The second function, GetEnv_PermitOnlyLevel2 allows entry to both the Env. variable UserName and SecTest. Note, the PermitOnly security action grants the permit to enter the function only. It does not have the power of removing the denied access. For Example, the deny set on the UserName Env. variable by the early function GetEnv_PermitOnlyLevel1 in the call stack cannot be removed.

3.2.4 LinkDemand Security Action

The third function GetEnv_PermitOnly is claiming the grant to read SecTest Env variable and the claim will succeed as all the functions in the call stack are having the demanded permission. If a demand succeeds, the caller can enter the function. With LinkDemand, Dotnet will stop the check at the direct caller of the function. In our example, this last function GetEnv_PermitOnly is marked with LinkDemand for the UserName Env variable. Hence, the permission check for reading UserName will be stopped at the direct caller and in our case it is GetEnv_PermitOnlyLevel2. Since the caller has the demanded permission for UserName, DotNet permits the call to the function GetEnv_PermitOnly. However the code which reads the Env variable throws error. This is explained in the below video.

Video 2: SecurityAction.PermitOnly and SecurityAction.LinkDemand

3.3 InheritanceDemand – Method Level CAS Actions

3.3.1 About InheritanceDemand

The base class can impose security permission on all its derived classes by making use of the InheritanceDemand Security Action. For example, let us say a class called BaseA, which marks the entire Class with FileIOPermission to claim Read access to C:\system32\Users.txt. We also assume that the class sets the Inheritance Demand security action to the FileIOPermission. Now, all the classes derived from the BaseA should also have the grant for FileIOPermission to read the text file. Let us explore this with our sample application.

3.3.2 Create Class Library Project

We will use a class library project to study the InheritanceDemand Security Action. Before dig into the code, we will look at the below screenshot:

Inheritance Demand Example - Class Relations
Inheritance Demand Example – Class Relations

The project, InhDemand is a VC# class library project (Marker 1). It has a class called InhDemandBase (Marker 3), which sets InheritanceDemand Security action on the Environment permission. Let us say the Env. Permission claims read access to SecTest Env. variable. Our SecMethods Windows Form project (Marker 2) defines a class called InhDemandDerived (Marker 4), which we derive from the class InhDemandBase (Marker 5). The below screenshot shows setting up the class library project:

Adding Class Library Project
Adding Class Library Project

After the setup of the class library project, we can add a method to the class which we can access outside of this class library project. Have a look at the code below:

Here, we claim the Environment permission to read the SecTest variable. Also, we pointed out the InheritanceDemand security action by using the enumeration constant  SecurityAction.InheritanceDemand in the Security Attribute. The method ReadEnvBase, just like our other examples, reads the SecTest Variable and returns that to the caller.

3.3.3 Our Example Using Class Library Class as Base Class

Now we can add reference to the class library project to our executable project. The below picture shows the steps:

Adding a reference to the Class Library Project
Adding a reference to the Class Library Project

After adding the reference to the project, we include a using directive to the SecMethods.cs project. That code is below:

We derive the class InhDemandDerived from class InhDemandBase which is defined in the class library project. Now, look at the below code which we write in our EXE project.

Here, we extend the class InhDemandDerived from our base class InhDemandBase. In this class, we are using the base class method GetEnvironmentVariable

While the client code makes the instance of InhDemandDerived, the security action imposed by the base class is checked. If the class InhDemandDerived had granted the permit for reading the SecTest Env variable, then we don’t have any issues. Otherwise, an exception is thrown when we try to enter a method which tries to create the instance of InhDemandDerived. The below video explains the InheritanceDemand security Action.

Video 3: Inheritance Demand Security Action

3.4 Assert – Method Level CAS Actions

The Assert Security Action is a relaxing action. With this action, DotNet can relax a denied permission to make an entry to a function. Look at the below code now:

In the above example, we deny the read access to both the Env. variables SecTest and UserName at the function GetEnv_AssertLevel1. Then, in the next function GetEnv_AssertLevel2, the security action denied in the past function call is revoked by setting the  Assert Security Action on the security permission  EnvironmentPermission.

In the last function call, we can attempt our claim for the UserName access permit. After trying this, we will also try to claim the Read access to SecTest. How an Assert Permission acts is shown in the below-given video.

Video 4: Assert Security Action

4. Security Actions through Imperative Method

In the Imperative Method, we apply the security actions by Dotnet Framework’s API function calls. First, we create a permission object and then we will carry out the security actions via a function call. For Example, in the imperative method, to deny the Read Access to UserName Env. variable, we need to create EnvironmentPermission object and then perform the required action like deny. Have a look at the below C-Sharp code:

In the above code, we can see how the code denies read access to the SecTest Env variable. First, we created an object of type  EnvironmentPermission by making use of the  EnvironmentPermissionAccess.Read Enum constant. After this step, we make a call to  Deny method and this will deny the permission to read value from the SecTest Env variable.

In the final function GetEnvDemand_Imperative, we create Permission Object and then make a call to  Demand method. Note how we claim the Demand Security Action at runtime and the demand may be for SecTest or UserName, depending on what we pass to the function. Handling the security demand like this is called Imperative Method.

In the above code example, one cannot read the username Env variable as we denied it in the function GetEnv_Imperative_DemandLevel1. The call to Demand method throws an exception when the demand is for SecTest. This is explained in the below video.

Video 5: Security Actions through Imperative Method

Source Code: Download Method Level CAS Example From Google Drive

Categories: C#

Tags: , , , , , , ,

Do you like this Example? Please comment about it for others!!

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: