apereo/cas · error · AccountDisabledException

Could not authenticate forbidden account for

Error message

Could not authenticate forbidden account for 

What it means

SyncopeAuthenticationHandler.authenticateUsernamePasswordInternal throws AccountDisabledException when the Syncope user JSON response contains "suspended": true. The account exists and the password was accepted (or at least the user was found), but Syncope marks the account suspended so CAS refuses authentication as a disabled account.

Solutions

  1. Unsuspend the account in the Apache Syncope admin console (or via Syncope REST: PATCH /users/{key} setting suspended=false)
  2. Check Syncope workflow/policies that auto-suspend users and adjust them
  3. Verify you are querying the right Syncope domain/realm so the unsuspended user is the one returned
  4. As a last resort, deactivate CAS-based login for that user in Syncope rather than repeatedly hitting the disabled state

Example fix

// before (Syncope console) user.status = suspended
// after (Syncope REST)
PATCH /syncope/rest/users/{key} {"type":"USER","operation":"DEPROVISION","suspended":false}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check via Syncope REST before CAS login
GET /syncope/rest/users?FIQLString=username=={u}
if (user.suspended) throw new AccountDisabledException("suspended in Syncope");

Try / catch

try {
    return authenticationManager.authenticate(transaction);
} catch (AccountDisabledException e) {
    model.put("errorCode", "account.disabled");
    return "casAccountDisabledView";
}

Prevention

When it happens

Trigger: Calling the authentication handler (standard CAS username/password flow) where authenticateSyncopeUser returns a user object with field suspended == true.

Common situations: Syncope admin suspended the user for policy or inactivity; user status 'suspended' in Syncope console; password resets not processed so account remains suspended; testing with a seeded demo user that is suspended.

Understand the failure class

Related errors


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

Appendix: source

Thrown at support/cas-server-support-syncope-authentication/src/main/java/org/apereo/cas/syncope/SyncopeAuthenticationHandler.java:62

    private final String syncopeDomain;

    public SyncopeAuthenticationHandler(final SyncopeAuthenticationProperties properties,
                                        final PrincipalFactory principalFactory,
                                        final String syncopeDomain) {
        super(properties.getName(), principalFactory, properties.getOrder());
        this.properties = properties;
        this.syncopeDomain = syncopeDomain;
    }

    @Override
    protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(
        final UsernamePasswordCredential credential, @Nullable final String originalPassword) throws Throwable {
        val result = authenticateSyncopeUser(credential);
        if (result.isPresent()) {
            val user = result.get();
            LOGGER.debug("Received Syncope user object as [{}]", user);
            if (user.has("suspended") && user.get("suspended").asBoolean()) {
                throw new AccountDisabledException(
                    "Could not authenticate forbidden account for " + credential.getUsername());
            }
            if (user.has("mustChangePassword") && user.get("mustChangePassword").asBoolean()) {
                throw new AccountPasswordMustChangeException(
                    "Account password must change for " + credential.getUsername());
            }
            val principalAttributes = SyncopeUtils.convertFromUserEntity(user, properties.getAttributeMappings());
            val name = properties.getAttributeMappings().getOrDefault("domain", "syncopeDomain");
            principalAttributes.put(name, CollectionUtils.wrapList(syncopeDomain));
            val principal = principalFactory.createPrincipal(user.get("username").asString(), principalAttributes);
            return createHandlerResult(credential, principal, new ArrayList<>());
        }
        throw new FailedLoginException("Could not authenticate account for " + credential.getUsername());
    }

    protected Optional<JsonNode> authenticateSyncopeUser(final UsernamePasswordCredential credential) {
        HttpResponse response = null;
        try {

View on GitHub (pinned to e7288fc434)