Skip to content

Commit 8a1c68c

Browse files
committed
Re-run routing for implicit middlewares that require endpoints
1 parent f107566 commit 8a1c68c

File tree

7 files changed

+218
-3
lines changed

7 files changed

+218
-3
lines changed

src/Antiforgery/src/AntiforgeryApplicationBuilderExtensions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
using Microsoft.AspNetCore.Antiforgery;
55
using Microsoft.AspNetCore.Antiforgery.Internal;
6+
using Microsoft.AspNetCore.Routing;
7+
using Microsoft.Extensions.DependencyInjection;
68

79
namespace Microsoft.AspNetCore.Builder;
810

@@ -24,6 +26,16 @@ public static IApplicationBuilder UseAntiforgery(this IApplicationBuilder builde
2426
builder.VerifyAntiforgeryServicesAreRegistered();
2527

2628
builder.Properties[AntiforgeryMiddlewareSetKey] = true;
29+
30+
if (builder.Properties.TryGetValue(RerouteHelper.GlobalRouteBuilderKey, out var routeBuilder) && routeBuilder is not null)
31+
{
32+
return builder.Use(next =>
33+
{
34+
var newNext = RerouteHelper.Reroute(builder, routeBuilder, next);
35+
var antiforgery = builder.ApplicationServices.GetRequiredService<IAntiforgery>();
36+
return new AntiforgeryMiddleware(antiforgery, newNext).Invoke;
37+
});
38+
}
2739
builder.UseMiddleware<AntiforgeryMiddleware>();
2840

2941
return builder;

src/Antiforgery/src/Microsoft.AspNetCore.Antiforgery.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@
2626

2727
<ItemGroup>
2828
<Compile Include="$(SharedSourceRoot)HttpMethodExtensions.cs" LinkBase="Shared"/>
29+
<Compile Include="$(SharedSourceRoot)Reroute.cs" LinkBase="Shared"/>
2930
</ItemGroup>
3031
</Project>

src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs

Lines changed: 173 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2697,7 +2697,7 @@ public void DebugView_UseMiddleware_HasMiddleware()
26972697
// 3. Generated delegate name from app.Use(...)
26982698
Assert.Collection(debugView.Middleware,
26992699
m => Assert.Equal(typeof(MiddlewareWithInterface).FullName, m),
2700-
m => Assert.Equal("Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", m),
2700+
m => Assert.StartsWith("Microsoft.AspNetCore.Builder.AuthAppBuilderExtensions", m),
27012701
m =>
27022702
{
27032703
Assert.Contains(nameof(DebugView_UseMiddleware_HasMiddleware), m);
@@ -2747,8 +2747,8 @@ public async Task DebugView_UseMiddleware_HasEndpointsAndAuth_Run_HasAutomaticMi
27472747
Assert.Collection(debugView.Middleware,
27482748
m => Assert.Equal("Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware", m),
27492749
m => Assert.Equal("Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware", m),
2750-
m => Assert.Equal("Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", m),
2751-
m => Assert.Equal("Microsoft.AspNetCore.Authorization.AuthorizationMiddlewareInternal", m),
2750+
m => Assert.StartsWith("Microsoft.AspNetCore.Builder.AuthAppBuilderExtensions", m),
2751+
m => Assert.StartsWith("Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions", m),
27522752
m => Assert.Equal(typeof(MiddlewareWithInterface).FullName, m),
27532753
m => Assert.Equal("Microsoft.AspNetCore.Routing.EndpointMiddleware", m));
27542754
}
@@ -2838,6 +2838,176 @@ public async Task DebugView_Endpoints_UseEndpoints_AvailableBeforeAndAfterStart(
28382838
ep => Assert.Equal("/hello", ep.Metadata.GetRequiredMetadata<IRouteDiagnosticsMetadata>().Route));
28392839
}
28402840

2841+
[Fact]
2842+
public async Task ImplicitMiddlewares_RunAfterExplicitRouting_MapGet()
2843+
{
2844+
var builder = WebApplication.CreateBuilder();
2845+
builder.WebHost.UseTestServer();
2846+
builder.Services.AddAuthentication("testSchemeName")
2847+
.AddScheme<AuthenticationSchemeOptions, UberHandler>("testSchemeName", "testDisplayName", _ => { });
2848+
builder.Services.AddAuthorization();
2849+
await using var app = builder.Build();
2850+
app.UseRouting();
2851+
app.MapGet("/", (HttpContext context, string username) =>
2852+
{
2853+
Assert.NotNull(context.Items["__AuthorizationMiddlewareWithEndpointInvoked"]);
2854+
return $"Hello {username}!";
2855+
}).RequireAuthorization();
2856+
2857+
await app.StartAsync();
2858+
2859+
var client = app.GetTestClient();
2860+
var exception = await Record.ExceptionAsync(async () => await client.GetAsync("/?username=test"));
2861+
Assert.Null(exception);
2862+
}
2863+
2864+
[Fact]
2865+
public async Task ImplicitMiddlewares_RunBeforeImplicitRouting_TerminalMiddleware()
2866+
{
2867+
var builder = WebApplication.CreateBuilder();
2868+
builder.WebHost.UseTestServer();
2869+
builder.Services.AddAuthentication("testSchemeName")
2870+
.AddScheme<AuthenticationSchemeOptions, UberHandler>("testSchemeName", "testDisplayName", _ => { });
2871+
builder.Services.AddAuthorization();
2872+
await using var app = builder.Build();
2873+
app.Run((HttpContext context) =>
2874+
{
2875+
Assert.NotNull(context.Features.Get<IAuthenticationFeature>());
2876+
return context.Response.WriteAsync($"Hello {context.Request.Query["username"]}!");
2877+
});
2878+
2879+
await app.StartAsync();
2880+
2881+
var client = app.GetTestClient();
2882+
var response = await client.GetAsync("/?username=test");
2883+
response.EnsureSuccessStatusCode();
2884+
Assert.Equal("Hello test!", await response.Content.ReadAsStringAsync());
2885+
}
2886+
2887+
[Fact]
2888+
public async Task ImplicitMiddlewares_RunBeforeExplicitRouting_TerminalMiddleware()
2889+
{
2890+
var builder = WebApplication.CreateBuilder();
2891+
builder.WebHost.UseTestServer();
2892+
builder.Services.AddAuthentication("testSchemeName")
2893+
.AddScheme<AuthenticationSchemeOptions, UberHandler>("testSchemeName", "testDisplayName", _ => { });
2894+
builder.Services.AddAuthorization();
2895+
await using var app = builder.Build();
2896+
2897+
app.Run((HttpContext context) =>
2898+
{
2899+
Assert.NotNull(context.Features.Get<IAuthenticationFeature>());
2900+
return context.Response.WriteAsync($"Hello {context.Request.Query["username"]}!");
2901+
});
2902+
2903+
app.UseRouting();
2904+
2905+
await app.StartAsync();
2906+
2907+
var client = app.GetTestClient();
2908+
var response = await client.GetAsync("/?username=test");
2909+
response.EnsureSuccessStatusCode();
2910+
Assert.Equal("Hello test!", await response.Content.ReadAsStringAsync());
2911+
}
2912+
2913+
[Fact]
2914+
public async Task ImplicitMiddlewares_RunBeforeExplicitRouting_TerminalMiddleware_AfterUseRouting()
2915+
{
2916+
var builder = WebApplication.CreateBuilder();
2917+
builder.WebHost.UseTestServer();
2918+
builder.Services.AddAuthentication("testSchemeName")
2919+
.AddScheme<AuthenticationSchemeOptions, UberHandler>("testSchemeName", "testDisplayName", _ => { });
2920+
builder.Services.AddAuthorization();
2921+
await using var app = builder.Build();
2922+
2923+
app.UseRouting();
2924+
2925+
app.Run((HttpContext context) =>
2926+
{
2927+
Assert.NotNull(context.Features.Get<IAuthenticationFeature>());
2928+
return context.Response.WriteAsync($"Hello {context.Request.Query["username"]}!");
2929+
});
2930+
2931+
await app.StartAsync();
2932+
2933+
var client = app.GetTestClient();
2934+
var response = await client.GetAsync("/?username=test");
2935+
response.EnsureSuccessStatusCode();
2936+
Assert.Equal("Hello test!", await response.Content.ReadAsStringAsync());
2937+
}
2938+
2939+
[Fact]
2940+
public async Task ImplicitMiddlewares_RunBetween_ExplicitRouting_TerminalMiddlewareMapGet()
2941+
{
2942+
var builder = WebApplication.CreateBuilder();
2943+
builder.WebHost.UseTestServer();
2944+
builder.Services.AddAuthentication("testSchemeName")
2945+
.AddScheme<AuthenticationSchemeOptions, UberHandler>("testSchemeName", "testDisplayName", _ => { });
2946+
builder.Services.AddAuthorization();
2947+
await using var app = builder.Build();
2948+
2949+
app.UseRouting();
2950+
2951+
app.Run((HttpContext context) =>
2952+
{
2953+
Assert.NotNull(context.Features.Get<IAuthenticationFeature>());
2954+
return context.Response.WriteAsync($"Hello {context.Request.Query["username"]}!");
2955+
});
2956+
2957+
app.MapGet("/endpoint", (HttpContext context, string username) =>
2958+
{
2959+
Assert.NotNull(context.Items["__AuthorizationMiddlewareWithEndpointInvoked"]);
2960+
Assert.NotNull(context.Features.Get<IAuthenticationFeature>());
2961+
return $"Hello {username}!";
2962+
}).AllowAnonymous();
2963+
2964+
await app.StartAsync();
2965+
2966+
var client = app.GetTestClient();
2967+
var response = await client.GetAsync("/?username=test");
2968+
response.EnsureSuccessStatusCode();
2969+
Assert.Equal("Hello test!", await response.Content.ReadAsStringAsync());
2970+
2971+
var endpointResponse = await client.GetAsync("/endpoint?username=test");
2972+
endpointResponse.EnsureSuccessStatusCode();
2973+
Assert.Equal("Hello test!", await endpointResponse.Content.ReadAsStringAsync());
2974+
}
2975+
2976+
[Fact]
2977+
public async Task ImplicitMiddlewares_RunBetween_TerminalMiddlewareMapGet()
2978+
{
2979+
var builder = WebApplication.CreateBuilder();
2980+
builder.WebHost.UseTestServer();
2981+
builder.Services.AddAuthentication("testSchemeName")
2982+
.AddScheme<AuthenticationSchemeOptions, UberHandler>("testSchemeName", "testDisplayName", _ => { });
2983+
builder.Services.AddAuthorization();
2984+
await using var app = builder.Build();
2985+
2986+
app.Run((HttpContext context) =>
2987+
{
2988+
Assert.NotNull(context.Features.Get<IAuthenticationFeature>());
2989+
return context.Response.WriteAsync($"Hello {context.Request.Query["username"]}!");
2990+
});
2991+
2992+
app.MapGet("/endpoint", (HttpContext context, string username) =>
2993+
{
2994+
Assert.NotNull(context.Items["__AuthorizationMiddlewareWithEndpointInvoked"]);
2995+
Assert.NotNull(context.Features.Get<IAuthenticationFeature>());
2996+
return $"Hello {username}!";
2997+
}).AllowAnonymous();
2998+
2999+
await app.StartAsync();
3000+
3001+
var client = app.GetTestClient();
3002+
var response = await client.GetAsync("/?username=test");
3003+
response.EnsureSuccessStatusCode();
3004+
Assert.Equal("Hello test!", await response.Content.ReadAsStringAsync());
3005+
3006+
var endpointResponse = await client.GetAsync("/endpoint?username=test");
3007+
endpointResponse.EnsureSuccessStatusCode();
3008+
Assert.Equal("Hello test!", await endpointResponse.Content.ReadAsStringAsync());
3009+
}
3010+
28413011
private class MiddlewareWithInterface : IMiddleware
28423012
{
28433013
public Task InvokeAsync(HttpContext context, RequestDelegate next)

src/Security/Authentication/Core/src/AuthAppBuilderExtensions.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using Microsoft.AspNetCore.Authentication;
5+
using Microsoft.Extensions.DependencyInjection;
6+
using Microsoft.AspNetCore.Routing;
57

68
namespace Microsoft.AspNetCore.Builder;
79

@@ -22,6 +24,17 @@ public static IApplicationBuilder UseAuthentication(this IApplicationBuilder app
2224
ArgumentNullException.ThrowIfNull(app);
2325

2426
app.Properties[AuthenticationMiddlewareSetKey] = true;
27+
28+
if (app.Properties.TryGetValue(RerouteHelper.GlobalRouteBuilderKey, out var routeBuilder) && routeBuilder is not null)
29+
{
30+
return app.Use(next =>
31+
{
32+
var newNext = RerouteHelper.Reroute(app, routeBuilder, next);
33+
var authenticationSchemeProvider = app.ApplicationServices.GetRequiredService<IAuthenticationSchemeProvider>();
34+
return new AuthenticationMiddleware(newNext, authenticationSchemeProvider).Invoke;
35+
});
36+
}
37+
2538
return app.UseMiddleware<AuthenticationMiddleware>();
2639
}
2740
}

src/Security/Authentication/Core/src/Microsoft.AspNetCore.Authentication.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
<ItemGroup>
1414
<Compile Include="$(SharedSourceRoot)SecurityHelper\**\*.cs" />
15+
<Compile Include="$(SharedSourceRoot)Reroute.cs" />
1516
</ItemGroup>
1617

1718
<ItemGroup>

src/Security/Authorization/Policy/src/AuthorizationAppBuilderExtensions.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
using Microsoft.AspNetCore.Authorization;
55
using Microsoft.AspNetCore.Authorization.Policy;
6+
using Microsoft.AspNetCore.Routing;
67
using Microsoft.Extensions.DependencyInjection;
8+
using Microsoft.Extensions.Logging;
79

810
namespace Microsoft.AspNetCore.Builder;
911

@@ -30,6 +32,21 @@ public static IApplicationBuilder UseAuthorization(this IApplicationBuilder app)
3032
VerifyServicesRegistered(app);
3133

3234
app.Properties[AuthorizationMiddlewareSetKey] = true;
35+
36+
if (app.Properties.TryGetValue(RerouteHelper.GlobalRouteBuilderKey, out var routeBuilder) && routeBuilder is not null)
37+
{
38+
return app.Use(next =>
39+
{
40+
var newNext = RerouteHelper.Reroute(app, routeBuilder, next);
41+
var authorizationPolicyProvider = app.ApplicationServices.GetRequiredService<IAuthorizationPolicyProvider>();
42+
var loggerFactory = app.ApplicationServices.GetRequiredService<ILoggerFactory>();
43+
return new AuthorizationMiddlewareInternal(newNext,
44+
app.ApplicationServices,
45+
authorizationPolicyProvider,
46+
loggerFactory.CreateLogger<AuthorizationMiddleware>()).Invoke;
47+
});
48+
}
49+
3350
return app.UseMiddleware<AuthorizationMiddlewareInternal>();
3451
}
3552

src/Security/Authorization/Policy/src/Microsoft.AspNetCore.Authorization.Policy.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<ItemGroup>
1414
<Compile Include="$(SharedSourceRoot)SecurityHelper\**\*.cs" />
1515
<Compile Include="..\..\..\..\Http\Routing\src\DataSourceDependentCache.cs" Link="DataSourceDependentCache.cs" />
16+
<Compile Include="$(SharedSourceRoot)Reroute.cs" />
1617
</ItemGroup>
1718

1819
<ItemGroup>

0 commit comments

Comments
 (0)