Skip to content

Commit 202fafe

Browse files
authored
Remove Authentication property from WebApplicationBuilder and fix up middleware auto-registration (#42585)
1 parent 5b64c73 commit 202fafe

File tree

7 files changed

+82
-74
lines changed

7 files changed

+82
-74
lines changed
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
#nullable enable
22
Microsoft.AspNetCore.Builder.WebApplication.Use(System.Func<Microsoft.AspNetCore.Http.RequestDelegate!, Microsoft.AspNetCore.Http.RequestDelegate!>! middleware) -> Microsoft.AspNetCore.Builder.IApplicationBuilder!
3-
Microsoft.AspNetCore.Builder.WebApplicationBuilder.Authentication.get -> Microsoft.AspNetCore.Authentication.AuthenticationBuilder!
43
static Microsoft.Extensions.Hosting.GenericHostBuilderExtensions.ConfigureWebHostDefaults(this Microsoft.Extensions.Hosting.IHostBuilder! builder, System.Action<Microsoft.AspNetCore.Hosting.IWebHostBuilder!>! configure, System.Action<Microsoft.Extensions.Hosting.WebHostBuilderOptions!>! configureOptions) -> Microsoft.Extensions.Hosting.IHostBuilder!

src/DefaultBuilder/src/WebApplicationAuthenticationBuilder.cs

Lines changed: 0 additions & 48 deletions
This file was deleted.

src/DefaultBuilder/src/WebApplicationBuilder.cs

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

44
using System.Diagnostics;
55
using Microsoft.AspNetCore.Authentication;
6+
using Microsoft.AspNetCore.Authorization;
67
using Microsoft.AspNetCore.Hosting;
78
using Microsoft.Extensions.Configuration;
89
using Microsoft.Extensions.DependencyInjection;
@@ -18,10 +19,10 @@ public sealed class WebApplicationBuilder
1819
{
1920
private const string EndpointRouteBuilderKey = "__EndpointRouteBuilder";
2021
private const string AuthenticationMiddlewareSetKey = "__AuthenticationMiddlewareSet";
22+
private const string AuthorizationMiddlewareSetKey = "__AuthorizationMiddlewareSet";
2123

2224
private readonly HostApplicationBuilder _hostApplicationBuilder;
2325
private readonly ServiceDescriptor _genericWebHostServiceDescriptor;
24-
private readonly WebApplicationAuthenticationBuilder _webAuthBuilder;
2526

2627
private WebApplication? _builtApplication;
2728

@@ -82,7 +83,6 @@ internal WebApplicationBuilder(WebApplicationOptions options, Action<IHostBuilde
8283

8384
Host = new ConfigureHostBuilder(bootstrapHostBuilder.Context, Configuration, Services);
8485
WebHost = new ConfigureWebHostBuilder(webHostContext, Configuration, Services);
85-
_webAuthBuilder = new WebApplicationAuthenticationBuilder(Services);
8686
}
8787

8888
/// <summary>
@@ -117,11 +117,6 @@ internal WebApplicationBuilder(WebApplicationOptions options, Action<IHostBuilde
117117
/// </summary>
118118
public ConfigureHostBuilder Host { get; }
119119

120-
/// <summary>
121-
/// An <see cref="AuthenticationBuilder"/> for configuring authentication-related properties.
122-
/// </summary>
123-
public AuthenticationBuilder Authentication => _webAuthBuilder;
124-
125120
/// <summary>
126121
/// Builds the <see cref="WebApplication"/>.
127122
/// </summary>
@@ -175,15 +170,25 @@ private void ConfigureApplication(WebHostBuilderContext context, IApplicationBui
175170
}
176171
}
177172

178-
if (_webAuthBuilder.IsAuthenticationConfigured)
173+
// Process authorization and authentication middlewares independently to avoid
174+
// registering middlewares for services that do not exist
175+
if (_builtApplication.Services.GetService<IAuthenticationSchemeProvider>() is not null)
179176
{
180177
// Don't add more than one instance of the middleware
181178
if (!_builtApplication.Properties.ContainsKey(AuthenticationMiddlewareSetKey))
182179
{
183180
// The Use invocations will set the property on the outer pipeline,
184-
// but we want to set it on the inner pipeline as well
181+
// but we want to set it on the inner pipeline as well.
185182
_builtApplication.Properties[AuthenticationMiddlewareSetKey] = true;
186183
app.UseAuthentication();
184+
}
185+
}
186+
187+
if (_builtApplication.Services.GetService<IAuthorizationHandlerProvider>() is not null)
188+
{
189+
if (!_builtApplication.Properties.ContainsKey(AuthorizationMiddlewareSetKey))
190+
{
191+
_builtApplication.Properties[AuthorizationMiddlewareSetKey] = true;
187192
app.UseAuthorization();
188193
}
189194
}

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

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1990,11 +1990,9 @@ public async Task RegisterAuthMiddlewaresCorrectly()
19901990
var username = "foobar";
19911991

19921992
var builder = WebApplication.CreateBuilder();
1993-
builder.Services.AddAuthenticationCore(o =>
1994-
{
1995-
o.DefaultScheme = "testSchemeName";
1996-
});
1997-
builder.Authentication.AddScheme<AuthenticationSchemeOptions, UberHandler>("testSchemeName", "testDisplayName", _ => { });
1993+
builder.Services.AddAuthorization();
1994+
builder.Services.AddAuthentication("testSchemeName")
1995+
.AddScheme<AuthenticationSchemeOptions, UberHandler>("testSchemeName", "testDisplayName", _ => { });
19981996
builder.WebHost.UseTestServer();
19991997
await using var app = builder.Build();
20001998

@@ -2027,6 +2025,43 @@ public async Task RegisterAuthMiddlewaresCorrectly()
20272025
Assert.True(customMiddlewareExecuted);
20282026
}
20292027

2028+
[Fact]
2029+
public async Task SupportsDisablingMiddlewareAutoRegistration()
2030+
{
2031+
var builder = WebApplication.CreateBuilder();
2032+
builder.Services.AddAuthorization();
2033+
builder.Services.AddAuthentication("testSchemeName")
2034+
.AddScheme<AuthenticationSchemeOptions, UberHandler>("testSchemeName", "testDisplayName", _ => { });
2035+
builder.WebHost.UseTestServer();
2036+
await using var app = builder.Build();
2037+
2038+
app.Use(next =>
2039+
{
2040+
return async context =>
2041+
{
2042+
// IAuthenticationFeature is added by the authentication middleware
2043+
// during invocation. This middleware should run after authentication
2044+
// and be able to access the feature.
2045+
var authFeature = context.Features.Get<IAuthenticationFeature>();
2046+
Assert.Null(authFeature);
2047+
Assert.Null(context.User.Identity.Name);
2048+
await next(context);
2049+
};
2050+
});
2051+
2052+
app.Properties["__AuthenticationMiddlewareSet"] = true;
2053+
2054+
app.MapGet("/hello", (ClaimsPrincipal user) => {}).AllowAnonymous();
2055+
2056+
Assert.True(app.Properties.ContainsKey("__AuthenticationMiddlewareSet"));
2057+
Assert.False(app.Properties.ContainsKey("__AuthorizationMiddlewareSet"));
2058+
2059+
await app.StartAsync();
2060+
2061+
Assert.True(app.Properties.ContainsKey("__AuthenticationMiddlewareSet"));
2062+
Assert.True(app.Properties.ContainsKey("__AuthorizationMiddlewareSet"));
2063+
}
2064+
20302065
private class UberHandler : AuthenticationHandler<AuthenticationSchemeOptions>
20312066
{
20322067
public UberHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { }

src/Security/Authentication/JwtBearer/samples/MinimalJwtBearerSample/Program.cs

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

44
using System.Security.Claims;
5-
using Microsoft.AspNetCore.Authentication.JwtBearer;
6-
using Microsoft.Extensions.DependencyInjection;
7-
using Microsoft.AspNetCore.Builder;
85

96
var builder = WebApplication.CreateBuilder(args);
107

11-
builder.Authentication.AddJwtBearer();
12-
builder.Authentication.AddJwtBearer("ClaimedDetails");
13-
builder.Authentication.AddJwtBearer("InvalidScheme");
8+
builder.Services.AddAuthentication()
9+
.AddJwtBearer()
10+
.AddJwtBearer("ClaimedDetails")
11+
.AddJwtBearer("InvalidScheme");
1412

1513
builder.Services.AddAuthorization(options =>
1614
options.AddPolicy("is_admin", policy =>

src/Security/Authentication/test/AuthenticationMiddlewareTests.cs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,33 +154,49 @@ public async Task IAuthenticateResultFeature_SettingResultSetsUser()
154154
}
155155

156156
[Fact]
157-
public async Task WebApplicationBuilder_RegistersAuthenticationMiddlewares()
157+
public async Task WebApplicationBuilder_RegistersAuthenticationAndAuthorizationMiddlewares()
158158
{
159159
var builder = WebApplication.CreateBuilder();
160160
builder.Configuration.AddInMemoryCollection(new[]
161161
{
162162
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:ClaimsIssuer", "SomeIssuer"),
163163
new KeyValuePair<string, string>("Authentication:Schemes:Bearer:Audiences:0", "https://localhost:5001")
164164
});
165-
builder.Authentication.AddJwtBearer();
165+
builder.Services.AddAuthorization();
166+
builder.Services.AddAuthentication().AddJwtBearer();
166167
await using var app = builder.Build();
167168

168-
var webAppAuthBuilder = Assert.IsType<WebApplicationAuthenticationBuilder>(builder.Authentication);
169-
Assert.True(webAppAuthBuilder.IsAuthenticationConfigured);
170-
171169
// Authentication middleware isn't registered until application
172170
// is built on startup
173171
Assert.False(app.Properties.ContainsKey("__AuthenticationMiddlewareSet"));
172+
Assert.False(app.Properties.ContainsKey("__AuthorizationMiddlewareSet"));
174173

175174
await app.StartAsync();
176175

177176
Assert.True(app.Properties.ContainsKey("__AuthenticationMiddlewareSet"));
177+
Assert.True(app.Properties.ContainsKey("__AuthorizationMiddlewareSet"));
178178

179179
var options = app.Services.GetService<IOptionsMonitor<JwtBearerOptions>>().Get(JwtBearerDefaults.AuthenticationScheme);
180180
Assert.Equal(new[] { "SomeIssuer" }, options.TokenValidationParameters.ValidIssuers);
181181
Assert.Equal(new[] { "https://localhost:5001" }, options.TokenValidationParameters.ValidAudiences);
182182
}
183183

184+
[Fact]
185+
public async Task WebApplicationBuilder_OnlyRegistersMiddlewareWithSupportedServices()
186+
{
187+
var builder = WebApplication.CreateBuilder();
188+
builder.Services.AddAuthentication().AddJwtBearer();
189+
await using var app = builder.Build();
190+
191+
Assert.False(app.Properties.ContainsKey("__AuthenticationMiddlewareSet"));
192+
Assert.False(app.Properties.ContainsKey("__AuthorizationMiddlewareSet"));
193+
194+
await app.StartAsync();
195+
196+
Assert.True(app.Properties.ContainsKey("__AuthenticationMiddlewareSet"));
197+
Assert.False(app.Properties.ContainsKey("__AuthorizationMiddlewareSet"));
198+
}
199+
184200
private HttpContext GetHttpContext(
185201
Action<IServiceCollection> registerServices = null,
186202
IAuthenticationService authenticationService = null)

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ namespace Microsoft.AspNetCore.Builder;
1212
/// </summary>
1313
public static class AuthorizationAppBuilderExtensions
1414
{
15+
internal const string AuthorizationMiddlewareSetKey = "__AuthorizationMiddlewareSet";
16+
1517
/// <summary>
1618
/// Adds the <see cref="AuthorizationMiddleware"/> to the specified <see cref="IApplicationBuilder"/>, which enables authorization capabilities.
1719
/// <para>
@@ -30,6 +32,7 @@ public static IApplicationBuilder UseAuthorization(this IApplicationBuilder app)
3032

3133
VerifyServicesRegistered(app);
3234

35+
app.Properties[AuthorizationMiddlewareSetKey] = true;
3336
return app.UseMiddleware<AuthorizationMiddleware>();
3437
}
3538

0 commit comments

Comments
 (0)