apereo/cas · error · FailedLoginException

Authentication has failed because LDAP password policy…

Error message

Authentication has failed because LDAP password policy handling strategy [{}] cannot handle [{}].

What it means

This error is thrown by CAS's LDAP authentication handler when the configured password policy handling strategy does not support the LdapAuthenticationResponse returned by the directory. The strategy (e.g. GNUPasswordPolicy, ActiveDirectory) can only interpret specific response/controls; when it cannot handle the response, CAS treats the attempt as a failed login and throws FailedLoginException. It usually signals a mismatch between the directory type and the configured passwordPolicyHandlingStrategy.

Solutions

  1. Set the password policy type (cas.authn.ldap[0].password-policy.type) to a strategy matching your directory (AD, FreeIPA, GNU, or default/custom)
  2. Enable the password policy request control on the LDAP connection (enablePasswordPolicyControls / connection pool controls) so the response carries data the strategy supports
  3. Inspect the logged 'LDAP response: [{}]' debug line to see what the response actually contains and adjust the strategy accordingly
  4. If policy handling is not needed, use the default strategy that accepts any response
  5. Update any custom PasswordPolicyHandlingStrategy so supports() matches the response types your server returns

Example fix

// before
cas.authn.ldap[0].password-policy.type=ActiveDirectory
// against OpenLDAP
// after
cas.authn.ldap[0].password-policy.type=GNU
cas.authn.ldap[0].password-policy.warning-attribute-display=false
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check strategy/response compatibility before login attempts
if (!ldapPasswordPolicyStrategy.supports(response)) {
    LOGGER.warn("Strategy {} cannot handle response {}; reconfigure cas.authn.ldap[0].password-policy.type",
        ldapPasswordPolicyStrategy.getClass().getSimpleName(), response.getAuthenticationResultCode());
}

Type guard

if (response != null && passwordPolicyHandlingStrategy.supports(response)) {
    // safe to call handle()
}

Try / catch

try {
    return handler.authenticate(credential);
} catch (FailedLoginException e) {
    LOGGER.warn("LDAP login rejected: {} — verify password-policy strategy matches directory controls", e.getMessage());
    return AuthenticationResult.FAILED;
}

Prevention

When it happens

Trigger: A login attempt reaches LdapAuthenticationHandler.authenticateUsernamePasswordInternal, getLdapAuthenticationResponse returns a response, and passwordPolicyHandlingStrategy.supports(response) returns false — e.g. strategy set to a specific policy type while the bind result carries no policy request/response controls, or using the GNU/AD strategy against a directory that returns none of the expected controls.

Common situations: Setting cas.authn.ldap[0].password-policy.type to an ActiveDirectory-specific strategy while authenticating against OpenLDAP (or vice versa); customizing the strategy class whose supports() rejects null/empty responses; LDAP server upgraded and stopped returning password-policy controls; strategy misconfigured for the authentication method (anonymous bind vs password comparison).

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-ldap-core/src/main/java/org/apereo/cas/authentication/LdapAuthenticationHandler.java:122

            LOGGER.debug("Configured to retrieve principal id attribute [{}]", this.principalIdAttribute);
            attributes.add(this.principalIdAttribute);
        }
        if (this.principalAttributeMap != null && !this.principalAttributeMap.isEmpty()) {
            val attrs = this.principalAttributeMap.keySet();
            attributes.addAll(attrs);
            LOGGER.debug("Configured to retrieve principal attribute collection of [{}]", attrs);
        }
        this.authenticatedEntryAttributes = attributes.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
        LOGGER.debug("LDAP authentication entry attributes for the authentication request are [{}]", (Object[]) this.authenticatedEntryAttributes);
    }

    @Override
    protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(final UsernamePasswordCredential upc,
                                                                                        @Nullable final String originalPassword) throws Throwable {
        val response = getLdapAuthenticationResponse(upc);
        LOGGER.debug("LDAP response: [{}]", response);
        if (!passwordPolicyHandlingStrategy.supports(response)) {
            LOGGER.warn("Authentication has failed because LDAP password policy handling strategy [{}] cannot handle [{}].",
                response, passwordPolicyHandlingStrategy.getClass().getSimpleName());
            throw new FailedLoginException("Invalid credentials");
        }
        LOGGER.debug("Attempting to examine and handle LDAP password policy via [{}]",
            passwordPolicyHandlingStrategy.getClass().getSimpleName());
        val messageList = passwordPolicyHandlingStrategy.handle(response, getPasswordPolicyConfiguration());
        if (response.isSuccess()) {
            LOGGER.debug("LDAP response returned a result [{}], creating the final LDAP principal", response.getLdapEntry());
            val principal = createPrincipal(upc.getUsername(), response.getLdapEntry());
            return createHandlerResult(upc, principal, messageList);
        }
        if (AuthenticationResultCode.DN_RESOLUTION_FAILURE == response.getAuthenticationResultCode()) {
            LOGGER.warn("DN resolution failed. [{}]", response.getDiagnosticMessage());
            throw new AccountNotFoundException(upc.getUsername() + " not found.");
        }
        throw new FailedLoginException("Invalid credentials");
    }

View on GitHub (pinned to e7288fc434)