{"record":{"id":"0a8397089d3c5486","repo":"apereo/cas","slug":"unable-to-accept-certificate","errorCode":null,"errorMessage":"Unable to accept certificate","messagePattern":"Unable to accept certificate","errorType":"exception","errorClass":"CredentialsException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-oauth-core-api/src/main/java/org/apereo/cas/support/oauth/authenticator/OAuth20X509Authenticator.java","lineNumber":79,"sourceCode":"            val profile = result.get().getUserProfile();\n            val certificate = ((X509Credentials) credentials).getCertificate();\n            val digest = EncodingUtils.encodeBase64(DigestUtils.digest(\"SHA-256\", certificate.getPublicKey().getEncoded()));\n            profile.addAttribute(OAuth20Constants.X509_CERTIFICATE_DIGEST, digest);\n            profile.addAttribute(AuthenticationManager.AUTHENTICATION_METHOD_ATTRIBUTE, \"X.509\");\n            profile.addAttribute(OAuth20Constants.CLIENT_ID, registeredService.getClientId());\n\n            val attributeMap = CollectionUtils.<String, String>wrap(\n                \"x509-sanEmail\", registeredService.getTlsClientAuthSanEmail(),\n                \"x509-sanDNS\", registeredService.getTlsClientAuthSanDns(),\n                \"x509-sanIP\", registeredService.getTlsClientAuthSanIp(),\n                \"x509-sanURI\", registeredService.getTlsClientAuthSanUri()\n            );\n            val accepted = attributeMap\n                .entrySet()\n                .stream()\n                .allMatch(entry -> isAcceptableX509Attribute(profile, entry.getKey(), entry.getValue()));\n            if (!accepted) {\n                throw new CredentialsException(\"Unable to accept certificate\");\n            }\n        }\n\n        return result;\n    }\n\n    protected @Nullable OAuthRegisteredService locateRegisteredService(\n        final CallContext ctx, final Credentials credentials) {\n        if (credentials instanceof final X509Credentials x509Credentials) {\n            val certificate = x509Credentials.getCertificate();\n            val subjectAltNames = FunctionUtils.doUnchecked(certificate::getSubjectAlternativeNames);\n            if (subjectAltNames != null) {\n                val spiffeEntries = new ArrayList<String>();\n                subjectAltNames.forEach(altName -> {\n                    altName.stream()\n                        .filter(String.class::isInstance)\n                        .map(String.class::cast)\n                        .filter(name -> Strings.CI.startsWith(name, SUBJECT_ALT_NAME_SPIFFE_PREFIX))","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oauth-core-api/src/main/java/org/apereo/cas/support/oauth/authenticator/OAuth20X509Authenticator.java#L61-L97","documentation":"Thrown by the X.509 client-certificate authenticator when one or more certificate attributes (configured required attributes) extracted from the presented TLS certificate do not match the acceptable values defined by the registered service. The certificate itself parsed and a profile was built, but attribute-level policy rejected it.","triggerScenarios":"Mutual-TLS request presents a client certificate whose subject/issuer/SAN/RFC822 attributes fail isAcceptableX509Attribute checks against the registered service's required certificate attribute map — any non-matching attribute makes the allMatch predicate false.","commonSituations":"Certificate reissued with a different subject DN or email SAN than what the service requires; DN formatting differences (spaces, ordering, escaped characters) breaking exact-string comparison; service registry configured with overly strict expected attribute values; expired/reissued certs after CA migration.","solutions":["Compare the actual certificate attributes (openssl x509 -text) against the required attribute map in the registered service and update the registry to match the real DN format","Normalize DN configuration (ordering of RDNs, spacing) to the exact string CAS extracts","Reissue or obtain a client certificate containing the required attributes (e.g. correct email SAN)","Relax or correct the acceptable-attribute configuration if it is unnecessarily strict"],"exampleFix":"// before\n\"requiredAttributes\": { \"subjectDN\": \"CN=Alice, OU=Org, O=Company\" }\n// after\n\"requiredAttributes\": { \"subjectDN\": \"CN=Alice,OU=Org,O=Company\" }","handlingStrategy":"validation","validationCode":"const cert = req.socket.getPeerCertificate();\nif (!cert || !cert.subject) throw new Error('mTLS client certificate required and must carry the attributes configured on the service');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Match the registered service's expected DN strings exactly to the issued certificate format","Include required SANs (e.g. email) when reissuing certificates","Re-verify certificate contents after any CA or issuance-policy change"],"tags":["oauth2","x509","mtls","certificate"],"backgroundTag":"insufficient-permissions","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"}