Class PasskeyChallenges

java.lang.Object
com.iizix.server.user.passkey.PasskeyChallenges

public final class PasskeyChallenges extends Object
The challenges of the passkey ceremonies that are under way (CC-LOGIN-L8-PASSKEYS): made by the server from its secure random source, kept in the memory of this server only, bound to the client session that asked and to the kind of ceremony, valid for one answer and for a limited time. A client session has one challenge per kind: a new one replaces the one before. Nothing is stored in a database and nothing is sent twice; a server restart forgets them all, and the client starts again.

The store is bounded (MAX_PENDING): when it is full of challenges that have not expired, a new one is refused - the client sources that make them are held back by the sign-in throttle long before.

Author:
Christopher Mindus
  • Field Details

    • CHALLENGE_BYTES

      public static final int CHALLENGE_BYTES
      The size of a challenge, in bytes.
      See Also:
    • MAX_PENDING

      public static final int MAX_PENDING
      The most challenges under way.
      See Also:
  • Constructor Details

    • PasskeyChallenges

      public PasskeyChallenges()
      Creates the store on the system clock and the server's secure random source.
    • PasskeyChallenges

      public PasskeyChallenges(LongSupplier clock, Supplier<byte[]> source)
      Creates the store on a clock and a source of challenges: for tests, which verify recorded ceremonies against the challenges they were recorded with.
      Parameters:
      clock - The clock, milliseconds.
      source - The source of the challenges, each 16 bytes at least.
      Throws:
      NullPointerException - If a parameter is null.
  • Method Details

    • create

      public PasskeyChallenges.Pending create(String session, PasskeyChallenges.Kind kind, long userID, String rpId, long validity) throws PasskeyException
      Makes the challenge of a ceremony. A challenge of the same client session and kind that is under way is replaced.
      Parameters:
      session - The key of the client session.
      kind - The kind of ceremony.
      userID - The user ID the ceremony is for, zero for a sign-in that names no user.
      rpId - The relying party ID the options are made for.
      validity - The time the challenge is valid, in milliseconds.
      Returns:
      The pending challenge.
      Throws:
      NullPointerException - If session, kind or rpId is null.
      IllegalArgumentException - If validity is not positive.
      PasskeyException - If the store is full.
    • take

      Takes the challenge of a ceremony: it is removed, so that it is answered once.
      Parameters:
      session - The key of the client session.
      kind - The kind of ceremony.
      Returns:
      The pending challenge, null when the client session has none of the kind or it has expired.
      Throws:
      NullPointerException - If a parameter is null.
    • renew

      public boolean renew(String session, PasskeyChallenges.Kind kind, long validity)
      Extends the time a challenge under way is valid, keeping the same challenge bytes (CC-FIX-PASSKEY-RETRY-CHALLENGE): the arming of a passkey ceremony renews the challenge of the button that waits before it would be forgotten, so that the user's click never runs a ceremony against a challenge the server has already expired. The challenge stays single-use - a take(String, PasskeyChallenges.Kind) still removes it - and bound to its session and kind; only the moment it would otherwise be forgotten moves.
      Parameters:
      session - The key of the client session.
      kind - The kind of ceremony.
      validity - The time from now the challenge is valid, in milliseconds.
      Returns:
      true when a challenge of the session and kind was under way and was extended; false when the session has none of the kind, or it had already expired.
      Throws:
      NullPointerException - If a parameter is null.
      IllegalArgumentException - If validity is not positive.
    • size

      public int size()
      Gets the count of challenges under way, expired ones that were not swept yet included.
      Returns:
      The count.