apereo/cas · error · FailedLoginException
Certificate subject does not match pattern
Error message
Certificate subject does not match pattern
What it means
X509CredentialsAuthenticationHandler.validate() only accepts end-entity certificates (basicConstraints pathLength < 0) whose subject DN matches the configured regExSubjectDnPattern. If the certificate's subject DN does not match, the credential is rejected with FailedLoginException.
Solutions
- Log the exact subject DN and update regExSubjectDnPattern to match it (mind component order and escaping of commas/spaces).
- Issue/obtain a client certificate whose subject DN conforms to the configured pattern.
- Use a permissive pattern such as '.*' if all subjects should be accepted.
- Enable debug logging on the handler to see the evaluated DN string.
Example fix
// before cas.authn.x509.reg-ex-subject-dn-pattern=CN=John Doe,OU=IT // after cas.authn.x509.reg-ex-subject-dn-pattern=CN=[^,]+,.*OU=IT.*
Defensive patterns
Strategy: validation
Validate before calling
String dn = cert.getSubjectX500Principal().getName();
if (dn == null || !Pattern.compile(configuredRegex).matcher(dn).matches()) { reject("subject DN not allowed"); } Type guard
boolean subjectAllowed(X509Certificate cert, Pattern p) {
return p.matcher(cert.getSubjectX500Principal().getName()).matches();
} Try / catch
try {
handler.authenticate(credential);
} catch (FailedLoginException e) {
// subject DN pattern mismatch: inspect cert.getSubjectX500Principal() vs configured regex
} Prevention
- Log the full subject DN and build the regex against its exact JDK rendering.
- Escape commas/spaces in DN components within the regex.
- Test the pattern against all certificates your CA issues.
- Keep the pattern as narrow as policy requires but verify with real certs.
When it happens
Trigger: A client presents a non-CA certificate whose subject DN does not match cas.authn.x509.regExSubjectDnPattern while isCertificateAllowed() is evaluated during authentication.
Common situations: Regex written with wrong DN component order (JDK renders DNs as 'CN=..., OU=..., O=...') or unescaped commas/spaces; a CA re-issues certs with different subject layout; a test client cert is used against a production pattern.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Certificate keyUsage constraint forbids SSL client…
- Unable to accept certificate
- No Certificates provided
- Expired or invalid certificate in metadata for
- Unlimited certificate path length not allowed by…
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/d1172c93cf2bda12.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-x509-core/src/main/java/org/apereo/cas/adaptors/x509/authentication/handler/support/X509CredentialsAuthenticationHandler.java:238
if (hasTrustedIssuer && clientCert != null) {
x509Credential.setCertificate(clientCert);
return new DefaultAuthenticationHandlerExecutionResult(this, x509Credential,
this.principalFactory.createPrincipal(x509Credential.getId()));
}
LOGGER.warn("Either client certificate could not be determined, or a trusted issuer could not be located");
throw new FailedLoginException();
}
private void validate(final X509Certificate cert) throws GeneralSecurityException {
cert.checkValidity();
this.revocationChecker.check(cert);
val pathLength = cert.getBasicConstraints();
if (pathLength < 0) {
if (!isCertificateAllowed(cert)) {
val msg = "Certificate subject does not match pattern " + this.regExSubjectDnPattern.pattern();
LOGGER.error(msg);
throw new FailedLoginException(msg);
}
if (this.checkKeyUsage && !isValidKeyUsage(cert)) {
val msg = "Certificate keyUsage constraint forbids SSL client authentication.";
LOGGER.error(msg);
throw new FailedLoginException(msg);
}
} else {
if (pathLength == Integer.MAX_VALUE && !this.maxPathLengthAllowUnspecified) {
val msg = "Unlimited certificate path length not allowed by configuration.";
LOGGER.error(msg);
throw new FailedLoginException(msg);
}
if (pathLength > this.maxPathLength && pathLength < Integer.MAX_VALUE) {
val msg = String.format("Certificate path length %s exceeds maximum value %s.", pathLength, this.maxPathLength);
LOGGER.error(msg);
throw new FailedLoginException(msg);
}
}View on GitHub (pinned to e7288fc434)