Fix bugs in sizing TableLayoutPanel (Xamarin bug 18638)
[mono.git] / mcs / class / System.Web.Mvc / System.Web.Mvc / AuthorizeAttribute.cs
1 /* ****************************************************************************\r
2  *\r
3  * Copyright (c) Microsoft Corporation. All rights reserved.\r
4  *\r
5  * This software is subject to the Microsoft Public License (Ms-PL). \r
6  * A copy of the license can be found in the license.htm file included \r
7  * in this distribution.\r
8  *\r
9  * You must not remove this notice, or any other, from this software.\r
10  *\r
11  * ***************************************************************************/\r
12 \r
13 namespace System.Web.Mvc {\r
14     using System;\r
15     using System.Diagnostics.CodeAnalysis;\r
16     using System.Linq;\r
17     using System.Security.Principal;\r
18     using System.Web;\r
19 \r
20     [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes",\r
21         Justification = "Unsealed so that subclassed types can set properties in the default constructor or override our behavior.")]\r
22     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]\r
23     public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter {\r
24 \r
25         private string _roles;\r
26         private string[] _rolesSplit = new string[0];\r
27         private string _users;\r
28         private string[] _usersSplit = new string[0];\r
29 \r
30         public string Roles {\r
31             get {\r
32                 return _roles ?? String.Empty;\r
33             }\r
34             set {\r
35                 _roles = value;\r
36                 _rolesSplit = SplitString(value);\r
37             }\r
38         }\r
39 \r
40         public string Users {\r
41             get {\r
42                 return _users ?? String.Empty;\r
43             }\r
44             set {\r
45                 _users = value;\r
46                 _usersSplit = SplitString(value);\r
47             }\r
48         }\r
49 \r
50         // This method must be thread-safe since it is called by the thread-safe OnCacheAuthorization() method.\r
51         protected virtual bool AuthorizeCore(HttpContextBase httpContext) {\r
52             if (httpContext == null) {\r
53                 throw new ArgumentNullException("httpContext");\r
54             }\r
55 \r
56             IPrincipal user = httpContext.User;\r
57             if (!user.Identity.IsAuthenticated) {\r
58                 return false;\r
59             }\r
60 \r
61             if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase)) {\r
62                 return false;\r
63             }\r
64 \r
65             if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole)) {\r
66                 return false;\r
67             }\r
68 \r
69             return true;\r
70         }\r
71 \r
72         private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus) {\r
73             validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));\r
74         }\r
75 \r
76         public virtual void OnAuthorization(AuthorizationContext filterContext) {\r
77             if (filterContext == null) {\r
78                 throw new ArgumentNullException("filterContext");\r
79             }\r
80 \r
81             if (AuthorizeCore(filterContext.HttpContext)) {\r
82                 // ** IMPORTANT **\r
83                 // Since we're performing authorization at the action level, the authorization code runs\r
84                 // after the output caching module. In the worst case this could allow an authorized user\r
85                 // to cause the page to be cached, then an unauthorized user would later be served the\r
86                 // cached page. We work around this by telling proxies not to cache the sensitive page,\r
87                 // then we hook our custom authorization code into the caching mechanism so that we have\r
88                 // the final say on whether a page should be served from the cache.\r
89 \r
90                 HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;\r
91                 cachePolicy.SetProxyMaxAge(new TimeSpan(0));\r
92                 cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);\r
93             }\r
94             else {\r
95                 // auth failed, redirect to login page\r
96                 filterContext.Result = new HttpUnauthorizedResult();\r
97             }\r
98         }\r
99 \r
100         // This method must be thread-safe since it is called by the caching module.\r
101         protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext) {\r
102             if (httpContext == null) {\r
103                 throw new ArgumentNullException("httpContext");\r
104             }\r
105 \r
106             bool isAuthorized = AuthorizeCore(httpContext);\r
107             return (isAuthorized) ? HttpValidationStatus.Valid : HttpValidationStatus.IgnoreThisRequest;\r
108         }\r
109 \r
110         internal static string[] SplitString(string original) {\r
111             if (String.IsNullOrEmpty(original)) {\r
112                 return new string[0];\r
113             }\r
114 \r
115             var split = from piece in original.Split(',')\r
116                         let trimmed = piece.Trim()\r
117                         where !String.IsNullOrEmpty(trimmed)\r
118                         select trimmed;\r
119             return split.ToArray();\r
120         }\r
121 \r
122     }\r
123 }\r