Ejemplo n.º 1
0
        // CacheAuthorizationHandler is only attached to the CachePolicy after first time success authorization

        /// <summary>
        /// When output is cached, the OnAuthorization will be skipped
        /// </summary>
        /// <param name="context">The context</param>
        /// <param name="data">The data</param>
        /// <param name="validationStatus">The validation status</param>
        private void CacheAuthorizationHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
        {
            //  when output is cached, the cachePolicy will trigger the CacheValidateHandler to authorize user

            if (data == null)
            {
                throw new ArgumentNullException(nameof(data), "data should be AuthorizationContext");
            }

            AuthorizationContext filterContext = (AuthorizationContext)data;

            if (filterContext == null)
            {
                throw new InvalidCastException("data should be AuthorizationContext");
            }

            AuthorizeResultEnum authorizeResult = AuthorizeUser(filterContext);

            // HttpValidationStatus.Valid => return cache data
            validationStatus = authorizeResult == AuthorizeResultEnum.Success ? HttpValidationStatus.Valid : HttpValidationStatus.IgnoreThisRequest;
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Stop processing the action and return HttpUnauthorizedResult
        /// </summary>
        /// <param name="filterContext">The filter context</param>
        /// <param name="authorizeResult">The authorize result</param>
        protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext, AuthorizeResultEnum authorizeResult)
        {
            switch (authorizeResult)
            {
            case AuthorizeResultEnum.Failed_NotLoggedIn:
                // User not logged in => redirect to login page by setting the error 401
                // Owin will automatically redirect all 401 errors to login page
                filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
                break;

            case AuthorizeResultEnum.PermissionNotDefined:
                ProcessUnauthorizedError(filterContext, "Permission is not defined");
                break;

            case AuthorizeResultEnum.Failed_SuperAdminOnly:
                ProcessUnauthorizedError(filterContext, "This functionality is available for system admin only");
                break;

            // AuthorizeResultEnum.NotAuthorized
            default:
                ProcessUnauthorizedError(filterContext, $"You need to be granted permission '{this.AuthorizingPermissionId}' to access this feature. Please contact administrator for support");
                break;
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Called when authorization is required.
        /// </summary>
        /// <param name="filterContext">The filter context</param>
        /// <exception cref="System.ArgumentNullException">filterContext</exception>
        /// <exception cref="System.InvalidOperationException">ActivePermissionAttribute: Cannot Use Within Child Action Cache</exception>
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            //filterContext.Controller.ControllerContext.

            if (filterContext == null)
            {
                throw new ArgumentNullException(nameof(filterContext));
            }

            if (OutputCacheAttribute.IsChildActionCacheActive(filterContext))
            {
                // If a child action cache block is active, we need to fail immediately, even if authorization
                // would have succeeded. The reason is that there's no way to hook a callback to rerun
                // authorization before the fragment is served from the cache, so we can't guarantee that this
                // filter will be re-run on subsequent requests.

                // MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache
                throw new InvalidOperationException("ActivePermissionAttribute: Cannot Use Within Child Action Cache");
            }

            #region Skip Authorization

            /*
             * Skip the authorization if
             * - Controller / Action has AllowAnonymousAttribute
             * - Action is NonAction
             * - Action is child action
             *
             * */

            if (filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true) ||
                filterContext.ActionDescriptor.IsDefined(typeof(NonActionAttribute), inherit: true) ||
                filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true))
            {
                return;
            }

            // Authorization must be done at Root action
            if (filterContext.IsChildAction)
            {
                return;
            }

            #endregion Skip Authorization

            AuthorizeResultEnum authorizeResult = AuthorizeUser(filterContext);

            if (authorizeResult == AuthorizeResultEnum.Success)
            {
                // ** IMPORTANT **
                // Since we're performing authorization at the action level, the authorization code runs
                // after the output caching module. In the worst case this could allow an authorized user
                // to cause the page to be cached, then an unauthorized user would later be served the
                // cached page. We work around this by telling proxies not to cache the sensitive page,
                // then we hook our custom authorization code into the caching mechanism so that we have
                // the final say on whether a page should be served from the cache.

                HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
                cachePolicy.SetProxyMaxAge(new TimeSpan(0));

                // add the authorization handler for cache
                // data is filterContext
                cachePolicy.AddValidationCallback(CacheAuthorizationHandler, filterContext);
            }
            else
            {
                HandleUnauthorizedRequest(filterContext, authorizeResult);
            }
        }