Skip to content

Commit f1e28e0

Browse files
committed
Match the path base and normalize OpenIddict opt-in endpoint paths
- Rename completedOnResponseStarting and fix response-start completion comments and docs
1 parent bb413e6 commit f1e28e0

4 files changed

Lines changed: 23 additions & 12 deletions

File tree

framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpAspNetCoreUnitOfWorkOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public class AbpAspNetCoreUnitOfWorkOptions
3333
/// <see cref="CompleteUnitOfWorkOnResponseStarting"/> even when it is globally disabled (for example
3434
/// "/connect" matches "/connect/token" but not "/connections"). A trailing slash is normalized; blank,
3535
/// non-absolute, and root ("/") entries are ignored - use <see cref="CompleteUnitOfWorkOnResponseStarting"/>
36-
/// to enable it for every request.
36+
/// to enable it for every request handled by the middleware.
3737
/// </summary>
3838
public List<string> CompleteUnitOfWorkOnResponseStartingUrls { get; } = new List<string>();
3939
}

framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public async override Task InvokeAsync(HttpContext context, RequestDelegate next
3737

3838
using (var uow = _unitOfWorkManager.Reserve(UnitOfWork.UnitOfWorkReservationName))
3939
{
40-
var completedOnResponseStarting = false;
40+
var completionAttemptedOnResponseStarting = false;
4141

4242
if (!context.Response.HasStarted && ShouldCompleteOnResponseStarting(context))
4343
{
@@ -47,15 +47,15 @@ public async override Task InvokeAsync(HttpContext context, RequestDelegate next
4747
if (_unitOfWorkManager.Current == uow)
4848
{
4949
// Set before completing so a post-commit failure isn't masked by the completion below.
50-
completedOnResponseStarting = true;
50+
completionAttemptedOnResponseStarting = true;
5151
await uow.CompleteAsync(_cancellationTokenProvider.Token);
5252
}
5353
});
5454
}
5555

5656
await next(context);
5757

58-
if (!completedOnResponseStarting)
58+
if (!completionAttemptedOnResponseStarting)
5959
{
6060
await uow.CompleteAsync(_cancellationTokenProvider.Token);
6161
}
@@ -84,8 +84,15 @@ private bool ShouldCompleteOnResponseStarting(HttpContext context)
8484

8585
// Normalize a trailing slash ("/connect/" behaves like "/connect") and ignore non-absolute entries.
8686
var prefix = url.TrimEnd('/');
87-
if (prefix.StartsWith("/", StringComparison.Ordinal) &&
88-
context.Request.Path.StartsWithSegments(prefix, StringComparison.OrdinalIgnoreCase))
87+
if (!prefix.StartsWith("/", StringComparison.Ordinal))
88+
{
89+
continue;
90+
}
91+
92+
// Match both the request path and the path base + path, so an absolute endpoint that includes
93+
// the path base still matches when the path base is stripped from Request.Path.
94+
if (context.Request.Path.StartsWithSegments(prefix, StringComparison.OrdinalIgnoreCase) ||
95+
context.Request.PathBase.Add(context.Request.Path).StartsWithSegments(prefix, StringComparison.OrdinalIgnoreCase))
8996
{
9097
return true;
9198
}

modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using Microsoft.AspNetCore.Identity;
45
using Microsoft.AspNetCore.Mvc.Razor;
@@ -50,7 +51,7 @@ public override void ConfigureServices(ServiceConfigurationContext context)
5051
options.RemoveClientIdClaim();
5152
});
5253

53-
// Commit tokens/authorizations/sessions written during sign-in before the response is flushed.
54+
// Complete data written while processing OpenIddict requests before the response starts.
5455
// Derived from the configured OpenIddict server endpoint paths (including the device endpoint).
5556
context.Services.AddOptions<AbpAspNetCoreUnitOfWorkOptions>()
5657
.Configure<IOptions<OpenIddictServerOptions>>((uowOptions, serverOptions) =>
@@ -65,6 +66,8 @@ public override void ConfigureServices(ServiceConfigurationContext context)
6566
});
6667
}
6768

69+
private static readonly Uri RootUri = new Uri("http://localhost/");
70+
6871
private static IEnumerable<string> GetServerEndpointPaths(OpenIddictServerOptions serverOptions)
6972
{
7073
var endpoints = serverOptions.TokenEndpointUris
@@ -77,10 +80,11 @@ private static IEnumerable<string> GetServerEndpointPaths(OpenIddictServerOption
7780

7881
foreach (var uri in endpoints)
7982
{
80-
var path = uri.IsAbsoluteUri ? uri.AbsolutePath : uri.OriginalString;
81-
if (!string.IsNullOrWhiteSpace(path))
83+
// Resolve relative endpoint URIs (e.g. "connect/token" or "./connect/token") to an absolute path.
84+
var path = (uri.IsAbsoluteUri ? uri : new Uri(RootUri, uri)).AbsolutePath;
85+
if (!string.IsNullOrWhiteSpace(path) && path != "/")
8286
{
83-
yield return "/" + path.TrimStart('/');
87+
yield return path;
8488
}
8589
}
8690
}

modules/openiddict/test/Volo.Abp.OpenIddict.AspNetCore.Tests/Volo/Abp/OpenIddict/Integration/OpenIddictTokenEndpoint_Integration_Tests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ private Task<HttpResponseMessage> RequestTokenAsync()
3434
[Fact]
3535
public async Task Token_Row_Is_Committed_Before_The_Connect_Token_Response_Is_Sent()
3636
{
37-
// The OpenIddict module opts "/connect" in by default.
37+
// The OpenIddict module opts its endpoint paths (including "/connect/token") in by default.
3838
var response = await RequestTokenAsync();
3939

4040
response.StatusCode.ShouldBe(HttpStatusCode.OK);

0 commit comments

Comments
 (0)