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