Class UserAuthentication

java.lang.Object
com.iizix.server.user.UserAuthentication
All Implemented Interfaces:
IAuthenticatedUserProvider

public final class UserAuthentication extends Object implements IAuthenticatedUserProvider
Helper class to perform user authentication. This class concentrates the calls to one location: here. It enabled implementation to external authentication systems such as JNDI or custom in-house through a Java API, etc.
Author:
Christopher Mindus
  • Field Details

    • LICENSE_SYSTEM_APP_ID

      public static final String LICENSE_SYSTEM_APP_ID
      The application ID the external license system passes to validateUser(UserIdentifier,String,String) (AbstractRemoteRequest.processLogin in com.iizix.server.license, the Mindus License System): no application is looked up, no failed sign-in is counted, and an account of an external Sign In Provider (an "EXT:" password hash) is accepted without a local password. It is the ONLY call that is: every other caller refuses such an account as it refuses a wrong password (CC-FIX-EXT-TAKEOVER, the owner's ruling D-3 of 2026-09-28).
      See Also:
  • Method Details

    • getInstance

      public static UserAuthentication getInstance()
      Gets the user authentication instance.
    • validateHashPW

      public static void validateHashPW(String hashPW)
      Validates a hashed password.
      Parameters:
      hashPW - The hashed password. It is based on PBKDF2 with Keyed-Hash Message Authentication Code (HMAC) with a SHA-256 hash. It can start with "EXT:" if the user has signed in using an external Sign In Provider, e.g. LinkedIn or Facebook, the remaining part of the string identifies the provider and the users identifier for that provider.
      Throws:
      NullPointerException - If hashPW is null.
      IllegalArgumentException - If hashPW is an empty string or has invalid format.
    • getUserLocations

      public List<UserLocation> getUserLocations()
      Finds locations of all users.
      Specified by:
      getUserLocations in interface IAuthenticatedUserProvider
    • isUserNameFree

      public boolean isUserNameFree(String userName) throws UserException
      Checks if the user name is free to use, i.e. has not yet been signed up.
      Parameters:
      userName - The user name.
      Returns:
      true if free, false if already taken.
      Throws:
      UserException - If the user name is invalid.
    • getUser

      public AuthenticatedUser getUser(String userName) throws NotFoundException
      Gets the instance of a user with its information.
      Specified by:
      getUser in interface IAuthenticatedUserProvider
      Parameters:
      userName - The user name.
      Returns:
      The instance holding the potentially authenticated user.
      Throws:
      NullPointerException - If the userName is null.
      NotFoundException - If the user name is not found or an SQL exception occurred.
    • getUserFromEmail

      public AuthenticatedUser getUserFromEmail(String emailAddress) throws NotFoundException
      Looks up a user from the email.
      Parameters:
      emailAddress - The email address.
      Throws:
      NullPointerException - If the emailAddress is null.
      NotFoundException - If user is not found.
    • getUsersFromEmail

      public List<AuthenticatedUser> getUsersFromEmail(String emailAddress) throws NotFoundException
      Looks up every user that holds an e-mail address as its registered address, matched exactly as registered (EM-D-1, CC-FIX-SIGNIN-ACCOUNT-MAIL: a shared address is allowed - the sign-in by address asks for the user name when there are several, a password reset mails one link per account). Each user is added to the cache as getUserFromEmail(String) adds it.
      Parameters:
      emailAddress - The email address.
      Returns:
      The users, in the order of the database; empty for none.
      Throws:
      NotFoundException - If the database cannot be read (with the SQL exception as the cause).
    • getUser

      public AuthenticatedUser getUser(Connection conn, String userName) throws NotFoundException, SQLException
      Gets the instance of a user with its information. This always gets the information from the database and never a cached user.
      Parameters:
      conn - The connection.
      userName - The user name.
      Returns:
      The instance holding the potentially authenticated user, or null if the user does not exist in the server's database.
      Throws:
      NotFoundException - If user is not found.
      SQLException - For SQL errors.
    • getUser

      public AuthenticatedUser getUser(Connection conn, String userName, String password) throws NotFoundException, SQLException
      Gets the instance of a user with its information.
      Parameters:
      conn - The database connection.
      userName - The user name.
      password - The clear text password. A stored hash is NOT accepted as a password.
      Returns:
      The instance holding the potentially authenticated user, or null if the user does not exist in the server's database, the password doesn't match or the account is disabled (IZS.USERS.disabled set: refused as validateUser refuses it, with the stored reason logged as a WARNING; the owner's ruling U-2 of 2026-09-27).
      Throws:
      NullPointerException - If the userName or password is null.
      NotFoundException - If user is not found.
      SQLException - For SQL errors.
    • getUser

      public AuthenticatedUser getUser(long id) throws NotFoundException
      Gets the basic user info for a user from its unique user ID. The value comes from UserInfoBase.id.
      Specified by:
      getUser in interface IAuthenticatedUserProvider
      Parameters:
      id - The unique user ID.
      Returns:
      The user information.
      Throws:
      NotFoundException - If the user ID is not found or an SQL exception occurred.
    • getUser

      public AuthenticatedUser getUser(Connection conn, long id) throws NotFoundException, SQLException
      Gets the basic user info for a user from its unique user ID. The value comes from UserInfoBase.id.
      Parameters:
      conn - The connection.
      id - The unique user ID.
      Returns:
      The user information.
      Throws:
      NotFoundException - If user is not found.
      SQLException - For SQL errors.
    • validateUser

      public final UserAuthenticationInfo validateUser(UserIdentifier userIdentifier, String appID, String validatePassword)
      Authenticates a user ID and password.
      Parameters:
      userIdentifier - The user identifier.
      appID - The app ID to validate, null to skip this test.
      validatePassword - The password to validate. If the password is empty, the user is authenticated as pre-validation used e.g. by the iiziRun Developer listing possible sessions, etc. When this parameter is null, the real password is not validated.
      Returns:
      The user authentication result.
    • validateUser

      public final UserAuthenticationInfo validateUser(UserIdentifier userIdentifier, AppFactory appFactory, String validatePassword)
      Authenticates a user ID and password.
      Parameters:
      userIdentifier - The user identifier.
      appFactory - The app to validate, null to skip this test.
      validatePassword - The password to validate. If the password is empty, the user is authenticated as pre-validation used e.g. by the iiziRun Developer listing possible sessions, etc. When this parameter is null, the real password is not validated.

      An account of an external Sign In Provider (an "EXT:" password hash) has no password: with a password to validate it is refused exactly as a wrong password is, and its hash is never replaced. Only the external license system's call, validateUser(UserIdentifier,String,String) with LICENSE_SYSTEM_APP_ID, accepts such an account (CC-FIX-EXT-TAKEOVER).

      An account with a second factor is not signed in by its password alone: with the right password the result is SECOND_FACTOR_REQUIRED, which is no success, and the sign-in is completed with a code by the SignIn module's IUserAuthenticationUI (UserMFA, SignIn L-6) - unless the sign-in policy of the application has the second factor off. A validation without a password - an empty or a null one - checks no factor at all and is not changed by it.

      A user may use an application only by an enabled group the application allows (ServerAppConfig.refusal(BasicUserInfo), T1-139): with the right password, and for a validation without one, the answer is otherwise SigninResult.APP_ACCESS_DENIED, with the reason in the log. An application with no configured group list admits every user.

      The refusal is answered only once the WHOLE sign-in is done (the owner's ruling SA-D-1 of 2026-10-02, CC-SIGNIN-NOACCESS-AFTER-2F): the right password of an account whose second factor is due is answered SECOND_FACTOR_REQUIRED whether the application admits the user or not, and the refusal is the answer of the validation without a password that completes the sign-in when the factor has passed. Who knows the password alone is not told that the account has no access.

      Returns:
      The user authentication result.
    • createNewPasswordHash

      public final String createNewPasswordHash(String userName, String password)
      Creates a new password hash to store in the database. The password is not decryptable.
      Parameters:
      userName - The basic user information.
      password - The new password.
      Returns:
      The new password hash.
    • isPasswordMatching

      public final boolean isPasswordMatching(String userName, String password, String hashedPassword)
      Checks a clear-text password against a stored IZ1 hash, as the database sign-in does, for a credential that is not a database user: a user of the Push Notification credentials file (PUSH-CREDENTIALS.md section 3.2). Nothing is logged.
      Parameters:
      userName - The user name the hash was created for.
      password - The clear-text password to verify.
      hashedPassword - The stored hash.
      Returns:
      true if the password matches.
    • getSourceThrottle

      public final SourceThrottle getSourceThrottle()
      Gets the per-source throttle of the sign-in paths that know their client (CC-LOGIN-SERVER-CORE): IUserAuthenticationUI counts a failed attempt against the client's remote address and refuses the address once it has failed too often in a window.
      Returns:
      The throttle, one per server.
    • getDeviceTokenStore

      public final DeviceTokenStore getDeviceTokenStore()
      Gets the device tokens (CC-LOGIN-L5-DEVICE-TOKEN): IUserAuthenticationUI issues one to a device its user stays signed in on and redeems it at the next sign-in, and every change of a password deletes the user's.
      Returns:
      The store, one per server, on the server's own database.
    • applicationRefusal

      public String applicationRefusal(BasicUserInfo bui, AppFactory appFactory) throws SQLException
      Decides whether a user may use an application, by the user's groups (T1-139, CC-SERVER-USERS-APP-ACCESS): the rule of ServerAppConfig.refusal(BasicUserInfo), applied by validateUser(UserIdentifier,AppFactory,String) before every successful answer for an application - the matched password and the validation without one - and offered here to the one sign-in that validates its user without an application, the device sign-in of UserAuthenticationUIImpl, which must not be held back as a password is.

      A user the groups admit is then put to the application's own gate (IAppSessionFocusProvider.getSignInRefusal(UserInfoBase, String), CC-SERVERADMIN-SIGNIN): ServerAdmin's admits only administrators. An application without a gate admits everyone its groups admit, except an application of one of ServerAdmin's IDs, which admits nobody without its gate.

      Parameters:
      bui - The user, as read from the database.
      appFactory - The application, null for none: nothing to decide.
      Returns:
      null when the user may use the application - by its groups always when the application has no configuration with a group list, as one started from the command line or from IZS.APPS has none - otherwise the reason of the refusal, for the log; the answer to give is SigninResult.APP_ACCESS_DENIED.
      Throws:
      SQLException - For SQL errors reading the groups.
    • isOldPasswordMatching

      public final boolean isOldPasswordMatching(BasicUserInfo bui, String oldPassword)
      Verifies that the old password matches before changing to a new one.
      Parameters:
      bui - The basic user information.
      oldPassword - The old (existing) password.
      Returns:
      true for success, false if not matching.
      Throws:
      RuntimeException - If not called from inside the iiziServer.