Fix bugs in sizing TableLayoutPanel (Xamarin bug 18638)
[mono.git] / mcs / class / System.Web.Mvc2 / 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 readonly object _typeId = new object();\r
26 \r
27         private string _roles;\r
28         private string[] _rolesSplit = new string[0];\r
29         private string _users;\r
30         private string[] _usersSplit = new string[0];\r
31 \r
32         public string Roles {\r
33             get {\r
34                 return _roles ?? String.Empty;\r
35             }\r
36             set {\r
37                 _roles = value;\r
38                 _rolesSplit = SplitString(value);\r
39             }\r
40         }\r
41 \r
42         public override object TypeId {\r
43             get {\r
44                 return _typeId;\r
45             }\r
46         }\r
47 \r
48         public string Users {\r
49             get {\r
50                 return _users ?? String.Empty;\r
51             }\r
52             set {\r
53                 _users = value;\r
54                 _usersSplit = SplitString(value);\r
55             }\r
56         }\r
57 \r
58         // This method must be thread-safe since it is called by the thread-safe OnCacheAuthorization() method.\r
59         protected virtual bool AuthorizeCore(HttpContextBase httpContext) {\r
60             if (httpContext == null) {\r
61                 throw new ArgumentNullException("httpContext");\r
62             }\r
63 \r
64             IPrincipal user = httpContext.User;\r
65             if (!user.Identity.IsAuthenticated) {\r
66                 return false;\r
67             }\r
68 \r
69             if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase)) {\r
70                 return false;\r
71             }\r
72 \r
73             if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole)) {\r
74                 return false;\r
75             }\r
76 \r
77             return true;\r
78         }\r
79 \r
80         private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus) {\r
81             validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));\r
82         }\r
83 \r
84         public virtual void OnAuthorization(AuthorizationContext filterContext) {\r
85             if (filterContext == null) {\r
86                 throw new ArgumentNullException("filterContext");\r
87             }\r
88 \r
89             if (AuthorizeCore(filterContext.HttpContext)) {\r
90                 // ** IMPORTANT **\r
91                 // Since we're performing authorization at the action level, the authorization code runs\r
92                 // after the output caching module. In the worst case this could allow an authorized user\r
93                 // to cause the page to be cached, then an unauthorized user would later be served the\r
94                 // cached page. We work around this by telling proxies not to cache the sensitive page,\r
95                 // then we hook our custom authorization code into the caching mechanism so that we have\r
96                 // the final say on whether a page should be served from the cache.\r
97 \r
98                 HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;\r
99                 cachePolicy.SetProxyMaxAge(new TimeSpan(0));\r
100                 cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);\r
101             }\r
102             else {\r
103                 HandleUnauthorizedRequest(filterContext);\r
104             }\r
105         }\r
106 \r
107         protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext) {\r
108             // Returns HTTP 401 - see comment in HttpUnauthorizedResult.cs.\r
109             filterContext.Result = new HttpUnauthorizedResult();\r
110         }\r
111 \r
112         // This method must be thread-safe since it is called by the caching module.\r
113         protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext) {\r
114             if (httpContext == null) {\r
115                 throw new ArgumentNullException("httpContext");\r
116             }\r
117 \r
118             bool isAuthorized = AuthorizeCore(httpContext);\r
119             return (isAuthorized) ? HttpValidationStatus.Valid : HttpValidationStatus.IgnoreThisRequest;\r
120         }\r
121 \r
122         internal static string[] SplitString(string original) {\r
123             if (String.IsNullOrEmpty(original)) {\r
124                 return new string[0];\r
125             }\r
126 \r
127             var split = from piece in original.Split(',')\r
128                         let trimmed = piece.Trim()\r
129                         where !String.IsNullOrEmpty(trimmed)\r
130                         select trimmed;\r
131             return split.ToArray();\r
132         }\r
133 \r
134     }\r
135 }\r