apereo/cas · error · FailedLoginException
NTLM not allowed
Error message
NTLM not allowed
What it means
JcifsSpnegoAuthenticationHandler validates SPNEGO/Kerberos tokens via JCIFS. When the incoming SPNEGO credential carries an NTLM token but spnegoProperties.isNtlmAllowed() is false, the handler immediately fails authentication with FailedLoginException because NTLM is a weaker protocol than Kerberos and is disabled by policy.
Solutions
- Set cas.authn.spnego.ntlm-allowed=true if NTLM fallback is acceptable in your environment.
- Fix client-side Kerberos: ensure the client is domain-joined, can reach the KDC, and SPNs for the CAS hostname are registered correctly.
- Configure browsers to enable integrated Windows authentication for the CAS host so proper Kerberos tokens are sent.
- Exclude the CAS host from IE/Chrome local-intranet exceptions that force NTLM.
Example fix
// before cas.authn.spnego.ntlm-allowed=false // after (if NTLM fallback is acceptable) cas.authn.spnego.ntlm-allowed=true
Defensive patterns
Strategy: validation
Validate before calling
// before enabling, verify clients can produce Kerberos tokens // on a Windows client: klist must show a TGT for the domain klist get krbtgt/CORP.LOCAL
Prevention
- Set ntlm-allowed=false deliberately and ensure all clients are domain-joined
- Register SPNs for the CAS hostname so clients use Kerberos, not NTLM
- Configure browsers' intranet/integrated-auth settings via GPO
- Monitor failed logins with 'NTLM not allowed' to find downgrade-prone clients
When it happens
Trigger: A Windows client that is not domain-joined (or cannot reach the KDC) falls back to NTLM and sends an NTLM token (starting with 'NTLMSSP') while cas.authn.spnego.ntlmAllowed=false.
Common situations: Client machine off the corporate network/VPN so Kerberos fails and the browser downgrades to NTLM; browser not configured for integrated Windows auth against the CAS host; spnego/kerberos KDC unreachable causing NTLM fallback.
Related errors
- Principal is null, the processing of the SPNEGO Token failed
- Cannot get connection from pool to validate SPNEGO Token
- User Agent header [ ] is empty, or no browsers are supported
- SPNEGO Authorization header is not found under
- SPNEGO Authorization header
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/57f9b725b091900d.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-spnego/src/main/java/org/apereo/cas/support/spnego/authentication/handler/support/JcifsSpnegoAuthenticationHandler.java:51
public class JcifsSpnegoAuthenticationHandler extends AbstractPreAndPostProcessingAuthenticationHandler {
private final BlockingQueue<List<Authentication>> authenticationsPool;
private final SpnegoProperties spnegoProperties;
public JcifsSpnegoAuthenticationHandler(final SpnegoProperties spnegoProperties,
final PrincipalFactory principalFactory,
final BlockingQueue<List<Authentication>> authenticationsPool) {
super(spnegoProperties.getName(), principalFactory, spnegoProperties.getOrder());
this.spnegoProperties = spnegoProperties;
this.authenticationsPool = authenticationsPool;
}
@Override
protected AuthenticationHandlerExecutionResult doAuthentication(final Credential credential, final Service service) throws Throwable {
val spnegoCredential = (SpnegoCredential) credential;
if (!spnegoProperties.isNtlmAllowed() && spnegoCredential.isNtlm()) {
throw new FailedLoginException("NTLM not allowed");
}
try {
LOGGER.debug("Waiting for connection to validate SPNEGO Token");
val poolTimeoutInMilliseconds = Beans.newDuration(spnegoProperties.getPoolTimeout()).toMillis();
val authentications = authenticationsPool.poll(poolTimeoutInMilliseconds, TimeUnit.MILLISECONDS);
if (authentications != null) {
try {
return doInternalAuthentication(authentications, spnegoCredential, service);
} finally {
authenticationsPool.add(authentications);
LOGGER.debug("Returned connection to pool");
}
}
throw new FailedLoginException("Cannot get connection from pool to validate SPNEGO Token");
} catch (final InterruptedException e) {
throw new FailedLoginException("Thread interrupted while waiting for connection to validate SPNEGO Token");
}View on GitHub (pinned to e7288fc434)