Class PasswordResetLink

java.lang.Object
com.iizix.server.security.PasswordResetLink

public final class PasswordResetLink extends Object
The token of a password reset link, and its verification (CC-LOGIN-SERVER-CORE; D-6 of the SignIn survey: a single-use link valid 30 minutes, no password ever mailed).

The link carries one query parameter, PARAM, whose value is the user ID, a mark of the user's current password hash, the purpose and the expiry time of the link, sealed with the server's own key through ISensitiveParameterHandler.encodeParameter(String) exactly as EmailVerificationLink seals a verification link: AES-256-GCM under the installation's key, the GCM tag as the keyed MAC of the link, so nothing in the URL lets a link be forged or altered. The purpose keeps a value the server sealed for anything else from being taken as a reset link.

Single use, without a store. The mark is the first 16 bytes of SHA-256 over the stored password hash. The reset the link makes replaces that hash, so the mark no longer matches and the same link is refused afterwards; so is a link sent before any other change of the password. Nothing is written for it and nothing needs a schema. Two links requested within the validity are both live until one is used, and both go to the same registered address. The mark reveals nothing about the hash to a holder of the link: the hash itself is a salted PBKDF2 output.

Author:
Christopher Mindus
  • Field Details

    • PARAM

      public static final String PARAM
      The query parameter carrying the token: "prt".
      See Also:
    • VALIDITY_MS

      public static final long VALIDITY_MS
      How long a link is valid from the moment it is built: 30 minutes.
      See Also:
  • Method Details

    • mark

      public static String mark(String hashPW)
      Marks a stored password hash: the first 16 bytes of its SHA-256, as 32 hexadecimal characters. The mark changes with the hash and reveals nothing of it.
      Parameters:
      hashPW - The stored password hash.
      Returns:
      The mark.
      Throws:
      NullPointerException - If hashPW is null.
    • buildQuery

      public static String buildQuery(ISensitiveParameterHandler keys, long userID, String hashPW, long expiresAt) throws GeneralSecurityException
      Builds the query string of a link: prt=token.
      Parameters:
      keys - The server's sealing keys.
      userID - The user ID the link resets.
      hashPW - The user's stored password hash now; the link is spent when it changes.
      expiresAt - The expiry time, milliseconds since the epoch.
      Returns:
      The query string, URL-safe.
      Throws:
      GeneralSecurityException - If the content cannot be sealed.
      NullPointerException - If keys or hashPW is null.
    • buildLink

      public static String buildLink(ISensitiveParameterHandler keys, String linkBase, long userID, String hashPW, long expiresAt) throws GeneralSecurityException
      Builds a link: the base with the query appended after ?, or after & when the base has a query already.
      Parameters:
      keys - The server's sealing keys.
      linkBase - The URL the link starts with.
      userID - The user ID the link resets.
      hashPW - The user's stored password hash now.
      expiresAt - The expiry time, milliseconds since the epoch.
      Returns:
      The link.
      Throws:
      GeneralSecurityException - If the content cannot be sealed.
      NullPointerException - If a parameter is null.
    • isOnBase

      public static boolean isOnBase(String linkBase, String base)
      Tells whether a link base is on a base URL: equal to it, or the base followed by / and more - so that https://host.example.evil is not on https://host.example, and neither is https://host.example:8443 (CC-FIX-RESET-LINK-BASE: the base passed to requestPasswordReset must be the client session's own external base).
      Parameters:
      linkBase - The URL a link starts with, e.g. https://host.example/app/signin/.
      base - The base URL without a trailing slash, e.g. https://host.example, null for none.
      Returns:
      true when the link base is on the base; false when it is not, or when either is null.
    • verify

      public static PasswordResetLink.Result verify(ISensitiveParameterHandler keys, String token, long now)
      Verifies a token.

      The token is opened with the server's keys, which fails for a token sealed by another server, for one altered anywhere and for anything that is not a token at all; the content must then carry the purpose; and the expiry time must not have passed. Whether the link is spent is the caller's check: the claim's mark against mark(String) of the user's stored hash now. Nothing is thrown for a bad token.

      Parameters:
      keys - The server's sealing keys.
      token - The token from the link, null or empty for none.
      now - The current time, milliseconds since the epoch.
      Returns:
      The result, never null.