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:

The Method Level Security comes with different Security Actions and those are below:
- Demand Action
- Link Demand Action
- Inheritance Demand Action
- Deny Action
- PermitOnly Action
- 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):

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:
1 2 3 4 |
//Sample 01: Required Using Directive using System.Security; using System.Security.Permissions; using System.Diagnostics; |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//Sample 02: Get Environment Variables private void btnReadUName_Click(object sender, EventArgs e) { //2.1: Demand Security action if (radDemand.Checked == true) { SecMethodsCheck obj = new SecMethodsCheck(); txtUserName.Text = obj.GetEnv_DemandLevel1("UserName"); } . . private void btnReadSecTest_Click(object sender, EventArgs e) { if (radDemand.Checked == true) { SecMethodsCheck obj = new SecMethodsCheck(); txtSecTest.Text = obj.GetEnv_DemandLevel1("SecTest"); } . . |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
public class SecMethodsCheck { //Sample 03: DEMAND & Deny SECURITY ACTION //Sample 3.1: Deny Sectest Permission [EnvironmentPermission(SecurityAction.Deny, Read = "SecTest")] public string GetEnv_DemandLevel1(string EnVarName) { string EnvVal = "None"; try { EnvVal = GetEnv_DemandLevel2(EnVarName); } catch (System.Security.SecurityException Ex) { Debugger.Log(1, "Information", Ex.Message); } return EnvVal; } //Sample 3.2: Catch the Exception private string GetEnv_DemandLevel2(string EnVarName) { string EnvVal = "None"; try { EnvVal = GetEnvDemand(EnVarName); } catch (System.Security.SecurityException Ex) { Debugger.Log(1, "Information", Ex.Message); } return EnvVal; } //Sample 3.3: Make sure all the callers in the call //stack has permission for accessing Sectest, //UserName Env. Variables [EnvironmentPermission(SecurityAction.Demand, Read = "SecTest")] [EnvironmentPermission(SecurityAction.Demand, Read = "UserName")] private string GetEnvDemand(string EnVarName) { return Environment.GetEnvironmentVariable(EnVarName); } }; |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
//Sample 04: PERMIT & LINK DEMAND SECURITY ACTION //Sample 4.1: By Saying permit only SecTest, we are skipping //the default Username permission given by the assembly [EnvironmentPermission( SecurityAction.PermitOnly, Read = "SecTest")] public string GetEnv_PermitOnlyLevel1(string EnVarName) { string EnvVal = "None"; try { EnvVal = GetEnv_PermitOnlyLevel2(EnVarName); } catch (System.Security.SecurityException Ex) { Debugger.Log(1, "Information", Ex.Message); } return EnvVal; } //Sample 4.2: Allow both SecTest and UserName [EnvironmentPermission( SecurityAction.PermitOnly, Read = "UserName")] [EnvironmentPermission( SecurityAction.PermitOnly, Read = "SecTest")] private string GetEnv_PermitOnlyLevel2(string EnVarName) { string EnvVal = "None"; try { EnvVal = GetEnv_PermitOnly(EnVarName); } catch (System.Security.SecurityException Ex) { Debugger.Log(1, "Information", Ex.Message); } return EnvVal; } //Sample 4.3: Demand Sectest permission and Link Demand //UserName Permission [EnvironmentPermission( SecurityAction.Demand, Read = "SecTest")] [EnvironmentPermission( SecurityAction.LinkDemand, Read = "UserName")] //[EnvironmentPermission( // SecurityAction.Demand, Read = "UserName")] private string GetEnv_PermitOnly(string EnVarName) { return Environment.GetEnvironmentVariable(EnVarName); } |
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:

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:

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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//Sample 06: Required Using Directive using System.Security; using System.Security.Permissions; using System.Diagnostics; namespace InhDemand { //Sample 07: Inheritance Demand [EnvironmentPermission( SecurityAction.InheritanceDemand, Read = "SecTest")] public class InhDemandBase { public string ReadEnvBase(string envName) { Debugger.Log(1, "Information", Environment.GetEnvironmentVariable(envName)); Debugger.Log(1, "Information", Environment.NewLine); return Environment.GetEnvironmentVariable(envName); } } } |
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:

After adding the reference to the project, we include a using directive to the SecMethods.cs project. That code is below:
1 2 |
//Sample 08: Referring different Assembly using InhDemand; |
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.
1 2 3 4 5 6 7 8 9 10 11 |
public class InhDemandDerived : InhDemandBase { public string ReadEnv(string EnvName) { Debugger.Log(1, "Information", Environment.GetEnvironmentVariable(EnvName)); Debugger.Log(1, "Information", Environment.NewLine); return Environment.GetEnvironmentVariable(EnvName); } } |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
//sample 8.0: ASSERT SECURITY ACTION [EnvironmentPermission(SecurityAction.Deny, Read = "UserName")] [EnvironmentPermission(SecurityAction.Deny, Read = "SecTest")] public string GetEnv_AssertLevel1(string EnVarName) { string EnvVal = "None"; try { EnvVal = GetEnv_AssertLevel2(EnVarName); } catch (System.Security.SecurityException Ex) { Debugger.Log(1, "Information", Ex.Message); } return EnvVal; } [EnvironmentPermission(SecurityAction.Assert, Read = "SecTest")] public string GetEnv_AssertLevel2(string EnVarName) { string EnvVal = "None"; try { EnvVal = GetEnv_Assert(EnVarName); } catch (System.Security.SecurityException Ex) { Debugger.Log(1, "Information", Ex.Message); } return EnvVal; } //Sample 8.1: First Try Demanding Only UserName and then try with //only SecTest. Here, Assert overrides the deny permission [EnvironmentPermission(SecurityAction.Demand, Read = "SecTest")] //[EnvironmentPermission(SecurityAction.Demand, Read = "UserName")] public string GetEnv_Assert(string EnVarName) { return Environment.GetEnvironmentVariable(EnVarName); } |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
//Sample 9.0: Demand and Deny Imperative Technique public string GetEnv_Imperative_DemandLevel1(string EnVarName) { string EnvVal = "None"; try { //9.1: Deny the Sectest permission - Imperative EnvironmentPermission envP = new EnvironmentPermission( EnvironmentPermissionAccess.Read, "SecTest"); envP.Deny(); EnvVal = GetEnv_Imperative_DemandLevel2(EnVarName); } catch (System.Security.SecurityException Ex) { Debugger.Log(1, "Information", Ex.Message); } return EnvVal; } private string GetEnv_Imperative_DemandLevel2(string EnVarName) { string EnvVal = "None"; try { EnvVal = GetEnvDemand_Imperative(EnVarName); } catch (System.Security.SecurityException Ex) { Debugger.Log(1, "Information", Ex.Message); } return EnvVal; } private string GetEnvDemand_Imperative(string EnVarName) { //9.2: Demand the Sectest permission - Imperative EnvironmentPermission envP = new EnvironmentPermission( EnvironmentPermissionAccess.Read, EnVarName); envP.Demand(); return Environment.GetEnvironmentVariable(EnVarName); } |
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: Assert CAS, CAS Declarative Method, CAS Imperative Method, Demand CAS, Deny CAS, InheritanceDemand CAS, LinkDemand Cas, PermitOnly CAS