apereo/cas · error · FailedLoginException

Invalid credentials

Error message

Invalid credentials

What it means

LdapAuthenticationHandler asks the configured password policy handling strategy whether it can interpret the ldaptive AuthenticationResponse. If strategy.supports(response) is false, the handler gives up and throws FailedLoginException 'Invalid credentials', even though the bind may otherwise have succeeded.

Solutions

  1. Switch passwordPolicyHandlingStrategy to DEFAULT (or the strategy matching your directory, e.g. AD-specific one for Active Directory).
  2. Confirm the ldap authType (AD/DIRECT/BIND/SEARCH) matches the actual directory server.
  3. Check the warning log line naming the unsupported strategy and response to see the mismatch.
  4. Upgrade/align the ldaptive library version so the response type is recognized.

Example fix

// before
cas.authn.ldap[0].password-policy-strategy= GrooviePasswordPolicyHandlingStrategy
// after
cas.authn.ldap[0].password-policy-strategy=DEFAULT
Defensive patterns

Strategy: try-catch

Try / catch

try { result = handler.authenticate(credential); }
catch (FailedLoginException e) {
  if ("Invalid credentials".equals(e.getMessage())) { checkLdapPolicyStrategyConfig(); }
}

Prevention

When it happens

Trigger: cas.authn.ldap[].passwordPolicyHandlingStrategy is set to a strategy (e.g. GROOWIE, EXTENDED) whose response type does not match the response produced by the configured authenticator/type (AD vs generic LDAP).

Common situations: Configuring AD-specific password policy strategy against a non-Active Directory directory; custom authenticator returning responses the strategy cannot parse; copy-pasted LDAP config between server types.

Understand the failure class

Related errors


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

Appendix: source

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

        }
        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");
    }

    /**
     * Creates a CAS principal with attributes if the LDAP entry contains principal attributes.

View on GitHub (pinned to e7288fc434)