PageRenderTime 110ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/release/v4.0/Microsoft.Security.Application.SecurityRuntimeEngine/AttributeExclusionChecker.cs

#
C# | 223 lines | 126 code | 26 blank | 71 comment | 24 complexity | 582fa4c1899cd87f61413d7e0174c60d MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. // --------------------------------------------------------------------------------------------------------------------
  2. // <copyright file="AttributeExclusionChecker.cs" company="Microsoft Corporation">
  3. // Copyright (c) 2010 All Rights Reserved, Microsoft Corporation
  4. //
  5. // This source is subject to the Microsoft Permissive License.
  6. // Please see the License.txt file for more information.
  7. // All other rights reserved.
  8. //
  9. // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  10. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  11. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  12. // PARTICULAR PURPOSE.
  13. // </copyright>
  14. // <summary>
  15. // A utility class for attribute based exclusion checks.
  16. // </summary>
  17. // --------------------------------------------------------------------------------------------------------------------
  18. namespace Microsoft.Security.Application.SecurityRuntimeEngine
  19. {
  20. using System;
  21. using System.Collections.Generic;
  22. using System.Globalization;
  23. using System.Linq;
  24. using System.Reflection;
  25. using System.Threading;
  26. using System.Web.UI;
  27. /// <summary>
  28. /// Provides attribute exclusion checks
  29. /// </summary>
  30. public static class AttributeExclusionChecker
  31. {
  32. /// <summary>
  33. /// The lock to use when reading or writing from the type exclusion cache.
  34. /// </summary>
  35. private static readonly ReaderWriterLockSlim TypeLevelSyncLock = new ReaderWriterLockSlim();
  36. /// <summary>
  37. /// A list of types where type checking has already occurred.
  38. /// </summary>
  39. private static readonly List<Type> TypeExclusionCheckPerformedCache = new List<Type>();
  40. /// <summary>
  41. /// A list of type level exclusions.
  42. /// </summary>
  43. private static readonly List<string> TypeExclusionsCache = new List<string>();
  44. /// <summary>
  45. /// Gets a list of unique identifiers of Web Forms controls contained within a page which are
  46. /// excluded from processing by the specified plug-in.
  47. /// </summary>
  48. /// <param name="container">The instance of a <see cref="System.Web.UI.Page"/> to examine.</param>
  49. /// <param name="plugIn">The type of the plug-in to exclude.</param>
  50. /// <returns>A list of <see cref="System.Web.UI.Control.UniqueID"/>s of any excluded controls.</returns>
  51. public static IEnumerable<string> GetExcludedControlUniqueIdsForContainer(Control container, Type plugIn)
  52. {
  53. if (container == null)
  54. {
  55. throw new ArgumentNullException("container");
  56. }
  57. if (plugIn == null)
  58. {
  59. throw new ArgumentNullException("plugIn");
  60. }
  61. List<string> excludedUniqueControlIds = new List<string>();
  62. if (!container.HasControls())
  63. {
  64. return excludedUniqueControlIds;
  65. }
  66. List<FieldInfo> pageFieldInformationForWebControls = new List<FieldInfo>();
  67. // Extract the field information for the provided page and filter it to only those fields which inherit from System.Web.UI.Control.
  68. FieldInfo[] publicFieldInfo = container.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public);
  69. pageFieldInformationForWebControls.AddRange(GetWebControlsWhichAreNotTypeExcluded(publicFieldInfo, plugIn));
  70. FieldInfo[] nonPublicFieldInfo = container.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
  71. pageFieldInformationForWebControls.AddRange(GetWebControlsWhichAreNotTypeExcluded(nonPublicFieldInfo, plugIn));
  72. // Loop through each of the controls looking for any with the SupressProtectionAttribute applied to them.
  73. foreach (FieldInfo fieldInfo in pageFieldInformationForWebControls)
  74. {
  75. object[] attributes = Attribute.GetCustomAttributes(fieldInfo, typeof(SuppressProtectionAttribute), true);
  76. if (attributes.Length == 0)
  77. {
  78. continue;
  79. }
  80. // Get the actual field instance.
  81. object fieldObject = fieldInfo.GetValue(container);
  82. // The Page class uses the composition pattern and contains a private field, Page which is itself.
  83. // We don't want that, otherwise we're going to get into all sorts of fun loops later on.
  84. // This should never happen - page level exclusion checks happen in the SRE code however better to be safe
  85. // than sorry.
  86. if (fieldObject == container)
  87. {
  88. continue;
  89. }
  90. Control control = fieldObject as Control;
  91. if (control != null)
  92. {
  93. excludedUniqueControlIds.AddRange(
  94. from exclusionAttribute in attributes.OfType<SuppressProtectionAttribute>()
  95. where exclusionAttribute.PlugInType == null || exclusionAttribute.PlugInType == plugIn
  96. select control.UniqueID);
  97. }
  98. }
  99. return excludedUniqueControlIds;
  100. }
  101. /// <summary>
  102. /// Returns a value indicating whether the specified processor has been excluded from the specified page type.
  103. /// </summary>
  104. /// <param name="type">The type of the page to check.</param>
  105. /// <param name="plugIn">The processor type to check.</param>
  106. /// <returns><c>true</c> if the processor has been excluded, otherwise <c>false</c>.</returns>
  107. internal static bool IsPlugInExcludedForType(Type type, Type plugIn)
  108. {
  109. if (type == null)
  110. {
  111. throw new ArgumentNullException("type");
  112. }
  113. if (plugIn == null)
  114. {
  115. throw new ArgumentNullException("plugIn");
  116. }
  117. if (!HasTypeLevelCheckingTakenPlace(type))
  118. {
  119. CacheAttributeBasedExclusions(type);
  120. }
  121. TypeLevelSyncLock.EnterReadLock();
  122. try
  123. {
  124. return TypeExclusionsCache.Contains(type.AssemblyQualifiedName) || // All plug-ins
  125. TypeExclusionsCache.Contains(GetTypePlugInCombinationCacheKey(type, plugIn)); // Specified plug-in
  126. }
  127. finally
  128. {
  129. TypeLevelSyncLock.ExitReadLock();
  130. }
  131. }
  132. /// <summary>
  133. /// Returns a subset of the specified <see cref="FieldInfo"/>s containing
  134. /// the fields which are web controls and are not excluded from processing by the plug-in, based on the field type.
  135. /// </summary>
  136. /// <param name="fields">The <see cref="FieldInfo"/>s to examine.</param>
  137. /// <param name="plugIn">The excluded plug-in.</param>
  138. /// <returns>A subset of the specified <see cref="FieldInfo"/>s which are web controls and are not excluded from plug-in processing based on their type.</returns>
  139. private static IEnumerable<FieldInfo> GetWebControlsWhichAreNotTypeExcluded(IEnumerable<FieldInfo> fields, Type plugIn)
  140. {
  141. return fields.Where(fieldInfo => fieldInfo.FieldType.IsSubclassOf(typeof(Control)) && !IsPlugInExcludedForType(fieldInfo.FieldType, plugIn)).ToList();
  142. }
  143. /// <summary>
  144. /// Returns a value indicating whether attribute checking has already taken place for the specified type.
  145. /// </summary>
  146. /// <param name="type">The type to check</param>
  147. /// <returns><c>true</c> if page level checking has already taken place, otherwise <c>false</c>.</returns>
  148. private static bool HasTypeLevelCheckingTakenPlace(Type type)
  149. {
  150. TypeLevelSyncLock.EnterReadLock();
  151. try
  152. {
  153. return TypeExclusionCheckPerformedCache.Contains(type);
  154. }
  155. finally
  156. {
  157. TypeLevelSyncLock.ExitReadLock();
  158. }
  159. }
  160. /// <summary>
  161. /// Extracts the attribute based exclusions for the specified type and caches them.
  162. /// </summary>
  163. /// <param name="type">The type to extract the exclusions from.</param>
  164. private static void CacheAttributeBasedExclusions(Type type)
  165. {
  166. TypeLevelSyncLock.EnterWriteLock();
  167. try
  168. {
  169. TypeExclusionCheckPerformedCache.Add(type);
  170. object[] attributeArray = type.GetCustomAttributes(typeof(SuppressProtectionAttribute), true);
  171. if (attributeArray.Length == 0)
  172. {
  173. return;
  174. }
  175. foreach (SuppressProtectionAttribute exclusionAttribute in
  176. attributeArray.OfType<SuppressProtectionAttribute>())
  177. {
  178. TypeExclusionsCache.Add(GetTypePlugInCombinationCacheKey(type, exclusionAttribute.PlugInType));
  179. }
  180. }
  181. finally
  182. {
  183. TypeLevelSyncLock.ExitWriteLock();
  184. }
  185. }
  186. /// <summary>
  187. /// Generates a cache key from the type and plug-in type provided.
  188. /// </summary>
  189. /// <param name="type">The type whose exclusions should be cached.</param>
  190. /// <param name="plugIn">The plug-in type to cache.</param>
  191. /// <returns>A cache key from the type and plug-in types provided.</returns>
  192. private static string GetTypePlugInCombinationCacheKey(Type type, Type plugIn)
  193. {
  194. return plugIn == null ? type.AssemblyQualifiedName : string.Format(CultureInfo.InvariantCulture, "{0}\\{1}", type.AssemblyQualifiedName, plugIn.AssemblyQualifiedName);
  195. }
  196. }
  197. }