apereo/cas · error · FailedLoginException

Password is null.

Error message

Password is null.

What it means

transformPassword in AbstractUsernamePasswordAuthenticationHandler throws FailedLoginException when the credential's password is blank before any encoding is attempted. CAS treats a missing password as an outright login failure rather than running it through the PasswordEncoder.

Solutions

  1. Require and validate a non-empty password in the form/webflow before calling the handler.
  2. Check that the extractor maps the password request parameter correctly (form field name typos).
  3. Fix REST/API clients to include the password in the request payload.
  4. Inspect any custom code that mutates the credential before authentication and may blank the password.
  5. If the password arrives encrypted, ensure decryption preprocessing hasn't produced an empty value.

Example fix

// before
val cred = new UsernamePasswordCredential(username, "");
// after
if (StringUtils.isBlank(password)) { throw new BindException("password required"); }
val cred = new UsernamePasswordCredential(username, password);
Defensive patterns

Strategy: validation

Validate before calling

// before authentication
if (password == null || password.isEmpty()) {
    throw new IllegalArgumentException("password is required");
}

Try / catch

try {
    return handler.authenticate(credential, service);
} catch (FailedLoginException e) {
    if (e.getMessage() != null && e.getMessage().contains("Password is null")) {
        LOGGER.error("Empty password credential reached the handler; check extractor/form binding");
    }
    throw new BadCredentialsAuthenticationException();
}

Prevention

When it happens

Trigger: doAuthentication -> authenticateUsernamePasswordInternal path invokes transformPassword with a UsernamePasswordCredential whose toPassword() returns null or empty — i.e. the password field was absent, empty, or never bound into the credential.

Common situations: Login form submitted with empty password field; password parameter name mismatch between form and extractor; API/REST authentication clients omitting the password attribute; password stripped by prior custom processing.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/cc8e237cdc8e574c. Report an issue: GitHub.

Appendix: source

Thrown at core/cas-server-core-authentication-api/src/main/java/org/apereo/cas/authentication/handler/support/AbstractUsernamePasswordAuthenticationHandler.java:83

    @Override
    public boolean supports(final Class<? extends Credential> clazz) {
        return UsernamePasswordCredential.class.isAssignableFrom(clazz);
    }

    @Override
    protected AuthenticationHandlerExecutionResult doAuthentication(final Credential credential, final Service service) throws Throwable {
        val originalUserPass = (UsernamePasswordCredential) credential;
        val userPass = new UsernamePasswordCredential();
        FunctionUtils.doUnchecked(_ -> BeanUtils.copyProperties(userPass, originalUserPass));
        transformUsername(userPass);
        transformPassword(userPass);
        LOGGER.debug("Attempting authentication internally for transformed credential [{}]", userPass);
        return authenticateUsernamePasswordInternal(userPass, originalUserPass.toPassword());
    }

    protected void transformPassword(final UsernamePasswordCredential userPass) throws FailedLoginException, AccountNotFoundException {
        if (StringUtils.isBlank(userPass.toPassword())) {
            throw new FailedLoginException("Password is null.");
        }
        LOGGER.debug("Attempting to encode credential password via [{}] for [{}]", passwordEncoder.getClass().getName(), userPass.getUsername());
        val transformedPsw = passwordEncoder.encode(userPass.toPassword());
        if (StringUtils.isBlank(transformedPsw)) {
            throw new AccountNotFoundException("Encoded password is null.");
        }
        userPass.assignPassword(transformedPsw);
    }
    
    /**
     * Authenticates a username/password credential by an arbitrary strategy with extra parameter original credential password before
     * encoding password. Override it if implementation need to use original password for authentication.
     *
     * @param credential       the credential object bearing the transformed username and password.
     * @param originalPassword original password from credential before password encoding
     * @return AuthenticationHandlerExecutionResult resolved from credential on authentication success or null if no principal could be resolved from the credential.
     * @throws Throwable the throwable
     */

View on GitHub (pinned to e7288fc434)