RequestRefuse and RequestOptional example

Dave asks
for an example of how to use RequestRefuse and RequestOtional. Here's my attempt to post a short blog entry that describes it (luckily I had the code already at hand... ;-) ).

The code
consists of two libraries ("Optional" and "Refuse") and a main program for accessing them both. Basically just copy each bit of code into the right file, run build.bat and then run main.exe.

The "Optional" file has the following declarations in it:

// Let us show MessageBox windows

[assembly:UIPermission(SecurityAction.RequestMinimum, Window=UIPermissionWindow.SafeSubWindows)]

 

// Nothing else is required

[assembly:PermissionSet(SecurityAction.RequestOptional, Name="Execution")]

As you can see, it requests the ability to display "safe" windows (MessageBoxes and the like) and says that Execution is optional (and since Execution is always granted by RequestOptional, this basically means that nothing else is required).

The "Refuse" file has the following declarations in it:

// Let us show MessageBox windows

[assembly:UIPermission(SecurityAction.RequestMinimum, Window=UIPermissionWindow.SafeSubWindows)]

 

// Refuse access to the Environment

[assembly:EnvironmentPermission(SecurityAction.RequestRefuse, Unrestricted=true)]

As you can see, it requests the ability to display "safe" windows (MessageBoxes and the like) and says that it refuses to access the Environment, even if policy grants it that permission.

The main program then simply tries to run a handful of (identical) methods on an object from each assembly, some of which will demand specific permissions:

Console.WriteLine("rnBasic execution:");

try
{ Console.WriteLine(t.ReturnAString()); }

catch
(Exception ex) { Console.WriteLine(ex.Message); }

Console.WriteLine("rnMessageBox:");

try
{ t.ShowMessageBox(); }

catch
(Exception ex) { Console.WriteLine(ex.Message); }

Console.WriteLine("rnEnvironment:");

try
{ Console.WriteLine(t.GetUsername()); }

catch
(Exception ex) { Console.WriteLine(ex.Message); }

Console.WriteLine("rnFile IO:");

try
{ Console.WriteLine(t.ReadFile()); }

catch
(Exception ex) { Console.WriteLine(ex.Message); }

If you have done everything successfully, you should see that code using RequestOptional fails to run both the GetUserName method (which needs EnvironmentPermission) and the ReadFile method (which needs FileIOPermission), whilst the code using RequestRefuse only fails to run GetUserName because it explicitly refused EnvironmentPermission but was still granted FileIOPermission.

The "Optional" code is therefore less susceptible to luring attacks because it can't do anything except execute and show MessageBox windows (even by accident), whereas the "Refuse" code could theoretically be tricked into doing anything other than accessing environment variables (yes, this is a very convoluted example ;-) ).