Class PasswordResetMail

java.lang.Object
com.iizix.server.user.PasswordResetMail

public final class PasswordResetMail extends Object
Resets a user's password and mails the new one to the user's own registered e-mail address, and to nobody else.

The steps, in this order:

  1. Refuse a user without an e-mail address; nothing is changed.
  2. Address the mail: from the mail sender's default sender address, to the user's address only, no CC and no BCC, so a mis-configured or unparsable address is found before the password moves.
  3. Reset the password through the reset step, normally BasicUserInfo.resetPassword(StringBuilder): a strong random password, "change password at next sign in" set, committed by that method.
  4. Send the mail synchronously through the send step, normally Mail.send().

The password is committed before the mail goes, because the reset step is the only owner of the users table and of the cached user, and it commits. So a send failure is not silent: the message returned to the administrator says that the password WAS changed and that the mail did not arrive, and the log carries the same. The password itself never appears in a returned message or in a log line.

The two steps are parameters so that the composition and the ordering can be proven with a fake mail send and a fake reset (PasswordResetMailTest); ServerAdmin passes the real ones.

resetAndMail(Connection,String,String,MailSender,IResetStep,ISendStep) is the same in ONE transaction on the caller's connection: the reset is written without a commit, the mail is sent, and only a sent mail commits the reset; a mail that cannot be sent rolls it back, so the old password keeps working and the administrator is told that nothing changed (CC-FIX-SERVERADMIN SA-4, the (a) of CC-FIX-NOTFOUND-AND-RESET's D-2). ServerAdmin uses it.

composeLink(MailSender, String, String, String) is the self-service reset of the SignIn module (CC-LOGIN-SERVER-CORE, D-6 of the SignIn survey): the mail carries a reset LINK (PasswordResetLink, sealed, 30 minutes, spent by the reset it makes) and no password at all, and nothing is changed until the user opens it. Same addressing, same class, so that there is one reset mail.

Author:
Christopher Mindus
  • Field Details

  • Method Details

    • compose

      public static Mail compose(MailSender sender, String email) throws MessagingException
      Addresses a reset mail: from the sender's default sender address, to the user's address only, subject set, no text yet.
      Parameters:
      sender - The mail sender.
      email - The user's registered e-mail address.
      Returns:
      The addressed mail.
      Throws:
      MessagingException - If the sender has no default sender address, or the user's address does not parse.
    • body

      public static String body(String userName, String newPassword)
      The text of the mail.
      Parameters:
      userName - The user name.
      newPassword - The new password.
      Returns:
      The plain text.
    • linkBody

      public static String linkBody(String userName, String link)
      The text of a reset link mail. The link is the only secret in it; the mail names the user so that a stranger's request is recognisable to the addressee.
      Parameters:
      userName - The user name.
      link - The reset link.
      Returns:
      The plain text.
    • composeLink

      public static Mail composeLink(MailSender sender, String email, String userName, String link) throws MessagingException
      Composes a reset link mail: addressed as compose(MailSender, String), with linkBody(String, String) as its text. Nothing is sent and nothing is changed here.
      Parameters:
      sender - The mail sender.
      email - The user's registered e-mail address.
      userName - The user name.
      link - The reset link.
      Returns:
      The mail, ready to send.
      Throws:
      MessagingException - If the sender has no default sender address, or the user's address does not parse.
    • resetAndMail

      public static String resetAndMail(String userName, String email, MailSender sender, PasswordResetMail.IResetStep reset, PasswordResetMail.ISendStep send) throws SQLException, NotFoundException
      Resets the password and mails it to the user, in the order the class comment gives.
      Parameters:
      userName - The user name, for the mail text and the messages.
      email - The user's registered e-mail address, null or blank for none.
      sender - The mail sender to send through.
      reset - The reset step.
      send - The send step.
      Returns:
      null if the password was reset and the mail sent, otherwise the reason to show the administrator. The reason never contains the password.
      Throws:
      SQLException - For SQL errors in the reset step; nothing has been sent.
      NotFoundException - If the user has been deleted since login; nothing has been sent.
    • resetAndMail

      public static String resetAndMail(Connection conn, String userName, String email, MailSender sender, PasswordResetMail.IResetStep reset, PasswordResetMail.ISendStep send) throws SQLException, NotFoundException
      Resets the password and mails it in ONE transaction on the caller's connection. The checks before the reset are those of resetAndMail(String,String,MailSender,IResetStep,ISendStep); then the reset step writes on the connection without committing, the mail is sent, and a sent mail commits the reset. A refused reset, a mail that is not accepted or a mail whose send throws roll the transaction back, and so does anything thrown by the reset step or the commit before it is rethrown.

      The caller's cached user is not updated by the reset step (see BasicUserInfo.resetPassword(Connection,StringBuilder)): after a null return the caller refreshes it from the row.

      Parameters:
      conn - The connection, auto-commit "off"; committed or rolled back here.
      userName - The user name, for the mail text and the messages.
      email - The user's registered e-mail address, null or blank for none.
      sender - The mail sender to send through.
      reset - The reset step, writing on conn without committing: (p)->user.resetPassword(conn,p).
      send - The send step.
      Returns:
      null if the password was reset, mailed and committed, otherwise the reason to show the administrator: nothing was changed. The reason never contains the password.
      Throws:
      SQLException - For SQL errors in the reset step or the commit; rolled back. A commit that fails after the mail was sent leaves the user with a mailed password that does not work: reset again.
      NotFoundException - If the user has been deleted since login; rolled back.