From ef59cd17356cf9b2d6cb74b529a6a76a886953bc Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Tue, 18 Aug 2026 14:02:07 +0100 Subject: [PATCH] fix(circle-api): use User.GetUserId() for owner scoping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The scoping that landed in e376aed8 ("restrict Circle + BlogAcl reads and writes to caller's own data") reads the caller's uid with User.FindFirstValue(ClaimTypes.NameIdentifier). That works when the JWT bearer middleware remaps the "sub" claim to the long ClaimTypes.NameIdentifier URI — which is the default behaviour. But the BlogsWebServerFixture test host and any host that sets MapInboundClaims = false (preserved here to keep "sub" as "sub" for the resource-based ownership checks in BlogSpotService) end up with no ClaimTypes.NameIdentifier claim at all, only "sub". On those hosts, every OwnerId == uid filter silently returns nothing, so the controller responds 404 even for the caller's own circles. Switch to the canonical User.GetUserId() extension helper (Yavsc.Server.Helpers.UserHelpers), which tries "sub" first, then ClaimTypes.NameIdentifier, then "nameid". This aligns CircleApiController with BlogApiController (which already uses GetUserId()) and restores correct behaviour on hosts that run with MapInboundClaims = false. Drop the now-unused System.Security.Claims using. No behavioural change for production: there, MapInboundClaims remains true, ClaimTypes.NameIdentifier is populated, and GetUserId() returns the same value as FindFirstValue would have. --- src/Yavsc.Blogs/Controllers/CircleApiController.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Yavsc.Blogs/Controllers/CircleApiController.cs b/src/Yavsc.Blogs/Controllers/CircleApiController.cs index 368b488a..71ae997e 100644 --- a/src/Yavsc.Blogs/Controllers/CircleApiController.cs +++ b/src/Yavsc.Blogs/Controllers/CircleApiController.cs @@ -1,5 +1,4 @@ using System.Linq; -using System.Security.Claims; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Yavsc.Models; @@ -27,7 +26,7 @@ namespace Yavsc.Blogs.Controllers [HttpGet] public IEnumerable GetCircle() { - var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); + var uid = User.GetUserId(); return _context.Circle.Where(c => c.OwnerId == uid); } @@ -43,7 +42,7 @@ namespace Yavsc.Blogs.Controllers return BadRequest(ModelState); } - var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); + var uid = User.GetUserId(); Circle circle = await _context.Circle.SingleOrDefaultAsync( m => m.Id == id && m.OwnerId == uid); @@ -74,7 +73,7 @@ namespace Yavsc.Blogs.Controllers return BadRequest(); } - var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); + var uid = User.GetUserId(); var existing = await _context.Circle.SingleOrDefaultAsync( c => c.Id == id && c.OwnerId == uid); if (existing is null) @@ -118,7 +117,7 @@ namespace Yavsc.Blogs.Controllers return BadRequest(ModelState); } - var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); + var uid = User.GetUserId(); circle.OwnerId = uid; _context.Circle.Add(circle); @@ -156,7 +155,7 @@ namespace Yavsc.Blogs.Controllers return BadRequest(ModelState); } - var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); + var uid = User.GetUserId(); Circle circle = await _context.Circle.SingleOrDefaultAsync( m => m.Id == id && m.OwnerId == uid); if (circle == null)