From e231c61c3ab1b3d9125f2563365aedb126c55210 Mon Sep 17 00:00:00 2001 From: Safia Abdalla Date: Tue, 1 Aug 2023 17:26:55 -0700 Subject: [PATCH] Re-run routing for implicit middlewares that require endpoints (#49732) * Re-run routing for implicit middlewares that require endpoints * Address feedback from peer review * Update generated code comment --- ...AntiforgeryApplicationBuilderExtensions.cs | 15 + .../Microsoft.AspNetCore.Antiforgery.csproj | 1 + .../WebApplicationTests.cs | 376 +++++++++++++++++- .../src/RequestDelegateFactory.cs | 10 +- .../Core/src/AuthAppBuilderExtensions.cs | 16 + ...Microsoft.AspNetCore.Authentication.csproj | 1 + .../src/AuthorizationAppBuilderExtensions.cs | 20 + ...oft.AspNetCore.Authorization.Policy.csproj | 1 + 8 files changed, 435 insertions(+), 5 deletions(-) diff --git a/src/Antiforgery/src/AntiforgeryApplicationBuilderExtensions.cs b/src/Antiforgery/src/AntiforgeryApplicationBuilderExtensions.cs index f7498933e384..646d31ad5b4d 100644 --- a/src/Antiforgery/src/AntiforgeryApplicationBuilderExtensions.cs +++ b/src/Antiforgery/src/AntiforgeryApplicationBuilderExtensions.cs @@ -3,6 +3,8 @@ using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Antiforgery.Internal; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Builder; @@ -24,6 +26,19 @@ public static IApplicationBuilder UseAntiforgery(this IApplicationBuilder builde builder.VerifyAntiforgeryServicesAreRegistered(); builder.Properties[AntiforgeryMiddlewareSetKey] = true; + + // The anti-forgery middleware adds annotations to HttpContext.Items to indicate that it has run + // that will be validated by the EndpointsRoutingMiddleware later. To do this, we need to ensure + // that routing has run and set the endpoint feature on the HttpContext associated with the request. + if (builder.Properties.TryGetValue(RerouteHelper.GlobalRouteBuilderKey, out var routeBuilder) && routeBuilder is not null) + { + return builder.Use(next => + { + var newNext = RerouteHelper.Reroute(builder, routeBuilder, next); + var antiforgery = builder.ApplicationServices.GetRequiredService(); + return new AntiforgeryMiddleware(antiforgery, newNext).Invoke; + }); + } builder.UseMiddleware(); return builder; diff --git a/src/Antiforgery/src/Microsoft.AspNetCore.Antiforgery.csproj b/src/Antiforgery/src/Microsoft.AspNetCore.Antiforgery.csproj index 69ecc7cb9f44..822f722379f1 100644 --- a/src/Antiforgery/src/Microsoft.AspNetCore.Antiforgery.csproj +++ b/src/Antiforgery/src/Microsoft.AspNetCore.Antiforgery.csproj @@ -26,5 +26,6 @@ + diff --git a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs index 5bdc09ecf4de..f92a32e0a4a1 100644 --- a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs +++ b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs @@ -5,10 +5,12 @@ using System.Diagnostics; using System.Diagnostics.Tracing; using System.Net; +using System.Net.Http; using System.Reflection; using System.Security.Claims; using System.Text; using System.Text.Encodings.Web; +using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.HostFiltering; @@ -2697,7 +2699,7 @@ public void DebugView_UseMiddleware_HasMiddleware() // 3. Generated delegate name from app.Use(...) Assert.Collection(debugView.Middleware, m => Assert.Equal(typeof(MiddlewareWithInterface).FullName, m), - m => Assert.Equal("Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", m), + m => Assert.StartsWith("Microsoft.AspNetCore.Builder.AuthAppBuilderExtensions", m), m => { Assert.Contains(nameof(DebugView_UseMiddleware_HasMiddleware), m); @@ -2747,8 +2749,8 @@ public async Task DebugView_UseMiddleware_HasEndpointsAndAuth_Run_HasAutomaticMi Assert.Collection(debugView.Middleware, m => Assert.Equal("Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware", m), m => Assert.Equal("Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware", m), - m => Assert.Equal("Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", m), - m => Assert.Equal("Microsoft.AspNetCore.Authorization.AuthorizationMiddlewareInternal", m), + m => Assert.StartsWith("Microsoft.AspNetCore.Builder.AuthAppBuilderExtensions", m), + m => Assert.StartsWith("Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions", m), m => Assert.Equal(typeof(MiddlewareWithInterface).FullName, m), m => Assert.Equal("Microsoft.AspNetCore.Routing.EndpointMiddleware", m)); } @@ -2838,6 +2840,374 @@ public async Task DebugView_Endpoints_UseEndpoints_AvailableBeforeAndAfterStart( ep => Assert.Equal("/hello", ep.Metadata.GetRequiredMetadata().Route)); } + [Fact] + public async Task ImplicitMiddlewares_RunAfterExplicitRouting_MapAction() + { + var builder = WebApplication.CreateBuilder(); + builder.WebHost.UseTestServer(); + builder.Services.AddAuthentication("testSchemeName") + .AddScheme("testSchemeName", "testDisplayName", _ => { }); + builder.Services.AddAuthorization(); + builder.Services.AddAntiforgery(); + await using var app = builder.Build(); + app.UseRouting(); + app.MapGet("/", (HttpContext context, string username) => + { + Assert.NotNull(context.Items["__AuthorizationMiddlewareWithEndpointInvoked"]); + return $"GET: {username}"; + }).AllowAnonymous(); + + app.MapPost("/form", (HttpContext context, string username, [FromForm] WebApplicationOptions options) => + { + Assert.NotNull(context.Items["__AuthorizationMiddlewareWithEndpointInvoked"]); + Assert.NotNull(context.Items["__AntiforgeryMiddlewareWithEndpointInvoked"]); + return $"POST: {username}"; + }).AllowAnonymous(); + + await app.StartAsync(); + + var client = app.GetTestClient(); + var getResponse = await client.GetAsync("/?username=test"); + getResponse.EnsureSuccessStatusCode(); + Assert.Equal("GET: test", await getResponse.Content.ReadAsStringAsync()); + + var antiforgery = app.Services.GetRequiredService(); + var antiforgeryOptions = app.Services.GetRequiredService>(); + var tokens = antiforgery.GetAndStoreTokens(new DefaultHttpContext()); + var request = new HttpRequestMessage(HttpMethod.Post, "form?username=test-form"); + request.Headers.Add("Cookie", antiforgeryOptions.Value.Cookie.Name + "=" + tokens.CookieToken); + var nameValueCollection = new List> + { + new KeyValuePair("__RequestVerificationToken", tokens.RequestToken), + }; + request.Content = new FormUrlEncodedContent(nameValueCollection); + var postResponse = await client.SendAsync(request); + postResponse.EnsureSuccessStatusCode(); + Assert.Equal("POST: test-form", await postResponse.Content.ReadAsStringAsync()); + } + + [Fact] + public async Task ExplicitMiddlewares_RunAfterExplicitRouting_MapAction() + { + var builder = WebApplication.CreateBuilder(); + builder.WebHost.UseTestServer(); + builder.Services.AddAuthentication("testSchemeName") + .AddScheme("testSchemeName", "testDisplayName", _ => { }); + builder.Services.AddAuthorization(); + builder.Services.AddAntiforgery(); + await using var app = builder.Build(); + + app.UseRouting(); + app.UseAuthentication(); + app.UseAuthorization(); + app.UseAntiforgery(); + + app.MapGet("/", (HttpContext context, string username) => + { + Assert.NotNull(context.Items["__AuthorizationMiddlewareWithEndpointInvoked"]); + return $"GET: {username}"; + }).AllowAnonymous(); + + app.MapPost("/form", (HttpContext context, string username, [FromForm] WebApplicationOptions options) => + { + Assert.NotNull(context.Items["__AuthorizationMiddlewareWithEndpointInvoked"]); + Assert.NotNull(context.Items["__AntiforgeryMiddlewareWithEndpointInvoked"]); + return $"POST: {username}"; + }).AllowAnonymous(); + + await app.StartAsync(); + + var client = app.GetTestClient(); + var getResponse = await client.GetAsync("/?username=test"); + getResponse.EnsureSuccessStatusCode(); + Assert.Equal("GET: test", await getResponse.Content.ReadAsStringAsync()); + + var antiforgery = app.Services.GetRequiredService(); + var antiforgeryOptions = app.Services.GetRequiredService>(); + var tokens = antiforgery.GetAndStoreTokens(new DefaultHttpContext()); + var request = new HttpRequestMessage(HttpMethod.Post, "form?username=test-form"); + request.Headers.Add("Cookie", antiforgeryOptions.Value.Cookie.Name + "=" + tokens.CookieToken); + var nameValueCollection = new List> + { + new KeyValuePair("__RequestVerificationToken", tokens.RequestToken), + }; + request.Content = new FormUrlEncodedContent(nameValueCollection); + var postResponse = await client.SendAsync(request); + postResponse.EnsureSuccessStatusCode(); + Assert.Equal("POST: test-form", await postResponse.Content.ReadAsStringAsync()); + } + + [Fact] + public async Task ImplicitMiddlewares_RunBeforeImplicitRouting_TerminalMiddleware() + { + var builder = WebApplication.CreateBuilder(); + builder.WebHost.UseTestServer(); + builder.Services.AddAuthentication("testSchemeName") + .AddScheme("testSchemeName", "testDisplayName", _ => { }); + builder.Services.AddAuthorization(); + builder.Services.AddAntiforgery(); + + await using var app = builder.Build(); + + app.Run((HttpContext context) => + { + Assert.NotNull(context.Features.Get()); + return context.Response.WriteAsync($"Hello {context.Request.Query["username"]}!"); + }); + + await app.StartAsync(); + + var client = app.GetTestClient(); + var response = await client.GetAsync("/?username=test"); + response.EnsureSuccessStatusCode(); + Assert.Equal("Hello test!", await response.Content.ReadAsStringAsync()); + } + + [Fact] + public async Task ImplicitMiddlewares_RunBeforeImplicitRouting_Antiforgery_MapRequestDelegate() + { + var builder = WebApplication.CreateBuilder(); + builder.WebHost.UseTestServer(); + builder.Services.AddAuthentication("testSchemeName") + .AddScheme("testSchemeName", "testDisplayName", _ => { }); + builder.Services.AddAuthorization(); + builder.Services.AddAntiforgery(); + + await using var app = builder.Build(); + var invoked = false; + + app.MapPost("/", (HttpContext context) => + { + Assert.NotNull(context.Features.Get()); + Assert.NotNull(context.Features.Get()); + var e = Assert.Throws(() => context.Request.Form); + Assert.Equal("This form is being accessed with an invalid anti-forgery token. Validate the `IAntiforgeryValidationFeature` on the request before reading from the form.", e.Message); + invoked = true; + }).WithMetadata(new RequireAntiforgeryTokenAttribute()).AllowAnonymous(); + + await app.StartAsync(); + + var client = app.GetTestClient(); + var response = await client.PostAsync("/?username=test", new FormUrlEncodedContent(new Dictionary())); + response.EnsureSuccessStatusCode(); + Assert.True(invoked); + } + + [Fact] + public async Task ExplicitMiddlewares_RunBeforeImplicitRouting_TerminalMiddleware() + { + var builder = WebApplication.CreateBuilder(); + builder.WebHost.UseTestServer(); + builder.Services.AddAuthentication("testSchemeName") + .AddScheme("testSchemeName", "testDisplayName", _ => { }); + builder.Services.AddAuthorization(); + await using var app = builder.Build(); + app.UseAuthentication(); + app.UseAuthorization(); + app.Run((HttpContext context) => + { + Assert.NotNull(context.Features.Get()); + return context.Response.WriteAsync($"Hello {context.Request.Query["username"]}!"); + }); + + await app.StartAsync(); + + var client = app.GetTestClient(); + var response = await client.GetAsync("/?username=test"); + response.EnsureSuccessStatusCode(); + Assert.Equal("Hello test!", await response.Content.ReadAsStringAsync()); + } + + [Fact] + public async Task ExplicitMiddlewares_RunBeforeImplicitRouting_Antiforgery_MapRequestDelegate() + { + var builder = WebApplication.CreateBuilder(); + builder.WebHost.UseTestServer(); + builder.Services.AddAuthentication("testSchemeName") + .AddScheme("testSchemeName", "testDisplayName", _ => { }); + builder.Services.AddAuthorization(); + builder.Services.AddAntiforgery(); + + await using var app = builder.Build(); + var invoked = false; + + app.UseAntiforgery(); + + app.MapPost("/", (HttpContext context) => + { + Assert.NotNull(context.Features.Get()); + Assert.NotNull(context.Features.Get()); + var e = Assert.Throws(() => context.Request.Form); + Assert.Equal("This form is being accessed with an invalid anti-forgery token. Validate the `IAntiforgeryValidationFeature` on the request before reading from the form.", e.Message); + invoked = true; + }).WithMetadata(new RequireAntiforgeryTokenAttribute()).AllowAnonymous(); + + await app.StartAsync(); + + var client = app.GetTestClient(); + var response = await client.PostAsync("/?username=test", new FormUrlEncodedContent(new Dictionary())); + response.EnsureSuccessStatusCode(); + Assert.True(invoked); + } + + [Fact] + public async Task ImplicitMiddlewares_RunBeforeExplicitRouting_TerminalMiddleware() + { + var builder = WebApplication.CreateBuilder(); + builder.WebHost.UseTestServer(); + builder.Services.AddAuthentication("testSchemeName") + .AddScheme("testSchemeName", "testDisplayName", _ => { }); + builder.Services.AddAuthorization(); + await using var app = builder.Build(); + + app.Run((HttpContext context) => + { + Assert.NotNull(context.Features.Get()); + return context.Response.WriteAsync($"Hello {context.Request.Query["username"]}!"); + }); + + app.UseRouting(); + + await app.StartAsync(); + + var client = app.GetTestClient(); + var response = await client.GetAsync("/?username=test"); + response.EnsureSuccessStatusCode(); + Assert.Equal("Hello test!", await response.Content.ReadAsStringAsync()); + } + + [Fact] + public async Task ImplicitMiddlewares_RunBeforeExplicitRouting_Antiforgery_MapRequestDelegate() + { + var builder = WebApplication.CreateBuilder(); + builder.WebHost.UseTestServer(); + builder.Services.AddAuthentication("testSchemeName") + .AddScheme("testSchemeName", "testDisplayName", _ => { }); + builder.Services.AddAuthorization(); + builder.Services.AddAntiforgery(); + + await using var app = builder.Build(); + var invoked = false; + + app.UseRouting(); + + app.MapPost("/", (HttpContext context) => + { + Assert.NotNull(context.Features.Get()); + Assert.NotNull(context.Features.Get()); + var e = Assert.Throws(() => context.Request.Form); + Assert.Equal("This form is being accessed with an invalid anti-forgery token. Validate the `IAntiforgeryValidationFeature` on the request before reading from the form.", e.Message); + invoked = true; + }).WithMetadata(new RequireAntiforgeryTokenAttribute()).AllowAnonymous(); + + await app.StartAsync(); + + var client = app.GetTestClient(); + var response = await client.PostAsync("/?username=test", new FormUrlEncodedContent(new Dictionary())); + response.EnsureSuccessStatusCode(); + Assert.True(invoked); + } + + [Fact] + public async Task ImplicitMiddlewares_RunBeforeExplicitRouting_TerminalMiddleware_AfterUseRouting() + { + var builder = WebApplication.CreateBuilder(); + builder.WebHost.UseTestServer(); + builder.Services.AddAuthentication("testSchemeName") + .AddScheme("testSchemeName", "testDisplayName", _ => { }); + builder.Services.AddAuthorization(); + await using var app = builder.Build(); + + app.UseRouting(); + + var invoked = false; + + app.Run(async (HttpContext context) => + { + Assert.NotNull(context.Features.Get()); + invoked = true; + await context.Response.WriteAsync("From terminal middleware"); + }); + + await app.StartAsync(); + + var client = app.GetTestClient(); + var response = await client.GetAsync("/?username=test"); + response.EnsureSuccessStatusCode(); + Assert.True(invoked); + } + + [Fact] + public async Task ImplicitMiddlewares_RunBetween_ExplicitRouting_MiddlewareMapGet() + { + var builder = WebApplication.CreateBuilder(); + builder.WebHost.UseTestServer(); + builder.Services.AddAuthentication("testSchemeName") + .AddScheme("testSchemeName", "testDisplayName", _ => { }); + builder.Services.AddAuthorization(); + builder.Services.AddAntiforgery(); + await using var app = builder.Build(); + + app.UseRouting(); + + app.Use((context, next) => + { + if (context.Request.Path.Value != "/") + { + return next(context); + } + Assert.NotNull(context.Features.Get()); + return context.Response.WriteAsync($"From terminal middleware: {context.Request.Query["username"]}"); + }); + + app.MapGet("/endpoint", (HttpContext context, string username) => + { + Assert.NotNull(context.Items["__AuthorizationMiddlewareWithEndpointInvoked"]); + Assert.NotNull(context.Features.Get()); + return $"From endpoint: {username}"; + }).AllowAnonymous(); + + app.MapPost("/form", (HttpContext context, string username, [FromForm] WebApplicationOptions options) => + { + Assert.NotNull(context.Items["__AuthorizationMiddlewareWithEndpointInvoked"]); + Assert.NotNull(context.Features.Get()); + Assert.NotNull(context.Items["__AntiforgeryMiddlewareWithEndpointInvoked"]); + Assert.NotNull(context.Features.Get()); + return $"From form endpoint: {username}"; + }).AllowAnonymous(); + + await app.StartAsync(); + + var client = app.GetTestClient(); + var response = await client.GetAsync("/?username=test"); + response.EnsureSuccessStatusCode(); + Assert.Equal("From terminal middleware: test", await response.Content.ReadAsStringAsync()); + + var endpointResponse = await client.GetAsync("/endpoint?username=test-endpoint"); + endpointResponse.EnsureSuccessStatusCode(); + Assert.Equal("From endpoint: test-endpoint", await endpointResponse.Content.ReadAsStringAsync()); + + var antiforgery = app.Services.GetRequiredService(); + var antiforgeryOptions = app.Services.GetRequiredService>(); + var tokens = antiforgery.GetAndStoreTokens(new DefaultHttpContext()); + var request = new HttpRequestMessage(HttpMethod.Post, "form?username=test-form"); + request.Headers.Add("Cookie", antiforgeryOptions.Value.Cookie.Name + "=" + tokens.CookieToken); + var nameValueCollection = new List> + { + new KeyValuePair("__RequestVerificationToken", tokens.RequestToken), + }; + request.Content = new FormUrlEncodedContent(nameValueCollection); + var formResponse = await client.SendAsync(request); + formResponse.EnsureSuccessStatusCode(); + Assert.Equal("From form endpoint: test-form", await formResponse.Content.ReadAsStringAsync()); + } + + [AttributeUsage(AttributeTargets.Parameter)] + public class FromFormAttribute(string name = "") : Attribute, IFromFormMetadata + { + public string Name { get; } = name; + } + private class MiddlewareWithInterface : IMiddleware { public Task InvokeAsync(HttpContext context, RequestDelegate next) diff --git a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs index 7b26a355783e..a3d9182ebb02 100644 --- a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs +++ b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs @@ -2014,12 +2014,18 @@ private static Expression BindComplexParameterFromFormItem( FormDataMapperMapMethod.MakeGenericMethod(parameter.ParameterType), formReader, Expression.Constant(FormDataMapperOptions)); - // ArrayPool.Shared.Return(form_buffer, false); + // if (form_buffer != null) + // { + // ArrayPool.Shared.Return(form_buffer, false); + // } var returnBufferExpr = Expression.Call( Expression.Property(null, typeof(ArrayPool).GetProperty(nameof(ArrayPool.Shared))!), ArrayPoolSharedReturnMethod, formBuffer, Expression.Constant(false)); + var conditionalReturnBufferExpr = Expression.IfThen( + Expression.NotEqual(formBuffer, Expression.Constant(null)), + returnBufferExpr); return Expression.Block( new[] { formArgument, formReader, formDict, formBuffer }, @@ -2028,7 +2034,7 @@ private static Expression BindComplexParameterFromFormItem( processFormExpr, initializeReaderExpr, Expression.Assign(formArgument, invokeMapMethodExpr)), - returnBufferExpr), + conditionalReturnBufferExpr), formArgument ); } diff --git a/src/Security/Authentication/Core/src/AuthAppBuilderExtensions.cs b/src/Security/Authentication/Core/src/AuthAppBuilderExtensions.cs index 7439748979ad..1c7c22da2de8 100644 --- a/src/Security/Authentication/Core/src/AuthAppBuilderExtensions.cs +++ b/src/Security/Authentication/Core/src/AuthAppBuilderExtensions.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNetCore.Routing; namespace Microsoft.AspNetCore.Builder; @@ -22,6 +24,20 @@ public static IApplicationBuilder UseAuthentication(this IApplicationBuilder app ArgumentNullException.ThrowIfNull(app); app.Properties[AuthenticationMiddlewareSetKey] = true; + + // The authentication middleware adds annotation to HttpContext.Items to indicate that it has run + // that will be validated by the EndpointsRoutingMiddleware later. To do this, we need to ensure + // that routing has run and set the endpoint feature on the HttpContext associated with the request. + if (app.Properties.TryGetValue(RerouteHelper.GlobalRouteBuilderKey, out var routeBuilder) && routeBuilder is not null) + { + return app.Use(next => + { + var newNext = RerouteHelper.Reroute(app, routeBuilder, next); + var authenticationSchemeProvider = app.ApplicationServices.GetRequiredService(); + return new AuthenticationMiddleware(newNext, authenticationSchemeProvider).Invoke; + }); + } + return app.UseMiddleware(); } } diff --git a/src/Security/Authentication/Core/src/Microsoft.AspNetCore.Authentication.csproj b/src/Security/Authentication/Core/src/Microsoft.AspNetCore.Authentication.csproj index 32546d575cb1..5b12df575ca7 100644 --- a/src/Security/Authentication/Core/src/Microsoft.AspNetCore.Authentication.csproj +++ b/src/Security/Authentication/Core/src/Microsoft.AspNetCore.Authentication.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Security/Authorization/Policy/src/AuthorizationAppBuilderExtensions.cs b/src/Security/Authorization/Policy/src/AuthorizationAppBuilderExtensions.cs index fa8a0898e496..0d9855ec3437 100644 --- a/src/Security/Authorization/Policy/src/AuthorizationAppBuilderExtensions.cs +++ b/src/Security/Authorization/Policy/src/AuthorizationAppBuilderExtensions.cs @@ -3,7 +3,9 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization.Policy; +using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Builder; @@ -30,6 +32,24 @@ public static IApplicationBuilder UseAuthorization(this IApplicationBuilder app) VerifyServicesRegistered(app); app.Properties[AuthorizationMiddlewareSetKey] = true; + + // The authorization middleware adds annotation to HttpContext.Items to indicate that it has run + // that will be validated by the EndpointsRoutingMiddleware later. To do this, we need to ensure + // that routing has run and set the endpoint feature on the HttpContext associated with the request. + if (app.Properties.TryGetValue(RerouteHelper.GlobalRouteBuilderKey, out var routeBuilder) && routeBuilder is not null) + { + return app.Use(next => + { + var newNext = RerouteHelper.Reroute(app, routeBuilder, next); + var authorizationPolicyProvider = app.ApplicationServices.GetRequiredService(); + var logger = app.ApplicationServices.GetRequiredService>(); + return new AuthorizationMiddlewareInternal(newNext, + app.ApplicationServices, + authorizationPolicyProvider, + logger).Invoke; + }); + } + return app.UseMiddleware(); } diff --git a/src/Security/Authorization/Policy/src/Microsoft.AspNetCore.Authorization.Policy.csproj b/src/Security/Authorization/Policy/src/Microsoft.AspNetCore.Authorization.Policy.csproj index 14912c54a988..d6df142a5654 100644 --- a/src/Security/Authorization/Policy/src/Microsoft.AspNetCore.Authorization.Policy.csproj +++ b/src/Security/Authorization/Policy/src/Microsoft.AspNetCore.Authorization.Policy.csproj @@ -13,6 +13,7 @@ +