Class UserMFA

java.lang.Object
com.iizix.server.user.mfa.UserMFA

public final class UserMFA extends Object
The second factor of the users of the server (SignIn L-6, the survey's section 9.3 item 7, and sections 3.5 and 6 of the SignIn flow design): what MFAUser and com.iizix.totp could not do on their own. They validate a code against a secret; this class is what makes that a factor of a sign-in:
  • the secret is stored, sealed (MFAStore, MFASecretSeal): until now it lived in the memory of the instance that generated it;
  • an enrolment is confirmed by a first valid code before anything is stored (beginEnrolment(Object, long, String, String), confirmEnrolment(Object, long, String)), so that an authenticator app that was enrolled wrongly locks nobody out;
  • a code is accepted once: the time step of the last accepted code is kept, and the code of that step or of an earlier one is refused (RFC 6238 section 5.2);
  • invalid codes are limited per account, by waits that grow with the count (waitAfter(int)), and per waiting sign-in (MAX_PENDING_FAILURES); the limit per client source is the caller's SourceThrottle;
  • recovery codes are made when the enrolment is confirmed, returned once, stored hashed as passwords are, and each is used once;
  • a passkey may be the second factor (CC-FIX-SIGNIN-2FA-CHOICE): the user who chose it, and registered one in the session a short time ago, has a second factor from enrolPasskey(Object, long, String) on - a row of the method passkey, without a secret, and the recovery codes, which are made at the first second factor of any kind. The passkeys themselves are the passkey store's; a passkey registered to sign in faster, by a user who has no second factor, is none;
  • a sign-in waits for its second factor, held for the client session it came from (holdSignIn(Object, long, String, boolean), completeSignIn(Object, String, String)): nothing is signed in before;
  • the proof of HUB-DESIGN 7.4 (RB-11) is kept for the session whose sign-in verified the factor (getProof(Object, long)). A passkey that was asserted with user verification is that proof too (methodOfPasskey(boolean), CC-LOGIN-M11-PASSKEY-PROOF): the passkey itself is not this class's, the proof is kept here, in the one place there is.

What is not here (CC-SIGNIN-MERGE-L5-L6-L8). The devices that are trusted not to be asked again are the rows of the device tokens (DeviceTokenStore, CC-LOGIN-L5-DEVICE-TOKEN): the trust is given and asked for by IUserAuthenticationUI, under the rules of this order - bound to the password, never by a recovery code, for the days of the policy. The recent sign-in a change of the second factor requires is the authentication time of the AppSession (CC-LOGIN-L8-PASSKEYS); what is kept here is whether the sign-in of a session verified a second factor, which has no time of its own.

The sessions are the keys of what is held, weakly: what is held for a session goes with it, and with the server. Nothing here logs a code, a secret or a recovery code.

Author:
Christopher Mindus
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final record 
    The answer to a code.
    static final record 
    A confirmed enrolment.
    static final record 
    A sign-in that waits for its second factor.
    static enum 
    What became of a request.
    static final class 
    A refusal of a request that answers with data.
    static final record 
    The names of the entry an authenticator app shows for a user's enrolment, as the enrolment's QR code gave them (CC-FIX-SIGNIN-RECOVERY): what the code page names, so that the user picks the right entry among several.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final int
    How many time steps away from this server's clock a refused code is looked for, to name the drift of a clock in the refusal (CC-FIX-SIGNIN-TOTP-ENROL, item 9): 10 steps of 30 seconds, 5 minutes.
    static final MFAUser.Hashing
    The hashing algorithm an authenticator app is enrolled with: SHA1, the algorithm of RFC 6238 that every authenticator app implements.
    static final int
    The invalid codes after which a waiting sign-in or enrolment ends: 5.
    static final Set<String>
    The methods of a second factor this class does: the authenticator app and the recovery codes.
    static final long
    How long an enrolment waits for its first code, in milliseconds: 10 minutes.
    static final long
    How long a sign-in waits for its second factor, in milliseconds: 5 minutes.
    static final int
    The quiet zone of the enrolment QR code, in modules: 4, the light margin around the code that ISO/IEC 18004 requires and that a scanner needs to find the code (QR-D-1).
    static final int
    The recovery codes made for a user: 10.
    static final String
    The method of the row of a user who chose a passkey as the second factor and enrolled an authenticator app beside it (CC-FIX-SIGNIN-2FA-CHOICE): "totp+passkey".
  • Constructor Summary

    Constructors
    Constructor
    Description
    Constructs an instance on its keys and clocks; the tests drive them.
  • Method Summary

    Modifier and Type
    Method
    Description
    beginEnrolment(Object session, long uid, String userName, String issuer)
    Begins the enrolment of an authenticator app for a user: the secret is generated and held for the client session, and nothing is stored.
    completeSignIn(Object session, String method, String code)
    Completes the sign-in the client session holds, with a verification code or a recovery code.
    confirmEnrolment(Object session, long uid, String code)
    Confirms the enrolment the client session holds with the first code of the authenticator app: the secret is sealed and stored, the time step of the code is the last accepted one (the code that confirmed is spent), the recovery codes are made and their hashes stored.
    enrolPasskey(Object session, long uid, String userName)
    Makes a passkey the second factor of a user (CC-FIX-SIGNIN-2FA-CHOICE): the user chose a passkey, and the client session registered one for the user a short time ago (onPasskeyRegistered(Object, long)).
    void
    forget(Object session)
    Forgets what is known of the sign-in of a session.
    Gets the sign-in that waits for a client session.
    static UserMFA
    Gets the second factor of the server's users.
    long
    Gets the time the password of a user was last changed: the time the newest replaced password of the password history was replaced.
    getMethods(long uid)
    Gets the second factors of a user as the user's own pages show them: the authenticator app and the recovery codes, each when the user has it.
    getProof(Object session, long uid)
    Gets the proof that the sign-in of a session verified the second factor of a user.
    Gets the method of the second factor a user has (CC-FIX-SIGNIN-2FA-CHOICE).
    getTotpLabel(long uid)
    Gets the names of the entry of a user's authenticator app, as the enrolment's QR code gave them (CC-FIX-SIGNIN-RECOVERY).
    boolean
    hasSecondFactor(long uid)
    Checks if a user has a second factor: the question every password sign-in asks.
    void
    holdSignIn(Object session, long uid, String userName, boolean enrolmentRequired)
    Holds a user whose first factor passed for the client session the sign-in came from, until completeSignIn(Object, String, String) has a code for it or confirmEnrolment(Object, long, String) an enrolment.
    static String
    methodOfPasskey(boolean userVerified)
    Gets the method of the proof a passkey gives (CC-LOGIN-M11-PASSKEY-PROOF, ruling M-11 (b) of CC-SIGNIN-MERGE-L5-L6-L8).
    void
    onPasskeyRegistered(Object session, long uid)
    Tells that a client session has registered a passkey for a user, now: what enrolPasskey(Object, long, String) makes the second factor of the user, when the user chose a passkey, for PENDING_ENROLMENT_MS.
    void
    onSignedIn(Object session, long uid, String method)
    Tells that a session has signed a user in, now - or that the user it has signed in has verified a second factor in it now: an enrolment that was confirmed, a passkey that confirmed the user.
    regenerateRecoveryCodes(long uid, String userName)
    Replaces the recovery codes of a user.
    void
    release(Object session)
    Lets go of what is held for a client session: the sign-in and the enrolment that wait.
    remove(long uid, String userName)
    Removes the second factor of a user: the secret and every recovery code.
    remove(long uid, String userName, boolean passkeyLeft)
    Removes the authenticator app of a user (CC-FIX-SIGNIN-2FA-CHOICE): of a user who chose a passkey as the second factor and has one still (TOTP_AND_PASSKEY), the passkey is the second factor that is left, with the recovery codes; of every other user the second factor goes, as remove(long,String) removes it - also of the user whose passkeys were registered to sign in faster, as before.
    removePasskeyFactor(long uid, String userName)
    Tells that the last passkey a user chose as the second factor was removed (CC-FIX-SIGNIN-2FA-CHOICE): the app beside it is the second factor that is left (TOTP_AND_PASSKEY becomes totp); of a user who has no app, the second factor goes with its recovery codes, as remove(long,String) removes it.
    restartEnrolment(Object session, long uid, String userName, String issuer)
    Begins the enrolment of an authenticator app for a user ANEW ("Start over", CC-FIX-SIGNIN-TOTP-ENROL): the enrolment the session held is dropped, whatever was shown before, and a new secret is generated as beginEnrolment(Object, long, String, String) generates it the first time.
    static boolean
    Checks if a proof trusts a device for MFA: a device is trusted by a verification code, or by a passkey that was asserted with user verification (CC-LOGIN-M11-PASSKEY-PROOF) - never by a recovery code, which is what is left when the device is lost, and not by a sign-in that verified nothing.
    verify(long uid, String userName, String method, String code)
    Verifies a code of a user: the account's wait after invalid codes first, then the code, which is accepted once.
    static long
    waitAfter(int failCount)
    Gets the wait after a count of invalid codes.
  • Field Details

    • METHODS

      public static final Set<String> METHODS
      The methods of a second factor this class does: the authenticator app and the recovery codes. A policy may name more; they are the orders' that build them.
    • RECOVERY_CODES

      public static final int RECOVERY_CODES
      The recovery codes made for a user: 10.
      See Also:
    • PENDING_SIGN_IN_MS

      public static final long PENDING_SIGN_IN_MS
      How long a sign-in waits for its second factor, in milliseconds: 5 minutes.
      See Also:
    • PENDING_ENROLMENT_MS

      public static final long PENDING_ENROLMENT_MS
      How long an enrolment waits for its first code, in milliseconds: 10 minutes. A sign-in that waits for the enrolment is kept waiting as long.
      See Also:
    • MAX_PENDING_FAILURES

      public static final int MAX_PENDING_FAILURES
      The invalid codes after which a waiting sign-in or enrolment ends: 5. The user begins again, with the first factor.
      See Also:
    • DRIFT_STEPS

      public static final int DRIFT_STEPS
      How many time steps away from this server's clock a refused code is looked for, to name the drift of a clock in the refusal (CC-FIX-SIGNIN-TOTP-ENROL, item 9): 10 steps of 30 seconds, 5 minutes. Nothing is accepted outside the verifier's own window (MFAUser.ALLOWED_DISCREPANCY).
      See Also:
    • ENROLMENT_ALGORITHM

      public static final MFAUser.Hashing ENROLMENT_ALGORITHM
      The hashing algorithm an authenticator app is enrolled with: SHA1, the algorithm of RFC 6238 that every authenticator app implements. Apps are known to ignore the algorithm of the QR code and to compute SHA1 whatever it says; enrolled with another algorithm, such an app shows codes that are never valid.
    • QR_QUIET_ZONE

      public static final int QR_QUIET_ZONE
      The quiet zone of the enrolment QR code, in modules: 4, the light margin around the code that ISO/IEC 18004 requires and that a scanner needs to find the code (QR-D-1).
      See Also:
    • TOTP_AND_PASSKEY

      public static final String TOTP_AND_PASSKEY
      The method of the row of a user who chose a passkey as the second factor and enrolled an authenticator app beside it (CC-FIX-SIGNIN-2FA-CHOICE): "totp+passkey". The row is the app's; the passkey is the second factor that is left when the app is removed. An app enrolled by a user whose passkeys are none (method totp) leaves nothing when it is removed, as before.
      See Also:
  • Constructor Details

    • UserMFA

      public UserMFA(Supplier<? extends ISensitiveParameterHandler> keys, LongSupplier clock, LongSupplier monotonic)
      Constructs an instance on its keys and clocks; the tests drive them.
      Parameters:
      keys - The sealing keys, asked for when a secret is sealed or opened.
      clock - The wall clock, milliseconds since the epoch.
      monotonic - The monotonic clock in milliseconds, any origin.
      Throws:
      NullPointerException - If a parameter is null.
  • Method Details

    • getInstance

      public static UserMFA getInstance()
      Gets the second factor of the server's users.
      Returns:
      The instance: the server's keys, the system clock.
    • waitAfter

      public static long waitAfter(int failCount)
      Gets the wait after a count of invalid codes.
      Parameters:
      failCount - The invalid codes since the last accepted one.
      Returns:
      The milliseconds to wait after the last invalid code, zero for none.
    • hasSecondFactor

      public boolean hasSecondFactor(long uid) throws SQLException
      Checks if a user has a second factor: the question every password sign-in asks.
      Parameters:
      uid - The user ID.
      Returns:
      true when the user has one; false when the user has none, and when the database has no tables of the second factor and none can be created (nobody has one then).
      Throws:
      SQLException - For SQL errors: whether the user has one is not known.
    • getSecondFactorMethod

      public String getSecondFactorMethod(long uid) throws SQLException
      Gets the method of the second factor a user has (CC-FIX-SIGNIN-2FA-CHOICE).
      Parameters:
      uid - The user ID.
      Returns:
      SignInPolicy.METHOD_TOTP for an authenticator app, SignInPolicy.METHOD_PASSKEY for a user whose second factor is a passkey and no app, TOTP_AND_PASSKEY for an app beside the passkey the user chose; null when the user has none - and when the database has no tables of the second factor and none can be created.
      Throws:
      SQLException - For SQL errors.
    • getMethods

      public List<SignInMethods.Method> getMethods(long uid)
      Gets the second factors of a user as the user's own pages show them: the authenticator app and the recovery codes, each when the user has it.
      Parameters:
      uid - The user ID.
      Returns:
      The second factors, strongest first; empty when the user has none and when they cannot be read (logged).
    • getTotpLabel

      public UserMFA.TotpLabel getTotpLabel(long uid)
      Gets the names of the entry of a user's authenticator app, as the enrolment's QR code gave them (CC-FIX-SIGNIN-RECOVERY).
      Parameters:
      uid - The user ID.
      Returns:
      The names, each null when the enrolment stored none (one made before this order); null when the user has no authenticator app, and when they cannot be read (logged).
    • getLastPasswordChange

      public long getLastPasswordChange(long uid)
      Gets the time the password of a user was last changed: the time the newest replaced password of the password history was replaced.
      Parameters:
      uid - The user ID.
      Returns:
      The time, milliseconds since the epoch; zero when it is not known - the password was never changed, or the policy keeps no history.
    • holdSignIn

      public void holdSignIn(Object session, long uid, String userName, boolean enrolmentRequired)
      Holds a user whose first factor passed for the client session the sign-in came from, until completeSignIn(Object, String, String) has a code for it or confirmEnrolment(Object, long, String) an enrolment. A sign-in and an enrolment the session held before are let go.
      Parameters:
      session - The client session, the key of what is held.
      uid - The user ID.
      userName - The user name.
      enrolmentRequired - Whether the sign-in waits for an enrolment: the user has no second factor and the policy requires one.
      Throws:
      NullPointerException - If session or userName is null.
    • getHeldSignIn

      public UserMFA.Held getHeldSignIn(Object session)
      Gets the sign-in that waits for a client session.
      Parameters:
      session - The client session, null for none.
      Returns:
      The sign-in, null when none waits or the one that did has expired.
    • release

      public void release(Object session)
      Lets go of what is held for a client session: the sign-in and the enrolment that wait. The session has signed a user in without them, or the user went back to the start.
      Parameters:
      session - The client session, null for none.
    • completeSignIn

      public UserMFA.Answer completeSignIn(Object session, String method, String code)
      Completes the sign-in the client session holds, with a verification code or a recovery code. When the code is accepted the sign-in is no longer held; the caller then signs the user in and tells so (onSignedIn(Object, long, String)). After MAX_PENDING_FAILURES invalid codes the sign-in is no longer held either.
      Parameters:
      session - The client session.
      method - The method the code is of.
      code - The code as typed.
      Returns:
      The answer: ACCEPTED with the user and the method, NO_PENDING when nothing waits, NOT_ENROLLED when the sign-in waits for an enrolment, or the refusal.
    • verify

      public UserMFA.Answer verify(long uid, String userName, String method, String code)
      Verifies a code of a user: the account's wait after invalid codes first, then the code, which is accepted once. An accepted code forgets the invalid ones; an invalid one is counted. A code that is not of the method given is invalid: a recovery code is no verification code and the reverse.
      Parameters:
      uid - The user ID.
      userName - The user name, for the log.
      method - The method the code is of, SignInPolicy.METHOD_TOTP or SignInPolicy.METHOD_RECOVERY.
      code - The code as typed, null for none.
      Returns:
      The answer, never null.
    • beginEnrolment

      public TotpEnrolment beginEnrolment(Object session, long uid, String userName, String issuer) throws UserMFA.Refusal
      Begins the enrolment of an authenticator app for a user: the secret is generated and held for the client session, and nothing is stored. An enrolment of this user the session holds already, and that waits, is shown AGAIN - the same secret, the same QR code - and waits another PENDING_ENROLMENT_MS: going back and forth on the set-up page mints no new secret silently (SIGNIN-TOTP-ENROL-RESTART-SILENT, CC-FIX-SIGNIN-TOTP-ENROL item 8); restartEnrolment(Object, long, String, String) is the one way to a new secret. An enrolment of another user the session held is replaced. A sign-in of this user that waits in the session is kept waiting as long as the enrolment.
      Parameters:
      session - The client session, the key of what is held.
      uid - The user ID.
      userName - The user name: the account the authenticator app shows.
      issuer - The issuer the authenticator app shows.
      Returns:
      What the user needs to enrol the app.
      Throws:
      UserMFA.Refusal - ALREADY_ENROLLED, or FAILED when the database failed or has no tables of the second factor (logged).
      NullPointerException - If a reference parameter is null.
    • restartEnrolment

      public TotpEnrolment restartEnrolment(Object session, long uid, String userName, String issuer) throws UserMFA.Refusal
      Begins the enrolment of an authenticator app for a user ANEW ("Start over", CC-FIX-SIGNIN-TOTP-ENROL): the enrolment the session held is dropped, whatever was shown before, and a new secret is generated as beginEnrolment(Object, long, String, String) generates it the first time. The entry an authenticator app made of the old QR code is dead from now on.
      Parameters:
      session - The client session, the key of what is held.
      uid - The user ID.
      userName - The user name: the account the authenticator app shows.
      issuer - The issuer the authenticator app shows.
      Returns:
      What the user needs to enrol the app.
      Throws:
      UserMFA.Refusal - ALREADY_ENROLLED, or FAILED when the database failed or has no tables of the second factor (logged).
      NullPointerException - If a reference parameter is null.
    • confirmEnrolment

      public UserMFA.Confirmed confirmEnrolment(Object session, long uid, String code) throws UserMFA.Refusal
      Confirms the enrolment the client session holds with the first code of the authenticator app: the secret is sealed and stored, the time step of the code is the last accepted one (the code that confirmed is spent), the recovery codes are made and their hashes stored. A sign-in of the user that waited in the session is no longer held: the caller signs the user in and tells so (onSignedIn(Object, long, String)).
      Parameters:
      session - The client session.
      uid - The user ID of the user the enrolment is confirmed for: the user whose sign-in waits, or the user the session has signed in. The enrolment that waits is confirmed for the user who began it, and for no other.
      code - The code as typed.
      Returns:
      The recovery codes, and whether a sign-in waited for the enrolment.
      Throws:
      UserMFA.Refusal - NOT_ENROLLED when no enrolment of this user waits, INVALID for an invalid code - with the drift of a clock the code would be right for (UserMFA.Refusal.driftSeconds, item 9), and UserMFA.Refusal.ended for the fifth invalid code, which drops the enrolment (CC-FIX-SIGNIN-TOTP-ENROL) -, ALREADY_ENROLLED when the user has got a second factor since, FAILED when the database or the server's keys failed (logged).
    • onPasskeyRegistered

      public void onPasskeyRegistered(Object session, long uid)
      Tells that a client session has registered a passkey for a user, now: what enrolPasskey(Object, long, String) makes the second factor of the user, when the user chose a passkey, for PENDING_ENROLMENT_MS. A passkey is registered with user verification only.
      Parameters:
      session - The client session, null for none.
      uid - The user ID.
    • enrolPasskey

      public UserMFA.Confirmed enrolPasskey(Object session, long uid, String userName) throws UserMFA.Refusal
      Makes a passkey the second factor of a user (CC-FIX-SIGNIN-2FA-CHOICE): the user chose a passkey, and the client session registered one for the user a short time ago (onPasskeyRegistered(Object, long)). A user without a second factor has one now: the row of the method passkey, and the recovery codes, made here as confirmEnrolment(Object, long, String) makes them. A user who has one keeps it, and its recovery codes. A sign-in of the user that waited in the session is no longer held: the caller signs the user in and tells so (onSignedIn(Object, long, String)).
      Parameters:
      session - The client session.
      uid - The user ID: the user whose sign-in waits, or the user the session has signed in. The passkey that was registered is one of this user, or nothing is done.
      userName - The user name, for the log.
      Returns:
      The recovery codes, empty when the user had a second factor already, and whether a sign-in waited for this enrolment.
      Throws:
      UserMFA.Refusal - NOT_ENROLLED when the session registered no passkey of this user a short time ago, FAILED when the database failed or has no tables of the second factor (logged).
    • remove

      public UserMFA.Outcome remove(long uid, String userName)
      Removes the second factor of a user: the secret and every recovery code. Whether the user may is the caller's check, and the trust of the user's devices is the caller's to end.
      Parameters:
      uid - The user ID.
      userName - The user name, for the log.
      Returns:
      ACCEPTED when it is removed, NOT_ENROLLED when the user had none, FAILED when the database failed (logged).
    • remove

      public UserMFA.Outcome remove(long uid, String userName, boolean passkeyLeft)
      Removes the authenticator app of a user (CC-FIX-SIGNIN-2FA-CHOICE): of a user who chose a passkey as the second factor and has one still (TOTP_AND_PASSKEY), the passkey is the second factor that is left, with the recovery codes; of every other user the second factor goes, as remove(long,String) removes it - also of the user whose passkeys were registered to sign in faster, as before. Whether the user may is the caller's check, and the trust of the user's devices is the caller's to end.
      Parameters:
      uid - The user ID.
      userName - The user name, for the log.
      passkeyLeft - Whether the user has a passkey that is the proof of a second factor.
      Returns:
      ACCEPTED when it is removed, NOT_ENROLLED when the user had no app, FAILED when the database failed (logged).
    • removePasskeyFactor

      public UserMFA.Outcome removePasskeyFactor(long uid, String userName)
      Tells that the last passkey a user chose as the second factor was removed (CC-FIX-SIGNIN-2FA-CHOICE): the app beside it is the second factor that is left (TOTP_AND_PASSKEY becomes totp); of a user who has no app, the second factor goes with its recovery codes, as remove(long,String) removes it. Whether the user may is the caller's check, and the trust of the user's devices is the caller's to end.
      Parameters:
      uid - The user ID.
      userName - The user name, for the log.
      Returns:
      ACCEPTED when the second factor went, ALREADY_ENROLLED when the app is left, NOT_ENROLLED when no passkey was the user's second factor, FAILED when the database failed (logged).
    • regenerateRecoveryCodes

      public String[] regenerateRecoveryCodes(long uid, String userName) throws UserMFA.Refusal
      Replaces the recovery codes of a user. Whether the user may is the caller's check.
      Parameters:
      uid - The user ID.
      userName - The user name, for the log.
      Returns:
      The new recovery codes, in clear, this once.
      Throws:
      UserMFA.Refusal - NOT_ENROLLED when the user has no second factor, FAILED when the database failed (logged).
    • onSignedIn

      public void onSignedIn(Object session, long uid, String method)
      Tells that a session has signed a user in, now - or that the user it has signed in has verified a second factor in it now: an enrolment that was confirmed, a passkey that confirmed the user.
      Parameters:
      session - The session, null for none.
      uid - The user ID.
      method - The method of the second factor that was verified, SignInPolicy.METHOD_TOTP, SignInPolicy.METHOD_RECOVERY, or what methodOfPasskey(boolean) gives for a passkey; null when the sign-in verified none: the user has none, the device is trusted or stays signed in.
    • methodOfPasskey

      public static String methodOfPasskey(boolean userVerified)
      Gets the method of the proof a passkey gives (CC-LOGIN-M11-PASSKEY-PROOF, ruling M-11 (b) of CC-SIGNIN-MERGE-L5-L6-L8). A passkey that was asserted with user verification is the proof of a second factor, as a verified code is: the passkey is what the user has, the verification what the user is or knows. An answer without user verification proves the device and no user: it is no proof. The server accepts no such answer; this is where the rule is, should one ever arrive.
      Parameters:
      userVerified - Whether the authenticator verified the user: the UV flag of the answer that was verified, not what the request asked for.
      Returns:
      SignInPolicy.METHOD_PASSKEY, the method to tell onSignedIn(Object, long, String); null for an answer that is no proof.
    • trustsDevice

      public static boolean trustsDevice(MFAProof proof)
      Checks if a proof trusts a device for MFA: a device is trusted by a verification code, or by a passkey that was asserted with user verification (CC-LOGIN-M11-PASSKEY-PROOF) - never by a recovery code, which is what is left when the device is lost, and not by a sign-in that verified nothing.
      Parameters:
      proof - The proof of the session, null for none.
      Returns:
      true when the session that has the proof may trust its device.
    • getProof

      public MFAProof getProof(Object session, long uid)
      Gets the proof that the sign-in of a session verified the second factor of a user.
      Parameters:
      session - The session, null for none.
      uid - The user ID of the user the session has signed in.
      Returns:
      The proof, MFAProof.NONE when the session verified no second factor of this user.
    • forget

      public void forget(Object session)
      Forgets what is known of the sign-in of a session.
      Parameters:
      session - The session, null for none.