< Summary - Heimdall API

Information
Class: ArturRios.Heimdall.Shared.Security.TwoFactorLifetimes
Assembly: ArturRios.Heimdall.Shared
File(s): /home/runner/work/heimdall-api/heimdall-api/src/Application/ArturRios.Heimdall.Shared/Security/TwoFactorLifetimes.cs
Line coverage
100%
Covered lines: 2
Uncovered lines: 0
Coverable lines: 2
Total lines: 55
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage
100%
Covered methods: 1
Fully covered methods: 1
Total methods: 1
Method coverage: 100%
Full method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%

File(s)

/home/runner/work/heimdall-api/heimdall-api/src/Application/ArturRios.Heimdall.Shared/Security/TwoFactorLifetimes.cs

#LineLine coverage
 1namespace ArturRios.Heimdall.Shared.Security;
 2
 3/// <summary>
 4///     The lifetimes a two-factor login attempt runs on: the emailed code's (FR-2F-03) and the
 5///     challenge token's (NFR-17). They are declared together, in one type, because between AF-11g
 6///     issuing them and UC-38 redeeming them they are not two clocks but one deadline.
 7/// </summary>
 8/// <remarks>
 9///     <para>
 10///         They were previously three separate constants — one in <c>LoginCommandHandler</c>, one in
 11///         <c>EnableTwoFactorAuthCommandHandler</c>, one in <c>JwtTwoFactorChallengeTokenIssuer</c> —
 12///         and the last of them disagreed with the other two. Both artefacts are stamped in the same
 13///         request, so a challenge token shorter than its code meant that for the second half of
 14///         every code's life the code was genuinely correct and there was nowhere left to present
 15///         it: FR-2F-10 makes second-factor verification the only endpoint that accepts a challenge
 16///         token, so once the token lapsed the code lapsed with it. Nothing was wrong with either
 17///         artefact; the login simply stopped being completable halfway through the window the
 18///         specification promised.
 19///     </para>
 20///     <para>
 21///         Defining <see cref="ChallengeToken" /> <em>as</em> <see cref="EmailCode" /> rather than
 22///         repeating the number is what keeps that from reappearing. A later change to one moves
 23///         both, which is the only relationship between them that is ever correct.
 24///     </para>
 25///     <para>
 26///         <b>Why ten minutes and not five.</b> Ten is the tolerance FR-2F-03 chose for the one part
 27///         of this flow outside anyone's control — how long an email takes to arrive. The App method
 28///         does not need it: an authenticator generates a code on demand, so its holder never races
 29///         delivery and would be served just as well by a much shorter window. The Email method
 30///         cannot do without it, and the two methods share one challenge token, so the window has to
 31///         be the longer of what they need. The cost is that a stolen challenge token is useful for
 32///         ten minutes rather than five — which is a smaller concession than it reads as, since the
 33///         token authorises nothing by itself: it is refused at every endpoint but second-factor
 34///         verification (FR-2F-10), and there it still buys nothing without a second factor.
 35///     </para>
 36///     <para>
 37///         Both remain fixed constants rather than configuration, for the reason NFR-17 gives: a
 38///         full login token's lifetime is meant to be tuned per deployment, but these two are
 39///         security properties of the use case itself, and an operator who could move them could
 40///         reintroduce the disagreement this type exists to prevent.
 41///     </para>
 42/// </remarks>
 43public static class TwoFactorLifetimes
 44{
 45    /// <summary>
 46    ///     How long an emailed 6-digit code stays redeemable after issue (FR-2F-03).
 47    /// </summary>
 448    public static readonly TimeSpan EmailCode = TimeSpan.FromMinutes(10);
 49
 50    /// <summary>
 51    ///     How long the challenge token issued alongside that code stays usable (NFR-17). Equal to
 52    ///     <see cref="EmailCode" /> by definition — see the remarks.
 53    /// </summary>
 454    public static readonly TimeSpan ChallengeToken = EmailCode;
 55}

Methods/Properties

.cctor()