Category: Umbraco


< Part One: Medium Trust primer

> Part Three: Download the code

Welcome to Part Two, wherein we will tackle the beast that is Medium Trust in our NUnit tests. If you just want a downloadable zip to get going, you can always jump to part three.

Based on what we learnt in the previous post around how the permissions are stored in configuration, a simple option is open to us. The basic premise is that in our unit test, we’re going to spin up an AppDomain and pass in the same permissions from configuration that the ASP.Net hosting engine uses. We’re then going to run the test method in that partially-trusted AppDomain, rather than in the full-trust AppDomain of the test runner.

Simples! The end. Bai!

Well, not quite. First, some gotchas.

Spinning up another AppDomain is called “sandboxing” for a reason: they are totally separate, and any communication between AppDomains has to be done via .NET Remoting using serializable objects, just like using your own Remoting channel, WCF or a good ol’ SOAP web service on another machine. Can you spot the first gotcha yet?

Gotcha 1: You can’t just use AppDomain.SetData to pass objects by value from your test to a Medium-Trust domain because it doesn’t have permissions to deserialize them fully.

Makes sense when I put it like that, but it took me an hour of wasted time before I facepalmed and almost quit coding forever.

There aren’t ways around this. Passing an object to another AppDomain, whether it’s via the SetData and GetData methods, requires the object to either be serializable (if you want to pass it by value) or inherit from MarshalByRefObject so that you can deal with the object as a regular Remoting proxy to the other AppDomain.

Part of the point of spinning up the other AppDomain is precisely to prevent certain code from running, you know, like serialization that can get/set private members.

Yeah, I wasn’t proud. A whole hour.

So the next idea was to use the power of MarshalByRefObject to instantiate something in the partially-trusted AppDomain, and control it from the original fully-trusted AppDomain of the test runner. This is pretty much how we’ll solve the problem, but wait:

Gotcha 2: It’s tempting, but we can’t just make our entire test fixture inherit from MarshalByRefObject.

Let’s agree that it would be a complete pain in the arse to have to replicate the nice, established features of a test runner. Agreed? OK, with that sorted: we can’t have our test fixture inherit from MarshalByRefObject to solve this problem.

We need the partially-trusted AppDomain to “own” the instance of the test, and run it there. If we’re going to try to use an existing test runner (NUnit’s, ReSharper’s, TeamCity’s, etc.) then our first point of entry into a test is when the fixture is already running.

The solution workflow

The concept I’ve arrived at is, as always once you’ve spent ages banging your head against a wall, quite simple in hindsight.

Here’s how the workflow will happen – again, this is just within a standard test runner:

  • During fixture setup:
    • Our fixture will get set up by running code marked with the [FixtureSetUp] attribute
    • We’ll then create the partially-trusted AppDomain
    • We’ll tell that AppDomain to create a new instance of a simple marshalling class that can run a method for us when given a MethodInfo class. By calling AppDomain.CreateInstanceAndUnwrap(..), we’ll get back a Remoting proxy to that object so that we can control it from our original test runner.
    • These will both live as fields on the test fixture that we can access from each test.
  • Before each test:
    • Out test setup code, still running in the full-trust AppDomain, will get run because it’s marked with the NUnit [SetUp] attribute
    • At this point, we’ll get the name of the current test from NUnit’s TestContext, and tell our simple marshalling class to do two things over in that partial trust AppDomain:
      • Run a TestSetup method, to make sure if it has “real” setup work to do, that’s still fine
      • Run the actual method. We get that by using Reflection in our full-trust AppDomain to grab the MethodInfo of the current test name from NUnit’s context.
    • Our marshaller will then run the exact test method in the partial trust domain.
    • If the test fails, we can figure out why, and if it’s to do with permissions, BAM our time has been officially saved

“But wait!” I hear someone wail at the back, “By running the test in the SetUp part, you’re now going to run the test again in Full Trust!”

Well, I thought of that.

NUnit has a funny thing called a SuccessException. It’s how it guarantees that if you call Assert.Pass() in your test, the rest of the test will likely not execute – pretty much what you’d expect.

So, in our “management” set-up code, we’re going to intentionally throw a SuccessException. I took a look at the NUnit codebase to clarify, and sure enough that prevents the test from executing a second time.

The code, where’s the code?

Well, I thought I would just give you theory. Kidding! I’m hilarious. The downloadable code is on the next post – I really need to make my blog more developer-friendly, so for now it’s a fresh new page for us.


This post originally started out life as a three-paragraph thing, but then I realised the topic really merits a lot of background, so I thought I’d get with the cool gang and do a multi-part post.

First, I’m going to cover a bit of background about Medium Trust, and how to understand what it actually means for your code in terms of permissions.

The second post covers a solution I’ve produced over the past week and in the latest build of Umbraco.Framework.Testing which allows you to easily ensure all your NUnit tests run in partial trust.

The third post has the download and some instructions, so jump there if you want to cut to the chase.

In these posts I’ll be talking about .NET 3.5 and above – just to be clear from the outset.

Medium Nightmare


Medium Trust is probably one of the most infamous parts of an ASP.NET developer’s coding life. If you work on your own applications, hosted in Full Trust environments under the control of you or your team, you’re fine. You may have never even come across an issue. It’s this phenomenon which has created such a painful situation: so many developers write code which they reasonably expect can be deployed anywhere; it passes its tests, and works on their machine.

But if you’ve ever put together a website with some cool fandangled bit of code that runs fine locally, and then you’ve deployed it to your hosting account, only to find your beautiful creation misses you dearly and is just sat there screaming complaints of SecurityPermission this, and FieldAccessPermission that, you’ll know how tough it can be.

For many it’s the beginning of a very long and arduous process of re-engineering and debugging in what can seem like an infinite loop, and many assumptions about the way the application works (such as lazy-loading proxies in NHibernate) often need to be entirely revisited. Or not, depending on how much luck you have with your Bing search. It’s another large part of the problem: it’s such a minefield, even searching for solutions can be spotty.

It’s not all in your hands either; it’s an easy mistake to make precisely because it’s so difficult to test in a reliable way and it’s so easy to begin developing in the default setting for many ASP.Net project templates, which is: Full Trust. Fluent NHibernate, AutoMapper, certain setups of Castle DynamicProxy, of NHibernate – these are Big Name Libraries, and they all have problems. We’ve all been there: Umbraco included up until the past year or so. It’s a long list – and unpicking the problems one by one, rebuilding, and pressing F5 in your browser is a pain in the arse.

I don’t like pains in my arse, and since we’re busy building Umbraco 5 right now, I’d rather we don’t become one in yours either. I figured the other features we’re coding have test coverage, let’s get the Medium Trust issue covered too. And since it’s all open source, everyone can do it. Yeay!

Security background – what exactly is Medium Trust and its permissions?

“Medium Trust” is a loose term for a set of Code Access Security policy settings that offer less freedom to bend the server to your every will. It’s complicated by the fact that what constitutes “medium trust” is actually a set of permissions listed in configuration, and some hosting companies tailor the settings, so you don’t quite know what you’re dealing with. But in general the policy means at least the following permissions:

  • AspNetHostingPermission of “medium” – For example, a minimum requirement that calls to public types in the System.Web namespace must be coming from code that is granted at least a certain “minimal” trust level.
  • A DnsPermission which is unrestricted. Go mad on those Dns lookups.
  • An EnvironmentPermission which grants access only to the following system environment variables by default:
  • A FileIOPermission that says you may only Read, Write, Append and browse the filesystem that starts with the root of your website and nowhere else. Shocker.
  • An IsolatedStorageFilePermission which permits isolation of storage first by user, and then by code assembly. It allows you a data store for the assembly that is accessible in any domain context.
  • Bizarrely, a PrintingPermission which permits programmatic printing to the default printer.
  • A SecurityPermission which allows the following flags:
    • Execution (to allow managed code to execute – yeay!)
    • ControlPrincipal (to manipulate the Principal object i.e. set the current logged-on user)
    • ControlThread (to allow the totally unambiguous “certain advanced operations on threads”, thanks MSDN!)
    • RemotingConfiguration (to configure Remoting types and channels)
  • An SmtpPermission which allows you to connect only to port 25
  • An unrestricted SqlClientPermission
  • An unrestricted TypeDescriptorPermission
  • An unrestricted WebPermission (confused? This actually signifies unrestricted access to make HTTP requests to other services)
  • And finally the one which crops up most often, a ReflectionPermission with flags of RestrictedMemberAccess. This signifies “partially trusted code can access nonpublic types and members, but only if the grant set of the partially trusted code includes all permissions in the grant set of the assembly that contains the nonpublic types and members being accessed”. Again, thanks MSDN! In practice, this means you can’t access private members of someone else’s assemblies – and this is what brings down most libraries.

What’s important about this set of permissions is actually what it doesn’t give you. For example, let’s look at some of the SecurityPermissionFlags you could have won:

  • Calling unmanaged code
  • Ability to provide serialization services
  • Ability to create and manipulate AppDomains

Or the “MemberAccess” ReflectionPermissionFlag, which would have allowed you to use reflection to operate on all members of a class (even its privates).

Also, no OleDbClientPermission or OdbcClientPermissions are in there by default – most hosting companies add these to their Medium Trust configurations.

And certainly no RegistryPermission.

How do you know this and where is it configured?

Well, perhaps the wider point is I don’t know this by reading one handy straightforward piece of simple documentation. The top Google result for me is a piece of “retired” MSDN content left there for reference or for anyone who has run out of everything else to read in the world ever. The top Bing result is an MSDN video from 2005. I’m sure it’s very good, but it’s an exe file download. From 2005.

90% of what you need to know about Medium Trust’s permission set is stored in the web_mediumtrust.config file for the .NET version on which your application is running. On my machine, for .NET 4, that’s C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\web_mediumtrust.config.

Web_MediumTrust.config explained

The config file has a simple job: declare named sets of permissions. It does this by first declaring a list of SecurityClass elements to predefine the type names of the permissions and give them a key, and then goes on to declare PermissionSet elements which refer back to those types and pass in arguments. Here is the one installed on my dev machine in full:

  1. <configuration>
  2. <mscorlib>
  3. <security>
  4. <policy>
  5. <PolicyLevel version=“1″>
  6. <SecurityClasses>
  7. <SecurityClass Name=“AllMembershipCondition” Description=“System.Security.Policy.AllMembershipCondition, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  8. <SecurityClass Name=“AspNetHostingPermission” Description=“System.Web.AspNetHostingPermission, System, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  9. <SecurityClass Name=“DnsPermission” Description=“System.Net.DnsPermission, System, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  10. <SecurityClass Name=“EnvironmentPermission” Description=“System.Security.Permissions.EnvironmentPermission, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  11. <SecurityClass Name=“FileIOPermission” Description=“System.Security.Permissions.FileIOPermission, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  12. <SecurityClass Name=“FirstMatchCodeGroup” Description=“System.Security.Policy.FirstMatchCodeGroup, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  13. <SecurityClass Name=“IsolatedStorageFilePermission” Description=“System.Security.Permissions.IsolatedStorageFilePermission, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  14. <SecurityClass Name=“NamedPermissionSet” Description=“System.Security.NamedPermissionSet”/>
  15. <SecurityClass Name=“PrintingPermission” Description=“System.Drawing.Printing.PrintingPermission, System.Drawing, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”/>
  16. <SecurityClass Name=“SecurityPermission” Description=“System.Security.Permissions.SecurityPermission, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  17. <SecurityClass Name=“SmtpPermission” Description=“System.Net.Mail.SmtpPermission, System, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  18. <SecurityClass Name=“SqlClientPermission” Description=“System.Data.SqlClient.SqlClientPermission, System.Data, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  19. <SecurityClass Name=“StrongNameMembershipCondition” Description=“System.Security.Policy.StrongNameMembershipCondition, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  20. <SecurityClass Name=“TypeDescriptorPermission” Description=“System.Security.Permissions.TypeDescriptorPermission, System, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  21. <SecurityClass Name=“UIPermission” Description=“System.Security.Permissions.UIPermission, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  22. <SecurityClass Name=“UnionCodeGroup” Description=“System.Security.Policy.UnionCodeGroup, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  23. <SecurityClass Name=“UrlMembershipCondition” Description=“System.Security.Policy.UrlMembershipCondition, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  24. <SecurityClass Name=“WebPermission” Description=“System.Net.WebPermission, System, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  25. <SecurityClass Name=“ZoneMembershipCondition” Description=“System.Security.Policy.ZoneMembershipCondition, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  26. <SecurityClass Name=“ReflectionPermission” Description=“System.Security.Permissions.ReflectionPermission, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″/>
  27. </SecurityClasses>
  28. <NamedPermissionSets>
  29. <PermissionSet
  30. class=“NamedPermissionSet”
  31. version=“1″
  32. Unrestricted=“true”
  33. Name=“FullTrust”
  34. Description=“Allows full access to all resources”
  35. />
  36. <PermissionSet
  37. class=“NamedPermissionSet”
  38. version=“1″
  39. Name=“Nothing”
  40. Description=“Denies all resources, including the right to execute”
  41. />
  42. <PermissionSet
  43. class=“NamedPermissionSet”
  44. version=“1″
  45. Name=“ASP.Net”>
  46. <IPermission
  47. class=“AspNetHostingPermission”
  48. version=“1″
  49. Level=“Medium”
  50. />
  51. <IPermission
  52. class=“DnsPermission”
  53. version=“1″
  54. Unrestricted=“true”
  55. />
  56. <IPermission
  57. class=“EnvironmentPermission”
  58. version=“1″
  60. />
  61. <IPermission
  62. class=“FileIOPermission”
  63. version=“1″
  64. Read=“$AppDir$”
  65. Write=“$AppDir$”
  66. Append=“$AppDir$”
  67. PathDiscovery=“$AppDir$”
  68. />
  69. <IPermission
  70. class=“IsolatedStorageFilePermission”
  71. version=“1″
  72. Allowed=“AssemblyIsolationByUser”
  73. UserQuota=“9223372036854775807″
  74. />
  75. <IPermission
  76. class=“PrintingPermission”
  77. version=“1″
  78. Level=“DefaultPrinting”
  79. />
  80. <IPermission
  81. class=“SecurityPermission”
  82. version=“1″
  83. Flags=“Execution, ControlThread, ControlPrincipal, RemotingConfiguration”
  84. />
  85. <IPermission
  86. class=“SmtpPermission”
  87. version=“1″
  88. Access=“Connect”
  89. />
  90. <IPermission
  91. class=“SqlClientPermission”
  92. version=“1″
  93. Unrestricted=“true”
  94. />
  95. <IPermission
  96. class=“TypeDescriptorPermission”
  97. version=“1″
  98. Unrestricted=“true”
  99. />
  100. <IPermission
  101. class=“WebPermission”
  102. version=“1″
  103. Unrestricted=“true”
  104. />
  105. <IPermission
  106. class=“ReflectionPermission”
  107. version=“1″
  108. Flags=“RestrictedMemberAccess”/>
  109. </PermissionSet>
  110. </NamedPermissionSets>
  111. <CodeGroup
  112. class=“FirstMatchCodeGroup”
  113. version=“1″
  114. PermissionSetName=“Nothing”>
  115. <IMembershipCondition
  116. class=“AllMembershipCondition”
  117. version=“1″
  118. />
  119. <CodeGroup
  120. class=“UnionCodeGroup”
  121. version=“1″
  122. PermissionSetName=“ASP.Net”>
  123. <IMembershipCondition
  124. class=“UrlMembershipCondition”
  125. version=“1″
  126. Url=“$AppDirUrl$/*”
  127. />
  128. </CodeGroup>
  129. <CodeGroup
  130. class=“UnionCodeGroup”
  131. version=“1″
  132. PermissionSetName=“ASP.Net”>
  133. <IMembershipCondition
  134. class=“UrlMembershipCondition”
  135. version=“1″
  136. Url=“$CodeGen$/*”
  137. />
  138. </CodeGroup>
  139. </CodeGroup>
  140. </PolicyLevel>
  141. </policy>
  142. </security>
  143. </mscorlib>
  144. </configuration>

When ASP.Net spins up the AppDomain for your website, it checks the <trust> element of your web.config file (which may be inherited from a parent config that the hoster has set), and then goes to the appropriate config file to load the right set of permissions needed for the AppDomain. After that, it’s all down to security which is built-in to the CLR which transparently checks the caller’s permissions vs the callee’s permission demands when running managed code.

Can you see where I’m going with this?

Let’s get on to how and why this matters to us. In the next post I’ll outline how we can use this information to restrict tests to a very similar set of permissions.