apereo/cas · error · FailedLoginException
Failed to authenticate user
Error message
Failed to authenticate user
What it means
StoredProcedureAuthenticationHandler calls the configured stored procedure with username/password and expects a 'status' output that is truthy. If the result map is empty or status evaluates false, FailedLoginException 'Failed to authenticate user' is thrown.
Solutions
- Inspect the debug log 'Procedure results are [...]' and confirm the actual key name; fix the procedure or the extraction to match it.
- Update the stored procedure to return status=1 on success.
- Verify procedureName matches the actual stored procedure and the user has EXECUTE permission.
- Confirm the function call parameters (username, password) match the procedure signature.
Example fix
// before: procedure outputs @status_value // after: name the output parameter 'status' in the procedure CREATE PROCEDURE auth_user(IN username VARCHAR, IN password VARCHAR, OUT status INT) BEGIN SELECT COUNT(*) INTO status FROM users WHERE ...; END;
Defensive patterns
Strategy: try-catch
Validate before calling
// Verify the procedure exists and is executable
jdbcTemplate.execute("CALL auth_user('probe','probe',@status)");
Integer status = jdbcTemplate.queryForObject("SELECT @status", Integer.class); Type guard
Object status = results.get("status");
if (status == null || !BooleanUtils.toBoolean(status.toString())) { throw new FailedLoginException(); } Try / catch
try { result = handler.authenticate(credential); }
catch (FailedLoginException e) { log.warn("Stored procedure auth returned failure: {}", e.getMessage()); } Prevention
- Ensure the procedure names its output parameter exactly 'status'.
- Grant EXECUTE permission to the CAS DB user.
- Log the full results map during initial integration.
When it happens
Trigger: SimpleJdbcCall.execute returns empty results, or the results map lacks a 'status' key, or status is '0'/'false' after BooleanUtils.toBoolean.
Common situations: Procedure returns keys with different case or naming (e.g. STATUS, return_status) so results.get("status") is null; procedure returns no result set on failure; procedure always returns 0 because of internal logic/schema drift.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- [e.getMessage()]
- Password does not match value on record.
- Password does not match value on record.
- Password has expired
- [username] not found with SQL query.
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/e5acb1205f2b486a.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-jdbc-authentication/src/main/java/org/apereo/cas/jdbc/StoredProcedureAuthenticationHandler.java:40
public class StoredProcedureAuthenticationHandler extends AbstractJdbcUsernamePasswordAuthenticationHandler<ProcedureJdbcAuthenticationProperties> {
public StoredProcedureAuthenticationHandler(
final ProcedureJdbcAuthenticationProperties properties,
final PrincipalFactory principalFactory, final DataSource dataSource) {
super(properties, principalFactory, dataSource);
}
@Override
protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(
final UsernamePasswordCredential credential, final String originalPassword) throws Throwable {
val username = credential.getUsername();
val password = credential.toPassword();
val jdbcCall = new SimpleJdbcCall(jdbcTemplate).withProcedureName(properties.getProcedureName());
val results = jdbcCall.execute(Map.of("username", username, "password", password));
LOGGER.debug("Procedure results are [{}]", results);
if (results.isEmpty() || !BooleanUtils.toBoolean(results.get("status").toString())) {
throw new FailedLoginException("Failed to authenticate user");
}
val principal = principalFactory.createPrincipal(username, CollectionUtils.toMultiValuedMap(results));
return createHandlerResult(credential, principal, new ArrayList<>());
}
}
View on GitHub (pinned to e7288fc434)