| | | 1 | | using ArturRios.Jwt; |
| | | 2 | | using ArturRios.Util.WebApi.Security.Authentication; |
| | | 3 | | using ArturRios.Util.WebApi.Security.Interfaces; |
| | | 4 | | using ArturRios.Util.WebApi.Security.Records; |
| | | 5 | | |
| | | 6 | | namespace ArturRios.Heimdall.WebApi.Security; |
| | | 7 | | |
| | | 8 | | /// <summary> |
| | | 9 | | /// The bearer-token validator <c>AuthenticationMiddleware</c> runs: the library's |
| | | 10 | | /// <see cref="JwtTokenValidator" />, which checks the signature and lifetime and maps the claims, |
| | | 11 | | /// followed by the issuer and audience check it does not make (<see cref="TokenOrigin" />). |
| | | 12 | | /// </summary> |
| | | 13 | | /// <remarks> |
| | | 14 | | /// <para> |
| | | 15 | | /// A token passes only under the configured issuer and one of the three person audiences |
| | | 16 | | /// (<see cref="PersonTokenAudiences" />). The challenge audience is among them so that |
| | | 17 | | /// <see cref="MfaPendingGuardFilter" /> still answers a challenge used as a bearer token with |
| | | 18 | | /// its own refusal; the application audience is not, since an application token is never a |
| | | 19 | | /// person (TH-35). |
| | | 20 | | /// </para> |
| | | 21 | | /// <para> |
| | | 22 | | /// A token refused here gets the answer a bad signature gets, so a correctly signed token for |
| | | 23 | | /// another service cannot be told apart from a forged one. |
| | | 24 | | /// </para> |
| | | 25 | | /// </remarks> |
| | 911 | 26 | | public sealed class PersonTokenValidator( |
| | 911 | 27 | | JwtTokenValidator inner, |
| | 911 | 28 | | JwtConfiguration configuration, |
| | 911 | 29 | | PersonTokenAudiences audiences) : ITokenValidator |
| | | 30 | | { |
| | | 31 | | /// <summary>The error <see cref="JwtTokenValidator" /> gives a token whose signature or lifetime fails.</summary> |
| | | 32 | | public const string InvalidToken = "Invalid token"; |
| | | 33 | | |
| | | 34 | | /// <inheritdoc /> |
| | | 35 | | public async Task<TokenValidationResult> ValidateAsync(string token, HttpContext context) |
| | | 36 | | { |
| | 1048 | 37 | | var result = await inner.ValidateAsync(token, context); |
| | | 38 | | |
| | 1048 | 39 | | if (result.User is null) |
| | | 40 | | { |
| | 100 | 41 | | return result; |
| | | 42 | | } |
| | | 43 | | |
| | 948 | 44 | | return TokenOrigin.IsIssuedFor( |
| | 948 | 45 | | token, configuration.Issuer, audiences.Person, audiences.TwoFactorChallenge, audiences.SubjectRights) |
| | 948 | 46 | | ? result |
| | 948 | 47 | | : new TokenValidationResult(null, InvalidToken); |
| | 1048 | 48 | | } |
| | | 49 | | } |