Skip to content

Commit

Permalink
Register AuthN/Z middleware automatically in CreateSlimBuilder (dotne…
Browse files Browse the repository at this point in the history
…t#47664)

WebApplication.CreateSlimBuilder() should auto-register AuthN/Z middleware when associated services are added This is consistent with CreateBuilder, and doesn't add much size to the app when AuthN/Z are not used.

Fix dotnet#47507
  • Loading branch information
eerhardt authored Apr 13, 2023
1 parent 0899b0a commit 53b9175
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 59 deletions.
67 changes: 25 additions & 42 deletions src/DefaultBuilder/src/WebApplicationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ internal WebApplicationBuilder(WebApplicationOptions options, bool slim, Action<
{
AspNetCore.WebHost.ConfigureWebDefaultsCore(webHostBuilder);

webHostBuilder.Configure(ConfigureEmptyApplication);
// Runs inline.
webHostBuilder.Configure(ConfigureApplication);

webHostBuilder.UseSetting(WebHostDefaults.ApplicationKey, _hostApplicationBuilder.Environment.ApplicationName ?? "");
webHostBuilder.UseSetting(WebHostDefaults.PreventHostingStartupKey, Configuration[WebHostDefaults.PreventHostingStartupKey]);
Expand Down Expand Up @@ -260,46 +261,6 @@ public WebApplication Build()
}

private void ConfigureApplication(WebHostBuilderContext context, IApplicationBuilder app)
{
ConfigureApplicationCore(
context,
app,
processAuthMiddlewares: () =>
{
Debug.Assert(_builtApplication is not null);

// Process authorization and authentication middlewares independently to avoid
// registering middlewares for services that do not exist
var serviceProviderIsService = _builtApplication.Services.GetService<IServiceProviderIsService>();
if (serviceProviderIsService?.IsService(typeof(IAuthenticationSchemeProvider)) is true)
{
// Don't add more than one instance of the middleware
if (!_builtApplication.Properties.ContainsKey(AuthenticationMiddlewareSetKey))
{
// The Use invocations will set the property on the outer pipeline,
// but we want to set it on the inner pipeline as well.
_builtApplication.Properties[AuthenticationMiddlewareSetKey] = true;
app.UseAuthentication();
}
}

if (serviceProviderIsService?.IsService(typeof(IAuthorizationHandlerProvider)) is true)
{
if (!_builtApplication.Properties.ContainsKey(AuthorizationMiddlewareSetKey))
{
_builtApplication.Properties[AuthorizationMiddlewareSetKey] = true;
app.UseAuthorization();
}
}
});
}

private void ConfigureEmptyApplication(WebHostBuilderContext context, IApplicationBuilder app)
{
ConfigureApplicationCore(context, app, processAuthMiddlewares: null);
}

private void ConfigureApplicationCore(WebHostBuilderContext context, IApplicationBuilder app, Action? processAuthMiddlewares)
{
Debug.Assert(_builtApplication is not null);

Expand Down Expand Up @@ -340,7 +301,29 @@ private void ConfigureApplicationCore(WebHostBuilderContext context, IApplicatio
}
}

processAuthMiddlewares?.Invoke();
// Process authorization and authentication middlewares independently to avoid
// registering middlewares for services that do not exist
var serviceProviderIsService = _builtApplication.Services.GetService<IServiceProviderIsService>();
if (serviceProviderIsService?.IsService(typeof(IAuthenticationSchemeProvider)) is true)
{
// Don't add more than one instance of the middleware
if (!_builtApplication.Properties.ContainsKey(AuthenticationMiddlewareSetKey))
{
// The Use invocations will set the property on the outer pipeline,
// but we want to set it on the inner pipeline as well.
_builtApplication.Properties[AuthenticationMiddlewareSetKey] = true;
app.UseAuthentication();
}
}

if (serviceProviderIsService?.IsService(typeof(IAuthorizationHandlerProvider)) is true)
{
if (!_builtApplication.Properties.ContainsKey(AuthorizationMiddlewareSetKey))
{
_builtApplication.Properties[AuthorizationMiddlewareSetKey] = true;
app.UseAuthorization();
}
}

// Wire the source pipeline to run in the destination pipeline
app.Use(next =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2260,31 +2260,21 @@ public void CanObserveDefaultServicesInServiceCollection(CreateBuilderFunc creat
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task RegisterAuthMiddlewaresCorrectly(bool useSlimBuilder)
[MemberData(nameof(CreateBuilderFuncs))]
public async Task RegisterAuthMiddlewaresCorrectly(CreateBuilderFunc createBuilder)
{
var helloEndpointCalled = false;
var customMiddlewareExecuted = false;
var username = "foobar";

var builder = useSlimBuilder ?
WebApplication.CreateSlimBuilder() :
WebApplication.CreateBuilder();
var builder = createBuilder();

builder.Services.AddAuthorization();
builder.Services.AddAuthentication("testSchemeName")
.AddScheme<AuthenticationSchemeOptions, UberHandler>("testSchemeName", "testDisplayName", _ => { });
builder.WebHost.UseTestServer();
await using var app = builder.Build();

if (useSlimBuilder)
{
// NOTE: CreateSlimBuilder doesn't support auto registration of auth middleware, so need to do it explicitly
app.UseAuthentication();
app.UseAuthorization();
}

app.Use(next =>
{
return async context =>
Expand Down Expand Up @@ -2314,11 +2304,11 @@ public async Task RegisterAuthMiddlewaresCorrectly(bool useSlimBuilder)
Assert.True(customMiddlewareExecuted);
}

[Fact]
public async Task SupportsDisablingMiddlewareAutoRegistration()
[Theory]
[MemberData(nameof(CreateBuilderFuncs))]
public async Task SupportsDisablingMiddlewareAutoRegistration(CreateBuilderFunc createBuilder)
{
// NOTE: CreateSlimBuilder doesn't support auto registration of auth middleware
var builder = WebApplication.CreateBuilder();
var builder = createBuilder();
builder.Services.AddAuthorization();
builder.Services.AddAuthentication("testSchemeName")
.AddScheme<AuthenticationSchemeOptions, UberHandler>("testSchemeName", "testDisplayName", _ => { });
Expand Down

0 comments on commit 53b9175

Please sign in to comment.