Merge pull request #757 from mlintner/master
[mono.git] / mcs / class / System.Web.Mvc3 / Mvc / SecurityUtil.cs
1 namespace System.Web.Mvc {
2     using System;
3     using System.Diagnostics.CodeAnalysis;
4     using System.Reflection;
5     using System.Security;
6
7     internal static class SecurityUtil {
8
9         private static Action<Action> _callInAppTrustThunk;
10
11         // !! IMPORTANT !!
12         // Do not try to optimize this method or perform any extra caching; doing so could lead to MVC not operating
13         // correctly until the AppDomain is restarted.
14         [SuppressMessage("Microsoft.Security", "CA2107:ReviewDenyAndPermitOnlyUsage",
15             Justification = "This is essentially the same logic as Page.ProcessRequest.")]
16         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
17             Justification = "If an exception is thrown, assume we're running in same trust level as the application itself, so we don't need to do anything special.")]
18         private static Action<Action> GetCallInAppTrustThunk() {
19             // do we need to create the thunk?
20             if (_callInAppTrustThunk == null) {
21                 try {
22                     if (!typeof(SecurityUtil).Assembly.IsFullyTrusted /* bin-deployed */
23                         || AppDomain.CurrentDomain.IsHomogenous /* .NET 4 CAS model */) {
24                         // we're already running in the application's trust level, so nothing to do
25                         _callInAppTrustThunk = f => f();
26                     }
27                     else {
28                         // legacy CAS model - need to lower own permission level to be compatible with legacy systems
29                         // This is essentially the same logic as Page.ProcessRequest(HttpContext)
30                         NamedPermissionSet namedPermissionSet = (NamedPermissionSet)typeof(HttpRuntime).GetProperty("NamedPermissionSet", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).GetValue(null, null);
31                         bool disableProcessRequestInApplicationTrust = (bool)typeof(HttpRuntime).GetProperty("DisableProcessRequestInApplicationTrust", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).GetValue(null, null);
32                         if (namedPermissionSet != null && !disableProcessRequestInApplicationTrust) {
33                             _callInAppTrustThunk = f => {
34                                 // lower permissions
35                                 namedPermissionSet.PermitOnly();
36                                 f();
37                             };
38                         }
39                         else {
40                             // application's trust level is FullTrust, so nothing to do
41                             _callInAppTrustThunk = f => f();
42                         }
43                     }
44                 }
45                 catch {
46                     // MVC assembly is already running in application trust, so swallow exceptions
47                 }
48             }
49
50             // if there was an error, just process transparently
51             return _callInAppTrustThunk ?? (Action<Action>)(f => f());
52         }
53
54         public static TResult ProcessInApplicationTrust<TResult>(Func<TResult> func) {
55             TResult result = default(TResult);
56             ProcessInApplicationTrust(delegate { result = func(); });
57             return result;
58         }
59
60         public static void ProcessInApplicationTrust(Action action) {
61             Action<Action> executor = GetCallInAppTrustThunk();
62             executor(action);
63         }
64
65     }
66 }