{"record":{"id":"d1172c93cf2bda12","repo":"apereo/cas","slug":"certificate-subject-does-not-match-pattern","errorCode":null,"errorMessage":"Certificate subject does not match pattern ","messagePattern":"Certificate subject does not match pattern ","errorType":"exception","errorClass":"FailedLoginException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-x509-core/src/main/java/org/apereo/cas/adaptors/x509/authentication/handler/support/X509CredentialsAuthenticationHandler.java","lineNumber":238,"sourceCode":"        if (hasTrustedIssuer && clientCert != null) {\n            x509Credential.setCertificate(clientCert);\n            return new DefaultAuthenticationHandlerExecutionResult(this, x509Credential,\n                this.principalFactory.createPrincipal(x509Credential.getId()));\n        }\n        LOGGER.warn(\"Either client certificate could not be determined, or a trusted issuer could not be located\");\n        throw new FailedLoginException();\n    }\n\n    private void validate(final X509Certificate cert) throws GeneralSecurityException {\n        cert.checkValidity();\n        this.revocationChecker.check(cert);\n\n        val pathLength = cert.getBasicConstraints();\n        if (pathLength < 0) {\n            if (!isCertificateAllowed(cert)) {\n                val msg = \"Certificate subject does not match pattern \" + this.regExSubjectDnPattern.pattern();\n                LOGGER.error(msg);\n                throw new FailedLoginException(msg);\n            }\n            if (this.checkKeyUsage && !isValidKeyUsage(cert)) {\n                val msg = \"Certificate keyUsage constraint forbids SSL client authentication.\";\n                LOGGER.error(msg);\n                throw new FailedLoginException(msg);\n            }\n        } else {\n            if (pathLength == Integer.MAX_VALUE && !this.maxPathLengthAllowUnspecified) {\n                val msg = \"Unlimited certificate path length not allowed by configuration.\";\n                LOGGER.error(msg);\n                throw new FailedLoginException(msg);\n            }\n            if (pathLength > this.maxPathLength && pathLength < Integer.MAX_VALUE) {\n                val msg = String.format(\"Certificate path length %s exceeds maximum value %s.\", pathLength, this.maxPathLength);\n                LOGGER.error(msg);\n                throw new FailedLoginException(msg);\n            }\n        }","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-x509-core/src/main/java/org/apereo/cas/adaptors/x509/authentication/handler/support/X509CredentialsAuthenticationHandler.java#L220-L256","documentation":"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.","triggerScenarios":"A client presents a non-CA certificate whose subject DN does not match cas.authn.x509.regExSubjectDnPattern while isCertificateAllowed() is evaluated during authentication.","commonSituations":"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.","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."],"exampleFix":"// before\ncas.authn.x509.reg-ex-subject-dn-pattern=CN=John Doe,OU=IT\n// after\ncas.authn.x509.reg-ex-subject-dn-pattern=CN=[^,]+,.*OU=IT.*","handlingStrategy":"validation","validationCode":"String dn = cert.getSubjectX500Principal().getName();\nif (dn == null || !Pattern.compile(configuredRegex).matcher(dn).matches()) { reject(\"subject DN not allowed\"); }","typeGuard":"boolean subjectAllowed(X509Certificate cert, Pattern p) {\n    return p.matcher(cert.getSubjectX500Principal().getName()).matches();\n}","tryCatchPattern":"try {\n    handler.authenticate(credential);\n} catch (FailedLoginException e) {\n    // subject DN pattern mismatch: inspect cert.getSubjectX500Principal() vs configured regex\n}","preventionTips":["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."],"tags":["x509","certificate","regex","authentication"],"backgroundTag":"certificate-subject-mismatch","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}