| | | 1 | | using ArturRios.Util.WebApi.Security.Interfaces; |
| | | 2 | | |
| | | 3 | | namespace ArturRios.Heimdall.WebApi.Security; |
| | | 4 | | |
| | | 5 | | /// <summary> |
| | | 6 | | /// The caller identity this API carries on an authenticated request, rebuilt from the token's |
| | | 7 | | /// claims by <see cref="IdentityUserMapper" /> (UC-11, FR-AU-04). Every identifier is a |
| | | 8 | | /// <c>PublicId</c>: internal <c>bigint</c> Ids never reach a token or the request pipeline |
| | | 9 | | /// (NFR-15). |
| | | 10 | | /// </summary> |
| | | 11 | | /// <param name="Id">The person's <c>PublicId</c>.</param> |
| | | 12 | | /// <param name="RoleId">The person's role value (see <c>Roles</c>).</param> |
| | | 13 | | /// <param name="ScopeId"> |
| | | 14 | | /// The <c>PublicId</c> of the scope a <c>User</c> belongs to; <c>null</c> for a |
| | | 15 | | /// <c>ScopeAdmin</c> or <c>SystemAdmin</c>. |
| | | 16 | | /// </param> |
| | | 17 | | /// <param name="OwnedScopeIds"> |
| | | 18 | | /// The <c>PublicId</c>s of the scopes a <c>ScopeAdmin</c> owns; empty for a <c>User</c> or |
| | | 19 | | /// <c>SystemAdmin</c>. |
| | | 20 | | /// </param> |
| | 1956 | 21 | | public sealed record IdentityUser( |
| | 3179 | 22 | | Guid Id, |
| | 3581 | 23 | | int RoleId, |
| | 934 | 24 | | Guid? ScopeId, |
| | 2873 | 25 | | IReadOnlyCollection<Guid> OwnedScopeIds) : IAuthenticatedUser |
| | | 26 | | { |
| | | 27 | | /// <summary> |
| | | 28 | | /// The caller's display name, included on full authentication tokens so downstream services |
| | | 29 | | /// can provision a local profile without calling Heimdall on the request path. |
| | | 30 | | /// </summary> |
| | 2120 | 31 | | public string? DisplayName { get; init; } |
| | | 32 | | |
| | | 33 | | /// <summary> |
| | | 34 | | /// The names of the acting scope's permissions whose <c>IncludeAsJwtClaim</c> flag is set, |
| | | 35 | | /// folded into the token at login so a downstream caller can authorize on them (UC-31…UC-35). |
| | | 36 | | /// Empty for a <c>SystemAdmin</c> (no scope) and when a scope has no flagged permissions. |
| | | 37 | | /// </summary> |
| | 4006 | 38 | | public IReadOnlyCollection<string> ScopePermissionClaims { get; init; } = []; |
| | | 39 | | |
| | | 40 | | /// <summary>An identity carrying no scope claim, for a <c>SystemAdmin</c>.</summary> |
| | 150 | 41 | | public IdentityUser(Guid id, int roleId) : this(id, roleId, null, []) |
| | | 42 | | { |
| | 150 | 43 | | } |
| | | 44 | | |
| | | 45 | | /// <summary> |
| | | 46 | | /// Whether this identity comes from a UC-38 challenge token rather than a full authentication |
| | | 47 | | /// token (FR-2F-07, NFR-17) — set on the token by <c>JwtTwoFactorChallengeTokenIssuer</c> and |
| | | 48 | | /// read back here by <see cref="IdentityUserMapper" />. <see cref="MfaPendingGuardFilter" /> |
| | | 49 | | /// rejects every request where this is <c>true</c>, per FR-2F-10. |
| | | 50 | | /// </summary> |
| | 4326 | 51 | | public bool MfaPending { get; init; } |
| | | 52 | | |
| | | 53 | | /// <summary> |
| | | 54 | | /// Which challenge a UC-38 challenge token stands for — set alongside <see cref="MfaPending" /> |
| | | 55 | | /// by <c>JwtTwoFactorChallengeTokenIssuer</c>, <c>null</c> on every other token. UC-38 honours |
| | | 56 | | /// the token only while this still equals the configuration's outstanding challenge, which is |
| | | 57 | | /// what makes a challenge redeemable once (FR-2F-10). |
| | | 58 | | /// </summary> |
| | 2228 | 59 | | public Guid? ChallengeId { get; init; } |
| | | 60 | | |
| | | 61 | | /// <summary> |
| | | 62 | | /// Whether this identity comes from a subject-rights-only token — issued at sign-in to an |
| | | 63 | | /// identity whose processing is restricted (NFR-24), by <c>JwtAuthTokenIssuer</c>. |
| | | 64 | | /// <see cref="SubjectRightsOnlyGuardFilter" /> refuses such a token on every action not marked |
| | | 65 | | /// <see cref="DataSubjectRightAttribute" />. |
| | | 66 | | /// </summary> |
| | 4119 | 67 | | public bool SubjectRightsOnly { get; init; } |
| | | 68 | | |
| | | 69 | | /// <summary> |
| | | 70 | | /// The person's <c>SecurityStamp</c> when the token was issued (FR-AU-11), carried by every |
| | | 71 | | /// person token — full, challenge and subject-rights-only — and <c>null</c> on a Google User's, |
| | | 72 | | /// which has no credential of its own here to rotate. <see cref="ActorLivenessFilter" /> |
| | | 73 | | /// refuses a person token whose stamp is missing or no longer the person's. |
| | | 74 | | /// </summary> |
| | 4489 | 75 | | public Guid? SecurityStamp { get; init; } |
| | | 76 | | } |