From afdfcaa30c5f299a61e3ff62fafc2af15129c226 Mon Sep 17 00:00:00 2001 From: Gareth James Date: Sat, 17 Mar 2018 08:32:19 +0000 Subject: [PATCH 1/5] Add StoreWebApInfoInHttpContextAuthorizeFilter to add enricher data for unauthorized requests. Fixes #12 --- .../WebApi/HttpActionContextExtensions.cs | 40 +++++++++++++++++++ ...StoreWebApInfoInHttpContextActionFilter.cs | 32 +-------------- ...reWebApInfoInHttpContextAuthorizeFilter.cs | 19 +++++++++ .../SerilogWeb.Classic.WebApi.csproj | 2 + .../Controllers/ValuesController.cs | 7 ++++ 5 files changed, 70 insertions(+), 30 deletions(-) create mode 100644 src/SerilogWeb.Classic.WebApi/Classic/WebApi/HttpActionContextExtensions.cs create mode 100644 src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthorizeFilter.cs diff --git a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/HttpActionContextExtensions.cs b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/HttpActionContextExtensions.cs new file mode 100644 index 0000000..d4d5173 --- /dev/null +++ b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/HttpActionContextExtensions.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Http.Controllers; + +namespace SerilogWeb.Classic.WebApi +{ + internal static class HttpActionContextExtensions + { + public static void StoreWebApInfoInHttpContext(this HttpActionContext actionContext) + { + var currentHttpContext = HttpContext.Current; + if (currentHttpContext == null) + return; + + var actionDescriptor = actionContext.ActionDescriptor; + var routeData = actionContext.RequestContext.RouteData; + + var actionName = actionDescriptor.ActionName; + var controllerName = actionDescriptor.ControllerDescriptor.ControllerName; + + var routeTemplate = routeData.Route.RouteTemplate; + var routeDataDictionary = new Dictionary(routeData.Values); + + var contextualInfo = + new Dictionary + { + [WebApiRequestInfoKey.RouteUrlTemplate] = routeTemplate, + [WebApiRequestInfoKey.RouteData] = routeDataDictionary, + [WebApiRequestInfoKey.ActionName] = actionName, + [WebApiRequestInfoKey.ControllerName] = controllerName + }; + + currentHttpContext.Items[Constants.WebApiContextInfoKey] = contextualInfo; + } + } +} diff --git a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextActionFilter.cs b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextActionFilter.cs index b7ec0b7..5c626a0 100644 --- a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextActionFilter.cs +++ b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextActionFilter.cs @@ -11,42 +11,14 @@ internal class StoreWebApInfoInHttpContextActionFilter : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { - StoreWebApInfoInHttpContext(actionContext); + actionContext.StoreWebApInfoInHttpContext(); base.OnActionExecuting(actionContext); } public override Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken) { - StoreWebApInfoInHttpContext(actionContext); + actionContext.StoreWebApInfoInHttpContext(); return base.OnActionExecutingAsync(actionContext, cancellationToken); } - - - private static void StoreWebApInfoInHttpContext(HttpActionContext actionContext) - { - var currentHttpContext = HttpContext.Current; - if (currentHttpContext == null) - return; - - var actionDescriptor = actionContext.ActionDescriptor; - var routeData = actionContext.RequestContext.RouteData; - - var actionName = actionDescriptor.ActionName; - var controllerName = actionDescriptor.ControllerDescriptor.ControllerName; - - var routeTemplate = routeData.Route.RouteTemplate; - var routeDataDictionary = new Dictionary(routeData.Values); - - var contextualInfo = - new Dictionary - { - [WebApiRequestInfoKey.RouteUrlTemplate] = routeTemplate, - [WebApiRequestInfoKey.RouteData] = routeDataDictionary, - [WebApiRequestInfoKey.ActionName] = actionName, - [WebApiRequestInfoKey.ControllerName] = controllerName - }; - - currentHttpContext.Items[Constants.WebApiContextInfoKey] = contextualInfo; - } } } \ No newline at end of file diff --git a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthorizeFilter.cs b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthorizeFilter.cs new file mode 100644 index 0000000..5e0ac9a --- /dev/null +++ b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthorizeFilter.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using System.Web; +using System.Web.Http; +using System.Web.Http.Controllers; +using System.Web.Http.Filters; + +namespace SerilogWeb.Classic.WebApi +{ + public class StoreWebApInfoInHttpContextAuthorizeFilter : AuthorizeAttribute + { + protected override void HandleUnauthorizedRequest(HttpActionContext actionContext) + { + actionContext.StoreWebApInfoInHttpContext(); + base.HandleUnauthorizedRequest(actionContext); + } + } +} \ No newline at end of file diff --git a/src/SerilogWeb.Classic.WebApi/SerilogWeb.Classic.WebApi.csproj b/src/SerilogWeb.Classic.WebApi/SerilogWeb.Classic.WebApi.csproj index db43504..27712b6 100644 --- a/src/SerilogWeb.Classic.WebApi/SerilogWeb.Classic.WebApi.csproj +++ b/src/SerilogWeb.Classic.WebApi/SerilogWeb.Classic.WebApi.csproj @@ -79,7 +79,9 @@ + + diff --git a/test/SerilogWeb.Classic.WebApi.Test/Controllers/ValuesController.cs b/test/SerilogWeb.Classic.WebApi.Test/Controllers/ValuesController.cs index ffc65ba..6e58284 100644 --- a/test/SerilogWeb.Classic.WebApi.Test/Controllers/ValuesController.cs +++ b/test/SerilogWeb.Classic.WebApi.Test/Controllers/ValuesController.cs @@ -18,6 +18,13 @@ public string ShouldThrowException() throw new SyntheticException(nameof(ShouldThrowException)); } + [Route("api/values/shouldbeunauthorized")] + [HttpGet] + [StoreWebApInfoInHttpContextAuthorizeFilter] + public void ShouldBeUnauthorized() + { + } + // GET api/values/5 public string Get(int id) { From e52a54074c92e1ba2220e03fc73d7b1224ab90a9 Mon Sep 17 00:00:00 2001 From: Gareth James Date: Sat, 17 Mar 2018 08:42:59 +0000 Subject: [PATCH 2/5] Update README.md with information about authorization. Explains #12 --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 558e3ef..46874ee 100644 --- a/README.md +++ b/README.md @@ -36,3 +36,15 @@ var log = new LoggerConfiguration() .Enrich.With(new WebApiRouteTemplateEnricher("RouteTemplate") .CreateLogger(); ``` + +## Authorization +In Web Api, authorization filters execute before action filters. If a request is unauthorized, the action filters are not processed. +An authorize filter attribute is available which adds enricher support in the event that the request is unauthorized. You can use this directly: +```csharp +[SerilogWeb.Classic.WebApi.StoreWebApInfoInHttpContextAuthorizeFilter] +public void Get() +{ +} +``` + +Alternatively, you can create your own Authorize filter attribute which inherits from ```SerilogWeb.Classic.WebApi.StoreWebApInfoInHttpContextAuthorizeFilter```, and use that instead. \ No newline at end of file From 3b6592de5f80869afffd6bcf69cab833d616592c Mon Sep 17 00:00:00 2001 From: Gareth James Date: Sat, 17 Mar 2018 15:32:20 +0000 Subject: [PATCH 3/5] Remove Action filter and Authorize filter and create new Authentication filter to augment HttpContext. #12 --- .../WebApi/PreApplicationStartModule.cs | 2 +- ...StoreWebApInfoInHttpContextActionFilter.cs | 24 ----------------- ...ApInfoInHttpContextAuthenticationFilter.cs | 26 +++++++++++++++++++ ...reWebApInfoInHttpContextAuthorizeFilter.cs | 19 -------------- .../SerilogWeb.Classic.WebApi.csproj | 3 +-- .../Controllers/ValuesController.cs | 2 +- 6 files changed, 29 insertions(+), 47 deletions(-) delete mode 100644 src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextActionFilter.cs create mode 100644 src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthenticationFilter.cs delete mode 100644 src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthorizeFilter.cs diff --git a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/PreApplicationStartModule.cs b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/PreApplicationStartModule.cs index e1f1774..f4c62f2 100644 --- a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/PreApplicationStartModule.cs +++ b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/PreApplicationStartModule.cs @@ -9,7 +9,7 @@ public static void Register() { GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new WebApiExceptionLogger()); - GlobalConfiguration.Configuration.Filters.Add(new StoreWebApInfoInHttpContextActionFilter()); + GlobalConfiguration.Configuration.Filters.Add(new StoreWebApInfoInHttpContextAuthenticationFilter()); } } } diff --git a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextActionFilter.cs b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextActionFilter.cs deleted file mode 100644 index 5c626a0..0000000 --- a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextActionFilter.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using System.Web; -using System.Web.Http.Controllers; -using System.Web.Http.Filters; - -namespace SerilogWeb.Classic.WebApi -{ - internal class StoreWebApInfoInHttpContextActionFilter : ActionFilterAttribute - { - public override void OnActionExecuting(HttpActionContext actionContext) - { - actionContext.StoreWebApInfoInHttpContext(); - base.OnActionExecuting(actionContext); - } - - public override Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken) - { - actionContext.StoreWebApInfoInHttpContext(); - return base.OnActionExecutingAsync(actionContext, cancellationToken); - } - } -} \ No newline at end of file diff --git a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthenticationFilter.cs b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthenticationFilter.cs new file mode 100644 index 0000000..a972185 --- /dev/null +++ b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthenticationFilter.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using System.Web; +using System.Web.Http; +using System.Web.Http.Controllers; +using System.Web.Http.Filters; + +namespace SerilogWeb.Classic.WebApi +{ + public class StoreWebApInfoInHttpContextAuthenticationFilter : IAuthenticationFilter + { + public bool AllowMultiple => false; + + public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken) + { + context.ActionContext.StoreWebApInfoInHttpContext(); + await Task.FromResult(0); + } + + public async Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken) + { + await Task.FromResult(0); + } + } +} \ No newline at end of file diff --git a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthorizeFilter.cs b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthorizeFilter.cs deleted file mode 100644 index 5e0ac9a..0000000 --- a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthorizeFilter.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using System.Web; -using System.Web.Http; -using System.Web.Http.Controllers; -using System.Web.Http.Filters; - -namespace SerilogWeb.Classic.WebApi -{ - public class StoreWebApInfoInHttpContextAuthorizeFilter : AuthorizeAttribute - { - protected override void HandleUnauthorizedRequest(HttpActionContext actionContext) - { - actionContext.StoreWebApInfoInHttpContext(); - base.HandleUnauthorizedRequest(actionContext); - } - } -} \ No newline at end of file diff --git a/src/SerilogWeb.Classic.WebApi/SerilogWeb.Classic.WebApi.csproj b/src/SerilogWeb.Classic.WebApi/SerilogWeb.Classic.WebApi.csproj index 27712b6..8564407 100644 --- a/src/SerilogWeb.Classic.WebApi/SerilogWeb.Classic.WebApi.csproj +++ b/src/SerilogWeb.Classic.WebApi/SerilogWeb.Classic.WebApi.csproj @@ -81,8 +81,7 @@ - - + diff --git a/test/SerilogWeb.Classic.WebApi.Test/Controllers/ValuesController.cs b/test/SerilogWeb.Classic.WebApi.Test/Controllers/ValuesController.cs index 6e58284..95b73dd 100644 --- a/test/SerilogWeb.Classic.WebApi.Test/Controllers/ValuesController.cs +++ b/test/SerilogWeb.Classic.WebApi.Test/Controllers/ValuesController.cs @@ -20,7 +20,7 @@ public string ShouldThrowException() [Route("api/values/shouldbeunauthorized")] [HttpGet] - [StoreWebApInfoInHttpContextAuthorizeFilter] + [Authorize] public void ShouldBeUnauthorized() { } From 1197ef4654acdcd363c51a2fc1c960e050cebb4a Mon Sep 17 00:00:00 2001 From: Gareth James Date: Sat, 17 Mar 2018 16:03:05 +0000 Subject: [PATCH 4/5] Marked authentication filter class as internal. Marked HttpActionContext extension method as internal. Removed authorization content from README.md. #12 --- README.md | 12 ------------ .../Classic/WebApi/HttpActionContextExtensions.cs | 2 +- ...toreWebApInfoInHttpContextAuthenticationFilter.cs | 2 +- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 46874ee..558e3ef 100644 --- a/README.md +++ b/README.md @@ -36,15 +36,3 @@ var log = new LoggerConfiguration() .Enrich.With(new WebApiRouteTemplateEnricher("RouteTemplate") .CreateLogger(); ``` - -## Authorization -In Web Api, authorization filters execute before action filters. If a request is unauthorized, the action filters are not processed. -An authorize filter attribute is available which adds enricher support in the event that the request is unauthorized. You can use this directly: -```csharp -[SerilogWeb.Classic.WebApi.StoreWebApInfoInHttpContextAuthorizeFilter] -public void Get() -{ -} -``` - -Alternatively, you can create your own Authorize filter attribute which inherits from ```SerilogWeb.Classic.WebApi.StoreWebApInfoInHttpContextAuthorizeFilter```, and use that instead. \ No newline at end of file diff --git a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/HttpActionContextExtensions.cs b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/HttpActionContextExtensions.cs index d4d5173..5239552 100644 --- a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/HttpActionContextExtensions.cs +++ b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/HttpActionContextExtensions.cs @@ -10,7 +10,7 @@ namespace SerilogWeb.Classic.WebApi { internal static class HttpActionContextExtensions { - public static void StoreWebApInfoInHttpContext(this HttpActionContext actionContext) + internal static void StoreWebApInfoInHttpContext(this HttpActionContext actionContext) { var currentHttpContext = HttpContext.Current; if (currentHttpContext == null) diff --git a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthenticationFilter.cs b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthenticationFilter.cs index a972185..f5bfc60 100644 --- a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthenticationFilter.cs +++ b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthenticationFilter.cs @@ -8,7 +8,7 @@ namespace SerilogWeb.Classic.WebApi { - public class StoreWebApInfoInHttpContextAuthenticationFilter : IAuthenticationFilter + internal class StoreWebApInfoInHttpContextAuthenticationFilter : IAuthenticationFilter { public bool AllowMultiple => false; From 88b35751381d36d95ebe320e923be4f6169be780 Mon Sep 17 00:00:00 2001 From: Gareth James Date: Sat, 17 Mar 2018 16:51:09 +0000 Subject: [PATCH 5/5] Remove unnecessary async/await from authentication filter. #12 --- .../StoreWebApInfoInHttpContextAuthenticationFilter.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthenticationFilter.cs b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthenticationFilter.cs index f5bfc60..b63c3cc 100644 --- a/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthenticationFilter.cs +++ b/src/SerilogWeb.Classic.WebApi/Classic/WebApi/StoreWebApInfoInHttpContextAuthenticationFilter.cs @@ -12,15 +12,15 @@ internal class StoreWebApInfoInHttpContextAuthenticationFilter : IAuthentication { public bool AllowMultiple => false; - public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken) + public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken) { context.ActionContext.StoreWebApInfoInHttpContext(); - await Task.FromResult(0); + return Task.FromResult(0); } - public async Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken) + public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken) { - await Task.FromResult(0); + return Task.FromResult(0); } } } \ No newline at end of file