Manual Authentication Discovery

I have a custom AuthorizeAttribute in an obsolete MVC5 project:

 public class AuthorizeWithLoggingAttribute : AuthorizeAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { if (!base.AuthorizeCore(httpContext)) {Log(FilterContext);} } } 

When we looked at the logs, we noticed that in addition to applying to controllers with [AuthorizeWithLogging] it was explicitly called in another place in the code, generating false logs:

 var filters = new FilterInfo(FilterProviders.Providers.GetFilters(controllerContext, actionDescriptor)); foreach (var authFilter in filters.AuthorizationFilters) { authFilter.OnAuthorization(authContext); if (authContext.Result != null) {return false;} } 

Is there a way to tell (via StackTrace or something else) whether the OnAuthorization method OnAuthorization explicitly called or called from an attribute? The best I have is Environment.StackTrace.Contains("at System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters") .

+7
c # asp.net-mvc-5 custom-attributes
source share
2 answers

AuthorizeAttribute has a separate responsibility: determine if the user is allowed. This can be used in several places of the application for various reasons.

Any actions taken as a result of non-authorization (for example, returning an HTTP 401 response) are delegated to a handler of type ActionResult , which is set to the AuthorizationContext.Result property. For example, the default implementation of AuthorizeAttribute.HandleUnauthorizedRequest is used here:

 protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext) { // Returns HTTP 401 - see comment in HttpUnauthorizedResult.cs. filterContext.Result = new HttpUnauthorizedResult(); } 

If you are trying to perform an audit when the user is not logged in, you should put the audit in the ActionResult handler, and not in the user AuthorizeAttribute . This ensures that an audit will only be performed if an ActionResult is ActionResult (that is, when the current page is not authorized), but authorization is not checked in all cases.

 public class AuthorizeWithLoggingAttribute : AuthorizeAttribute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { filterContext.Result = new LoggingActionResult(new HttpUnauthorizedResult(), filterContext); } } public class LoggingActionResult : ActionResult { private readonly ActionResult innerActionResult; private readonly AuthorizationContext filterContext; public LoggingActionResult(ActionResult innerActionResult, AuthorizationContext filterContext) { if (innerActionResult == null) throw new ArgumentNullException("innerActionResult"); if (filterContext == null) throw new ArgumentNullException("filterContext"); this.innerActionResult = innerActionResult; this.filterContext = filterContext; } public override void ExecuteResult(ControllerContext context) { // Do logging (or apparently you want auditing) here Log(this.filterContext); innerActionResult.ExecuteResult(context); } } 

NOTE. I would call them AuthorizeWithAuditingAttribute and AuditingActionResult , since you explicitly need an audit, not registration in this case.

+1
source share

One route you could go with would be using a StackFrame . It will be a little cleaner than what you currently have. More information can be found here: How to find the method that called the current method

+1
source share

All Articles