PageRenderTime 39ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/Test/SystemWebMvcTest/Mvc/Test/AspNetHostingPermissionAttributeTest.cs

https://bitbucket.org/markhneedham/aspnet-mvc
C# | 190 lines | 156 code | 21 blank | 13 comment | 29 complexity | 73b4d0c5ec263f2480d4e3cea8ffbd3d MD5 | raw file
  1. namespace System.Web.Mvc.Test {
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Reflection;
  5. using System.Security;
  6. using System.Security.Permissions;
  7. using System.Web;
  8. using System.Web.Mvc;
  9. using Microsoft.VisualStudio.TestTools.UnitTesting;
  10. [TestClass]
  11. public class AspNetHostingPermissionAttributeTest {
  12. private List<string> _failures;
  13. [TestInitialize]
  14. public void Setup() {
  15. _failures = new List<string>();
  16. }
  17. private static bool AccessibleFromPartiallyTrustedClientApplication(Type type) {
  18. return (type.Namespace.StartsWith("System.Web.ClientServices") ||
  19. type.Assembly.GetName().Name == "System.ComponentModel.DataAnnotations");
  20. }
  21. private static bool AssemblyIsSecurityTransparent(Assembly assembly) {
  22. Attribute[] attrs = Attribute.GetCustomAttributes(assembly, typeof(SecurityTransparentAttribute));
  23. return attrs.Length > 0;
  24. }
  25. [TestMethod]
  26. // Verifies that all types in System.Web.Mvc have the correct AspNetHostingPermission attributes.
  27. public void AspNetHostingPermissionAttribute() {
  28. VerifyRuntimeAssembly(typeof(Controller).Assembly);
  29. Assert.AreEqual(0, _failures.Count,
  30. Environment.NewLine + String.Join(Environment.NewLine, _failures.ToArray()));
  31. }
  32. private void VerifyRuntimeAssembly(Assembly asm) {
  33. foreach (Type type in asm.GetTypes()) {
  34. object[] attrs = type.GetCustomAttributes(typeof(AspNetHostingPermissionAttribute), false);
  35. VerifyActions(type, attrs);
  36. if (IsPublic(type)) {
  37. if (AccessibleFromPartiallyTrustedClientApplication(type)) {
  38. VerifyNoLinkDemand(type, attrs, "accessible from partially-trusted client applications",
  39. "Types accessible from partially-trusted client applications");
  40. VerifyNoInheritanceDemand(type, attrs, "accessible from partially-trusted client applications",
  41. "Types accessible from partially-trusted client applications");
  42. }
  43. else if (AssemblyIsSecurityTransparent(type.Assembly)) {
  44. // We should eventually ensure there are no link or inheritance demands for these assemblies.
  45. // However, we do a no-op for now, since I don't want to remove the attributes until we are sure
  46. // we are shipping as SecurityTransparent.
  47. /*
  48. VerifyNoLinkDemand(type, attrs, "in a SecurityTransparent assembly",
  49. "Types in SecurityTransparent assemblies");
  50. VerifyNoInheritanceDemand(type, attrs, "in a SecurityTransparent assembly",
  51. "Types in SecurityTransparent assemblies");
  52. */
  53. }
  54. else if (!type.IsValueType) {
  55. VerifyLinkDemand(type, attrs);
  56. if (!type.IsSealed) {
  57. VerifyInheritanceDemand(type, attrs);
  58. }
  59. else {
  60. VerifyNoInheritanceDemand(type, attrs, "sealed", "Sealed types");
  61. }
  62. }
  63. else {
  64. VerifyNoLinkDemand(type, attrs, "a value type", "Value types");
  65. VerifyNoInheritanceDemand(type, attrs, "a value type", "Value types");
  66. }
  67. }
  68. else {
  69. VerifyNoLinkDemand(type, attrs, "non-public", "Non-public types");
  70. VerifyNoInheritanceDemand(type, attrs, "non-public", "Non-public types");
  71. }
  72. VerifyMembers(type);
  73. }
  74. }
  75. private void AssertIsTrue(bool condition, string message, params object[] parameters) {
  76. if (!condition) {
  77. _failures.Add(String.Format(message, parameters));
  78. }
  79. }
  80. private void AssertIsFalse(bool condition, string message, params object[] parameters) {
  81. AssertIsTrue(!condition, message, parameters);
  82. }
  83. private static bool HasLinkDemand(Type type, object[] attrs) {
  84. foreach (AspNetHostingPermissionAttribute attr in attrs) {
  85. if (attr.Action == SecurityAction.LinkDemand && attr.Level >= AspNetHostingPermissionLevel.Minimal) {
  86. return true;
  87. }
  88. }
  89. return false;
  90. }
  91. private static bool HasInheritanceDemand(Type type, object[] attrs) {
  92. foreach (AspNetHostingPermissionAttribute attr in attrs) {
  93. if (attr.Action == SecurityAction.InheritanceDemand && attr.Level >= AspNetHostingPermissionLevel.Minimal) {
  94. return true;
  95. }
  96. }
  97. return false;
  98. }
  99. private static bool IsPublic(Type type) {
  100. // We only consider a nested type public if its enclosing type is also considered public.
  101. return (type.IsPublic || (type.IsNestedPublic && IsPublic(type.DeclaringType)));
  102. }
  103. private void VerifyActions(Type type, object[] attrs) {
  104. bool hasLinkDemand = false;
  105. bool hasInheritanceDemand = false;
  106. foreach (AspNetHostingPermissionAttribute attr in attrs) {
  107. AssertIsTrue(
  108. attr.Action == SecurityAction.LinkDemand || attr.Action == SecurityAction.InheritanceDemand,
  109. "Type '{0}' uses the AspNetHostingPermission attribute with SecurityAction.{1}. " +
  110. "It should only be used with SecurityAction.LinkDemand or SecurityAction.InheritanceDemand.",
  111. type.FullName, attr.Action.ToString());
  112. if (attr.Action == SecurityAction.LinkDemand) {
  113. AssertIsFalse(
  114. hasLinkDemand,
  115. "Type '{0}' specifies AspNetHostingPermission(SecurityAction.LinkDemand) multiple times. " +
  116. "The attribute should be specified at most one time.",
  117. type.FullName);
  118. hasLinkDemand = true;
  119. }
  120. if (attr.Action == SecurityAction.InheritanceDemand) {
  121. AssertIsFalse(
  122. hasInheritanceDemand,
  123. "Type '{0}' specifies AspNetHostingPermission(SecurityAction.InheritanceDemand) multiple times. " +
  124. "The attribute should be specified at most one time.",
  125. type.FullName);
  126. hasInheritanceDemand = true;
  127. }
  128. }
  129. }
  130. private void VerifyInheritanceDemand(Type type, object[] attrs) {
  131. AssertIsTrue(HasInheritanceDemand(type, attrs),
  132. "Type '{0}' is missing AspNetHostingPermission(SecurityAction.InheritanceDemand) with Level >= Minimal. " +
  133. "All public unsealed reference types in assembly '{1}' must have this attribute.",
  134. type.FullName, type.Assembly.GetName().Name);
  135. }
  136. private void VerifyLinkDemand(Type type, object[] attrs) {
  137. AssertIsTrue(HasLinkDemand(type, attrs),
  138. "Type '{0}' is missing AspNetHostingPermission(SecurityAction.LinkDemand) with Level >= Minimal. " +
  139. "All public reference types in assembly '{1}' must have this attribute.",
  140. type.FullName, type.Assembly.GetName().Name);
  141. }
  142. private void VerifyMembers(Type type) {
  143. MemberInfo[] members = type.GetMembers(BindingFlags.Public | BindingFlags.NonPublic |
  144. BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
  145. foreach (MemberInfo member in members) {
  146. object[] attrs = member.GetCustomAttributes(typeof(AspNetHostingPermissionAttribute), false);
  147. object[] allCasAttrs = member.GetCustomAttributes(typeof(CodeAccessSecurityAttribute), false);
  148. // Members should only have the AspNetHostingPermission attribute if they have other CAS attributes
  149. // as well (FxCop rule CA2114:MethodSecurityShouldBeASupersetOfType).
  150. AssertIsTrue((attrs.Length == 0) || (attrs.Length < allCasAttrs.Length),
  151. "Member '{0}.{1}' has the AspNetHostingPermission attribute. Members should only have this " +
  152. "attribute if they have other CodeAccessSecurityAttributes as well.",
  153. member.DeclaringType.FullName, member.Name);
  154. }
  155. }
  156. private void VerifyNoInheritanceDemand(Type type, object[] attrs, string reason1, string reason2) {
  157. AssertIsFalse(HasInheritanceDemand(type, attrs),
  158. "Type '{0}' is {1}, but it has AspNetHostingPermission(SecurityAction.InheritanceDemand) with Level >= Minimal. " +
  159. "{2} should not have this attribute.",
  160. type.FullName, reason1, reason2);
  161. }
  162. private void VerifyNoLinkDemand(Type type, object[] attrs, string reason1, string reason2) {
  163. AssertIsFalse(HasLinkDemand(type, attrs),
  164. "Type '{0}' is {1}, but it has AspNetHostingPermission(SecurityAction.LinkDemand) with Level >= Minimal. " +
  165. "{2} should not have this attribute.",
  166. type.FullName, reason1, reason2);
  167. }
  168. }
  169. }