{"record":{"id":"2bdccfc3388436ea","repo":"apereo/cas","slug":"either-client-certificate-could-not-be-determined","errorCode":null,"errorMessage":"Either client certificate could not be determined, or a trusted issuer could not be located","messagePattern":"Either client certificate could not be determined, or a trusted issuer could not be located","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":225,"sourceCode":"\n            if (!hasTrustedIssuer) {\n                hasTrustedIssuer = isCertificateFromTrustedIssuer(certificate);\n            }\n\n            val pathLength = certificate.getBasicConstraints();\n            if (pathLength < 0) {\n                LOGGER.debug(\"Found valid client certificate\");\n                clientCert = certificate;\n            } else {\n                LOGGER.debug(\"Found valid CA certificate\");\n            }\n        }\n        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);","sourceCodeStart":207,"sourceCodeEnd":243,"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#L207-L243","documentation":"X509CredentialsAuthenticationHandler could not complete X.509 authentication because either no client certificate could be extracted from the presented credentials or the certificate was not issued by a trusted issuer in the configured trust store. The handler logs a warning and throws FailedLoginException, failing the authentication attempt.","triggerScenarios":"doAuthentication checks hasTrustedIssuer (the certificate's issuer is in the configured trust managers) and clientCert != null; if either condition is false - e.g. trustManagers are null because none were configured, the issuer is not in the trust store, or the client certificate could not be determined from the X509CertificateCredential - this branch logs and throws.","commonSituations":"TLS mutual-auth config sets the client auth to optional and the browser/app sends no client certificate; the CA that signed the client cert is missing from the configured trustStore (keystore); intermediate CA not imported so chain validation fails; misconfigured cas.authn.x509 trust store settings.","solutions":["Import the issuing CA (and intermediates) of the client certificate into the configured X.509 trust store/keystore so hasTrustedIssuer becomes true.","Ensure the TLS connector/web server actually requests and forwards the client certificate (clientAuth=want/need and correct header forwarding behind proxies).","Check cas.authn.x509 trust store configuration paths and passwords; confirm the trust managers are properly initialized rather than null.","Enable debug logging in X509CredentialsAuthenticationHandler and inspect why clientCert extraction or issuer validation failed, then fix the specific mismatch."],"exampleFix":"// before: clientAuth=\"false\" on the Tomcat connector\n<Connector ... clientAuth=\"want\" truststoreFile=\"/etc/cas/truststore.jks\" />\n// after\n<Connector ... clientAuth=\"true\" truststoreFile=\"/etc/cas/truststore.jks\" />","handlingStrategy":"validation","validationCode":"// Guard before invoking the handler:\nval certs = x509Credential.getCertificates();\nif (certs == null || certs.length == 0) {\n    throw new FailedLoginException(\"No client certificate presented\");\n}\nval issuerDn = certs[0].getIssuerX500Principal().getName();\nif (!trustedIssuers.contains(issuerDn)) {\n    throw new FailedLoginException(\"Issuer not trusted: \" + issuerDn);\n}","typeGuard":null,"tryCatchPattern":"try {\n    return handler.authenticate(x509Credential);\n} catch (FailedLoginException e) {\n    logger.warn(\"X509 authentication failed: check client cert presence and trust store\", e);\n    throw e;\n}","preventionTips":["Import the full CA chain (root + intermediates) into the X.509 trust store.","Set the web server/TLS connector to require client certificates where mTLS is mandatory.","Forward the client certificate header correctly when terminating TLS on a reverse proxy.","Keep trust-store configuration per-environment validated in deployment checks."],"tags":["x509","certificate-authentication","trust-store","failed-login"],"backgroundTag":"missing-credentials","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"}