Skip to content

Rerun PostRoutingPipeline on Rerouting#67618

Merged
DeagleGross merged 2 commits into
dotnet:mainfrom
DeagleGross:dmkorolev/blazor-templates-csrf
Jul 8, 2026
Merged

Rerun PostRoutingPipeline on Rerouting#67618
DeagleGross merged 2 commits into
dotnet:mainfrom
DeagleGross:dmkorolev/blazor-templates-csrf

Conversation

@DeagleGross

@DeagleGross DeagleGross commented Jul 6, 2026

Copy link
Copy Markdown
Member

As found out in #67588 and #67589, there are blazor template test which repros the bug with CsrfProtectionMiddleware used with UseStatusCodePagesWithReExecute on the same app. I reproduced it in CsrfProtectionIntegrationTests and am fixing in current PR.

The major change is to start reruning PostRoutingPipeline on each reroute - technically, that is a breaking change, but is safer and more explanative.

Related #67588

…nmiddleware + extensive rerouting test suite
Copilot AI review requested due to automatic review settings July 6, 2026 15:33
@DeagleGross DeagleGross requested a review from halter73 as a code owner July 6, 2026 15:33
@DeagleGross DeagleGross changed the title Rerun PostRoutingPipeline on rerouting Rerun PostRoutingPipeline on Rerouting Jul 6, 2026
@DeagleGross DeagleGross self-assigned this Jul 6, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts how the framework’s deferred “post-routing” pipeline (implicit auth/authz/CSRF middleware) is applied so it also runs correctly when the request pipeline is re-executed via rerouting (e.g., UseStatusCodePagesWithReExecute’s reroute branch). It also tightens CSRF marker stamping to only occur when an endpoint opts into antiforgery metadata, and expands integration test coverage for rerouting-related scenarios.

Changes:

  • Stop consuming/removing the __Internal_PostRoutingPipeline application property so reroute-built routing branches can still observe and apply the framework’s post-routing pipeline.
  • Update CsrfProtectionMiddleware to early-return unless the matched endpoint has IAntiforgeryMetadata, reducing HttpContext.Items allocations on the non-antiforgery path.
  • Add routing/rerouting-focused CSRF integration tests (and required Rewrite assembly reference).
Show a summary per file
File Description
src/Http/Routing/src/EndpointRoutingMiddleware.cs Keeps the framework post-routing pipeline available so it can be applied again in reroute-created routing branches.
src/DefaultBuilder/src/Internal/CsrfProtectionMiddleware.cs Only stamps the CSRF sentinel when the matched endpoint has antiforgery metadata; avoids work on endpoint-less / non-antiforgery paths.
src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/Microsoft.AspNetCore.Tests.csproj Adds Microsoft.AspNetCore.Rewrite reference for new test coverage using UseRewriter.
src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/CsrfProtectionIntegrationTests.cs Adds integration tests for CSRF marker/endpoint behavior across rerouting and pipeline variants.

Copilot's findings

  • Files reviewed: 4/4 changed files
  • Comments generated: 2

} No newline at end of file

[Fact]
public async Task Repro_BlazorTemplatePipeline_CsrfMarkerIsStampedBeforeEndpoint_OnReroute()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't look like it reroutes. The request to / returns 200, so StatusCodePages never re-executes /not-found.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it does not "reroute", but calls app.UseStatusCodePagesWithReExecute() which essentially adds the following to the pipeline:

return app.Use(next =>
{
    var newNext = RerouteHelper.Reroute(app, routeBuilder, next);
    return new StatusCodePagesMiddleware(next,
        Options.Create(new StatusCodePagesOptions()
        {
            HandleAsync = CreateHandler(pathFormat, queryFormat, newNext),
            CreateScopeForStatusCodePages = createScopeForStatusCodePages,
            PathFormat = pathFormat
        })).Invoke;
});

and in the previous code was causing problems - it happens after routing always, and has no PostRoutingPipeline in the applicationBuilder.Properties, meaning that it was not invoking CSRF on "reroute". I am sure this test must exist - do you think we should change it anyhow?

renamed to Repro_BlazorTemplatePipeline_CsrfMarkerIsStampedBeforeEndpoint_WithStatusCodePagesMiddleware to not bring confusion.

}

[Fact]
public async Task CsrfProtection_UseStatusCodePagesWithReExecute_CsrfMarkerStampedOnReroutedRequest()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this cover the CORS metadata case too? The original concern was ValidateAsync running before the re-executed endpoint's RequireCors metadata was available, and this only checks antiforgery metadata.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added test which touches CORS and verifies it runs. The flow is the following:

  1. EndpointRoutingMiddleware runs, does not find match and sets context.Endpoint = null

  2. PostRoutingPipeline with CSRF just skips CSRF run

  3. EndpointMiddleware does not see endpoint either (null), and skips

  4. StatusCodePagesMiddleware starts reroute because it sees 404

    1. Path is set to not-found now, so it matches on EndpointRoutingMiddleware now
    2. It triggers PostRoutingPipeline, which calls CsrfProtectionMiddleware which now sees endpoint, and calls CORS policy resolve
    3. It resolves ICorsMetadata, and which calls ICorsPolicyProvider and it resolves the policy

CORS knows how to match if the context.GetEndpoint() is not null. Since we now skip if (endpoint is null) { return ... } in CSRF, then its safe.

@javiercn javiercn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

I think there is still an issue lurking on #67588 though as it needs to be updated to rely on the new antiforgery check. I believe this change by itself won't fix that.

@DeagleGross DeagleGross merged commit caa7a7a into dotnet:main Jul 8, 2026
25 checks passed
@DeagleGross DeagleGross deleted the dmkorolev/blazor-templates-csrf branch July 8, 2026 09:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants