loginmodules/password/pwcommon/src/main/java/org/beiter/michael/authn/jaas/loginmodules/password/common/PasswordLoginModule.java
@Override
    // Check is broken [LOG.info()]: PMD reports issues although log stmt is guarded. @todo revisit when upgrading PMD.
    @SuppressWarnings("PMD.GuardLogStatementJavaUtil")
    public final boolean login()
            throws LoginException {

        LOG.debug("Attempting login");

        if (pCallbackHandler == null) {
            final String error = "No CallbackHandler available to garner authentication information from the user";
            LOG.error(error);
            throw new LoginException(error);
        }
        Callback[] callbacks = new Callback[3];
        callbacks[0] = new TextInputCallback("j_domain");
        callbacks[1] = new NameCallback("j_username");
        callbacks[2] = new PasswordCallback("j_password", false);

        try {
            pCallbackHandler.handle(callbacks);

            // store the domain
            domain = ((TextInputCallback) callbacks[0]).getText();

            // store the username
            username = ((NameCallback) callbacks[1]).getName();

            // store the password (i.e. a copy of the password)
            final char[] tempPassword = ((PasswordCallback) callbacks[2]).getPassword();
            password = tempPassword.clone();

            // clear the password in the callback
            ((PasswordCallback) callbacks[2]).clearPassword();
        } catch (java.io.IOException e) {
            cleanState();
            final String error = "Encountered an I/O exception during login";
            LOG.warn(error, e);
            throw Util.newLoginException(error, e);
        } catch (UnsupportedCallbackException e) {
            cleanState();
            final String error =
                    e.getCallback().toString() + " not available to garner authentication information from the user";
            LOG.warn(error, e);
            throw Util.newLoginException(error, e);
        }

        LOG.debug("Attempting login - discovered user '" + username + "@" + domain + "'");

        // Using a try/catch construct for managing control flows is really a bad idea.
        // Unfortunately, this is how JAAS works :-(
        try {
            // authenticate, and update state and pending subject if successful
            pendingSubject = pwAuthenticator.authenticate(domain, username, password, pwValidator);

            // then clear the password
            Cleanser.wipe(password);

            final String baseError = new StringBuilder().
                    append("Login successful for '").
                    append(username).
                    append("@").
                    append(domain).
                    toString();
            AuditHelper.auditEvent(audit, domain, username, Events.AUTHN_ATTEMPT,
                    baseError + "', but cannot audit login attempt, and hence fail the operation");
            MessageHelper.postMessage(messageQ, domain, username, Events.AUTHN_ATTEMPT,
                    baseError + "', but cannot post MQ login attempt event, and hence fail the operation");

            // string concatenation is only executed if log level is actually enabled
            if (LOG.isInfoEnabled()) {
                LOG.info("Login complete for '" + username + "@" + domain + "'");
            }
            return true;
        } catch (LoginException e) {
            // the login failed

            // cache the username and domain, for they will be purged by "cleanState()"
            final String tempUsername = username;
            final String tempDomain = domain;

            cleanState();

            final String baseError = new StringBuilder().
                    append("Login failed for '").
                    append(tempUsername).
                    append("@").
                    append(tempDomain).
                    toString();
            AuditHelper.auditEvent(audit, tempDomain, tempUsername, Events.AUTHN_FAILURE,
                    baseError + "', but cannot audit login attempt");
            MessageHelper.postMessage(messageQ, tempDomain, tempUsername, Events.AUTHN_FAILURE,
                    baseError + "', but cannot post MQ login attempt event");

            final String error = "Login failed for '" + tempUsername + "@" + tempDomain + "'";
            LOG.info(error, e);

            throw e;
        }
    }
@Override
    // Check is broken [LOG.info()]: PMD reports issues although log stmt is guarded. @todo revisit when upgrading PMD.
    @SuppressWarnings("PMD.GuardLogStatementJavaUtil")
    public final boolean login()
            throws LoginException {

        LOG.debug("Attempting login");

        if (pCallbackHandler == null) {
            final String error = "No CallbackHandler available to garner authentication information from the user";
            LOG.error(error);
            throw new LoginException(error);
        }
        Callback[] callbacks = new Callback[3];
        callbacks[0] = new TextInputCallback("j_domain");
        callbacks[1] = new NameCallback("j_username");
        callbacks[2] = new PasswordCallback("j_password", false);

        try {
            pCallbackHandler.handle(callbacks);

            // store the domain
            domain = ((TextInputCallback) callbacks[0]).getText();

            // store the username
            username = ((NameCallback) callbacks[1]).getName();

            // store the password (i.e. a copy of the password)
            final char[] tempPassword = ((PasswordCallback) callbacks[2]).getPassword();
            password = tempPassword.clone();

            // clear the password in the callback
            ((PasswordCallback) callbacks[2]).clearPassword();
        } catch (java.io.IOException e) {
            cleanState();
            final String error = "Encountered an I/O exception during login";
            LOG.warn(error, e);
            throw Util.newLoginException(error, e);
        } catch (UnsupportedCallbackException e) {
            cleanState();
            final String error =
                    e.getCallback().toString() + " not available to garner authentication information from the user";
            LOG.warn(error, e);
            throw Util.newLoginException(error, e);
        }

        LOG.debug("Attempting login - discovered user '" + username + "@" + domain + "'");

        // Using a try/catch construct for managing control flows is really a bad idea.
        // Unfortunately, this is how JAAS works :-(
        try {
            // authenticate, and update state and pending subject if successful
            pendingSubject = pwAuthenticator.authenticate(domain, username, password, pwValidator);

            // then clear the password
            Cleanser.wipe(password);

            final String baseError = new StringBuilder().
                    append("Login successful for '").
                    append(username).
                    append("@").
                    append(domain).
                    toString();
            AuditHelper.auditEvent(audit, domain, username, Events.AUTHN_ATTEMPT,
                    baseError + "', but cannot audit login attempt, and hence fail the operation");
            MessageHelper.postMessage(messageQ, domain, username, Events.AUTHN_ATTEMPT,
                    baseError + "', but cannot post MQ login attempt event, and hence fail the operation");

            // string concatenation is only executed if log level is actually enabled
            if (LOG.isInfoEnabled()) {
                LOG.info("Login complete for '" + username + "@" + domain + "'");
            }
            return true;
        } catch (LoginException e) {
            // the login failed

            // cache the username and domain, for they will be purged by "cleanState()"
            final String tempUsername = username;
            final String tempDomain = domain;

            cleanState();

            final String baseError = new StringBuilder().
                    append("Login failed for '").
                    append(tempUsername).
                    append("@").
                    append(tempDomain).
                    toString();
            AuditHelper.auditEvent(audit, tempDomain, tempUsername, Events.AUTHN_FAILURE,
                    baseError + "', but cannot audit login attempt");
            MessageHelper.postMessage(messageQ, tempDomain, tempUsername, Events.AUTHN_FAILURE,
                    baseError + "', but cannot post MQ login attempt event");

            final String error = "Login failed for '" + tempUsername + "@" + tempDomain + "'";
            LOG.info(error, e);

            throw e;
        }
    }
{@inheritDoc}

@return {@code true} if authentication succeeds
@throws LoginException if this {@code LoginModule} is unable to perform the authentication. Catch a
{@link javax.security.auth.login.FailedLoginException} to determine if the authentication
failed (wrong username or password)