Jump to navigation

Poupou's Corner of the Web

Looking for perfect security? Try a wireless brick.
Otherwise you may find some unperfect stuff here...


Mono Security Manager Part III - Using Non-CAS permissions

Are there such things as non-CAS permissions ? Well I surely hope so, code security is fairly new compared to Role-Based Access Control (RBAC) or any arbitrary permission (e.g. time based). But technically the CLR doesn't make much difference of them and most differences are hidden to developpers.

So what are the technical differences between CAS and non-CAS permissions ?

  • All CAS permissions classes inherits from System.Security.CodeAccessPermission. This means they implement both the IPermission and the IStackWalk interfaces;
  • Non CAS permissions don't have to inherit from any specific class but must implement the IPermission interface. The only example in the framework is the PrincipalPermission class - a classic RBAC example;
  • As non CAS permissions do not implement the IStackWalk interface they cannot be used to Assert, Deny or PermitOnly (i.e. the stack modifiers). In fact they do not provoke a stack walk at all.

Non CAS permission have been working for a while on Mono. In fact this sample, with a few subtle changes, would work under Mono 1.0.x. The subtlety is that we can now use declarative security syntax (i.e. attributes) instead of using imperative security (i.e. source code).

To be used for declarative security, a permission class must have a corresponding security attribute class (e.g. PrincipalPermissionAttribute). The attribute class must inherit from SecurityAttribute, otherwise it attribute will be encoded as a custom attribute (i.e. the security manager won't execute it). Now just to confuse things all security attributes do not inherit directly from SecurityAttribute but from CodeAccessSecurityAttribute - even non CAS permissions (note that the class isn't named CodeAccessPermissionAttribute after all ;-).

The following sample restrict execution of the Execute method to the user named root. Unlike my two previous blog entries, it doesn't restrict a specific resource or something specific to the assembly (i.e. code identity), but the user itself.

using System; using System.Security; using System.Security.Permissions; using System.Security.Principal; using System.Threading; public class Program { [PrincipalPermission (SecurityAction.Demand, Name="root")] public void Execute () { Console.WriteLine ("Welcome {0}", Environment.UserName); } static void Main () { Console.WriteLine ("Security is {0}", SecurityManager.SecurityEnabled ? "ON" : "OFF"); // note 1: PrincipalPolicy.WindowsPrincipal work as well for POSIX with Mono // note 2: AppDomain.SetPrincipalPolicy requires the ControlPrincipal right. // so a Demand/stackwalk is being done just before our sample starts... AppDomain.CurrentDomain.SetPrincipalPolicy (PrincipalPolicy.WindowsPrincipal); try { new Program ().Execute (); } catch (SecurityException) { Console.WriteLine ("Program limited to 'root' user."); Console.WriteLine ("You are currently logged as '{0}'.", Thread.CurrentPrincipal.Identity.Name); } } }

Now compile the sample, try to execute it without the security manager, then execute it with the security manager and finally execute it as root with the security manager still enabled...

> mcs root.cs > mono root.exe Security is OFF Welcome poupou > mono --security root.exe Security is ON Program limited to 'root' user. You are currently logged as 'poupou'. > su -c "mono --security root.exe" Password: ******** Security is ON Welcome root

So the security manager does more then just handle CAS. But CAS is so big that most people don't make any distinction between CAS and the security manager. As I said before the framework itself doesn't help much in making a distinction, let's try a variation: Insert a line to disable the SecurityManager just before calling the Execute method...

try { // Insert the next line SecurityManager.SecurityEnabled = false; new Program ().Execute (); }

and execute it again, as yourself and as root, with the security manager enabled...

> mono --security root.exe Security is ON Program limited to 'root' user. You are currently logged as 'poupou'. > su -c "mono --security root.exe" Password: ******** Security is ON Welcome root

and the PrincipalPermission still gets called! It's not a Mono specific behavior but don't trust me just because I wrote this on the internet, go ahead and try it on the MS framework ;-). The "security manager" is an overloaded keyword in the CLR. Also note that on Mono it won't work (i.e. it won't get called) if you do not enable the security manager.

This leads to an important feature, supplying the --security to Mono means more than just turning on the SecurityManager.SecurityEnabled property. The reverse is also true, and potentially more dangerous, not enabling the security manager disable more security than turning off the SecurityManager.SecurityEnabled property!


Q - What happens if I use a [PrincipalPermission(...)] in my code and execute it with Mono 1.0.x or before Mono 1.1.4 ?

A - It will be ignored as any type (CAS or non-CAS) of declarative security. In fact it will also be ignore with 1.1.4 onward if you do not activate the security manager (--security).

Q - Can non-CAS permission be used for LinkDemand (JIT time) and InheritanceDemand (load time) ?

A - PrincipalPermission wouldn't be very useful, but it's still usable. Other custom non-CAS permission could be more useful.

There is much more to say (and do) on CAS but the last three entries covers what's available in Mono 1.1.4, so I'll probably keep quiet on CAS until 1.1.5 is released with even more goodies ;-).

2/23/2005 18:58:29 | Comments

The views expressed on this website/weblog are mine alone and do not necessarily reflect the views of my employer.