| | | 1 | | using ArturRios.Data.Relational.Core.Interfaces; |
| | | 2 | | using ArturRios.Heimdall.Domain.Entities; |
| | | 3 | | using ArturRios.Heimdall.Domain.Enums; |
| | | 4 | | using Microsoft.EntityFrameworkCore; |
| | | 5 | | |
| | | 6 | | namespace ArturRios.Heimdall.Shared.Services; |
| | | 7 | | |
| | | 8 | | /// <summary> |
| | | 9 | | /// Default <see cref="IScopeOwnershipChecker" />: a System Admin bypasses ownership; any other |
| | | 10 | | /// actor is authorized only when a <c>SCOPE_OWNER</c> row links their person id to the scope. |
| | | 11 | | /// </summary> |
| | 300 | 12 | | public class ScopeOwnershipChecker(IAsyncReadOnlyRepository<Person, long> personReader) : IScopeOwnershipChecker |
| | | 13 | | { |
| | | 14 | | public async Task<bool> ActorMayManageScopeAsync(int actingRole, Guid actingPersonId, long scopeId) |
| | | 15 | | { |
| | | 16 | | // A System Admin bypasses the ownership check entirely (no query needed). |
| | 190 | 17 | | if (actingRole == (int)Roles.SystemAdmin) |
| | | 18 | | { |
| | 123 | 19 | | return true; |
| | | 20 | | } |
| | | 21 | | |
| | | 22 | | // Otherwise the actor must own the scope. A logically deleted person owns nothing: they can |
| | | 23 | | // no longer authenticate (UC-11 AF-11c), so a token issued before their deletion must not |
| | | 24 | | // keep working until it expires. |
| | 67 | 25 | | return await personReader.Query().AnyAsync(person => |
| | 67 | 26 | | person.PublicId == actingPersonId && !person.IsDeleted && |
| | 67 | 27 | | person.ScopeOwnerships.Any(ownership => ownership.ScopeId == scopeId)); |
| | 190 | 28 | | } |
| | | 29 | | } |