| | | 1 | | using ArturRios.Jwt; |
| | | 2 | | |
| | | 3 | | namespace ArturRios.Heimdall.WebApi.Security; |
| | | 4 | | |
| | | 5 | | /// <summary> |
| | | 6 | | /// The audiences of the three tokens Heimdall issues to a person: the full token's, configured as |
| | | 7 | | /// <c>HEIMDALL_AUTH_TOKEN_AUDIENCE</c>, and the two derived from it for the tokens that are not a |
| | | 8 | | /// sign-in — the UC-38 challenge token (NFR-17) and the subject-rights-only token (NFR-24). |
| | | 9 | | /// </summary> |
| | | 10 | | /// <remarks> |
| | | 11 | | /// <para> |
| | | 12 | | /// <b>Why the audiences differ.</b> All three are signed with the same keys under the same |
| | | 13 | | /// issuer. What makes a challenge token or a subject-rights-only token less than a sign-in is a |
| | | 14 | | /// claim only Heimdall reads (<c>mfaPending</c>, <c>subjectRightsOnly</c>). A consumer that |
| | | 15 | | /// validates the signature, issuer, audience and lifetime would take either for a full token |
| | | 16 | | /// if they shared its audience: a password alone would get past the second factor there, and a |
| | | 17 | | /// restricted identity would act as an unrestricted one (Threat Model TH-06, TH-35). A distinct |
| | | 18 | | /// audience makes a consumer that pins the person audience refuse both, by construction and |
| | | 19 | | /// with no knowledge of Heimdall's claims, as it refuses application tokens. |
| | | 20 | | /// </para> |
| | | 21 | | /// <para> |
| | | 22 | | /// <b>Why derived rather than configured.</b> Unlike <see cref="ApplicationTokenOptions" />, no |
| | | 23 | | /// variable is read: a suffix on the person audience is distinct from it and from the other |
| | | 24 | | /// suffix whatever the person audience is, so the three person audiences can never be set |
| | | 25 | | /// equal, and there is nothing new to set. The application audience is configured, though, |
| | | 26 | | /// and could be; <see cref="ApplicationTokenOptions.Parse" /> refuses it equal to either |
| | | 27 | | /// derived audience at start-up. The suffixes are fixed so a consumer can name the audiences |
| | | 28 | | /// too. |
| | | 29 | | /// </para> |
| | | 30 | | /// <para> |
| | | 31 | | /// <b>Inside Heimdall.</b> <see cref="PersonTokenValidator" /> admits a bearer token only |
| | | 32 | | /// under the configured issuer and one of these three audiences (<see cref="TokenOrigin" />), |
| | | 33 | | /// and <see cref="IdentityUserMapper" /> holds each audience to its claim: a token is mapped |
| | | 34 | | /// only when its audience and its <c>mfaPending</c> and <c>subjectRightsOnly</c> claims agree. |
| | | 35 | | /// </para> |
| | | 36 | | /// </remarks> |
| | | 37 | | /// <param name="Person"> |
| | | 38 | | /// The audience of a full token, <c>HEIMDALL_AUTH_TOKEN_AUDIENCE</c> exactly as configured. |
| | | 39 | | /// </param> |
| | 13608 | 40 | | public sealed record PersonTokenAudiences(string Person) |
| | | 41 | | { |
| | | 42 | | /// <summary>The suffix that turns the person audience into the challenge token's.</summary> |
| | | 43 | | public const string TwoFactorChallengeSuffix = ".2fa-challenge"; |
| | | 44 | | |
| | | 45 | | /// <summary>The suffix that turns the person audience into the subject-rights-only token's.</summary> |
| | | 46 | | public const string SubjectRightsSuffix = ".subject-rights"; |
| | | 47 | | |
| | | 48 | | /// <summary>The audience of a UC-38 challenge token: the person audience plus <see cref="TwoFactorChallengeSuffix" |
| | 4012 | 49 | | public string TwoFactorChallenge => Person + TwoFactorChallengeSuffix; |
| | | 50 | | |
| | | 51 | | /// <summary>The audience of a subject-rights-only token: the person audience plus <see cref="SubjectRightsSuffix" / |
| | 3851 | 52 | | public string SubjectRights => Person + SubjectRightsSuffix; |
| | | 53 | | |
| | | 54 | | /// <summary>The audiences derived from the configuration full tokens are issued and validated with.</summary> |
| | 899 | 55 | | public static PersonTokenAudiences From(JwtConfiguration configuration) => new(configuration.Audience); |
| | | 56 | | } |