Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Web / misc / SecurityUtils.cs
blob159dedbb6c64824800d5117d1e9af67d2c300f84
1 //------------------------------------------------------------------------------
2 // <copyright file="SecurityUtils.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
7 /*
8 */
11 #if Microsoft_NAMESPACE
12 namespace System.Windows.Forms
13 #elif DRAWING_NAMESPACE
14 namespace System.Drawing
15 #elif Microsoft_PUBLIC_GRAPHICS_LIBRARY
16 namespace System.Internal
17 #elif SYSTEM_NAMESPACE
18 namespace System
19 #elif SYSTEM_WEB
20 namespace System.Web
21 #elif SYSTEM_DATA_LINQ
22 namespace System.Data.Linq
23 #else
24 namespace System.Windows.Forms
25 #endif
27 using System;
28 using System.Reflection;
29 using System.Diagnostics.CodeAnalysis;
30 using System.Security;
31 using System.Security.Permissions;
33 /// <devdoc>
34 /// Useful methods to securely call 'dangerous' managed APIs (especially reflection).
35 /// See http://wiki/default.aspx/Microsoft.Projects.DotNetClient.SecurityConcernsAroundReflection
36 /// for more information specifically about why we need to be careful about reflection invocations.
37 /// </devdoc>
38 internal static class SecurityUtils {
40 private static volatile ReflectionPermission memberAccessPermission = null;
41 private static volatile ReflectionPermission restrictedMemberAccessPermission = null;
43 private static ReflectionPermission MemberAccessPermission
45 get {
46 if (memberAccessPermission == null) {
47 memberAccessPermission = new ReflectionPermission(ReflectionPermissionFlag.MemberAccess);
49 return memberAccessPermission;
53 private static ReflectionPermission RestrictedMemberAccessPermission {
54 get {
55 if (restrictedMemberAccessPermission == null) {
56 restrictedMemberAccessPermission = new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess);
58 return restrictedMemberAccessPermission;
62 private static void DemandReflectionAccess(Type type) {
63 try {
64 MemberAccessPermission.Demand();
66 catch (SecurityException) {
67 DemandGrantSet(type.Assembly);
71 [SecuritySafeCritical]
72 private static void DemandGrantSet(Assembly assembly) {
73 PermissionSet targetGrantSet = assembly.PermissionSet;
74 targetGrantSet.AddPermission(RestrictedMemberAccessPermission);
75 targetGrantSet.Demand();
78 private static bool HasReflectionPermission(Type type) {
79 try {
80 DemandReflectionAccess(type);
81 return true;
83 catch (SecurityException) {
86 return false;
90 /// <devdoc>
91 /// This helper method provides safe access to Activator.CreateInstance.
92 /// NOTE: This overload will work only with public .ctors.
93 /// </devdoc>
94 internal static object SecureCreateInstance(Type type) {
95 return SecureCreateInstance(type, null, false);
99 /// <devdoc>
100 /// This helper method provides safe access to Activator.CreateInstance.
101 /// Set allowNonPublic to true if you want non public ctors to be used.
102 /// </devdoc>
103 internal static object SecureCreateInstance(Type type, object[] args, bool allowNonPublic) {
104 if (type == null) {
105 throw new ArgumentNullException("type");
108 BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance;
110 // if it's an internal type, we demand reflection permission.
111 if (!type.IsVisible) {
112 DemandReflectionAccess(type);
114 else if (allowNonPublic && !HasReflectionPermission(type)) {
115 // Someone is trying to instantiate a public type in *our* assembly, but does not
116 // have full reflection permission. We shouldn't pass BindingFlags.NonPublic in this case.
117 // The reason we don't directly demand the permission here is because we don't know whether
118 // a public or non-public .ctor will be invoked. We want to allow the public .ctor case to
119 // succeed.
120 allowNonPublic = false;
123 if (allowNonPublic) {
124 flags |= BindingFlags.NonPublic;
127 return Activator.CreateInstance(type, flags, null, args, null);
130 #if (!Microsoft_NAMESPACE)
132 /// <devdoc>
133 /// This helper method provides safe access to Activator.CreateInstance.
134 /// NOTE: This overload will work only with public .ctors.
135 /// </devdoc>
136 internal static object SecureCreateInstance(Type type, object[] args) {
137 return SecureCreateInstance(type, args, false);
141 /// <devdoc>
142 /// Helper method to safely invoke a .ctor. You should prefer SecureCreateInstance to this.
143 /// Set allowNonPublic to true if you want non public ctors to be used.
144 /// </devdoc>
145 internal static object SecureConstructorInvoke(Type type, Type[] argTypes, object[] args, bool allowNonPublic) {
146 return SecureConstructorInvoke(type, argTypes, args, allowNonPublic, BindingFlags.Default);
149 /// <devdoc>
150 /// Helper method to safely invoke a .ctor. You should prefer SecureCreateInstance to this.
151 /// Set allowNonPublic to true if you want non public ctors to be used.
152 /// The 'extraFlags' parameter is used to pass in any other flags you need,
153 /// besides Public, NonPublic and Instance.
154 /// </devdoc>
155 internal static object SecureConstructorInvoke(Type type, Type[] argTypes, object[] args,
156 bool allowNonPublic, BindingFlags extraFlags) {
157 if (type == null) {
158 throw new ArgumentNullException("type");
161 // if it's an internal type, we demand reflection permission.
162 if (!type.IsVisible) {
163 DemandReflectionAccess(type);
165 else if (allowNonPublic && !HasReflectionPermission(type)) {
166 // Someone is trying to invoke a ctor on a public type, but does not
167 // have full reflection permission. We shouldn't pass BindingFlags.NonPublic in this case.
168 allowNonPublic = false;
171 BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | extraFlags;
172 if (!allowNonPublic) {
173 flags &= ~BindingFlags.NonPublic;
176 ConstructorInfo ctor = type.GetConstructor(flags, null, argTypes, null);
177 if (ctor != null) {
178 return ctor.Invoke(args);
181 return null;
184 private static bool GenericArgumentsAreVisible(MethodInfo method) {
185 if (method.IsGenericMethod) {
186 Type[] parameterTypes = method.GetGenericArguments();
187 foreach (Type type in parameterTypes) {
188 if (!type.IsVisible) {
189 return false;
193 return true;
196 /// <devdoc>
197 /// This helper method provides safe access to FieldInfo's GetValue method.
198 /// </devdoc>
199 internal static object FieldInfoGetValue(FieldInfo field, object target) {
200 Type type = field.DeclaringType;
201 if (type == null) {
202 // Type is null for Global fields.
203 if (!field.IsPublic) {
204 DemandGrantSet(field.Module.Assembly);
206 } else if (!(type != null && type.IsVisible && field.IsPublic)) {
207 DemandReflectionAccess(type);
209 return field.GetValue(target);
212 /// <devdoc>
213 /// This helper method provides safe access to MethodInfo's Invoke method.
214 /// </devdoc>
215 internal static object MethodInfoInvoke(MethodInfo method, object target, object[] args) {
216 Type type = method.DeclaringType;
217 if (type == null) {
218 // Type is null for Global methods. In this case we would need to demand grant set on
219 // the containing assembly for internal methods.
220 if (!(method.IsPublic && GenericArgumentsAreVisible(method))) {
221 DemandGrantSet(method.Module.Assembly);
223 } else if (!(type.IsVisible && method.IsPublic && GenericArgumentsAreVisible(method))) {
224 // this demand is required for internal types in system.dll and its friend assemblies.
225 DemandReflectionAccess(type);
227 return method.Invoke(target, args);
230 /// <devdoc>
231 /// This helper method provides safe access to ConstructorInfo's Invoke method.
232 /// Constructors can't be generic, so we don't check if argument types are visible
233 /// </devdoc>
234 internal static object ConstructorInfoInvoke(ConstructorInfo ctor, object[] args) {
235 Type type = ctor.DeclaringType;
236 if ((type != null) && !(type.IsVisible && ctor.IsPublic)) {
237 DemandReflectionAccess(type);
239 return ctor.Invoke(args);
242 /// <devdoc>
243 /// This helper method provides safe access to Array.CreateInstance.
244 /// </devdoc>
245 internal static object ArrayCreateInstance(Type type, int length) {
246 if (!type.IsVisible) {
247 DemandReflectionAccess(type);
249 return Array.CreateInstance(type, length);
251 #endif