Code Access Security is one of the powerful features of .NET but at the same time some confusion exists about its terminology and its usage. With this, I would like to make an attempt to explain some of the terminology with diagrams. This document does not explain all the details related to CAS, as lot of information already exists on the internet and only gives a jump start to Code Access Security.
The basics thing is whenever any code is being executed in managed world the .NET runtime verifies whether that code is allowed or not based on evidence and set of permissions.
Evidence
Where from the code came?
Permissions
What permissions are allowed for the code?
Basics Details
With the above basics let us explore Evidence and Permissions and other Code Access Security terminology.
Evidence
Evidence of an assembly is about its identity who it is and where it came from.
- From where the assembly is being loaded?
- If the assembly is downloaded from the web, what is the URL of the source directory?
- What is Strong Name (if any)?
- Who is the publisher (if digitally signed)?
How does System find out about this?
Codebase property of an assembly determines about its location which will result in either local directory, intranet/internet.One can get strong name and publisher details from the assembly manifest.
Once the Evidence of the assembly is gathered, the system grants some permission to this assembly.
How does System find out what permissions an assembly can have?
Time to explain some more terms. Let’s try to understand the following.
Policy Levels
.NET runtime security has 4 policy levels viz., Enterprise, Machine, User, and AppDomain. (which can be done programmatically).
Each policy has multiple code groups and multiple permission sets.
Code groups
Code group is a group of assemblies which satisfies the same condition. A code group will have one member condition which decides about particular assembly can be a member of this (group) or not.
Permissions and Permission Sets
Permission is what the code can do with a particular resource like File, Registry etc., and Permission Set is collection of permission.
.NET Default Policies will be
Now, we understood Policy Levels, Code Groups and their Permissions. It is time to find out how the system assigns the permissions to the loaded assembly.
Below is pseudo code how .NET Security system grants the permission to the assembly (Assumes no programmatic security)
public PermissionSet GetPermission(Assembly asm )
{
foreach( PolicyLevel pl in System.Security.Configuration.PolicyLevels )
{
foreach( CodeGroup cg in pl.CodeGroups )
{
if( cg.MembershipCondition exists in asm.Evidence )
{
// In given level it is the UNION of permissions across code groups
permissionSet[pl] = permissionSet[pl] Union cg.PermissionSet;
}
}
}
// Across levels it is intersecion of permissions
finalPermissionSet = permissionSet[“Enterprise”] Intersecion permissionSet[“Machine”] Intersecion permissionSet[“User”];
return finalPermissionSet;
// Assume Exclusive and LevelFinal are not set
}
From above the .NET Security system assigns the permission set to the assembly.
At this point system has assigned the permission to the assembly
How does it get enforced?
The .NET classes ( System.IO.File , Microsoft.Win32.Registry classes will do the rest ) will enforce this by calling to appropriate security class.
Lets’ see how the File.OpenText code does this.
Pseudo code for OpenText()
{
string[] pathList = new string[1];
pathList[0] = pathToOpenFile;
new FileIOPermission( FileIOPermissionAccess.Read,pathList).Demand();
}
The call to .Demand will check the permission and throw an exception if it is not permitted to open the file.
If you have call to unmanaged dll where you open the text file the .NET will not be able to check whether you have permission to open or not.
Exclusive
Each code group in a policy consists of one property called Exclusive which means don’t consider any other permissions in that policy.
Lets’ walk through this…
Suppose your assembly belongs to Code group A, Code Group B and Code group C in Machine Policy.
Machine Policy
Code Group A
Permission Set A
Code Group B
Permission Set B
Code Group C
Permission Set C
And ‘Assembly Z’ falls in all code groups. Then permission set in this policy will be
Machine Level Policy for Assembly Z = (Permission Set A) U (Permission Set B) U (Permission Set C)
But if set Exclusive property True in Code Group B then permission set in Machine Policy will be
MacineLevel Policy for Assembly Z = ( Permission Set B )
Note: Still the final permission set will be intersection of Enterprise, Machine and User.
The exclusive property in .NET Configuration tool will be having check mark as
Level Final
There is another property called Level Final when checked, On Code Group, the policy in the next level will not considered.
Lets’ walk through this…
Enterprise Policy
Code Group
All_Code
Permission E
Machine Policy
Code Group
All_Code
Code Group A
Permission Set_A
Code Group B
Permission Set_B
Code Group C
Permission Set_C
User Policy
Code Group
Code Group 1
Permission Set_1
Code Group 2
Permission Set_2
Code Group 3
Permission Set_3
Suppose if an assembly belongs to All_Code in Enterprise, Code Group A,B,C in Machine and Code Group 1,2,3 in User then
Final Permission set = (Permision E) Intersection (Permision_A U Permission_B U Permission_C) Intersection (PermissionSet_1 U PermissionSet_2 U PermissionSet_3)
With Final Property set on Code Group B in Machine Policy then User Policy will not be evaluated and hence.
Final Permission set = (Permision E) Intersection ( Permision_A U Permission_B U Permission_C )
In .Net Security Configuration tool the Level Final property will be shown like below
With Exclusive and Level Final property one can precisely control the permission set applied to an assembly.